aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit55f4e4a5ec657a017e3bf75299ad71fd1c968dd3 (patch)
tree550ce922ea0e125ac6a9738210ce2939bf2fe901
parent413f05aaf54fa08c0ae7e997327a4f4a473c0a8d (diff)
downloadexternal_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.zip
external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.gz
external_qemu-55f4e4a5ec657a017e3bf75299ad71fd1c968dd3.tar.bz2
Initial Contribution
-rw-r--r--.cvsignore42
-rw-r--r--Android.mk10
-rw-r--r--CHANGES.TXT533
-rw-r--r--MODULE_LICENSE_GPL0
-rw-r--r--Makefile40
-rw-r--r--Makefile.android454
-rw-r--r--Makefile.target407
-rw-r--r--NOTICE339
-rw-r--r--README14
-rw-r--r--aes.h47
-rw-r--r--alpha-dis.c1960
-rwxr-xr-xandroid-rebuild.sh265
-rw-r--r--android.h105
-rw-r--r--android/config/config.h14
-rw-r--r--android/config/darwin-ppc/config-host.h13
-rw-r--r--android/config/darwin-x86/config-host.h13
-rw-r--r--android/config/linux-x86/config-host.h10
-rw-r--r--android/config/windows/config-host.h10
-rw-r--r--android_avm.c42
-rw-r--r--android_avm.h39
-rw-r--r--android_charmap.c148
-rw-r--r--android_charmap.h133
-rw-r--r--android_config.c471
-rw-r--r--android_config.h57
-rw-r--r--android_console.c2134
-rw-r--r--android_debug.c141
-rw-r--r--android_debug.h89
-rw-r--r--android_events.c222
-rw-r--r--android_events.h184
-rw-r--r--android_gps.c36
-rw-r--r--android_gps.h23
-rw-r--r--android_help.c1246
-rw-r--r--android_help.h36
-rw-r--r--android_icons.h984
-rw-r--r--android_kmsg.c69
-rw-r--r--android_kmsg.h31
-rw-r--r--android_main.c2620
-rw-r--r--android_option.c240
-rw-r--r--android_option.h42
-rw-r--r--android_options.h126
-rw-r--r--android_profile.c127
-rw-r--r--android_profile.h34
-rw-r--r--android_qemud.c497
-rw-r--r--android_qemud.h71
-rw-r--r--android_resource.c64
-rw-r--r--android_resource.h26
-rw-r--r--android_timezone.c720
-rw-r--r--android_timezone.h33
-rw-r--r--android_utils.c1764
-rw-r--r--android_utils.h404
-rw-r--r--audio/alsaaudio.c215
-rw-r--r--audio/audio.c349
-rw-r--r--audio/audio.h11
-rw-r--r--audio/audio_int.h8
-rw-r--r--audio/audio_pt_int.c149
-rw-r--r--audio/audio_pt_int.h22
-rw-r--r--audio/audio_template.h15
-rw-r--r--audio/coreaudio.c696
-rw-r--r--audio/dsoundaudio.c2
-rw-r--r--audio/esdaudio.c692
-rw-r--r--audio/noaudio.c2
-rw-r--r--audio/ossaudio.c2
-rw-r--r--audio/sdlaudio.c241
-rw-r--r--audio/wavaudio.c265
-rw-r--r--audio/wavcapture.c6
-rw-r--r--audio/winaudio.c668
-rw-r--r--block-bochs.c224
-rw-r--r--block-cow.c271
-rw-r--r--block-vmdk.c446
-rw-r--r--block-vpc.c242
-rw-r--r--block-vvfat.c72
-rw-r--r--block.c71
-rw-r--r--cbuffer.c231
-rw-r--r--cbuffer.h61
-rw-r--r--charpipe.c298
-rw-r--r--charpipe.h26
-rwxr-xr-xconfigure308
-rw-r--r--console.c72
-rw-r--r--cpu-all.h8
-rw-r--r--cpu-exec.c191
-rw-r--r--dcache.c342
-rw-r--r--dcache.h24
-rw-r--r--distrib/Makefile8
-rw-r--r--distrib/README50
-rwxr-xr-xdistrib/build-emulator.sh37
-rwxr-xr-xdistrib/build_gcc_qemu_darwin.sh482
-rw-r--r--distrib/libpng-1.2.19/Makefile25
-rw-r--r--distrib/libpng-1.2.19/png.c895
-rw-r--r--distrib/libpng-1.2.19/png.h3525
-rw-r--r--distrib/libpng-1.2.19/pngconf.h1535
-rw-r--r--distrib/libpng-1.2.19/pngerror.c326
-rw-r--r--distrib/libpng-1.2.19/pnggccrd.c6041
-rw-r--r--distrib/libpng-1.2.19/pngget.c962
-rw-r--r--distrib/libpng-1.2.19/pngmem.c608
-rw-r--r--distrib/libpng-1.2.19/pngpread.c1585
-rw-r--r--distrib/libpng-1.2.19/pngread.c1478
-rw-r--r--distrib/libpng-1.2.19/pngrio.c167
-rw-r--r--distrib/libpng-1.2.19/pngrtran.c4284
-rw-r--r--distrib/libpng-1.2.19/pngrutil.c4189
-rw-r--r--distrib/libpng-1.2.19/pngset.c1284
-rw-r--r--distrib/libpng-1.2.19/pngtrans.c662
-rw-r--r--distrib/libpng-1.2.19/pngvcrd.c3922
-rw-r--r--distrib/libpng-1.2.19/pngwio.c234
-rw-r--r--distrib/libpng-1.2.19/pngwrite.c1530
-rw-r--r--distrib/libpng-1.2.19/pngwtran.c572
-rw-r--r--distrib/libpng-1.2.19/pngwutil.c2782
-rw-r--r--distrib/libpng-1.2.19/sources.make14
-rwxr-xr-xdistrib/make-distrib.sh112
-rwxr-xr-xdistrib/update-audio.sh85
-rw-r--r--distrib/zlib-1.2.3/Makefile15
-rw-r--r--distrib/zlib-1.2.3/adler32.c149
-rw-r--r--distrib/zlib-1.2.3/compress.c79
-rwxr-xr-xdistrib/zlib-1.2.3/configure459
-rw-r--r--distrib/zlib-1.2.3/crc32.c423
-rw-r--r--distrib/zlib-1.2.3/crc32.h441
-rw-r--r--distrib/zlib-1.2.3/deflate.c1736
-rw-r--r--distrib/zlib-1.2.3/deflate.h331
-rw-r--r--distrib/zlib-1.2.3/gzio.c1026
-rw-r--r--distrib/zlib-1.2.3/infback.c623
-rw-r--r--distrib/zlib-1.2.3/inffast.c318
-rw-r--r--distrib/zlib-1.2.3/inffast.h11
-rw-r--r--distrib/zlib-1.2.3/inffixed.h94
-rw-r--r--distrib/zlib-1.2.3/inflate.c1368
-rw-r--r--distrib/zlib-1.2.3/inflate.h115
-rw-r--r--distrib/zlib-1.2.3/inftrees.c329
-rw-r--r--distrib/zlib-1.2.3/inftrees.h55
-rw-r--r--distrib/zlib-1.2.3/sources.make4
-rw-r--r--distrib/zlib-1.2.3/trees.c1219
-rw-r--r--distrib/zlib-1.2.3/trees.h128
-rw-r--r--distrib/zlib-1.2.3/uncompr.c61
-rw-r--r--distrib/zlib-1.2.3/zconf.h332
-rw-r--r--distrib/zlib-1.2.3/zlib.h1357
-rw-r--r--distrib/zlib-1.2.3/zutil.c318
-rw-r--r--distrib/zlib-1.2.3/zutil.h269
-rw-r--r--dyngen-exec.h49
-rw-r--r--dyngen.c1428
-rw-r--r--elf.h2
-rw-r--r--exec-all.h25
-rw-r--r--fpu/softfloat.c2
-rw-r--r--fpu/softfloat.h4
-rw-r--r--framebuffer.c243
-rw-r--r--framebuffer.h149
-rw-r--r--gdbstub.c17
-rw-r--r--gen-charmap.py180
-rwxr-xr-xgen-skin.py78
-rw-r--r--hpet.h22
-rw-r--r--hw/acpi-dsdt.dsl559
-rw-r--r--hw/acpi-dsdt.hex278
-rw-r--r--hw/acpi.c615
-rw-r--r--hw/adb.c410
-rw-r--r--hw/adlib.c341
-rw-r--r--hw/android_arm.c149
-rw-r--r--hw/apb_pci.c232
-rw-r--r--hw/apic.c1042
-rw-r--r--hw/arm_pic.c43
-rw-r--r--hw/arm_pic.h6
-rw-r--r--hw/arm_timer.c383
-rw-r--r--hw/cirrus_vga.c3193
-rw-r--r--hw/cirrus_vga_rop.h78
-rw-r--r--hw/cirrus_vga_rop2.h281
-rw-r--r--hw/cuda.c656
-rw-r--r--hw/es1370.c1062
-rw-r--r--hw/esp.c571
-rw-r--r--hw/fdc.c1757
-rw-r--r--hw/fmopl.c1390
-rw-r--r--hw/fmopl.h174
-rw-r--r--hw/goldfish_audio.c521
-rw-r--r--hw/goldfish_battery.c261
-rw-r--r--hw/goldfish_device.c200
-rw-r--r--hw/goldfish_device.h58
-rw-r--r--hw/goldfish_events_device.c423
-rw-r--r--hw/goldfish_fb.c405
-rw-r--r--hw/goldfish_interrupt.c190
-rw-r--r--hw/goldfish_memlog.c78
-rw-r--r--hw/goldfish_mmc.c465
-rw-r--r--hw/goldfish_nand.c639
-rw-r--r--hw/goldfish_nand.h28
-rw-r--r--hw/goldfish_nand_reg.h54
-rw-r--r--hw/goldfish_switch.c172
-rw-r--r--hw/goldfish_timer.c255
-rw-r--r--hw/goldfish_trace.c252
-rw-r--r--hw/goldfish_trace.h78
-rw-r--r--hw/goldfish_tty.c225
-rw-r--r--hw/grackle_pci.c156
-rw-r--r--hw/heathrow_pic.c168
-rw-r--r--hw/i8254.c482
-rw-r--r--hw/i8259.c561
-rw-r--r--hw/ide.c2535
-rw-r--r--hw/integratorcp.c546
-rw-r--r--hw/iommu.c258
-rw-r--r--hw/irq.c71
-rw-r--r--hw/irq.h32
-rw-r--r--hw/lance.c462
-rw-r--r--hw/lsi53c895a.c1571
-rw-r--r--hw/m48t59.c614
-rw-r--r--hw/m48t59.h13
-rw-r--r--hw/mc146818rtc.c463
-rw-r--r--hw/mips_r4k.c291
-rw-r--r--hw/mmc.h214
-rw-r--r--hw/ne2000.c816
-rw-r--r--hw/openpic.c1027
-rw-r--r--hw/parallel.c183
-rw-r--r--hw/pc.c911
-rw-r--r--hw/pci.c40
-rw-r--r--hw/pckbd.c370
-rw-r--r--hw/pcnet.c1789
-rw-r--r--hw/pcspk.c147
-rw-r--r--hw/pflash_cfi02.c624
-rw-r--r--hw/piix_pci.c419
-rw-r--r--hw/pl011.c251
-rw-r--r--hw/pl050.c127
-rw-r--r--hw/pl080.c328
-rw-r--r--hw/pl110.c420
-rw-r--r--hw/pl110_template.h252
-rw-r--r--hw/pl190.c252
-rw-r--r--hw/power_supply.h109
-rw-r--r--hw/ppc.c428
-rw-r--r--hw/ppc_chrp.c566
-rw-r--r--hw/ppc_prep.c694
-rw-r--r--hw/prep_pci.c167
-rw-r--r--hw/ps2.c566
-rw-r--r--hw/rtl8139.c3471
-rw-r--r--hw/sb16.c1451
-rw-r--r--hw/sd.h83
-rw-r--r--hw/serial.c456
-rw-r--r--hw/sh7750.c836
-rw-r--r--hw/sh7750_regnames.c128
-rw-r--r--hw/sh7750_regnames.h6
-rw-r--r--hw/sh7750_regs.h1623
-rw-r--r--hw/shix.c111
-rw-r--r--hw/slavio_intctl.c400
-rw-r--r--hw/slavio_misc.c244
-rw-r--r--hw/slavio_serial.c545
-rw-r--r--hw/slavio_timer.c288
-rw-r--r--hw/smc91c111.c12
-rw-r--r--hw/sun4m.c324
-rw-r--r--hw/sun4u.c368
-rw-r--r--hw/tc58128.c181
-rw-r--r--hw/tcx.c330
-rw-r--r--hw/unin_pci.c261
-rw-r--r--hw/usb-hid.c18
-rw-r--r--hw/usb-hub.c12
-rw-r--r--hw/usb-msd.c16
-rw-r--r--hw/usb-uhci.c674
-rw-r--r--hw/usb.c5
-rw-r--r--hw/usb.h5
-rw-r--r--hw/versatile_pci.c119
-rw-r--r--hw/versatilepb.c473
-rw-r--r--hw/vga.c1945
-rw-r--r--hw/vga_int.h173
-rw-r--r--hw/vga_template.h525
-rw-r--r--images/android_icon.icobin0 -> 300318 bytes
-rw-r--r--images/android_icon.rc3
-rw-r--r--images/android_icon_16.pngbin0 -> 460 bytes
-rw-r--r--images/android_icon_256.pngbin0 -> 13369 bytes
-rw-r--r--images/android_icon_32.pngbin0 -> 1321 bytes
-rw-r--r--linux-2.6.9-qemu-fast.patch70
-rw-r--r--linux-user/arm-semi.c203
-rw-r--r--linux-user/arm/syscall.h42
-rw-r--r--linux-user/arm/syscall_nr.h262
-rw-r--r--linux-user/arm/termbits.h215
-rw-r--r--linux-user/elfload.c1240
-rw-r--r--linux-user/flat.h67
-rw-r--r--linux-user/flatload.c793
-rw-r--r--linux-user/i386/syscall.h221
-rw-r--r--linux-user/i386/syscall_nr.h274
-rw-r--r--linux-user/i386/termbits.h214
-rw-r--r--linux-user/ioctls.h302
-rw-r--r--linux-user/linuxload.c195
-rw-r--r--linux-user/main.c1716
-rw-r--r--linux-user/mips/syscall.h23
-rw-r--r--linux-user/mips/syscall_nr.h288
-rw-r--r--linux-user/mips/termbits.h229
-rw-r--r--linux-user/mmap.c417
-rw-r--r--linux-user/path.c147
-rw-r--r--linux-user/ppc/syscall.h130
-rw-r--r--linux-user/ppc/syscall_nr.h258
-rw-r--r--linux-user/ppc/termbits.h235
-rw-r--r--linux-user/qemu.h308
-rw-r--r--linux-user/sh4/syscall.h12
-rw-r--r--linux-user/sh4/syscall_nr.h292
-rw-r--r--linux-user/sh4/termbits.h274
-rw-r--r--linux-user/signal.c2067
-rw-r--r--linux-user/socket.h138
-rw-r--r--linux-user/sparc/syscall.h9
-rw-r--r--linux-user/sparc/syscall_nr.h220
-rw-r--r--linux-user/sparc/termbits.h279
-rw-r--r--linux-user/sparc64/syscall.h10
-rw-r--r--linux-user/sparc64/syscall_nr.h286
-rw-r--r--linux-user/sparc64/termbits.h279
-rw-r--r--linux-user/syscall.c3841
-rw-r--r--linux-user/syscall_defs.h1516
-rw-r--r--linux-user/syscall_types.h81
-rw-r--r--linux-user/vm86.c482
-rw-r--r--linux_keycodes.h452
-rw-r--r--loader.c8
-rw-r--r--loadpng.c275
-rw-r--r--m68k-dis.c5051
-rw-r--r--mips-dis.c3999
-rw-r--r--monitor.c160
-rwxr-xr-xoffset_layout.py111
-rw-r--r--osdep.c46
-rw-r--r--osdep.h4
-rw-r--r--proxy/proxy_common.c502
-rw-r--r--proxy/proxy_common.h79
-rw-r--r--proxy/proxy_http.c371
-rw-r--r--proxy/proxy_http.h24
-rw-r--r--proxy/proxy_int.h145
-rw-r--r--qemu-doc.texi21
-rw-r--r--qemu_file.h121
-rw-r--r--qemu_socket.h30
-rw-r--r--qemu_timers.c1103
-rw-r--r--qemu_timers.h62
-rw-r--r--s390.ld204
-rw-r--r--sdl.c9
-rw-r--r--sh4-dis.c2096
-rw-r--r--shaper.c593
-rw-r--r--shaper.h51
-rw-r--r--skins/skin_argb.h856
-rw-r--r--skins/skin_composer.c398
-rw-r--r--skins/skin_composer.h102
-rw-r--r--skins/skin_default.h7414
-rw-r--r--skins/skin_file.c699
-rw-r--r--skins/skin_file.h132
-rw-r--r--skins/skin_image.c742
-rw-r--r--skins/skin_image.h92
-rw-r--r--skins/skin_keyboard.c783
-rw-r--r--skins/skin_keyboard.h59
-rw-r--r--skins/skin_keyset.c540
-rw-r--r--skins/skin_keyset.h121
-rw-r--r--skins/skin_rect.c241
-rw-r--r--skins/skin_rect.h71
-rw-r--r--skins/skin_region.c1448
-rw-r--r--skins/skin_region.h103
-rw-r--r--skins/skin_scaler.c129
-rw-r--r--skins/skin_scaler.h36
-rw-r--r--skins/skin_surface.c613
-rw-r--r--skins/skin_surface.h101
-rw-r--r--skins/skin_trackball.c579
-rw-r--r--skins/skin_trackball.h39
-rw-r--r--skins/skin_window.c1233
-rw-r--r--skins/skin_window.h60
-rw-r--r--slirp/bootp.c13
-rw-r--r--slirp/bootp.h2
-rw-r--r--slirp/cksum.c4
-rw-r--r--slirp/ctl.h3
-rw-r--r--slirp/debug.c26
-rw-r--r--slirp/if.c12
-rw-r--r--slirp/if.h2
-rw-r--r--slirp/ip_icmp.c83
-rw-r--r--slirp/ip_icmp.h6
-rw-r--r--slirp/ip_input.c54
-rw-r--r--slirp/ip_output.c20
-rw-r--r--slirp/libslirp.h12
-rw-r--r--slirp/main.h9
-rw-r--r--slirp/mbuf.c195
-rw-r--r--slirp/mbuf.h130
-rw-r--r--slirp/misc.c724
-rw-r--r--slirp/misc.h25
-rw-r--r--slirp/sbuf.c91
-rw-r--r--slirp/sbuf.h40
-rw-r--r--slirp/slirp.c540
-rw-r--r--slirp/slirp.h18
-rw-r--r--slirp/socket.c245
-rw-r--r--slirp/socket.h27
-rw-r--r--slirp/tcp.h4
-rw-r--r--slirp/tcp_input.c270
-rw-r--r--slirp/tcp_output.c16
-rw-r--r--slirp/tcp_subr.c680
-rw-r--r--slirp/tcp_timer.c4
-rw-r--r--slirp/tcp_var.h5
-rw-r--r--slirp/tftp.c149
-rw-r--r--slirp/tftp.h3
-rw-r--r--slirp/udp.c204
-rw-r--r--slirp/udp.h9
-rw-r--r--sockets.c449
-rw-r--r--sockets.h73
-rw-r--r--softmmu_header.h15
-rw-r--r--softmmu_template.h36
-rw-r--r--sparc-dis.c3265
-rw-r--r--tap-win32.c2
-rw-r--r--target-arm/cpu.h14
-rw-r--r--target-arm/helper.c27
-rw-r--r--target-arm/op.c27
-rw-r--r--target-arm/op_helper.c126
-rw-r--r--target-arm/op_mem.h48
-rw-r--r--target-arm/translate.c181
-rw-r--r--target-i386/cpu.h653
-rw-r--r--target-i386/exec.h575
-rw-r--r--target-i386/helper.c3540
-rw-r--r--target-i386/helper2.c1031
-rw-r--r--target-i386/op.c2444
-rw-r--r--target-i386/opreg_template.h190
-rw-r--r--target-i386/ops_mem.h156
-rw-r--r--target-i386/ops_sse.h1374
-rw-r--r--target-i386/ops_template.h597
-rw-r--r--target-i386/ops_template_mem.h483
-rw-r--r--target-i386/translate-copy.c1323
-rw-r--r--target-i386/translate.c6523
-rw-r--r--target-mips/cpu.h279
-rw-r--r--target-mips/exec.h119
-rw-r--r--target-mips/fop_template.c99
-rw-r--r--target-mips/helper.c432
-rw-r--r--target-mips/mips-defs.h67
-rw-r--r--target-mips/op.c1155
-rw-r--r--target-mips/op_helper.c786
-rw-r--r--target-mips/op_helper_mem.c141
-rw-r--r--target-mips/op_mem.c149
-rw-r--r--target-mips/op_template.c65
-rw-r--r--target-mips/translate.c2443
-rw-r--r--target-ppc/cpu.h1025
-rw-r--r--target-ppc/exec.h90
-rw-r--r--target-ppc/helper.c1458
-rw-r--r--target-ppc/op.c1296
-rw-r--r--target-ppc/op_helper.c589
-rw-r--r--target-ppc/op_helper_mem.h100
-rw-r--r--target-ppc/op_mem.h371
-rw-r--r--target-ppc/op_template.h183
-rw-r--r--target-ppc/translate.c2701
-rw-r--r--target-ppc/translate_init.c2067
-rw-r--r--target-sh4/README.sh4150
-rw-r--r--target-sh4/cpu.h146
-rw-r--r--target-sh4/exec.h80
-rw-r--r--target-sh4/helper.c441
-rw-r--r--target-sh4/op.c967
-rw-r--r--target-sh4/op_helper.c372
-rw-r--r--target-sh4/op_mem.c78
-rw-r--r--target-sh4/translate.c1219
-rw-r--r--target-sparc/cpu.h277
-rw-r--r--target-sparc/exec.h104
-rw-r--r--target-sparc/fbranch_template.h89
-rw-r--r--target-sparc/fop_template.h81
-rw-r--r--target-sparc/helper.c589
-rw-r--r--target-sparc/op.c1597
-rw-r--r--target-sparc/op_helper.c918
-rw-r--r--target-sparc/op_mem.h114
-rw-r--r--target-sparc/op_template.h48
-rw-r--r--target-sparc/translate.c2845
-rw-r--r--telephony/Jamfile13
-rw-r--r--telephony/android_modem.c1869
-rw-r--r--telephony/android_modem.h137
-rw-r--r--telephony/gsm.c1217
-rw-r--r--telephony/gsm.h196
-rw-r--r--telephony/modem_driver.c147
-rw-r--r--telephony/modem_driver.h29
-rw-r--r--telephony/remote_call.c429
-rw-r--r--telephony/remote_call.h55
-rw-r--r--telephony/sim_card.c432
-rw-r--r--telephony/sim_card.h54
-rw-r--r--telephony/simulator.c195
-rw-r--r--telephony/sms.c1655
-rw-r--r--telephony/sms.h117
-rw-r--r--telephony/sysdeps.h80
-rw-r--r--telephony/sysdeps_posix.c645
-rw-r--r--telephony/sysdeps_qemu.c376
-rw-r--r--telephony/test1.c49
-rw-r--r--telephony/test2.c215
-rw-r--r--tests/.cvsignore23
-rw-r--r--tests/qruncom.c32
-rw-r--r--tests/runcom.c12
-rw-r--r--trace.c1875
-rw-r--r--trace.h157
-rw-r--r--trace_common.h139
-rw-r--r--translate-all.c91
-rw-r--r--translate-op.c44
-rw-r--r--translate.make36
-rw-r--r--usb-linux.c13
-rw-r--r--varint.c118
-rw-r--r--varint.h15
-rw-r--r--vl.c2160
-rw-r--r--vl.h324
-rw-r--r--vnc.c20
472 files changed, 109744 insertions, 131220 deletions
diff --git a/.cvsignore b/.cvsignore
deleted file mode 100644
index 7be41c4..0000000
--- a/.cvsignore
+++ /dev/null
@@ -1,42 +0,0 @@
-arm-user
-arm-softmmu
-armeb-user
-config-host.*
-dyngen
-i386
-i386-softmmu
-i386-user
-ppc-softmmu
-ppc64-softmmu
-ppc-user
-qemu-doc.html
-qemu-tech.html
-qemu-doc.info
-qemu-tech.info
-qemu.1
-qemu.pod
-qemu-img.1
-qemu-img.pod
-sparc-user
-qemu-img
-sparc-softmmu
-x86_64-softmmu
-sparc64-user
-sparc64-softmmu
-mips-softmmu
-mipsel-softmmu
-mips-user
-mipsel-user
-.gdbinit
-sh4-user
-sh4-softmmu
-*.aux
-*.cp
-*.dvi
-*.fn
-*.ky
-*.log
-*.pg
-*.toc
-*.tp
-*.vr
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..5cff342
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,10 @@
+# the following test is made to detect that we were called
+# through the 'm' or 'mm' build commands. if not, we use the
+# standard QEMU Makefile
+#
+ifeq ($(DEFAULT_TARGET),droid)
+ LOCAL_PATH:= $(call my-dir)
+ include $(LOCAL_PATH)/Makefile.android
+else
+ include Makefile.qemu
+endif
diff --git a/CHANGES.TXT b/CHANGES.TXT
new file mode 100644
index 0000000..b6ced26
--- /dev/null
+++ b/CHANGES.TXT
@@ -0,0 +1,533 @@
+Android Emulator changes:
+=========================
+
+Versions:
+
+ 1.0 => SDK M3 release
+ 1.1 => SDK M5 release
+ 1.2 => Internal release (build 72264)
+ 1.3 => Internal release (build 77780)
+ 1.4 => Internal release (build 84853)
+ 1.5 => SDK 0.9_r1
+ 1.6 => SDK 1.0_r1
+ 1.7 => SDK 1.0_r2 (planned, unreleased)
+
+==============================================================================
+Changes between 1.6 and 1.7
+
+IMPORTANT BUG FIXES:
+
+- Properly create ~/.android directory when needed.
+
+- Do not leave temporary files in Android app-specific directory on Win32
+
+- Trackball mode toggle key (Ctrl-T by default) now works after rotating
+ your skin once.
+
+OTHER:
+
+- New option '-nand-limits <limits>' allows you to send a signal to a remote
+ process when a read or write threshold on flash storage is reached. This is
+ only useful for hardcore Android system hackers.
+
+- Fix emulator build on recent Cygwin releases (the -mno-cygwin headers do not
+ tolerate the _GNU_SOURCE macro definition anymore)
+
+- Fix Win32 emulator to support SD Card images larger than 2 GiB
+
+==============================================================================
+Changes between 1.5 and 1.6
+
+IMPORTANT CHANGES:
+
+- Emulator now saves the user image in <android>/SDK1.0/
+
+OTHER:
+
+- Get rid of EsounD-related freezes on Linux (again)
+
+- Fix the documentation in -help-audio. '-audio list' doesn't work, one
+ needs to call -help-audio-out and -help-audio-in to get the list of valid
+ audio backends
+
+- Fix scrollwheel Dpad emulation in rotated mode. before that, using the
+ scroll-wheel would always generated Dpad Up/Down events, even when in
+ landscape mode.
+
+- Re-enable CPU fault emulation in case of unaligned data access. this was
+ previously disabled because it crashed the emulated kernel in previous
+ releases.
+
+- The emulator no longer prints an obscure warning when it doesn't find
+ the emulator.cfg configuration file in ~/.android.
+
+ 'broken configuration file doesn't have a 'window' element'
+
+- Removed a bunch of obsolete options (e.g. -console, -adb-port, etc...)
+
+- Setting the network speed through the console or the -netspeed option will
+ properly modify the connectivity icon on the device.
+
+- Setting the GSM voice registration state to 'roaming' in the console will
+ properly modify the voice icon on the device
+
+==============================================================================
+Changes between 1.4 and 1.5
+
+IMPORTANT BUG FIXES:
+
+- fix spurious discards of SMS messages when using two emulators.
+
+==============================================================================
+Changes between 1.3 and 1.4
+
+IMPORTANT BUG FIXES:
+
+- fix for audio-related Linux startup freezes when using the 'esd' and 'alsa'
+ backends
+
+- the number of audio buffers in the Windows backend has been incremented.
+ this gets rid of audio chopiness issues on Vista (and sometimes on XP too)
+
+NEW FEATURES:
+
+NEW CONSOLE COMMANDS:
+
+- new 'geo fix <lontitude> <latitude> [<altitude>]' command allows you to
+ send a simple GPS fix to the emulated system, without the headaches of
+ NMEA 1083 formatting.
+
+OTHER BUG FIXES:
+
+- fixed the -audio, -audio-in and -audio-out options (the <backend> values
+ were sometimes ignored)
+
+REGRESSIONS:
+
+OTHER:
+
+- the transitional '-qemud' option introduced in 1.3 is now gone. its
+ behaviour is now the default.
+
+- use the new '-old-system' option if you need to use a 1.4+ emulator binary
+ with older system images. if you don't use it, GSM and GPS emulation will
+ not work correctly (among other things).
+
+- the obsolete '-oldradio' option is now gone
+
+- on some Unix systems, SIGALRM is blocked by default, so unblock it when
+ creating the alarm timer
+
+- the 'esd' and 'alsa' libraries dump a lot of error messages to the console
+ by default on Linux. these are now disabled unless you use '-debug audio'
+
+- added the '-help-char-devices' help topic that describe the specification
+ of the <device> parameter of options like -serial, -gps, -shell-serial,
+ etc...
+
+KNOWN ISSUES:
+
+- no support for video input
+- no support for mutable SIM Card emulation yet
+- no support for bluetooth
+- no support for WiFi
+
+- on some Linux machines, the emulator might get stuck at startup. this
+ seems to be related to audio input support. try starting with
+ '-audio-in none' or even '-noaudio' to disable sound, or choose a
+ different audio backend by defining QEMU_AUDIO_DRV to an appropriate
+ value (read below).
+
+ you can also select different audio backends for both output and input
+ by defining QEMU_AUDIO_OUT_DRV and QEMU_AUDIO_IN_DRV independently.
+
+- on Windows, the emulator takes about 10-15% of the CPU even when the
+ emulated system is idle. this is a known issue related to QEMU's internal
+ event loop and Winsock. this should be fixed in a future emulator release.
+
+- GPS emulation only if you use the '-qemud' option. this is an experimental
+ option that is soon going to be the default. without this option, the
+ emulated system will start but GPS emulation will not work.
+
+ for the record, 'qemud' is a serial port multiplexer that is used to
+ multiplex several communication channels between the emulator and the
+ emulated system, though a single serial port.
+
+==============================================================================
+Changes between 1.2 and 1.3
+
+IMPORTANT BUG FIXES:
+
+NEW FEATURES:
+
+- '-audio-in <backend>' allows you to select the audio input backend from the
+ command line. this is equivalent to defining QEMU_AUDIO_IN_DRV=<backend>
+
+ '-audio-out <backend>' works for the audio output, and '-audio <backend>'
+ will select both input and output at the same time
+
+- '-debug <tags>' has replaced the old '-verbose-<tag1> -verbose-<tag2> ...'
+ debugging option. <tags> is a comma-separated list of debug tags
+ (see -help-debug-tags for a complete list). you can also use the special
+ value 'all' to indicate all debug tags, or prefix a '-' before a tag
+ name to disable it. for example:
+
+ -debug all,-audio
+
+ enables all debugging except audio. '-debug-<tag>' still works though.
+
+ note that while '-verbose-<tag>' is deprecated, '-verbose' is still supported
+ as an alias to '-debug-init'
+
+- '-keyset <file>' allows you to specific the keyset file to use. the default
+ is still ~/.android/default.keyset on Unix. for Windows, use -help-keyset
+ to get its default location (which differs between XP and Vista)
+
+
+NEW CONSOLE COMMANDS:
+
+- the 'geo nmea <sentence>' can be used to send a NMEA 1083 sentence as if
+ it came from an emulated GPS unit. NOTE: this doesn't work unless you
+ also use the '-qemud' option (see KNOWN ISSUES below)
+
+OTHER BUG FIXES:
+
+- severe color artefact issues when scaling the emulator window < 1.0 were
+ fixed.
+
+- fix rare random emulator freezes on Linux by disabling the 'dynticks' timer.
+
+REGRESSIONS:
+
+OTHER:
+
+- the ambiguous '-console' option is now obsolete. use '-shell' instead
+
+- the new '-shell-serial <device>' allows you to specify a device to
+ connect a root shell session to the emulated system.
+
+- the '-debug-kernel' option is now known as '-show-kernel' (the -debug-
+ prefix is reserved for strict emulator debugging features)
+
+- '-adb-port' has been removed from the list of options. similarly
+ '-port <port>' will accept an odd port number, but will print a warning
+ that it is using <port>-1 instead.
+
+- MMX is used on x86 to speed up window rescaling.
+
+- a new '-qemud' option is required to have GPS support work in this
+ SDK (either through '-gps <device>' or the 'geo nmea <sentence>'
+ console command)
+
+ this option is purely experimental and will soon become the default.
+
+KNOWN ISSUES:
+
+- no support for video input
+- no support for mutable SIM Card emulation yet
+- no support for bluetooth
+- no support for WiFi
+
+- on some Linux machines, the emulator might get stuck at startup. this
+ seems to be related to audio input support. try starting with
+ '-audio-in none' or even '-noaudio' to disable sound, or choose a
+ different audio backend by defining QEMU_AUDIO_DRV to an appropriate
+ value (read below).
+
+ you can also select different audio backends for both output and input
+ by defining QEMU_AUDIO_OUT_DRV and QEMU_AUDIO_IN_DRV independently.
+
+- on Windows, the emulator takes about 10-15% of the CPU even when the
+ emulated system is idle. this is a known issue related to QEMU's internal
+ event loop and Winsock. this should be fixed in a future emulator release.
+
+- GPS emulation only if you use the '-qemud' option. this is an experimental
+ option that is soon going to be the default. without this option, the
+ emulated system will start but GPS emulation will not work.
+
+ for the record, 'qemud' is a serial port multiplexer that is used to
+ multiplex several communication channels between the emulator and the
+ emulated system, though a single serial port.
+
+==============================================================================
+Changes between 1.1 and 1.2
+
+
+IMPORTANT BUG FIXES:
+
+- fixed a typo that prevented the F9/F10 keyboard shortcuts from working
+ properly, making non-programatically tracing unusable.
+
+- halve the emulator's memory requirements, saving around 130 megabytes
+ of memory by changing the way flash images are accessed (we now use
+ temporary files instead)
+
+- this emulator binary should be 10% to 20% faster than previous ones on
+ the Windows and OS X platforms. for faster boots, you may also want to
+ use the -no-boot-anim option described below to speed up the initial
+ boot sequence as well on slow machines.
+
+- proper rotation support when using Keypad 7/9 to switch between layouts
+ in the default HVGA skin. no need to use Ctrl-PageDown anymore
+
+- the -http-proxy <proxy> option didn't work correctly on Windows (unless
+ you were very lucky).
+
+- general socket handling code on Windows has been significantly improved.
+
+
+NEW FEATURES:
+
+- the console port number of a given emulator instance is now displayed in
+ its window's title bar.
+
+- voice/sms are automatically forwarded to other emulator instances running
+ on the same machine, as long as you use their console port number as the
+ destination phone number.
+
+ for example, if you have two emulator running, the first one will usually
+ use console port 5554, and the second one will use port 5556
+
+ then dialing 5556 on the 1st emulator will generate an incoming call on
+ the 2nd emulator. you can also hold/unhold calls as well.
+
+ this also works when sending SMS messages from one emulator to the other
+
+- the help system has been totally revamped:
+
+ * -help prints a summary of all options and help topics
+ * -help-<option> prints option-specific help
+ * -help-<topic> prints various topical help text
+ * -help-all prints *all* help content at once
+
+- the emulator now tries to automatically detect the host time zone and sends
+ it to the emulated system at startup (through the GSM modem). there is also
+ a new '-timezone <timezone>' option to be able to specify a different one.
+
+ IMPORTANT: the <timezone> name must be in zoneinfo format, i.e.
+ Area/Location, human-friendly abbreviations like "PST" or "CET"
+ will not work. examples are:
+
+ America/Los_Angeles
+ Europe/Paris
+
+- the emulator can now use up to 4 distinct DNS servers (instead of only one).
+ by default, they are taken from your system's list, which is obtained by
+ calling GetNetworkParams() on Win32, and parsing /etc/resolv.conf on
+ Unix.
+
+- a new '-dns-server <server>' option can be used to specify a comma-separated
+ list of alternative DNS servers to be used by the emulated system, instead of
+ the system's default.
+
+- a new '-scale <fraction>' option allows you to scale the emulator
+ window. <fraction> can be a number between 0.1 and 3.0.
+
+ you can also use '-scale <value>dpi', (e.g. '-scale 110dpi') to indicate the
+ resolution of your host monitor screen. it will be divided by the emulated
+ device's resolution to get an absolute scale.
+
+- a new '-dpi-device <dpi>' option allows you to specific the resolution of
+ the emulated device's screen. Note that this is not required: the default
+ used is 165, which is the average of several prototypes we've been working
+ with.
+
+- add a new '-port <port>' option to specify which port the emulator should
+ bind to for the console, instead of letting it guess. <port> must be an
+ *even* integer between 5554 and 5584 included. the corresponding ADB port
+ will be <port>+1
+
+- [DEPRECATED] add a new '-adb-port <port>' option to specify which port the
+ emulator should bind to, instead of letting it guess. <port> must be an odd
+ integer between 5555 and 5585 included. the corresponding control console
+ will be on <port>-1
+
+ NOTE: -adb-port is deprecated, don't use it, it will probably disappear
+ NOTE2: you cannot use both -port and -adb-port at the same time.
+
+- a new '-no-boot-anim' options tells the emulated system to disable the boot
+ animation. on slow systems, this can *significantly* reduce the time to
+ boot the system in the emulator.
+
+- you can now redefine the emulator's keybinding by writing a 'keyset' file
+ and use '-keyset <filename>' to use it when starting the emulator. use
+ -help-keyset and -help-keyset-file for all details.
+
+ this allows you to use the emulator effectively on keyboards which don't
+ have a keypad, by using different keys..
+
+- you can now toggle between windowed and fullscreen mode at runtime by
+ pressing Alt-Enter (only works on Linux at the moment !!)
+
+- use '-audio-out <backend>' and '-audio-in <backend>' to change the output
+ and input audio backends used by the emulator. see -help-audio-out and
+ -help-audio-in for a list of valid values.
+
+ this is equivalent to setting the QEMU_AUDIO_OUT_DRV and QEMU_AUDIO_IN_DRV
+ environment variables.
+
+ use '-audio <backend>' to set both the input and output backends at the
+ same time. this is equivalent to setting the QEMU_AUDIO_DRV environment
+ variable.
+
+
+NEW CONSOLE COMMANDS:
+
+- the new 'power' command can be used to control the power/battery state of
+ the emulated device.
+
+- the new 'event send' command can be used to send simulated hardware events
+ to the Android Linux kernel. each event must be in the form
+ <type>:<code>:<value> where:
+
+ <type> is either an integer or a corresponding string alias
+ (use "event types" to see a list of aliases)
+
+ <code> is either an integer or a corresponding string alias
+ that depends on the value of <type> (use "event codes <type>"
+ to see a list of these aliases)
+
+ <value> is an integer
+
+ NOTE: Be warned that it is very easy to confuse the kernel about the state
+ of emulated hardware by sending the wrong event. An *excellent*
+ knowledge of the Linux kernel internals is encouraged before playing
+ with "event send".
+
+- the new 'event text <textMessage>' command can be used to simulate
+ keypresses of small text messages, where <textMessage> is an utf-8 string.
+
+- the new 'vm stop' and 'vm start' command can be used to stop/start the
+ emulation. you can also use 'vm status' to query the current state.
+
+- the new 'window scale <scale>' command allows you to change the scale of
+ the emulator window dynamically. <scale> is either an integer followed by
+ the 'dpi' suffix (e.g. '120dpi') or a real number between 0.1 and 3.0.
+
+ in the first case, <scale> specifies your monitor dpi; in the second one,
+ the new window scale itself.
+
+
+OTHER BUG FIXES:
+
+- in case of SDL_Init() failure, print the SDL error message.
+- disable networking code's logging to /tmp/slirp.log
+- the emulator now works with 2GB SD Card files
+- the emulator doesn't prevent the screensaver to kick in on OS X anymore
+- the -onion and -onion-alpha options now work properly
+- a second emulator instance trying to use the same SD Card instance than a
+ first one will no longer crash
+- it's now possible to properly start the emulator in the background on all
+ Unix shells (e.g. "emulator &") without being interrupted/stopped by a
+ SIGTTIN or SIGTTOU signal.
+- fixed a bug in the SMS emulation that happened when using GSM 7-bit escaped
+ characters, i.e. anything in the following: [|]~\{}^
+- fixed a small regression where -data <foo> would fail if the file <foo>
+ did not exist.
+
+
+REGRESSIONS:
+
+- the -flash-keys options doesn't work anymore
+
+
+KNOWN ISSUES:
+
+- no support for video input
+- no support for mutable SIM Card emulation yet
+- no support for bluetooth
+- no support for WiFi
+
+- on some Linux machines, the emulator might get stuck at startup. this
+ seems to be related to audio input support. try starting with
+ '-audio-in none' or even '-noaudio' to disable sound, or choose a different
+ audio backend by defining QEMU_AUDIO_DRV to an appropriate value
+ (read below).
+
+ you can also select different audio backends for both output and input
+ by defining QEMU_AUDIO_OUT_DRV and QEMU_AUDIO_IN_DRV independently.
+
+- on Windows, the emulator takes about 10-15% of the CPU even when the
+ emulated system is idle. this is a known issue related to QEMU's internal
+ event loop and Winsock. this should be fixed in a future emulator release.
+
+OTHER:
+
+- you can now use -debug-<component> and/or -debug-no-<component> to
+ enable or disable the debug messages of a given emulator component. this
+ can be very useful for troubleshooting. for all details, use -help-debug
+ and -help-debug-tags
+
+- you can also use '-debug <tags>' where <tags> is a comma-separated list
+ of component names, optionally prefixed by a single '-'. see -help-debug
+ and -help-debug-tags for all details
+
+- you can now define the ANDROID_VERBOSE environment variable as a list
+ of "debug" items (each <item> corresponds to a -debug-<item> option).
+ for example, defining:
+
+ ANDROID_VERBOSE=socket,keys
+
+ is equivalent to using "-debug socket,keys" when invoking the emulator
+
+- as a special case, -debug-slirp enables logging of the router/firewall
+ operations to a temporary file (e.g. /tmp/android/slirp.log). you can
+ also specify a logging bitmask with the ANDROID_SLIRP_LOGMASK environment
+ variable (the default is a mask of 7).
+
+- removed many obsolete / unused source files from the repository. also
+ performed a rather heavy cleanup of the sources to make them somewhat
+ more manageable.
+
+- integrate dynticks support from upstream QEMU depot. this only allows one
+ to provide more precise timing accuracy in the guest under Linux.
+ (NOTE: disabled in the source code, since it seems that it freezes
+ the emulator sometimes)
+
+- audio input is now working on OS X, Windows and Linux. on Linux, there
+ are four different backends supported: EsounD, ALSA, OSS and SDL. they
+ are accessed through dlopen/dlsym, which means that the emulator binary
+ will run on any system.
+
+ you can specify a given backend by defining the QEMU_AUDIO_DRV environment
+ variable to one of these values:
+
+ alsa
+ esd
+ sdl
+ oss
+ none
+
+ note that the "sdl" audio backend is the most compatible, but doesn't
+ support audio input at all !!
+
+- a new option '-cpu-delay <delay>' can be used to slow down the CPU
+ emulation. the <delay> is an integer between 0 and 1000. note that it
+ doesn't necessarily scale linearly with effective performance.
+
+ the delay process is not exactly deterministic. this is just a hack that
+ may disappear or be completely re-implemented in the future
+
+- some new "gsm" and "sms" subcommands were added to the control console.
+ they are used internally by the voice/sms auto-forwarder and are probably
+ not very useful to typical developers
+
+- some code has been added to support save/restore of the VM state to/from
+ a file. however this is not properly tested yet, and requires that you
+ use exactly the same options and disk images when reloading the VM state.
+
+- added a new -cache <file> option to specify the cache partition image
+ file. the default is to use a temporary file instead
+
+- added a new -report-console <socket> option to be able to report the
+ automatically assigned console port to a remote third-party (e.g. a
+ script) before starting the emulation. see the output of -help for all
+ the details
+
+- (only useful to Android engineers)
+ the audio sub-system is now compiled in its own static library (called
+ libqemu-audio.a), which gets copied to the Android "prebuilt/Linux/qemu"
+ directory. this is done to avoid forcing all developers to install various
+ development packages on Linux, as well as all build servers. there is also
+ now a script named "distrib/update-audio.sh" which will update the depot
+ file automatically for you: call it whenever you change the audio sources.
diff --git a/MODULE_LICENSE_GPL b/MODULE_LICENSE_GPL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_GPL
diff --git a/Makefile b/Makefile
index d6e6f61..9731afb 100644
--- a/Makefile
+++ b/Makefile
@@ -3,45 +3,48 @@
include config-host.mak
.PHONY: all clean distclean dvi info install install-doc tar tarbin \
- speed test test2 html dvi info
+ speed test test2 html dvi info zlib-lib libgpng-lib
-CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I.
+CFLAGS=-Wall -O2 -g -fno-strict-aliasing -I. -MMD -MP
ifdef CONFIG_DARWIN
-CFLAGS+= -mdynamic-no-pic
+CFLAGS+= -mdynamic-no-pic -I/opt/local/include
endif
ifeq ($(ARCH),sparc)
CFLAGS+=-mcpu=ultrasparc
endif
LDFLAGS=-g
LIBS=
-DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
-TOOLS=qemu-img$(EXESUF)
+DEFINES+=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+TOOLS=
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
-ifdef BUILD_DOCS
-DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1
-else
DOCS=
+
+UNAME=$(shell uname -s)
+ifneq ($(findstring CYGWIN,$(UNAME)),)
+CFLAGS+=-mno-cygwin -D_WIN32
+LDFLAGS+=-mno-cygwin
endif
-all: $(TOOLS) $(DOCS) recurse-all
+all: $(TOOLS) $(DOCS) recurse-all zlib-lib libgpng-lib
subdir-%: dyngen$(EXESUF)
$(MAKE) -C $(subst subdir-,,$@) all
+include $(SRC_PATH)/distrib/Makefile
+
recurse-all: $(patsubst %,subdir-%, $(TARGET_DIRS))
-
-qemu-img$(EXESUF): qemu-img.c block.c block-cow.c block-qcow.c aes.c block-vmdk.c block-cloop.c block-dmg.c block-bochs.c block-vpc.c block-vvfat.c
- $(CC) -DQEMU_TOOL $(CFLAGS) $(LDFLAGS) $(DEFINES) -o $@ $^ -lz $(LIBS)
+
+libz.a: subdir-distrib
dyngen$(EXESUF): dyngen.c
$(HOST_CC) $(CFLAGS) $(DEFINES) -o $@ $^
-clean:
+clean: clean-zlib clean-libpng
# avoid old build problems by removing potentially incorrect old files
- rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
- rm -f *.o *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
+ rm -f config.mak config.h op-i386.h opc-i386.h gen-op-i386.h op-arm.h opc-arm.h gen-op-arm.h
+ rm -f *.o *.d *.a $(TOOLS) dyngen$(EXESUF) TAGS *.pod *~ */*~
$(MAKE) -C tests clean
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
@@ -88,7 +91,7 @@ endif
test speed test2: all
$(MAKE) -C tests $@
-TAGS:
+TAGS:
etags *.[ch] tests/*.[ch]
cscope:
@@ -158,6 +161,5 @@ tarbin:
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
-ifneq ($(wildcard .depend),)
-include .depend
-endif
+include $(wildcard *.d)
+
diff --git a/Makefile.android b/Makefile.android
new file mode 100644
index 0000000..a139f4d
--- /dev/null
+++ b/Makefile.android
@@ -0,0 +1,454 @@
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_PATH:= $(call my-dir)
+
+# determine the location of platform-specific directories
+#
+CONFIG_DIRS := \
+ $(LOCAL_PATH)/android/config \
+ $(LOCAL_PATH)/android/config/$(HOST_PREBUILT_TAG)
+CONFIG_INCLUDES := $(CONFIG_DIRS:%=-I%)
+
+MY_CFLAGS := $(CONFIG_INCLUDES)
+# this is needed to build the emulator on 64-bit Linux systems
+ifeq ($(HOST_OS),linux)
+ MY_CFLAGS += -Wa,--32
+endif
+
+ifeq ($(HOST_OS),windows)
+ MY_CFLAGS += -D_WIN32 -mno-cygwin
+ # we need Win32 features that are available since Windows 2000 (NT 5.0)
+ MY_CFLAGS += -DWINVER=0x500
+endif
+
+# We're going to use a specific version of gcc (3.4.6) if it is available
+# from the prebuilt directory. This prevents many nasty emulator problems
+# due to the way QEMU works
+#
+MY_CC :=
+
+ifneq ($(strip $(wildcard $(GCCQEMU))),)
+ # GCCQEMU is set by the host file under build/core/combo/
+ MY_CC := $(GCCQEMU)
+endif
+
+ifdef MY_CC
+ ifneq ($(USE_CCACHE),)
+ MY_CC := prebuilt/$(HOST_PREBUILT_TAG)/ccache/ccache $(MY_CC)
+ endif
+else
+ MY_CC := $(HOST_CC)
+endif
+
+include $(CLEAR_VARS)
+
+###############################################################################
+# compile the 'dyngen' executable, it is used to generate the various
+# runtime code generators used by the emulator. it does that by parsing a
+# special .o file containing routines for each one of the pseudo-opcodes
+# handled by the CPU-specific translator
+#
+LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
+LOCAL_CC := $(MY_CC)
+LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS)
+LOCAL_SRC_FILES := dyngen.c
+
+ifeq ($(HOST_OS),windows)
+ LOCAL_LDLIBS += -mno-cygwin -mconsole
+endif
+
+LOCAL_MODULE := emulator-dyngen
+include $(BUILD_HOST_EXECUTABLE)
+
+DYNGEN := $(LOCAL_BUILT_MODULE)
+
+###############################################################################
+# build the normal dynamic translation code as a library, because it needs
+# specific compilation flags. not that we are poking some object
+# files directly through dyngen !
+#
+
+# determine the C flags used to compile op.c into op.h and others
+#
+OP_CFLAGS := -I$(LOCAL_PATH)/target-arm \
+ -I$(LOCAL_PATH)/fpu \
+ $(MY_CFLAGS)
+
+OP_CFLAGS += -O2 -g -fomit-frame-pointer -fno-strict-aliasing -falign-functions=0 \
+ -fno-gcse -fno-reorder-blocks -fno-optimize-sibling-calls \
+ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
+ -fno-PIC
+
+ifeq ($(HOST_ARCH),ppc)
+ OP_CFLAGS += -D__powerpc__ -mdynamic-no-pic
+endif
+
+ifeq ($(HOST_ARCH),x86)
+ifeq ($(HOST_OS),darwin)
+ OP_CFLAGS += -mpreferred-stack-boundary=4 -mdynamic-no-pic
+else
+ OP_CFLAGS += -mpreferred-stack-boundary=2
+endif
+endif
+
+# build the nomal dynamic translation code as the 'emulator-op' library
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := emulator-op
+OP_SUFFIX :=
+
+include $(LOCAL_PATH)/translate.make
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# build the tracing dynamic translation code as the 'emulator-op-trace' library
+#
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := emulator-op-trace
+LOCAL_CFLAGS := -DGEN_TRACE=1
+OP_SUFFIX := -trace
+
+include $(LOCAL_PATH)/translate.make
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+# define to true to build the ARM-specific code generator as an independent
+# static library. this allows you to apply different optimization strategy
+BUILD_ARM_LIBRARY := true
+
+ifeq ($(BUILD_ARM_LIBRARY),true)
+##############################################################################
+# build the ARM-specific target sources
+#
+include $(CLEAR_VARS)
+
+LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
+LOCAL_CC := $(MY_CC)
+LOCAL_MODULE := emulator-arm
+
+LOCAL_CFLAGS := -fno-PIC -fomit-frame-pointer -Wno-sign-compare
+LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS)
+
+ifeq ($(HOST_OS),darwin)
+LOCAL_CFLAGS += -O2
+endif
+ifeq ($(HOST_OS),windows)
+LOCAL_CFLAGS += -O2
+endif
+
+# generate the normal translator source files from emulator-op library
+#
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/target-arm \
+ -I$(LOCAL_PATH)/fpu \
+ -I$(INTERMEDIATE)
+
+ifeq ($(HOST_ARCH),ppc)
+ LOCAL_CFLAGS += -D__powerpc__
+endif
+
+ifeq ($(HOST_OS),darwin)
+ LOCAL_CFLAGS += -mdynamic-no-pic
+endif
+
+# include CPU translation sources
+#
+LOCAL_SRC_FILES += exec.c cpu-exec.c \
+ target-arm/op_helper.c \
+ target-arm/helper.c
+
+# include ARM-specific soft-float implementation
+#
+NWFPE_SOURCES := fpa11.c fpa11_cpdo.c fpa11_cpdt.c fpa11_cprt.c fpopcode.c single_cpdo.c \
+ double_cpdo.c extended_cpdo.c
+
+FPU_SOURCES := softfloat.c
+
+LOCAL_SRC_FILES += $(XXNWFPE_SOURCES:%=target-arm/nwfpe/%) \
+ $(FPU_SOURCES:%=fpu/%)
+
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/target-arm/nwfpe \
+ -I$(LOCAL_PATH)/linux-user \
+ -I$(LOCAL_PATH)/linux-user/arm
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+endif # BUILD_ARM_LIBRARY
+
+##############################################################################
+# now build the emulator itself
+#
+include $(CLEAR_VARS)
+
+LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
+LOCAL_CC := $(MY_CC)
+LOCAL_MODULE := emulator
+LOCAL_STATIC_LIBRARIES := $(EMULATOR_OP_LIBRARIES) emulator-arm
+
+# don't remove the -fno-strict-aliasing, or you'll break things
+# (e.g. slirp/network support)
+#
+LOCAL_CFLAGS := -fno-PIC -fomit-frame-pointer -Wno-sign-compare \
+ -fno-strict-aliasing
+
+LOCAL_CFLAGS := $(MY_CFLAGS) $(LOCAL_CFLAGS)
+
+ifeq ($(HOST_OS),darwin)
+LOCAL_CFLAGS += -O2
+endif
+ifeq ($(HOST_OS),windows)
+LOCAL_CFLAGS += -O2
+endif
+# add the build ID to the default macro definitions
+LOCAL_CFLAGS += -DANDROID_BUILD_ID="$(strip $(BUILD_ID))-$(strip $(BUILD_NUMBER))"
+
+ifeq ($(HOST_ARCH),ppc)
+ LOCAL_CFLAGS += -D__powerpc__
+endif
+
+ifeq ($(HOST_OS),darwin)
+ LOCAL_CFLAGS += -mdynamic-no-pic
+endif
+
+# include the Zlib sources
+#
+ZLIB_DIR := distrib/zlib-1.2.3
+include $(LOCAL_PATH)/$(ZLIB_DIR)/sources.make
+LOCAL_SRC_FILES += $(ZLIB_SOURCES)
+LOCAL_CFLAGS += $(ZLIB_CFLAGS) -I$(LOCAL_PATH)/$(ZLIB_DIR)
+
+# include the Libpng sources
+#
+LIBPNG_DIR := distrib/libpng-1.2.19
+include $(LOCAL_PATH)/$(LIBPNG_DIR)/sources.make
+LOCAL_SRC_FILES += $(LIBPNG_SOURCES)
+LOCAL_CFLAGS += $(LIBPNG_CFLAGS) -I$(LOCAL_PATH)/$(LIBPNG_DIR)
+
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/target-arm \
+ -I$(LOCAL_PATH)/fpu \
+ -I$(INTERMEDIATE)
+
+ifneq ($(BUILD_ARM_LIBRARY),true)
+# generate the normal translator source files from emulator-op library
+#
+
+# include CPU translation sources
+#
+LOCAL_SRC_FILES += exec.c cpu-exec.c \
+ target-arm/op_helper.c \
+ target-arm/helper.c
+
+# include ARM-specific soft-float implementation
+#
+NWFPE_SOURCES := fpa11.c fpa11_cpdo.c fpa11_cpdt.c fpa11_cprt.c fpopcode.c single_cpdo.c \
+ double_cpdo.c extended_cpdo.c
+
+FPU_SOURCES := softfloat.c
+
+LOCAL_SRC_FILES += $(XXNWFPE_SOURCES:%=target-arm/nwfpe/%) \
+ $(FPU_SOURCES:%=fpu/%)
+
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/target-arm/nwfpe \
+ -I$(LOCAL_PATH)/linux-user \
+ -I$(LOCAL_PATH)/linux-user/arm
+endif # !BUILD_ARM_LIBRARY
+
+# include telephony stuff
+#
+TELEPHONY_SOURCES := android_modem.c modem_driver.c gsm.c sim_card.c sysdeps_qemu.c sms.c remote_call.c
+LOCAL_SRC_FILES += $(TELEPHONY_SOURCES:%=telephony/%)
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/telephony
+
+# include sound support source files. we first try to see if we have a prebuilt audio
+# library. if not, we build things the "hard" way.
+#
+# note that to generate the prebuilt audio library, you should do the following:
+#
+# cd tools/qemu
+# ./android-rebuild.sh
+# distrib/update-audio.sh
+#
+QEMU_AUDIO_LIB := $(wildcard \
+ prebuilt/$(HOST_PREBUILT_TAG)/emulator/libqemu-audio.a)
+
+ifeq ($(QEMU_AUDIO_LIB),)
+ AUDIO_SOURCES := audio.c noaudio.c wavaudio.c sdlaudio.c wavcapture.c mixeng.c
+
+ ifeq ($(HOST_OS),darwin)
+ AUDIO_SOURCES += coreaudio.c
+ LOCAL_CFLAGS += -DCONFIG_COREAUDIO
+ LOCAL_LDLIBS += -Wl,-framework,CoreAudio
+ endif
+
+ ifeq ($(HOST_OS),windows)
+ AUDIO_SOURCES += winaudio.c
+ LOCAL_CFLAGS += -DCONFIG_WINAUDIO
+ endif
+
+ ifeq ($(HOST_OS),linux)
+ AUDIO_SOURCES += esdaudio.c alsaaudio.c audio_pt_int.c
+ LOCAL_CFLAGS += -DCONFIG_ESD -DCONFIG_ALSA
+ endif
+
+ LOCAL_SRC_FILES += $(AUDIO_SOURCES:%=audio/%)
+endif # !QEMU_AUDIO_LIB
+
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/audio
+LOCAL_CFLAGS += -DHAS_AUDIO
+
+# include emulated hardware source files
+#
+HW_SOURCES := android_arm.c arm_boot.c arm_pic.c cdrom.c \
+ goldfish_events_device.c pci.c irq.c \
+ goldfish_nand.c \
+ goldfish_audio.c goldfish_device.c goldfish_fb.c \
+ goldfish_interrupt.c goldfish_mmc.c goldfish_switch.c \
+ goldfish_memlog.c goldfish_battery.c \
+ goldfish_timer.c goldfish_tty.c scsi-disk.c \
+ smc91c111.c goldfish_trace.c usb-hid.c usb-hub.c usb-msd.c usb-ohci.c \
+ usb.c \
+ dma.c
+
+LOCAL_SRC_FILES += $(HW_SOURCES:%=hw/%)
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/hw
+
+# include slirp code, i.e. the user-level networking stuff
+#
+SLIRP_SOURCES := bootp.c cksum.c debug.c if.c ip_icmp.c ip_input.c ip_output.c \
+ mbuf.c misc.c sbuf.c slirp.c socket.c tcp_input.c tcp_output.c \
+ tcp_subr.c tcp_timer.c tftp.c udp.c
+
+LOCAL_SRC_FILES += $(SLIRP_SOURCES:%=slirp/%)
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/slirp
+
+# socket proxy support
+#
+PROXY_SOURCES := proxy_common.c proxy_http.c
+
+LOCAL_SRC_FILES += $(PROXY_SOURCES:%=proxy/%)
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/proxy
+
+# the linux-user sources, I doubt we really need these
+#
+#LINUX_SOURCES := main.c elfload.c mmap.c signal.c path.c syscall.c
+#LOCAL_SRC_FILES += $(LINUX_SOURCES:%=linux-user/%)
+
+# the skin support sources
+#
+SKIN_SOURCES := skin_rect.c \
+ skin_region.c \
+ skin_image.c \
+ skin_trackball.c \
+ skin_keyboard.c \
+ skin_keyset.c \
+ skin_file.c \
+ skin_window.c \
+ skin_scaler.c \
+ skin_composer.c \
+ skin_surface.c \
+
+LOCAL_SRC_FILES += $(SKIN_SOURCES:%=skins/%)
+LOCAL_CFLAGS += -I$(LOCAL_PATH)/skins
+
+ifeq ($(HOST_ARCH),x86)
+# enable MMX code for our skin scaler
+LOCAL_CFLAGS += -DUSE_MMX=1 -mmmx
+endif
+
+# include other sources
+#
+VL_SOURCES := vl.c osdep.c \
+ block.c readline.c monitor.c console.c loader.c sockets.c \
+ block-qcow.c aes.c block-cloop.c block-dmg.c \
+ cbuffer.c \
+ gdbstub.c usb-linux.c \
+ trace.c dcache.c varint.c vnc.c disas.c arm-dis.c \
+ qemu_timers.c \
+ shaper.c charpipe.c loadpng.c \
+ framebuffer.c \
+ android_debug.c \
+ android_help.c \
+ android_option.c \
+ android_main.c \
+ android_charmap.c \
+ android_resource.c \
+ android_utils.c \
+ android_profile.c \
+ android_console.c \
+ android_events.c \
+ android_timezone.c \
+ android_config.c \
+ android_gps.c \
+ android_qemud.c \
+ android_kmsg.c \
+
+ifeq ($(HOST_OS),linux)
+ LOCAL_LDLIBS += -lX11
+endif
+
+ifeq ($(HOST_ARCH),x86)
+ VL_SOURCES += i386-dis.c
+endif
+ifeq ($(HOST_ARCH),ppc)
+ VL_SOURCES += ppc-dis.c
+endif
+
+ifeq ($(HOST_OS),windows)
+ VL_SOURCES += tap-win32.c
+ LOCAL_LDLIBS += -mno-cygwin -mwindows -mconsole
+endif
+
+LOCAL_SRC_FILES += $(VL_SOURCES)
+
+ifeq ($(HOST_OS),linux)
+ LOCAL_LDLIBS += -lutil -lrt
+endif
+
+# add SDL-specific flags
+#
+SDL_CONFIG := prebuilt/$(HOST_PREBUILT_TAG)/sdl/bin/sdl-config
+SDL_CFLAGS := $(shell $(SDL_CONFIG) --cflags)
+
+# We need to filter out the _GNU_SOURCE variable because it breaks recent
+# releases of Cygwin when using the -mno-cygwin option. Moreover, we don't
+# need this macro at all to build the Android emulator.
+SDL_CFLAGS := $(filter-out -D_GNU_SOURCE=1,$(SDL_CFLAGS))
+
+LOCAL_CFLAGS += $(SDL_CFLAGS)
+LOCAL_LDLIBS += $(filter-out %.a %.lib,$(shell $(SDL_CONFIG) --static-libs))
+LOCAL_STATIC_LIBRARIES += libSDL libSDLmain
+
+# on Windows, link the icon file as well into the executable
+# unfortunately, our build system doesn't help us much, so we need
+# to use some weird pathnames to make this work...
+#
+ifeq ($(HOST_OS),windows)
+INTERMEDIATE := $(call intermediates-dir-for,EXECUTABLES,$(LOCAL_MODULE),true)
+ANDROID_ICON_OBJ := android_icon.o
+ANDROID_ICON_PATH := $(LOCAL_PATH)/images
+$(ANDROID_ICON_PATH)/$(ANDROID_ICON_OBJ): $(ANDROID_ICON_PATH)/android_icon.rc
+ windres $< -I $(ANDROID_ICON_PATH) -o $@
+
+# seems to be the only way to add an object file that was not generated from
+# a C/C++/Java source file to our build system. and very unfortunately,
+# $(TOPDIR)/$(LOCALPATH) will always be prepend to this value, which forces
+# use to put the object file in the source directory...
+#
+LOCAL_PREBUILT_OBJ_FILES += images/$(ANDROID_ICON_OBJ)
+endif
+
+# other flags
+LOCAL_CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+LOCAL_LDLIBS += -lm -lpthread
+
+ifeq ($(HOST_OS),windows)
+ LOCAL_LDLIBS += -lwinmm -lws2_32 -liphlpapi
+endif
+
+LOCAL_LDLIBS += $(QEMU_AUDIO_LIB)
+
+LOCAL_MODULE := emulator
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif # TARGET_ARCH == arm
diff --git a/Makefile.target b/Makefile.target
index 91516ed..a5964b4 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -1,23 +1,14 @@
include config.mak
+include $(SRC_PATH)/distrib/Makefile
TARGET_BASE_ARCH:=$(TARGET_ARCH)
-ifeq ($(TARGET_ARCH), x86_64)
-TARGET_BASE_ARCH:=i386
-endif
-ifeq ($(TARGET_ARCH), ppc64)
-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
-DEFINES=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
-ifdef CONFIG_USER_ONLY
-VPATH+=:$(SRC_PATH)/linux-user
-DEFINES+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
+VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio:$(SRC_PATH)/telephony:$(SRC_PATH)/proxy:$(SRC_PATH)/skins
+DEFINES=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH) -I$(SRC_PATH)/telephony -I$(SRC_PATH)/proxy -I$(SRC_PATH)/skins
+CFLAGS=-Wall $(OPTIM) -g $(ZLIB_CFLAGS) $(LIBPNG_CFLAGS) -MMD -MP
+ifeq ($(CONFIG_DARWIN),yes)
+CFLAGS+=-mdynamic-no-pic
endif
-CFLAGS=-Wall -O2 -g -fno-strict-aliasing
#CFLAGS+=-Werror
LDFLAGS=-g
LIBS=
@@ -30,44 +21,30 @@ ifeq ($(TARGET_ARCH),arm)
TARGET_ARCH2=armeb
endif
endif
-ifeq ($(TARGET_ARCH),sh4)
- ifeq ($(TARGET_WORDS_BIGENDIAN),yes)
- TARGET_ARCH2=sh4eb
- endif
-endif
-ifeq ($(TARGET_ARCH),mips)
- ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
- TARGET_ARCH2=mipsel
- endif
-endif
-QEMU_USER=qemu-$(TARGET_ARCH2)
# system emulator name
ifdef CONFIG_SOFTMMU
-ifeq ($(TARGET_ARCH), i386)
-QEMU_SYSTEM=qemu$(EXESUF)
-else
QEMU_SYSTEM=qemu-system-$(TARGET_ARCH2)$(EXESUF)
-endif
else
QEMU_SYSTEM=qemu-fast
endif
-ifdef CONFIG_USER_ONLY
-PROGS=$(QEMU_USER)
-else
PROGS+=$(QEMU_SYSTEM)
ifndef CONFIG_SOFTMMU
CONFIG_STATIC=y
endif
-endif # !CONFIG_USER_ONLY
ifdef CONFIG_STATIC
LDFLAGS+=-static
endif
ifeq ($(ARCH),i386)
-CFLAGS+=-fomit-frame-pointer
-OP_CFLAGS=$(CFLAGS) -mpreferred-stack-boundary=2
+OP_CFLAGS=$(CFLAGS) -O2 -fomit-frame-pointer
+CFLAGS+=-DUSE_MMX -mmmx
+ifneq ($(CONFIG_DARWIN),yes)
+OP_CFLAGS+= -mpreferred-stack-boundary=2
+else
+OP_CFLAGS+= -mpreferred-stack-boundary=4
+endif
ifeq ($(HAVE_GCC3_OPTIONS),yes)
OP_CFLAGS+= -falign-functions=0 -fno-gcse
else
@@ -77,7 +54,7 @@ endif
ifdef TARGET_GPROF
USE_I386_LD=y
endif
-ifdef CONFIG_STATIC
+ifdef wwCONFIG_STATIC
USE_I386_LD=y
endif
ifdef USE_I386_LD
@@ -112,7 +89,7 @@ CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
LDFLAGS+=-m32
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
else
-CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
+CFLAGS+=-m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m32
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
@@ -122,9 +99,8 @@ endif
endif
ifeq ($(ARCH),sparc64)
-CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
+CFLAGS+=-m64 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
LDFLAGS+=-m64
-LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
OP_CFLAGS=$(CFLAGS) -fno-delayed-branch -ffixed-i0
endif
@@ -159,17 +135,24 @@ OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
endif
ifeq ($(CONFIG_DARWIN),yes)
-OP_CFLAGS+= -mdynamic-no-pic
+CFLAGS+= -I/opt/local/include
LIBS+=-lmx
endif
+ifeq ($(CONFIG_WIN32),yes)
+UNAME := $(shell uname -s)
+ifneq ($(findstring CYGWIN,$(UNAME)),)
+CFLAGS += -mno-cygwin -D_WIN32
+LDFLAGS += -mno-cygwin -mwindows
+endif
+endif
+
#########################################################
-DEFINES+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+DEFINES+=-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LIBS+=-lm
-ifndef CONFIG_USER_ONLY
-LIBS+=-lz
-endif
+#now using our own zlib static version
+#LIBS+=-L/usr/lib -lz
ifdef CONFIG_WIN32
LIBS+=-lwinmm -lws2_32 -liphlpapi
endif
@@ -189,9 +172,6 @@ ifdef TARGET_HAS_BFLT
OBJS+= flatload.o
endif
-ifeq ($(TARGET_ARCH), i386)
-OBJS+= vm86.o
-endif
ifeq ($(TARGET_ARCH), arm)
OBJS+=nwfpe/fpa11.o nwfpe/fpa11_cpdo.o \
nwfpe/fpa11_cpdt.o nwfpe/fpa11_cprt.o nwfpe/fpopcode.o nwfpe/single_cpdo.o \
@@ -201,8 +181,8 @@ SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a
# cpu emulator library
-LIBOBJS=exec.o kqemu.o translate-op.o translate-all.o cpu-exec.o\
- translate.o op.o
+LIBOBJS=exec.o kqemu.o translate-all.o translate-op.o cpu-exec.o\
+ translate.o
ifdef CONFIG_SOFTFLOAT
LIBOBJS+=fpu/softfloat.o
else
@@ -210,39 +190,15 @@ LIBOBJS+=fpu/softfloat-native.o
endif
DEFINES+=-I$(SRC_PATH)/fpu
-ifeq ($(TARGET_ARCH), i386)
-LIBOBJS+=helper.o helper2.o
-ifeq ($(ARCH), i386)
-LIBOBJS+=translate-copy.o
-endif
-endif
-
-ifeq ($(TARGET_ARCH), x86_64)
-LIBOBJS+=helper.o helper2.o
-endif
-
-ifeq ($(TARGET_BASE_ARCH), ppc)
-LIBOBJS+= op_helper.o helper.o
-endif
-
-ifeq ($(TARGET_ARCH), mips)
-LIBOBJS+= op_helper.o helper.o
-endif
-
-ifeq ($(TARGET_BASE_ARCH), sparc)
-LIBOBJS+= op_helper.o helper.o
-endif
-
ifeq ($(TARGET_BASE_ARCH), arm)
-LIBOBJS+= op_helper.o helper.o
+ifdef CONFIG_TRACE
+LIBOBJS += translate-trace.o translate-all-trace.o translate-op-trace.o
endif
-
-ifeq ($(TARGET_BASE_ARCH), sh4)
LIBOBJS+= op_helper.o helper.o
endif
# NOTE: the disassembler code is only needed for debugging
-LIBOBJS+=disas.o
+LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
USE_I386_DIS=y
endif
@@ -258,9 +214,6 @@ endif
ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
LIBOBJS+=ppc-dis.o
endif
-ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips)
-LIBOBJS+=mips-dis.o
-endif
ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
LIBOBJS+=sparc-dis.o
endif
@@ -270,18 +223,16 @@ endif
ifeq ($(findstring m68k, $(TARGET_ARCH) $(ARCH)),m68k)
LIBOBJS+=m68k-dis.o
endif
-ifeq ($(findstring sh4, $(TARGET_ARCH) $(ARCH)),sh4)
-LIBOBJS+=sh4-dis.o
-endif
ifdef CONFIG_GDBSTUB
OBJS+=gdbstub.o
endif
+OBJS+=android_console.o android_modem.c sim_card.o gsm.o sysdeps_qemu.o charpipe.o modem_driver.o sms.o \
+ android_gps.o
+
all: $(PROGS)
-$(QEMU_USER): $(OBJS)
- $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
ifeq ($(ARCH),alpha)
# Mark as 32 bit binary, i. e. it will be mapped into the low 31 bit of
# the address space (31 bit so sign extending doesn't matter)
@@ -289,14 +240,26 @@ ifeq ($(ARCH),alpha)
endif
# must use static linking to avoid leaving stuff in virtual address space
-VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o loader.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
+VL_OBJS=vl.o osdep.o block.o readline.o monitor.o pci.o console.o loader.o sockets.o qemu_timers.o
+VL_OBJS+= block-cloop.o block-dmg.o block-qcow.o aes.o
+ifdef CONFIG_TRACE
+VL_OBJS+=trace.o dcache.o varint.o
+endif
+
+vl.o: android.h
+
+ifdef CONFIG_SHAPER
+VL_OBJS+=shaper.o
+vl.o: shaper.h shaper.c
+endif
ifdef CONFIG_WIN32
VL_OBJS+=tap-win32.o
endif
-SOUND_HW = sb16.o es1370.o
-AUDIODRV = audio.o noaudio.o wavaudio.o
+AUDIODRV = audio.o noaudio.o wavaudio.o mixeng.o
+ifdef CONFIG_WINAUDIO
+AUDIODRV += winaudio.o
+endif
ifdef CONFIG_SDL
AUDIODRV += sdlaudio.o
endif
@@ -308,7 +271,13 @@ AUDIODRV += coreaudio.o
endif
ifdef CONFIG_ALSA
AUDIODRV += alsaaudio.o
-LIBS += -lasound
+alsaaudio.o: DEFINES := $(CONFIG_ALSA_INC) $(DEFINES)
+#LIBS += -lasound # we use dlopen/dlsym to get ALSA functions when available
+endif
+ifdef CONFIG_ESD
+AUDIODRV += esdaudio.o audio_pt_int.o
+esdaudio.o: DEFINES := $(CONFIG_ESD_INC) $(DEFINES)
+#LIBS += -lesd # we use dlopen/dlsym to get esound function, when available
endif
ifdef CONFIG_DSOUND
AUDIODRV += dsoundaudio.o
@@ -324,65 +293,94 @@ SOUND_HW += fmopl.o adlib.o
endif
AUDIODRV+= wavcapture.o
+AUDIOLIB := libqemu-audio.a
+$(AUDIOLIB): $(AUDIODRV)
+ rm -f $@
+ $(AR) rcs $@ $(AUDIODRV)
+
+# DMA
+VL_OBJS+=dma.o
+
# SCSI layer
-VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
+VL_OBJS+= scsi-disk.o cdrom.o
# USB layer
VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o
-# PCI network cards
-VL_OBJS+= ne2000.o rtl8139.o pcnet.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 mixeng.o apic.o parallel.o acpi.o piix_pci.o
-VL_OBJS+= usb-uhci.o
-DEFINES += -DHAS_AUDIO
-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+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
-VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
+ifeq ($(TARGET_BASE_ARCH), arm)
+VL_OBJS+= smc91c111.o arm_pic.o arm_boot.o
+VL_OBJS+= android_arm.o goldfish_device.o goldfish_interrupt.o goldfish_timer.o \
+ goldfish_fb.o goldfish_tty.o goldfish_switch.o goldfish_mmc.o \
+ goldfish_memlog.o \
+ goldfish_battery.o \
+ irq.o
+
+# platform_audio support
DEFINES += -DHAS_AUDIO
+VL_OBJS += goldfish_audio.o
+
+ifeq ($(CONFIG_QFB), yes)
+VL_OBJS+= qfb_dev.o qfb_fuse.o qfb_fs.o
endif
-ifeq ($(TARGET_ARCH), mips)
-VL_OBJS+= mips_r4k.o dma.o vga.o serial.o i8254.o i8259.o
-#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o
-endif
-ifeq ($(TARGET_BASE_ARCH), sparc)
-ifeq ($(TARGET_ARCH), sparc64)
-VL_OBJS+= sun4u.o ide.o pckbd.o ps2.o vga.o apb_pci.o
-VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o
-VL_OBJS+= cirrus_vga.o parallel.o
-else
-VL_OBJS+= sun4m.o tcx.o lance.o iommu.o m48t59.o slavio_intctl.o
-VL_OBJS+= slavio_timer.o slavio_serial.o slavio_misc.o fdc.o esp.o
+ifeq ($(CONFIG_TRACE), yes)
+VL_OBJS+= goldfish_trace.o
endif
+ifeq ($(CONFIG_SKINS), yes)
+VL_OBJS+= goldfish_events_device.o
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
+ifeq ($(CONFIG_NAND), yes)
+VL_OBJS+= goldfish_nand.o
endif
-ifeq ($(TARGET_BASE_ARCH), sh4)
-VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
endif
ifdef CONFIG_GDBSTUB
-VL_OBJS+=gdbstub.o
-endif
+VL_OBJS+=gdbstub.o
+endif
+
+VL_OBJS+=android_console.o android_modem.o sim_card.o gsm.o sysdeps_qemu.o \
+ charpipe.o modem_driver.o sms.o remote_call.o \
+ cbuffer.o \
+ android_gps.o
+
+VL_OBJS+=proxy_common.o proxy_http.o
+
+VL_OBJS+=android_debug.o \
+ android_help.o \
+ android_option.o \
+ android_utils.o \
+ android_resource.o \
+ android_config.o \
+ android_timezone.o \
+ android_events.o \
+ android_profile.o \
+ android_qemud.o \
+ android_kmsg.o \
+ skin_image.o \
+ skin_trackball.o \
+ skin_keyboard.o \
+ skin_file.o \
+ skin_window.o \
+ skin_scaler.o \
+ skin_keyset.o \
+ skin_rect.o \
+ skin_region.o \
+ skin_composer.o \
+ skin_surface.o \
+ framebuffer.o
+
ifdef CONFIG_SDL
+ifdef CONFIG_SKINS
+VL_OBJS += loadpng.o android_main.o android_charmap.o
+else
VL_OBJS+=sdl.o
endif
+endif
VL_OBJS+=vnc.o
ifdef CONFIG_COCOA
VL_OBJS+=cocoa.o
COCOA_LIBS=-F/System/Library/Frameworks -framework Cocoa -framework IOKit
-ifdef CONFIG_COREAUDIO
-COCOA_LIBS+=-framework CoreAudio
endif
+ifdef CONFIG_COREAUDIO
+COCOA_LIBS+=-F/System/Library/Frameworks -framework CoreAudio
endif
ifdef CONFIG_SLIRP
DEFINES+=-I$(SRC_PATH)/slirp
@@ -393,17 +391,33 @@ VL_OBJS+=$(addprefix slirp/, $(SLIRP_OBJS))
endif
VL_LDFLAGS=
+ifdef CONFIG_WIN32
+VL_LDFLAGS+=-mno-cygwin -mwindows
+endif
+ifndef CONFIG_WIN32
+ifndef CONFIG_DARWIN
+VL_LDFLAGS+=-lX11
+endif
+endif
+
+android_main.c: android_utils.h android_resource.h android_config.h \
+ skin_image.h android_icons.h skin_file.h \
+ skin_window.h
+
# specific flags are needed for non soft mmu emulator
+ifdef CONFIG_SKINS
+VL_LIBS+=$(PNG_LIBS)
+endif
ifdef CONFIG_STATIC
VL_LDFLAGS+=-static
endif
ifndef CONFIG_SOFTMMU
-VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
+VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/i386-vl.ld
endif
ifndef CONFIG_DARWIN
ifndef CONFIG_WIN32
ifndef CONFIG_SOLARIS
-VL_LIBS=-lutil -lrt
+VL_LIBS+=-lutil -lrt
endif
endif
endif
@@ -412,26 +426,58 @@ vl.o: CFLAGS+=-p
VL_LDFLAGS+=-p
endif
-ifeq ($(ARCH),ia64)
-VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
+# we need to filter out _GNU_SOURCE from the SDL C Flags if any, because
+# this macro is not needed at all and will break recent versions of Cygwin
+# with the -mno-cygwin option (blame it on Cygwin/Mingw)
+#
+SDL_CFLAGS := $(filter-out -D_GNU_SOURCE=1,$(SDL_CFLAGS))
+
+$(info SDL_CFLAGS is $(SDL_CFLAGS))
+
+ifdef CONFIG_DARWIN
+ifdef CONFIG_SDL
+CFLAGS += $(SDL_CFLAGS)
+endif
endif
-ifeq ($(ARCH),sparc64)
-VL_LDFLAGS+=-m64
-VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
+#skin_%.o android_main.o: CFLAGS+=-O0 -g -fno-omit-frame-pointer
+
+ifeq ($(ARCH),ia64)
+VL_LDFLAGS+=-Wl,-G0 -Wl,-T,$(SRC_PATH)/ia64.ld
endif
ifdef CONFIG_WIN32
SDL_LIBS := $(filter-out -mwindows, $(SDL_LIBS)) -mconsole
+VL_OBJS+=android_icon.o
+android_icon.o: images/android_icon.rc
+ windres $< -o $@
endif
-$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
+$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a $(AUDIOLIB) $(LIBPNG_LIB) $(ZLIB_LIB)
$(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
cocoa.o: cocoa.m
$(CC) $(CFLAGS) $(DEFINES) -c -o $@ $<
-sdl.o: sdl.c keymaps.c sdl_keysym.h
+android_main.o: android_main.c android.h android_icons.h android_charmap.h android_utils.h android_resource.h skin_image.h
+ $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+
+android_console.o: android_console.c # we need SDL_CFLAGS
+ $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+
+android_resource.o: android_resource.c android_resource.h skin_default.h
+ $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+
+skin_image.o: skin_image.c skin_image.h android_resource.h
+ $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+
+skin_%.o: skin_%.c skin_%.h
+ $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+
+android_charmap.o: android_charmap.c android_charmap.h
+ $(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+
+android_utils.o: android_utils.c android_utils.h
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
@@ -440,13 +486,17 @@ vnc.o: vnc.c keymaps.c sdl_keysym.h vnchextile.h
sdlaudio.o: sdlaudio.c
$(CC) $(CFLAGS) $(DEFINES) $(SDL_CFLAGS) -c -o $@ $<
+esdaudio.o: esdaudio.c
+ $(CC) $(CFLAGS) -O0 $(DEFINES) -c -o $@ $<
+
+
depend: $(SRCS)
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
vldepend: $(VL_OBJS:.o=.c)
$(CC) -MM $(CFLAGS) $(DEFINES) $^ 1>.depend
-# libqemu
+# libqemu
libqemu.a: $(LIBOBJS)
rm -f $@
@@ -454,9 +504,14 @@ libqemu.a: $(LIBOBJS)
translate.o: translate.c gen-op.h opc.h cpu.h
+ifdef CONFIG_TRACE
+translate-trace.o: translate.c gen-op-trace.h opc-trace.h cpu.h
+ $(CC) $(CFLAGS) $(DEFINES) -DGEN_TRACE -c -o $@ $<
+endif
+
translate-all.o: translate-all.c opc.h cpu.h
-translate-op.o: translate-all.c op.h opc.h cpu.h
+translate-op.o: translate-op.c op.h opc.h cpu.h
op.h: op.o $(DYNGEN)
$(DYNGEN) -o $@ $<
@@ -470,53 +525,41 @@ gen-op.h: op.o $(DYNGEN)
op.o: op.c
$(CC) $(OP_CFLAGS) $(DEFINES) -c -o $@ $<
-helper.o: helper.c
- $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
+ifdef CONFIG_TRACE
+op-trace.h: op-trace.o $(DYNGEN)
+ $(DYNGEN) -o $@ $<
-ifeq ($(TARGET_BASE_ARCH), i386)
-op.o: op.c opreg_template.h ops_template.h ops_template_mem.h ops_mem.h ops_sse.h
-endif
+opc-trace.h: op-trace.o $(DYNGEN)
+ $(DYNGEN) -c -o $@ $<
-ifeq ($(TARGET_ARCH), arm)
-op.o: op.c op_template.h
-pl110.o: pl110_template.h
-endif
+gen-op-trace.h: op-trace.o $(DYNGEN)
+ $(DYNGEN) -g -o $@ $<
-ifeq ($(TARGET_BASE_ARCH), sparc)
-op.o: op.c op_template.h op_mem.h fop_template.h fbranch_template.h
-magic_load.o: elf_op.h
-endif
+op-trace.o: op.c
+ $(CC) $(OP_CFLAGS) $(DEFINES) -DGEN_TRACE -c -o $@ $<
-ifeq ($(TARGET_BASE_ARCH), ppc)
-op.o: op.c op_template.h op_mem.h
-op_helper.o: op_helper_mem.h
-translate.o: translate.c translate_init.c
-endif
+translate-all-trace.o: translate-all.c op-trace.h opc-trace.h cpu.h
+ $(CC) $(OP_CFLAGS) $(DEFINES) -DGEN_TRACE -c -o $@ $<
+
+translate-op-trace.o: translate-op.c op-trace.h opc-trace.h cpu.h
+ $(CC) $(OP_CFLAGS) $(DEFINES) -DGEN_TRACE -c -o $@ $<
-ifeq ($(TARGET_ARCH), mips)
-op.o: op.c op_template.c op_mem.c
-op_helper.o: op_helper_mem.c
endif
-loader.o: loader.c elf_ops.h
+skin_scaler.o: CFLAGS += -O2 -g -fno-omit-frame-pointer
-acpi.o: acpi.c acpi-dsdt.hex
+helper.o: helper.c
+ $(CC) $(HELPER_CFLAGS) $(DEFINES) -c -o $@ $<
-ifdef BUILD_ACPI_TABLES
-$(SRC_PATH)/hw/acpi-dsdt.hex: acpi-dsdt.dsl
- iasl -tc -p $@ $<
+ifeq ($(TARGET_ARCH), arm)
+op.o: op.c op_template.h
+ifdef CONFIG_TRACE
+op-trace.o: op.c op_template.h
endif
-
-ifeq ($(TARGET_ARCH), sh4)
-op.o: op.c op_mem.c cpu.h
-op_helper.o: op_helper.c exec.h cpu.h
-helper.o: helper.c exec.h cpu.h
-sh7750.o: sh7750.c sh7750_regs.h sh7750_regnames.h cpu.h
-shix.o: shix.c sh7750_regs.h sh7750_regnames.h
-sh7750_regnames.o: sh7750_regnames.c sh7750_regnames.h sh7750_regs.h
-tc58128.o: tc58128.c
endif
+loader.o: loader.c elf_ops.h
+
$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
%.o: %.c
@@ -526,9 +569,12 @@ $(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
$(CC) $(DEFINES) -c -o $@ $<
clean:
- rm -f *.o *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o
+ rm -f *.o *.d *.a *~ $(PROGS) gen-op.h opc.h op.h nwfpe/*.o slirp/*.o fpu/*.o
+ifdef CONFIG_TRACE
+ rm -f opc-trace.h op-trace.h gen-op-trace.h
+endif
-install: all
+install: all
ifneq ($(PROGS),)
$(INSTALL) -m 755 -s $(PROGS) "$(DESTDIR)$(bindir)"
endif
@@ -537,8 +583,5 @@ ifneq ($(wildcard .depend),)
include .depend
endif
-ifeq (1, 0)
-audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \
-fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \
-CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare
-endif
+# Include automatically generated dependency files
+-include $(wildcard *.d)
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..e77696a
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/README b/README
index 1a39500..c333804 100644
--- a/README
+++ b/README
@@ -1,3 +1,13 @@
-Read the documentation in qemu-doc.html.
+This package contains the sources to the Android emulator program.
+
+Building the emulator:
+----------------------
+
+you can build this program either form within the Android build system,
+or as a standalone binary executable.
+
+ + in the former case, simply type "m emulator" to build the emulator
+
+ + in the second case, read the INSTALL document for details on
+ requirement and build/install steps.
-Fabrice Bellard. \ No newline at end of file
diff --git a/aes.h b/aes.h
index a0167eb..6fb9023 100644
--- a/aes.h
+++ b/aes.h
@@ -4,23 +4,34 @@
#define AES_MAXNR 14
#define AES_BLOCK_SIZE 16
-struct aes_key_st {
- uint32_t rd_key[4 *(AES_MAXNR + 1)];
- int rounds;
-};
-typedef struct aes_key_st AES_KEY;
-
-int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
- AES_KEY *key);
-int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
- AES_KEY *key);
-
-void AES_encrypt(const unsigned char *in, unsigned char *out,
- const AES_KEY *key);
-void AES_decrypt(const unsigned char *in, unsigned char *out,
- const AES_KEY *key);
-void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
- const unsigned long length, const AES_KEY *key,
- unsigned char *ivec, const int enc);
+typedef struct aes_key_st
+{
+ uint32_t rd_key[4 *(AES_MAXNR + 1)];
+ int rounds;
+
+} AES_KEY;
+
+int AES_set_encrypt_key(const unsigned char* userKey,
+ const int bits,
+ AES_KEY* key);
+
+int AES_set_decrypt_key(const unsigned char* userKey,
+ const int bits,
+ AES_KEY* key);
+
+void AES_encrypt(const unsigned char* in,
+ unsigned char* out,
+ const AES_KEY* key);
+
+void AES_decrypt(const unsigned char* in,
+ unsigned char* out,
+ const AES_KEY* key);
+
+void AES_cbc_encrypt(const unsigned char* in,
+ unsigned char* out,
+ const unsigned long length,
+ const AES_KEY* key,
+ unsigned char* ivec,
+ const int enc);
#endif
diff --git a/alpha-dis.c b/alpha-dis.c
deleted file mode 100644
index 81a55e9..0000000
--- a/alpha-dis.c
+++ /dev/null
@@ -1,1960 +0,0 @@
-/* alpha-dis.c -- Disassemble Alpha AXP instructions
- Copyright 1996, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
- Contributed by Richard Henderson <rth@tamu.edu>,
- patterned after the PPC opcode handling written by Ian Lance Taylor.
-
-This file is part of GDB, GAS, and the GNU binutils.
-
-GDB, GAS, and the GNU binutils are free software; you can redistribute
-them and/or modify them under the terms of the GNU General Public
-License as published by the Free Software Foundation; either version
-2, or (at your option) any later version.
-
-GDB, GAS, and the GNU binutils are distributed in the hope that they
-will be useful, but WITHOUT ANY WARRANTY; without even the implied
-warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
-the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this file; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
-
-#include <stdio.h>
-#include "dis-asm.h"
-
-/* The opcode table is an array of struct alpha_opcode. */
-
-struct alpha_opcode
-{
- /* The opcode name. */
- const char *name;
-
- /* The opcode itself. Those bits which will be filled in with
- operands are zeroes. */
- unsigned opcode;
-
- /* The opcode mask. This is used by the disassembler. This is a
- mask containing ones indicating those bits which must match the
- opcode field, and zeroes indicating those bits which need not
- match (and are presumably filled in by operands). */
- unsigned mask;
-
- /* One bit flags for the opcode. These are primarily used to
- indicate specific processors and environments support the
- instructions. The defined values are listed below. */
- unsigned flags;
-
- /* An array of operand codes. Each code is an index into the
- operand table. They appear in the order which the operands must
- appear in assembly code, and are terminated by a zero. */
- unsigned char operands[4];
-};
-
-/* The table itself is sorted by major opcode number, and is otherwise
- in the order in which the disassembler should consider
- instructions. */
-extern const struct alpha_opcode alpha_opcodes[];
-extern const unsigned alpha_num_opcodes;
-
-/* Values defined for the flags field of a struct alpha_opcode. */
-
-/* CPU Availability */
-#define AXP_OPCODE_BASE 0x0001 /* Base architecture -- all cpus. */
-#define AXP_OPCODE_EV4 0x0002 /* EV4 specific PALcode insns. */
-#define AXP_OPCODE_EV5 0x0004 /* EV5 specific PALcode insns. */
-#define AXP_OPCODE_EV6 0x0008 /* EV6 specific PALcode insns. */
-#define AXP_OPCODE_BWX 0x0100 /* Byte/word extension (amask bit 0). */
-#define AXP_OPCODE_CIX 0x0200 /* "Count" extension (amask bit 1). */
-#define AXP_OPCODE_MAX 0x0400 /* Multimedia extension (amask bit 8). */
-
-#define AXP_OPCODE_NOPAL (~(AXP_OPCODE_EV4|AXP_OPCODE_EV5|AXP_OPCODE_EV6))
-
-/* A macro to extract the major opcode from an instruction. */
-#define AXP_OP(i) (((i) >> 26) & 0x3F)
-
-/* The total number of major opcodes. */
-#define AXP_NOPS 0x40
-
-
-/* The operands table is an array of struct alpha_operand. */
-
-struct alpha_operand
-{
- /* The number of bits in the operand. */
- unsigned int bits : 5;
-
- /* How far the operand is left shifted in the instruction. */
- unsigned int shift : 5;
-
- /* The default relocation type for this operand. */
- signed int default_reloc : 16;
-
- /* One bit syntax flags. */
- unsigned int flags : 16;
-
- /* Insertion function. This is used by the assembler. To insert an
- operand value into an instruction, check this field.
-
- If it is NULL, execute
- i |= (op & ((1 << o->bits) - 1)) << o->shift;
- (i is the instruction which we are filling in, o is a pointer to
- this structure, and op is the opcode value; this assumes twos
- complement arithmetic).
-
- If this field is not NULL, then simply call it with the
- instruction and the operand value. It will return the new value
- of the instruction. If the ERRMSG argument is not NULL, then if
- the operand value is illegal, *ERRMSG will be set to a warning
- string (the operand will be inserted in any case). If the
- operand value is legal, *ERRMSG will be unchanged (most operands
- can accept any value). */
- unsigned (*insert) PARAMS ((unsigned instruction, int op,
- const char **errmsg));
-
- /* Extraction function. This is used by the disassembler. To
- extract this operand type from an instruction, check this field.
-
- If it is NULL, compute
- op = ((i) >> o->shift) & ((1 << o->bits) - 1);
- if ((o->flags & AXP_OPERAND_SIGNED) != 0
- && (op & (1 << (o->bits - 1))) != 0)
- op -= 1 << o->bits;
- (i is the instruction, o is a pointer to this structure, and op
- is the result; this assumes twos complement arithmetic).
-
- If this field is not NULL, then simply call it with the
- instruction value. It will return the value of the operand. If
- the INVALID argument is not NULL, *INVALID will be set to
- non-zero if this operand type can not actually be extracted from
- this operand (i.e., the instruction does not match). If the
- operand is valid, *INVALID will not be changed. */
- int (*extract) PARAMS ((unsigned instruction, int *invalid));
-};
-
-/* Elements in the table are retrieved by indexing with values from
- the operands field of the alpha_opcodes table. */
-
-extern const struct alpha_operand alpha_operands[];
-extern const unsigned alpha_num_operands;
-
-/* Values defined for the flags field of a struct alpha_operand. */
-
-/* Mask for selecting the type for typecheck purposes */
-#define AXP_OPERAND_TYPECHECK_MASK \
- (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA | AXP_OPERAND_IR | \
- AXP_OPERAND_FPR | AXP_OPERAND_RELATIVE | AXP_OPERAND_SIGNED | \
- AXP_OPERAND_UNSIGNED)
-
-/* This operand does not actually exist in the assembler input. This
- is used to support extended mnemonics, for which two operands fields
- are identical. The assembler should call the insert function with
- any op value. The disassembler should call the extract function,
- ignore the return value, and check the value placed in the invalid
- argument. */
-#define AXP_OPERAND_FAKE 01
-
-/* The operand should be wrapped in parentheses rather than separated
- from the previous by a comma. This is used for the load and store
- instructions which want their operands to look like "Ra,disp(Rb)". */
-#define AXP_OPERAND_PARENS 02
-
-/* Used in combination with PARENS, this supresses the supression of
- the comma. This is used for "jmp Ra,(Rb),hint". */
-#define AXP_OPERAND_COMMA 04
-
-/* This operand names an integer register. */
-#define AXP_OPERAND_IR 010
-
-/* This operand names a floating point register. */
-#define AXP_OPERAND_FPR 020
-
-/* This operand is a relative branch displacement. The disassembler
- prints these symbolically if possible. */
-#define AXP_OPERAND_RELATIVE 040
-
-/* This operand takes signed values. */
-#define AXP_OPERAND_SIGNED 0100
-
-/* This operand takes unsigned values. This exists primarily so that
- a flags value of 0 can be treated as end-of-arguments. */
-#define AXP_OPERAND_UNSIGNED 0200
-
-/* Supress overflow detection on this field. This is used for hints. */
-#define AXP_OPERAND_NOOVERFLOW 0400
-
-/* Mask for optional argument default value. */
-#define AXP_OPERAND_OPTIONAL_MASK 07000
-
-/* This operand defaults to zero. This is used for jump hints. */
-#define AXP_OPERAND_DEFAULT_ZERO 01000
-
-/* This operand should default to the first (real) operand and is used
- in conjunction with AXP_OPERAND_OPTIONAL. This allows
- "and $0,3,$0" to be written as "and $0,3", etc. I don't like
- it, but it's what DEC does. */
-#define AXP_OPERAND_DEFAULT_FIRST 02000
-
-/* Similarly, this operand should default to the second (real) operand.
- This allows "negl $0" instead of "negl $0,$0". */
-#define AXP_OPERAND_DEFAULT_SECOND 04000
-
-
-/* Register common names */
-
-#define AXP_REG_V0 0
-#define AXP_REG_T0 1
-#define AXP_REG_T1 2
-#define AXP_REG_T2 3
-#define AXP_REG_T3 4
-#define AXP_REG_T4 5
-#define AXP_REG_T5 6
-#define AXP_REG_T6 7
-#define AXP_REG_T7 8
-#define AXP_REG_S0 9
-#define AXP_REG_S1 10
-#define AXP_REG_S2 11
-#define AXP_REG_S3 12
-#define AXP_REG_S4 13
-#define AXP_REG_S5 14
-#define AXP_REG_FP 15
-#define AXP_REG_A0 16
-#define AXP_REG_A1 17
-#define AXP_REG_A2 18
-#define AXP_REG_A3 19
-#define AXP_REG_A4 20
-#define AXP_REG_A5 21
-#define AXP_REG_T8 22
-#define AXP_REG_T9 23
-#define AXP_REG_T10 24
-#define AXP_REG_T11 25
-#define AXP_REG_RA 26
-#define AXP_REG_PV 27
-#define AXP_REG_T12 27
-#define AXP_REG_AT 28
-#define AXP_REG_GP 29
-#define AXP_REG_SP 30
-#define AXP_REG_ZERO 31
-
-#define bfd_mach_alpha_ev4 0x10
-#define bfd_mach_alpha_ev5 0x20
-#define bfd_mach_alpha_ev6 0x30
-
-enum bfd_reloc_code_real {
- BFD_RELOC_23_PCREL_S2,
- BFD_RELOC_ALPHA_HINT
-};
-
-/* This file holds the Alpha AXP opcode table. The opcode table includes
- almost all of the extended instruction mnemonics. This permits the
- disassembler to use them, and simplifies the assembler logic, at the
- cost of increasing the table size. The table is strictly constant
- data, so the compiler should be able to put it in the text segment.
-
- This file also holds the operand table. All knowledge about inserting
- and extracting operands from instructions is kept in this file.
-
- The information for the base instruction set was compiled from the
- _Alpha Architecture Handbook_, Digital Order Number EC-QD2KB-TE,
- version 2.
-
- The information for the post-ev5 architecture extensions BWX, CIX and
- MAX came from version 3 of this same document, which is also available
- on-line at http://ftp.digital.com/pub/Digital/info/semiconductor
- /literature/alphahb2.pdf
-
- The information for the EV4 PALcode instructions was compiled from
- _DECchip 21064 and DECchip 21064A Alpha AXP Microprocessors Hardware
- Reference Manual_, Digital Order Number EC-Q9ZUA-TE, preliminary
- revision dated June 1994.
-
- The information for the EV5 PALcode instructions was compiled from
- _Alpha 21164 Microprocessor Hardware Reference Manual_, Digital
- Order Number EC-QAEQB-TE, preliminary revision dated April 1995. */
-
-/* Local insertion and extraction functions */
-
-static unsigned insert_rba PARAMS((unsigned, int, const char **));
-static unsigned insert_rca PARAMS((unsigned, int, const char **));
-static unsigned insert_za PARAMS((unsigned, int, const char **));
-static unsigned insert_zb PARAMS((unsigned, int, const char **));
-static unsigned insert_zc PARAMS((unsigned, int, const char **));
-static unsigned insert_bdisp PARAMS((unsigned, int, const char **));
-static unsigned insert_jhint PARAMS((unsigned, int, const char **));
-static unsigned insert_ev6hwjhint PARAMS((unsigned, int, const char **));
-
-static int extract_rba PARAMS((unsigned, int *));
-static int extract_rca PARAMS((unsigned, int *));
-static int extract_za PARAMS((unsigned, int *));
-static int extract_zb PARAMS((unsigned, int *));
-static int extract_zc PARAMS((unsigned, int *));
-static int extract_bdisp PARAMS((unsigned, int *));
-static int extract_jhint PARAMS((unsigned, int *));
-static int extract_ev6hwjhint PARAMS((unsigned, int *));
-
-
-/* The operands table */
-
-const struct alpha_operand alpha_operands[] =
-{
- /* The fields are bits, shift, insert, extract, flags */
- /* The zero index is used to indicate end-of-list */
-#define UNUSED 0
- { 0, 0, 0, 0, 0, 0 },
-
- /* The plain integer register fields */
-#define RA (UNUSED + 1)
- { 5, 21, 0, AXP_OPERAND_IR, 0, 0 },
-#define RB (RA + 1)
- { 5, 16, 0, AXP_OPERAND_IR, 0, 0 },
-#define RC (RB + 1)
- { 5, 0, 0, AXP_OPERAND_IR, 0, 0 },
-
- /* The plain fp register fields */
-#define FA (RC + 1)
- { 5, 21, 0, AXP_OPERAND_FPR, 0, 0 },
-#define FB (FA + 1)
- { 5, 16, 0, AXP_OPERAND_FPR, 0, 0 },
-#define FC (FB + 1)
- { 5, 0, 0, AXP_OPERAND_FPR, 0, 0 },
-
- /* The integer registers when they are ZERO */
-#define ZA (FC + 1)
- { 5, 21, 0, AXP_OPERAND_FAKE, insert_za, extract_za },
-#define ZB (ZA + 1)
- { 5, 16, 0, AXP_OPERAND_FAKE, insert_zb, extract_zb },
-#define ZC (ZB + 1)
- { 5, 0, 0, AXP_OPERAND_FAKE, insert_zc, extract_zc },
-
- /* The RB field when it needs parentheses */
-#define PRB (ZC + 1)
- { 5, 16, 0, AXP_OPERAND_IR|AXP_OPERAND_PARENS, 0, 0 },
-
- /* The RB field when it needs parentheses _and_ a preceding comma */
-#define CPRB (PRB + 1)
- { 5, 16, 0,
- AXP_OPERAND_IR|AXP_OPERAND_PARENS|AXP_OPERAND_COMMA, 0, 0 },
-
- /* The RB field when it must be the same as the RA field */
-#define RBA (CPRB + 1)
- { 5, 16, 0, AXP_OPERAND_FAKE, insert_rba, extract_rba },
-
- /* The RC field when it must be the same as the RB field */
-#define RCA (RBA + 1)
- { 5, 0, 0, AXP_OPERAND_FAKE, insert_rca, extract_rca },
-
- /* The RC field when it can *default* to RA */
-#define DRC1 (RCA + 1)
- { 5, 0, 0,
- AXP_OPERAND_IR|AXP_OPERAND_DEFAULT_FIRST, 0, 0 },
-
- /* The RC field when it can *default* to RB */
-#define DRC2 (DRC1 + 1)
- { 5, 0, 0,
- AXP_OPERAND_IR|AXP_OPERAND_DEFAULT_SECOND, 0, 0 },
-
- /* The FC field when it can *default* to RA */
-#define DFC1 (DRC2 + 1)
- { 5, 0, 0,
- AXP_OPERAND_FPR|AXP_OPERAND_DEFAULT_FIRST, 0, 0 },
-
- /* The FC field when it can *default* to RB */
-#define DFC2 (DFC1 + 1)
- { 5, 0, 0,
- AXP_OPERAND_FPR|AXP_OPERAND_DEFAULT_SECOND, 0, 0 },
-
- /* The unsigned 8-bit literal of Operate format insns */
-#define LIT (DFC2 + 1)
- { 8, 13, -LIT, AXP_OPERAND_UNSIGNED, 0, 0 },
-
- /* The signed 16-bit displacement of Memory format insns. From here
- we can't tell what relocation should be used, so don't use a default. */
-#define MDISP (LIT + 1)
- { 16, 0, -MDISP, AXP_OPERAND_SIGNED, 0, 0 },
-
- /* The signed "23-bit" aligned displacement of Branch format insns */
-#define BDISP (MDISP + 1)
- { 21, 0, BFD_RELOC_23_PCREL_S2,
- AXP_OPERAND_RELATIVE, insert_bdisp, extract_bdisp },
-
- /* The 26-bit PALcode function */
-#define PALFN (BDISP + 1)
- { 26, 0, -PALFN, AXP_OPERAND_UNSIGNED, 0, 0 },
-
- /* The optional signed "16-bit" aligned displacement of the JMP/JSR hint */
-#define JMPHINT (PALFN + 1)
- { 14, 0, BFD_RELOC_ALPHA_HINT,
- AXP_OPERAND_RELATIVE|AXP_OPERAND_DEFAULT_ZERO|AXP_OPERAND_NOOVERFLOW,
- insert_jhint, extract_jhint },
-
- /* The optional hint to RET/JSR_COROUTINE */
-#define RETHINT (JMPHINT + 1)
- { 14, 0, -RETHINT,
- AXP_OPERAND_UNSIGNED|AXP_OPERAND_DEFAULT_ZERO, 0, 0 },
-
- /* The 12-bit displacement for the ev[46] hw_{ld,st} (pal1b/pal1f) insns */
-#define EV4HWDISP (RETHINT + 1)
-#define EV6HWDISP (EV4HWDISP)
- { 12, 0, -EV4HWDISP, AXP_OPERAND_SIGNED, 0, 0 },
-
- /* The 5-bit index for the ev4 hw_m[ft]pr (pal19/pal1d) insns */
-#define EV4HWINDEX (EV4HWDISP + 1)
- { 5, 0, -EV4HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
-
- /* The 8-bit index for the oddly unqualified hw_m[tf]pr insns
- that occur in DEC PALcode. */
-#define EV4EXTHWINDEX (EV4HWINDEX + 1)
- { 8, 0, -EV4EXTHWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
-
- /* The 10-bit displacement for the ev5 hw_{ld,st} (pal1b/pal1f) insns */
-#define EV5HWDISP (EV4EXTHWINDEX + 1)
- { 10, 0, -EV5HWDISP, AXP_OPERAND_SIGNED, 0, 0 },
-
- /* The 16-bit index for the ev5 hw_m[ft]pr (pal19/pal1d) insns */
-#define EV5HWINDEX (EV5HWDISP + 1)
- { 16, 0, -EV5HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
-
- /* The 16-bit combined index/scoreboard mask for the ev6
- hw_m[ft]pr (pal19/pal1d) insns */
-#define EV6HWINDEX (EV5HWINDEX + 1)
- { 16, 0, -EV6HWINDEX, AXP_OPERAND_UNSIGNED, 0, 0 },
-
- /* The 13-bit branch hint for the ev6 hw_jmp/jsr (pal1e) insn */
-#define EV6HWJMPHINT (EV6HWINDEX+ 1)
- { 8, 0, -EV6HWJMPHINT,
- AXP_OPERAND_RELATIVE|AXP_OPERAND_DEFAULT_ZERO|AXP_OPERAND_NOOVERFLOW,
- insert_ev6hwjhint, extract_ev6hwjhint }
-};
-
-const unsigned alpha_num_operands = sizeof(alpha_operands)/sizeof(*alpha_operands);
-
-/* The RB field when it is the same as the RA field in the same insn.
- This operand is marked fake. The insertion function just copies
- the RA field into the RB field, and the extraction function just
- checks that the fields are the same. */
-
-/*ARGSUSED*/
-static unsigned
-insert_rba(insn, value, errmsg)
- unsigned insn;
- int value ATTRIBUTE_UNUSED;
- const char **errmsg ATTRIBUTE_UNUSED;
-{
- return insn | (((insn >> 21) & 0x1f) << 16);
-}
-
-static int
-extract_rba(insn, invalid)
- unsigned insn;
- int *invalid;
-{
- if (invalid != (int *) NULL
- && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f))
- *invalid = 1;
- return 0;
-}
-
-
-/* The same for the RC field */
-
-/*ARGSUSED*/
-static unsigned
-insert_rca(insn, value, errmsg)
- unsigned insn;
- int value ATTRIBUTE_UNUSED;
- const char **errmsg ATTRIBUTE_UNUSED;
-{
- return insn | ((insn >> 21) & 0x1f);
-}
-
-static int
-extract_rca(insn, invalid)
- unsigned insn;
- int *invalid;
-{
- if (invalid != (int *) NULL
- && ((insn >> 21) & 0x1f) != (insn & 0x1f))
- *invalid = 1;
- return 0;
-}
-
-
-/* Fake arguments in which the registers must be set to ZERO */
-
-/*ARGSUSED*/
-static unsigned
-insert_za(insn, value, errmsg)
- unsigned insn;
- int value ATTRIBUTE_UNUSED;
- const char **errmsg ATTRIBUTE_UNUSED;
-{
- return insn | (31 << 21);
-}
-
-static int
-extract_za(insn, invalid)
- unsigned insn;
- int *invalid;
-{
- if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != 31)
- *invalid = 1;
- return 0;
-}
-
-/*ARGSUSED*/
-static unsigned
-insert_zb(insn, value, errmsg)
- unsigned insn;
- int value ATTRIBUTE_UNUSED;
- const char **errmsg ATTRIBUTE_UNUSED;
-{
- return insn | (31 << 16);
-}
-
-static int
-extract_zb(insn, invalid)
- unsigned insn;
- int *invalid;
-{
- if (invalid != (int *) NULL && ((insn >> 16) & 0x1f) != 31)
- *invalid = 1;
- return 0;
-}
-
-/*ARGSUSED*/
-static unsigned
-insert_zc(insn, value, errmsg)
- unsigned insn;
- int value ATTRIBUTE_UNUSED;
- const char **errmsg ATTRIBUTE_UNUSED;
-{
- return insn | 31;
-}
-
-static int
-extract_zc(insn, invalid)
- unsigned insn;
- int *invalid;
-{
- if (invalid != (int *) NULL && (insn & 0x1f) != 31)
- *invalid = 1;
- return 0;
-}
-
-
-/* The displacement field of a Branch format insn. */
-
-static unsigned
-insert_bdisp(insn, value, errmsg)
- unsigned insn;
- int value;
- const char **errmsg;
-{
- if (errmsg != (const char **)NULL && (value & 3))
- *errmsg = _("branch operand unaligned");
- return insn | ((value / 4) & 0x1FFFFF);
-}
-
-/*ARGSUSED*/
-static int
-extract_bdisp(insn, invalid)
- unsigned insn;
- int *invalid ATTRIBUTE_UNUSED;
-{
- return 4 * (((insn & 0x1FFFFF) ^ 0x100000) - 0x100000);
-}
-
-
-/* The hint field of a JMP/JSR insn. */
-
-static unsigned
-insert_jhint(insn, value, errmsg)
- unsigned insn;
- int value;
- const char **errmsg;
-{
- if (errmsg != (const char **)NULL && (value & 3))
- *errmsg = _("jump hint unaligned");
- return insn | ((value / 4) & 0x3FFF);
-}
-
-/*ARGSUSED*/
-static int
-extract_jhint(insn, invalid)
- unsigned insn;
- int *invalid ATTRIBUTE_UNUSED;
-{
- return 4 * (((insn & 0x3FFF) ^ 0x2000) - 0x2000);
-}
-
-/* The hint field of an EV6 HW_JMP/JSR insn. */
-
-static unsigned
-insert_ev6hwjhint(insn, value, errmsg)
- unsigned insn;
- int value;
- const char **errmsg;
-{
- if (errmsg != (const char **)NULL && (value & 3))
- *errmsg = _("jump hint unaligned");
- return insn | ((value / 4) & 0x1FFF);
-}
-
-/*ARGSUSED*/
-static int
-extract_ev6hwjhint(insn, invalid)
- unsigned insn;
- int *invalid ATTRIBUTE_UNUSED;
-{
- return 4 * (((insn & 0x1FFF) ^ 0x1000) - 0x1000);
-}
-
-
-/* Macros used to form opcodes */
-
-/* The main opcode */
-#define OP(x) (((x) & 0x3F) << 26)
-#define OP_MASK 0xFC000000
-
-/* Branch format instructions */
-#define BRA_(oo) OP(oo)
-#define BRA_MASK OP_MASK
-#define BRA(oo) BRA_(oo), BRA_MASK
-
-/* Floating point format instructions */
-#define FP_(oo,fff) (OP(oo) | (((fff) & 0x7FF) << 5))
-#define FP_MASK (OP_MASK | 0xFFE0)
-#define FP(oo,fff) FP_(oo,fff), FP_MASK
-
-/* Memory format instructions */
-#define MEM_(oo) OP(oo)
-#define MEM_MASK OP_MASK
-#define MEM(oo) MEM_(oo), MEM_MASK
-
-/* Memory/Func Code format instructions */
-#define MFC_(oo,ffff) (OP(oo) | ((ffff) & 0xFFFF))
-#define MFC_MASK (OP_MASK | 0xFFFF)
-#define MFC(oo,ffff) MFC_(oo,ffff), MFC_MASK
-
-/* Memory/Branch format instructions */
-#define MBR_(oo,h) (OP(oo) | (((h) & 3) << 14))
-#define MBR_MASK (OP_MASK | 0xC000)
-#define MBR(oo,h) MBR_(oo,h), MBR_MASK
-
-/* Operate format instructions. The OPRL variant specifies a
- literal second argument. */
-#define OPR_(oo,ff) (OP(oo) | (((ff) & 0x7F) << 5))
-#define OPRL_(oo,ff) (OPR_((oo),(ff)) | 0x1000)
-#define OPR_MASK (OP_MASK | 0x1FE0)
-#define OPR(oo,ff) OPR_(oo,ff), OPR_MASK
-#define OPRL(oo,ff) OPRL_(oo,ff), OPR_MASK
-
-/* Generic PALcode format instructions */
-#define PCD_(oo) OP(oo)
-#define PCD_MASK OP_MASK
-#define PCD(oo) PCD_(oo), PCD_MASK
-
-/* Specific PALcode instructions */
-#define SPCD_(oo,ffff) (OP(oo) | ((ffff) & 0x3FFFFFF))
-#define SPCD_MASK 0xFFFFFFFF
-#define SPCD(oo,ffff) SPCD_(oo,ffff), SPCD_MASK
-
-/* Hardware memory (hw_{ld,st}) instructions */
-#define EV4HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12))
-#define EV4HWMEM_MASK (OP_MASK | 0xF000)
-#define EV4HWMEM(oo,f) EV4HWMEM_(oo,f), EV4HWMEM_MASK
-
-#define EV5HWMEM_(oo,f) (OP(oo) | (((f) & 0x3F) << 10))
-#define EV5HWMEM_MASK (OP_MASK | 0xF800)
-#define EV5HWMEM(oo,f) EV5HWMEM_(oo,f), EV5HWMEM_MASK
-
-#define EV6HWMEM_(oo,f) (OP(oo) | (((f) & 0xF) << 12))
-#define EV6HWMEM_MASK (OP_MASK | 0xF000)
-#define EV6HWMEM(oo,f) EV6HWMEM_(oo,f), EV6HWMEM_MASK
-
-#define EV6HWMBR_(oo,h) (OP(oo) | (((h) & 7) << 13))
-#define EV6HWMBR_MASK (OP_MASK | 0xE000)
-#define EV6HWMBR(oo,h) EV6HWMBR_(oo,h), EV6HWMBR_MASK
-
-/* Abbreviations for instruction subsets. */
-#define BASE AXP_OPCODE_BASE
-#define EV4 AXP_OPCODE_EV4
-#define EV5 AXP_OPCODE_EV5
-#define EV6 AXP_OPCODE_EV6
-#define BWX AXP_OPCODE_BWX
-#define CIX AXP_OPCODE_CIX
-#define MAX AXP_OPCODE_MAX
-
-/* Common combinations of arguments */
-#define ARG_NONE { 0 }
-#define ARG_BRA { RA, BDISP }
-#define ARG_FBRA { FA, BDISP }
-#define ARG_FP { FA, FB, DFC1 }
-#define ARG_FPZ1 { ZA, FB, DFC1 }
-#define ARG_MEM { RA, MDISP, PRB }
-#define ARG_FMEM { FA, MDISP, PRB }
-#define ARG_OPR { RA, RB, DRC1 }
-#define ARG_OPRL { RA, LIT, DRC1 }
-#define ARG_OPRZ1 { ZA, RB, DRC1 }
-#define ARG_OPRLZ1 { ZA, LIT, RC }
-#define ARG_PCD { PALFN }
-#define ARG_EV4HWMEM { RA, EV4HWDISP, PRB }
-#define ARG_EV4HWMPR { RA, RBA, EV4HWINDEX }
-#define ARG_EV5HWMEM { RA, EV5HWDISP, PRB }
-#define ARG_EV6HWMEM { RA, EV6HWDISP, PRB }
-
-/* The opcode table.
-
- The format of the opcode table is:
-
- NAME OPCODE MASK { OPERANDS }
-
- NAME is the name of the instruction.
-
- OPCODE is the instruction opcode.
-
- MASK is the opcode mask; this is used to tell the disassembler
- which bits in the actual opcode must match OPCODE.
-
- OPERANDS is the list of operands.
-
- The preceding macros merge the text of the OPCODE and MASK fields.
-
- The disassembler reads the table in order and prints the first
- instruction which matches, so this table is sorted to put more
- specific instructions before more general instructions.
-
- Otherwise, it is sorted by major opcode and minor function code.
-
- There are three classes of not-really-instructions in this table:
-
- ALIAS is another name for another instruction. Some of
- these come from the Architecture Handbook, some
- come from the original gas opcode tables. In all
- cases, the functionality of the opcode is unchanged.
-
- PSEUDO a stylized code form endorsed by Chapter A.4 of the
- Architecture Handbook.
-
- EXTRA a stylized code form found in the original gas tables.
-
- And two annotations:
-
- EV56 BUT opcodes that are officially introduced as of the ev56,
- but with defined results on previous implementations.
-
- EV56 UNA opcodes that were introduced as of the ev56 with
- presumably undefined results on previous implementations
- that were not assigned to a particular extension.
-*/
-
-const struct alpha_opcode alpha_opcodes[] = {
- { "halt", SPCD(0x00,0x0000), BASE, ARG_NONE },
- { "draina", SPCD(0x00,0x0002), BASE, ARG_NONE },
- { "bpt", SPCD(0x00,0x0080), BASE, ARG_NONE },
- { "bugchk", SPCD(0x00,0x0081), BASE, ARG_NONE },
- { "callsys", SPCD(0x00,0x0083), BASE, ARG_NONE },
- { "chmk", SPCD(0x00,0x0083), BASE, ARG_NONE },
- { "imb", SPCD(0x00,0x0086), BASE, ARG_NONE },
- { "rduniq", SPCD(0x00,0x009e), BASE, ARG_NONE },
- { "wruniq", SPCD(0x00,0x009f), BASE, ARG_NONE },
- { "gentrap", SPCD(0x00,0x00aa), BASE, ARG_NONE },
- { "call_pal", PCD(0x00), BASE, ARG_PCD },
- { "pal", PCD(0x00), BASE, ARG_PCD }, /* alias */
-
- { "lda", MEM(0x08), BASE, { RA, MDISP, ZB } }, /* pseudo */
- { "lda", MEM(0x08), BASE, ARG_MEM },
- { "ldah", MEM(0x09), BASE, { RA, MDISP, ZB } }, /* pseudo */
- { "ldah", MEM(0x09), BASE, ARG_MEM },
- { "ldbu", MEM(0x0A), BWX, ARG_MEM },
- { "unop", MEM_(0x0B) | (30 << 16),
- MEM_MASK, BASE, { ZA } }, /* pseudo */
- { "ldq_u", MEM(0x0B), BASE, ARG_MEM },
- { "ldwu", MEM(0x0C), BWX, ARG_MEM },
- { "stw", MEM(0x0D), BWX, ARG_MEM },
- { "stb", MEM(0x0E), BWX, ARG_MEM },
- { "stq_u", MEM(0x0F), BASE, ARG_MEM },
-
- { "sextl", OPR(0x10,0x00), BASE, ARG_OPRZ1 }, /* pseudo */
- { "sextl", OPRL(0x10,0x00), BASE, ARG_OPRLZ1 }, /* pseudo */
- { "addl", OPR(0x10,0x00), BASE, ARG_OPR },
- { "addl", OPRL(0x10,0x00), BASE, ARG_OPRL },
- { "s4addl", OPR(0x10,0x02), BASE, ARG_OPR },
- { "s4addl", OPRL(0x10,0x02), BASE, ARG_OPRL },
- { "negl", OPR(0x10,0x09), BASE, ARG_OPRZ1 }, /* pseudo */
- { "negl", OPRL(0x10,0x09), BASE, ARG_OPRLZ1 }, /* pseudo */
- { "subl", OPR(0x10,0x09), BASE, ARG_OPR },
- { "subl", OPRL(0x10,0x09), BASE, ARG_OPRL },
- { "s4subl", OPR(0x10,0x0B), BASE, ARG_OPR },
- { "s4subl", OPRL(0x10,0x0B), BASE, ARG_OPRL },
- { "cmpbge", OPR(0x10,0x0F), BASE, ARG_OPR },
- { "cmpbge", OPRL(0x10,0x0F), BASE, ARG_OPRL },
- { "s8addl", OPR(0x10,0x12), BASE, ARG_OPR },
- { "s8addl", OPRL(0x10,0x12), BASE, ARG_OPRL },
- { "s8subl", OPR(0x10,0x1B), BASE, ARG_OPR },
- { "s8subl", OPRL(0x10,0x1B), BASE, ARG_OPRL },
- { "cmpult", OPR(0x10,0x1D), BASE, ARG_OPR },
- { "cmpult", OPRL(0x10,0x1D), BASE, ARG_OPRL },
- { "addq", OPR(0x10,0x20), BASE, ARG_OPR },
- { "addq", OPRL(0x10,0x20), BASE, ARG_OPRL },
- { "s4addq", OPR(0x10,0x22), BASE, ARG_OPR },
- { "s4addq", OPRL(0x10,0x22), BASE, ARG_OPRL },
- { "negq", OPR(0x10,0x29), BASE, ARG_OPRZ1 }, /* pseudo */
- { "negq", OPRL(0x10,0x29), BASE, ARG_OPRLZ1 }, /* pseudo */
- { "subq", OPR(0x10,0x29), BASE, ARG_OPR },
- { "subq", OPRL(0x10,0x29), BASE, ARG_OPRL },
- { "s4subq", OPR(0x10,0x2B), BASE, ARG_OPR },
- { "s4subq", OPRL(0x10,0x2B), BASE, ARG_OPRL },
- { "cmpeq", OPR(0x10,0x2D), BASE, ARG_OPR },
- { "cmpeq", OPRL(0x10,0x2D), BASE, ARG_OPRL },
- { "s8addq", OPR(0x10,0x32), BASE, ARG_OPR },
- { "s8addq", OPRL(0x10,0x32), BASE, ARG_OPRL },
- { "s8subq", OPR(0x10,0x3B), BASE, ARG_OPR },
- { "s8subq", OPRL(0x10,0x3B), BASE, ARG_OPRL },
- { "cmpule", OPR(0x10,0x3D), BASE, ARG_OPR },
- { "cmpule", OPRL(0x10,0x3D), BASE, ARG_OPRL },
- { "addl/v", OPR(0x10,0x40), BASE, ARG_OPR },
- { "addl/v", OPRL(0x10,0x40), BASE, ARG_OPRL },
- { "negl/v", OPR(0x10,0x49), BASE, ARG_OPRZ1 }, /* pseudo */
- { "negl/v", OPRL(0x10,0x49), BASE, ARG_OPRLZ1 }, /* pseudo */
- { "subl/v", OPR(0x10,0x49), BASE, ARG_OPR },
- { "subl/v", OPRL(0x10,0x49), BASE, ARG_OPRL },
- { "cmplt", OPR(0x10,0x4D), BASE, ARG_OPR },
- { "cmplt", OPRL(0x10,0x4D), BASE, ARG_OPRL },
- { "addq/v", OPR(0x10,0x60), BASE, ARG_OPR },
- { "addq/v", OPRL(0x10,0x60), BASE, ARG_OPRL },
- { "negq/v", OPR(0x10,0x69), BASE, ARG_OPRZ1 }, /* pseudo */
- { "negq/v", OPRL(0x10,0x69), BASE, ARG_OPRLZ1 }, /* pseudo */
- { "subq/v", OPR(0x10,0x69), BASE, ARG_OPR },
- { "subq/v", OPRL(0x10,0x69), BASE, ARG_OPRL },
- { "cmple", OPR(0x10,0x6D), BASE, ARG_OPR },
- { "cmple", OPRL(0x10,0x6D), BASE, ARG_OPRL },
-
- { "and", OPR(0x11,0x00), BASE, ARG_OPR },
- { "and", OPRL(0x11,0x00), BASE, ARG_OPRL },
- { "andnot", OPR(0x11,0x08), BASE, ARG_OPR }, /* alias */
- { "andnot", OPRL(0x11,0x08), BASE, ARG_OPRL }, /* alias */
- { "bic", OPR(0x11,0x08), BASE, ARG_OPR },
- { "bic", OPRL(0x11,0x08), BASE, ARG_OPRL },
- { "cmovlbs", OPR(0x11,0x14), BASE, ARG_OPR },
- { "cmovlbs", OPRL(0x11,0x14), BASE, ARG_OPRL },
- { "cmovlbc", OPR(0x11,0x16), BASE, ARG_OPR },
- { "cmovlbc", OPRL(0x11,0x16), BASE, ARG_OPRL },
- { "nop", OPR(0x11,0x20), BASE, { ZA, ZB, ZC } }, /* pseudo */
- { "clr", OPR(0x11,0x20), BASE, { ZA, ZB, RC } }, /* pseudo */
- { "mov", OPR(0x11,0x20), BASE, { ZA, RB, RC } }, /* pseudo */
- { "mov", OPR(0x11,0x20), BASE, { RA, RBA, RC } }, /* pseudo */
- { "mov", OPRL(0x11,0x20), BASE, { ZA, LIT, RC } }, /* pseudo */
- { "or", OPR(0x11,0x20), BASE, ARG_OPR }, /* alias */
- { "or", OPRL(0x11,0x20), BASE, ARG_OPRL }, /* alias */
- { "bis", OPR(0x11,0x20), BASE, ARG_OPR },
- { "bis", OPRL(0x11,0x20), BASE, ARG_OPRL },
- { "cmoveq", OPR(0x11,0x24), BASE, ARG_OPR },
- { "cmoveq", OPRL(0x11,0x24), BASE, ARG_OPRL },
- { "cmovne", OPR(0x11,0x26), BASE, ARG_OPR },
- { "cmovne", OPRL(0x11,0x26), BASE, ARG_OPRL },
- { "not", OPR(0x11,0x28), BASE, ARG_OPRZ1 }, /* pseudo */
- { "not", OPRL(0x11,0x28), BASE, ARG_OPRLZ1 }, /* pseudo */
- { "ornot", OPR(0x11,0x28), BASE, ARG_OPR },
- { "ornot", OPRL(0x11,0x28), BASE, ARG_OPRL },
- { "xor", OPR(0x11,0x40), BASE, ARG_OPR },
- { "xor", OPRL(0x11,0x40), BASE, ARG_OPRL },
- { "cmovlt", OPR(0x11,0x44), BASE, ARG_OPR },
- { "cmovlt", OPRL(0x11,0x44), BASE, ARG_OPRL },
- { "cmovge", OPR(0x11,0x46), BASE, ARG_OPR },
- { "cmovge", OPRL(0x11,0x46), BASE, ARG_OPRL },
- { "eqv", OPR(0x11,0x48), BASE, ARG_OPR },
- { "eqv", OPRL(0x11,0x48), BASE, ARG_OPRL },
- { "xornot", OPR(0x11,0x48), BASE, ARG_OPR }, /* alias */
- { "xornot", OPRL(0x11,0x48), BASE, ARG_OPRL }, /* alias */
- { "amask", OPR(0x11,0x61), BASE, ARG_OPRZ1 }, /* ev56 but */
- { "amask", OPRL(0x11,0x61), BASE, ARG_OPRLZ1 }, /* ev56 but */
- { "cmovle", OPR(0x11,0x64), BASE, ARG_OPR },
- { "cmovle", OPRL(0x11,0x64), BASE, ARG_OPRL },
- { "cmovgt", OPR(0x11,0x66), BASE, ARG_OPR },
- { "cmovgt", OPRL(0x11,0x66), BASE, ARG_OPRL },
- { "implver", OPRL_(0x11,0x6C)|(31<<21)|(1<<13),
- 0xFFFFFFE0, BASE, { RC } }, /* ev56 but */
-
- { "mskbl", OPR(0x12,0x02), BASE, ARG_OPR },
- { "mskbl", OPRL(0x12,0x02), BASE, ARG_OPRL },
- { "extbl", OPR(0x12,0x06), BASE, ARG_OPR },
- { "extbl", OPRL(0x12,0x06), BASE, ARG_OPRL },
- { "insbl", OPR(0x12,0x0B), BASE, ARG_OPR },
- { "insbl", OPRL(0x12,0x0B), BASE, ARG_OPRL },
- { "mskwl", OPR(0x12,0x12), BASE, ARG_OPR },
- { "mskwl", OPRL(0x12,0x12), BASE, ARG_OPRL },
- { "extwl", OPR(0x12,0x16), BASE, ARG_OPR },
- { "extwl", OPRL(0x12,0x16), BASE, ARG_OPRL },
- { "inswl", OPR(0x12,0x1B), BASE, ARG_OPR },
- { "inswl", OPRL(0x12,0x1B), BASE, ARG_OPRL },
- { "mskll", OPR(0x12,0x22), BASE, ARG_OPR },
- { "mskll", OPRL(0x12,0x22), BASE, ARG_OPRL },
- { "extll", OPR(0x12,0x26), BASE, ARG_OPR },
- { "extll", OPRL(0x12,0x26), BASE, ARG_OPRL },
- { "insll", OPR(0x12,0x2B), BASE, ARG_OPR },
- { "insll", OPRL(0x12,0x2B), BASE, ARG_OPRL },
- { "zap", OPR(0x12,0x30), BASE, ARG_OPR },
- { "zap", OPRL(0x12,0x30), BASE, ARG_OPRL },
- { "zapnot", OPR(0x12,0x31), BASE, ARG_OPR },
- { "zapnot", OPRL(0x12,0x31), BASE, ARG_OPRL },
- { "mskql", OPR(0x12,0x32), BASE, ARG_OPR },
- { "mskql", OPRL(0x12,0x32), BASE, ARG_OPRL },
- { "srl", OPR(0x12,0x34), BASE, ARG_OPR },
- { "srl", OPRL(0x12,0x34), BASE, ARG_OPRL },
- { "extql", OPR(0x12,0x36), BASE, ARG_OPR },
- { "extql", OPRL(0x12,0x36), BASE, ARG_OPRL },
- { "sll", OPR(0x12,0x39), BASE, ARG_OPR },
- { "sll", OPRL(0x12,0x39), BASE, ARG_OPRL },
- { "insql", OPR(0x12,0x3B), BASE, ARG_OPR },
- { "insql", OPRL(0x12,0x3B), BASE, ARG_OPRL },
- { "sra", OPR(0x12,0x3C), BASE, ARG_OPR },
- { "sra", OPRL(0x12,0x3C), BASE, ARG_OPRL },
- { "mskwh", OPR(0x12,0x52), BASE, ARG_OPR },
- { "mskwh", OPRL(0x12,0x52), BASE, ARG_OPRL },
- { "inswh", OPR(0x12,0x57), BASE, ARG_OPR },
- { "inswh", OPRL(0x12,0x57), BASE, ARG_OPRL },
- { "extwh", OPR(0x12,0x5A), BASE, ARG_OPR },
- { "extwh", OPRL(0x12,0x5A), BASE, ARG_OPRL },
- { "msklh", OPR(0x12,0x62), BASE, ARG_OPR },
- { "msklh", OPRL(0x12,0x62), BASE, ARG_OPRL },
- { "inslh", OPR(0x12,0x67), BASE, ARG_OPR },
- { "inslh", OPRL(0x12,0x67), BASE, ARG_OPRL },
- { "extlh", OPR(0x12,0x6A), BASE, ARG_OPR },
- { "extlh", OPRL(0x12,0x6A), BASE, ARG_OPRL },
- { "mskqh", OPR(0x12,0x72), BASE, ARG_OPR },
- { "mskqh", OPRL(0x12,0x72), BASE, ARG_OPRL },
- { "insqh", OPR(0x12,0x77), BASE, ARG_OPR },
- { "insqh", OPRL(0x12,0x77), BASE, ARG_OPRL },
- { "extqh", OPR(0x12,0x7A), BASE, ARG_OPR },
- { "extqh", OPRL(0x12,0x7A), BASE, ARG_OPRL },
-
- { "mull", OPR(0x13,0x00), BASE, ARG_OPR },
- { "mull", OPRL(0x13,0x00), BASE, ARG_OPRL },
- { "mulq", OPR(0x13,0x20), BASE, ARG_OPR },
- { "mulq", OPRL(0x13,0x20), BASE, ARG_OPRL },
- { "umulh", OPR(0x13,0x30), BASE, ARG_OPR },
- { "umulh", OPRL(0x13,0x30), BASE, ARG_OPRL },
- { "mull/v", OPR(0x13,0x40), BASE, ARG_OPR },
- { "mull/v", OPRL(0x13,0x40), BASE, ARG_OPRL },
- { "mulq/v", OPR(0x13,0x60), BASE, ARG_OPR },
- { "mulq/v", OPRL(0x13,0x60), BASE, ARG_OPRL },
-
- { "itofs", FP(0x14,0x004), CIX, { RA, ZB, FC } },
- { "sqrtf/c", FP(0x14,0x00A), CIX, ARG_FPZ1 },
- { "sqrts/c", FP(0x14,0x00B), CIX, ARG_FPZ1 },
- { "itoff", FP(0x14,0x014), CIX, { RA, ZB, FC } },
- { "itoft", FP(0x14,0x024), CIX, { RA, ZB, FC } },
- { "sqrtg/c", FP(0x14,0x02A), CIX, ARG_FPZ1 },
- { "sqrtt/c", FP(0x14,0x02B), CIX, ARG_FPZ1 },
- { "sqrts/m", FP(0x14,0x04B), CIX, ARG_FPZ1 },
- { "sqrtt/m", FP(0x14,0x06B), CIX, ARG_FPZ1 },
- { "sqrtf", FP(0x14,0x08A), CIX, ARG_FPZ1 },
- { "sqrts", FP(0x14,0x08B), CIX, ARG_FPZ1 },
- { "sqrtg", FP(0x14,0x0AA), CIX, ARG_FPZ1 },
- { "sqrtt", FP(0x14,0x0AB), CIX, ARG_FPZ1 },
- { "sqrts/d", FP(0x14,0x0CB), CIX, ARG_FPZ1 },
- { "sqrtt/d", FP(0x14,0x0EB), CIX, ARG_FPZ1 },
- { "sqrtf/uc", FP(0x14,0x10A), CIX, ARG_FPZ1 },
- { "sqrts/uc", FP(0x14,0x10B), CIX, ARG_FPZ1 },
- { "sqrtg/uc", FP(0x14,0x12A), CIX, ARG_FPZ1 },
- { "sqrtt/uc", FP(0x14,0x12B), CIX, ARG_FPZ1 },
- { "sqrts/um", FP(0x14,0x14B), CIX, ARG_FPZ1 },
- { "sqrtt/um", FP(0x14,0x16B), CIX, ARG_FPZ1 },
- { "sqrtf/u", FP(0x14,0x18A), CIX, ARG_FPZ1 },
- { "sqrts/u", FP(0x14,0x18B), CIX, ARG_FPZ1 },
- { "sqrtg/u", FP(0x14,0x1AA), CIX, ARG_FPZ1 },
- { "sqrtt/u", FP(0x14,0x1AB), CIX, ARG_FPZ1 },
- { "sqrts/ud", FP(0x14,0x1CB), CIX, ARG_FPZ1 },
- { "sqrtt/ud", FP(0x14,0x1EB), CIX, ARG_FPZ1 },
- { "sqrtf/sc", FP(0x14,0x40A), CIX, ARG_FPZ1 },
- { "sqrtg/sc", FP(0x14,0x42A), CIX, ARG_FPZ1 },
- { "sqrtf/s", FP(0x14,0x48A), CIX, ARG_FPZ1 },
- { "sqrtg/s", FP(0x14,0x4AA), CIX, ARG_FPZ1 },
- { "sqrtf/suc", FP(0x14,0x50A), CIX, ARG_FPZ1 },
- { "sqrts/suc", FP(0x14,0x50B), CIX, ARG_FPZ1 },
- { "sqrtg/suc", FP(0x14,0x52A), CIX, ARG_FPZ1 },
- { "sqrtt/suc", FP(0x14,0x52B), CIX, ARG_FPZ1 },
- { "sqrts/sum", FP(0x14,0x54B), CIX, ARG_FPZ1 },
- { "sqrtt/sum", FP(0x14,0x56B), CIX, ARG_FPZ1 },
- { "sqrtf/su", FP(0x14,0x58A), CIX, ARG_FPZ1 },
- { "sqrts/su", FP(0x14,0x58B), CIX, ARG_FPZ1 },
- { "sqrtg/su", FP(0x14,0x5AA), CIX, ARG_FPZ1 },
- { "sqrtt/su", FP(0x14,0x5AB), CIX, ARG_FPZ1 },
- { "sqrts/sud", FP(0x14,0x5CB), CIX, ARG_FPZ1 },
- { "sqrtt/sud", FP(0x14,0x5EB), CIX, ARG_FPZ1 },
- { "sqrts/suic", FP(0x14,0x70B), CIX, ARG_FPZ1 },
- { "sqrtt/suic", FP(0x14,0x72B), CIX, ARG_FPZ1 },
- { "sqrts/suim", FP(0x14,0x74B), CIX, ARG_FPZ1 },
- { "sqrtt/suim", FP(0x14,0x76B), CIX, ARG_FPZ1 },
- { "sqrts/sui", FP(0x14,0x78B), CIX, ARG_FPZ1 },
- { "sqrtt/sui", FP(0x14,0x7AB), CIX, ARG_FPZ1 },
- { "sqrts/suid", FP(0x14,0x7CB), CIX, ARG_FPZ1 },
- { "sqrtt/suid", FP(0x14,0x7EB), CIX, ARG_FPZ1 },
-
- { "addf/c", FP(0x15,0x000), BASE, ARG_FP },
- { "subf/c", FP(0x15,0x001), BASE, ARG_FP },
- { "mulf/c", FP(0x15,0x002), BASE, ARG_FP },
- { "divf/c", FP(0x15,0x003), BASE, ARG_FP },
- { "cvtdg/c", FP(0x15,0x01E), BASE, ARG_FPZ1 },
- { "addg/c", FP(0x15,0x020), BASE, ARG_FP },
- { "subg/c", FP(0x15,0x021), BASE, ARG_FP },
- { "mulg/c", FP(0x15,0x022), BASE, ARG_FP },
- { "divg/c", FP(0x15,0x023), BASE, ARG_FP },
- { "cvtgf/c", FP(0x15,0x02C), BASE, ARG_FPZ1 },
- { "cvtgd/c", FP(0x15,0x02D), BASE, ARG_FPZ1 },
- { "cvtgq/c", FP(0x15,0x02F), BASE, ARG_FPZ1 },
- { "cvtqf/c", FP(0x15,0x03C), BASE, ARG_FPZ1 },
- { "cvtqg/c", FP(0x15,0x03E), BASE, ARG_FPZ1 },
- { "addf", FP(0x15,0x080), BASE, ARG_FP },
- { "negf", FP(0x15,0x081), BASE, ARG_FPZ1 }, /* pseudo */
- { "subf", FP(0x15,0x081), BASE, ARG_FP },
- { "mulf", FP(0x15,0x082), BASE, ARG_FP },
- { "divf", FP(0x15,0x083), BASE, ARG_FP },
- { "cvtdg", FP(0x15,0x09E), BASE, ARG_FPZ1 },
- { "addg", FP(0x15,0x0A0), BASE, ARG_FP },
- { "negg", FP(0x15,0x0A1), BASE, ARG_FPZ1 }, /* pseudo */
- { "subg", FP(0x15,0x0A1), BASE, ARG_FP },
- { "mulg", FP(0x15,0x0A2), BASE, ARG_FP },
- { "divg", FP(0x15,0x0A3), BASE, ARG_FP },
- { "cmpgeq", FP(0x15,0x0A5), BASE, ARG_FP },
- { "cmpglt", FP(0x15,0x0A6), BASE, ARG_FP },
- { "cmpgle", FP(0x15,0x0A7), BASE, ARG_FP },
- { "cvtgf", FP(0x15,0x0AC), BASE, ARG_FPZ1 },
- { "cvtgd", FP(0x15,0x0AD), BASE, ARG_FPZ1 },
- { "cvtgq", FP(0x15,0x0AF), BASE, ARG_FPZ1 },
- { "cvtqf", FP(0x15,0x0BC), BASE, ARG_FPZ1 },
- { "cvtqg", FP(0x15,0x0BE), BASE, ARG_FPZ1 },
- { "addf/uc", FP(0x15,0x100), BASE, ARG_FP },
- { "subf/uc", FP(0x15,0x101), BASE, ARG_FP },
- { "mulf/uc", FP(0x15,0x102), BASE, ARG_FP },
- { "divf/uc", FP(0x15,0x103), BASE, ARG_FP },
- { "cvtdg/uc", FP(0x15,0x11E), BASE, ARG_FPZ1 },
- { "addg/uc", FP(0x15,0x120), BASE, ARG_FP },
- { "subg/uc", FP(0x15,0x121), BASE, ARG_FP },
- { "mulg/uc", FP(0x15,0x122), BASE, ARG_FP },
- { "divg/uc", FP(0x15,0x123), BASE, ARG_FP },
- { "cvtgf/uc", FP(0x15,0x12C), BASE, ARG_FPZ1 },
- { "cvtgd/uc", FP(0x15,0x12D), BASE, ARG_FPZ1 },
- { "cvtgq/vc", FP(0x15,0x12F), BASE, ARG_FPZ1 },
- { "addf/u", FP(0x15,0x180), BASE, ARG_FP },
- { "subf/u", FP(0x15,0x181), BASE, ARG_FP },
- { "mulf/u", FP(0x15,0x182), BASE, ARG_FP },
- { "divf/u", FP(0x15,0x183), BASE, ARG_FP },
- { "cvtdg/u", FP(0x15,0x19E), BASE, ARG_FPZ1 },
- { "addg/u", FP(0x15,0x1A0), BASE, ARG_FP },
- { "subg/u", FP(0x15,0x1A1), BASE, ARG_FP },
- { "mulg/u", FP(0x15,0x1A2), BASE, ARG_FP },
- { "divg/u", FP(0x15,0x1A3), BASE, ARG_FP },
- { "cvtgf/u", FP(0x15,0x1AC), BASE, ARG_FPZ1 },
- { "cvtgd/u", FP(0x15,0x1AD), BASE, ARG_FPZ1 },
- { "cvtgq/v", FP(0x15,0x1AF), BASE, ARG_FPZ1 },
- { "addf/sc", FP(0x15,0x400), BASE, ARG_FP },
- { "subf/sc", FP(0x15,0x401), BASE, ARG_FP },
- { "mulf/sc", FP(0x15,0x402), BASE, ARG_FP },
- { "divf/sc", FP(0x15,0x403), BASE, ARG_FP },
- { "cvtdg/sc", FP(0x15,0x41E), BASE, ARG_FPZ1 },
- { "addg/sc", FP(0x15,0x420), BASE, ARG_FP },
- { "subg/sc", FP(0x15,0x421), BASE, ARG_FP },
- { "mulg/sc", FP(0x15,0x422), BASE, ARG_FP },
- { "divg/sc", FP(0x15,0x423), BASE, ARG_FP },
- { "cvtgf/sc", FP(0x15,0x42C), BASE, ARG_FPZ1 },
- { "cvtgd/sc", FP(0x15,0x42D), BASE, ARG_FPZ1 },
- { "cvtgq/sc", FP(0x15,0x42F), BASE, ARG_FPZ1 },
- { "addf/s", FP(0x15,0x480), BASE, ARG_FP },
- { "negf/s", FP(0x15,0x481), BASE, ARG_FPZ1 }, /* pseudo */
- { "subf/s", FP(0x15,0x481), BASE, ARG_FP },
- { "mulf/s", FP(0x15,0x482), BASE, ARG_FP },
- { "divf/s", FP(0x15,0x483), BASE, ARG_FP },
- { "cvtdg/s", FP(0x15,0x49E), BASE, ARG_FPZ1 },
- { "addg/s", FP(0x15,0x4A0), BASE, ARG_FP },
- { "negg/s", FP(0x15,0x4A1), BASE, ARG_FPZ1 }, /* pseudo */
- { "subg/s", FP(0x15,0x4A1), BASE, ARG_FP },
- { "mulg/s", FP(0x15,0x4A2), BASE, ARG_FP },
- { "divg/s", FP(0x15,0x4A3), BASE, ARG_FP },
- { "cmpgeq/s", FP(0x15,0x4A5), BASE, ARG_FP },
- { "cmpglt/s", FP(0x15,0x4A6), BASE, ARG_FP },
- { "cmpgle/s", FP(0x15,0x4A7), BASE, ARG_FP },
- { "cvtgf/s", FP(0x15,0x4AC), BASE, ARG_FPZ1 },
- { "cvtgd/s", FP(0x15,0x4AD), BASE, ARG_FPZ1 },
- { "cvtgq/s", FP(0x15,0x4AF), BASE, ARG_FPZ1 },
- { "addf/suc", FP(0x15,0x500), BASE, ARG_FP },
- { "subf/suc", FP(0x15,0x501), BASE, ARG_FP },
- { "mulf/suc", FP(0x15,0x502), BASE, ARG_FP },
- { "divf/suc", FP(0x15,0x503), BASE, ARG_FP },
- { "cvtdg/suc", FP(0x15,0x51E), BASE, ARG_FPZ1 },
- { "addg/suc", FP(0x15,0x520), BASE, ARG_FP },
- { "subg/suc", FP(0x15,0x521), BASE, ARG_FP },
- { "mulg/suc", FP(0x15,0x522), BASE, ARG_FP },
- { "divg/suc", FP(0x15,0x523), BASE, ARG_FP },
- { "cvtgf/suc", FP(0x15,0x52C), BASE, ARG_FPZ1 },
- { "cvtgd/suc", FP(0x15,0x52D), BASE, ARG_FPZ1 },
- { "cvtgq/svc", FP(0x15,0x52F), BASE, ARG_FPZ1 },
- { "addf/su", FP(0x15,0x580), BASE, ARG_FP },
- { "subf/su", FP(0x15,0x581), BASE, ARG_FP },
- { "mulf/su", FP(0x15,0x582), BASE, ARG_FP },
- { "divf/su", FP(0x15,0x583), BASE, ARG_FP },
- { "cvtdg/su", FP(0x15,0x59E), BASE, ARG_FPZ1 },
- { "addg/su", FP(0x15,0x5A0), BASE, ARG_FP },
- { "subg/su", FP(0x15,0x5A1), BASE, ARG_FP },
- { "mulg/su", FP(0x15,0x5A2), BASE, ARG_FP },
- { "divg/su", FP(0x15,0x5A3), BASE, ARG_FP },
- { "cvtgf/su", FP(0x15,0x5AC), BASE, ARG_FPZ1 },
- { "cvtgd/su", FP(0x15,0x5AD), BASE, ARG_FPZ1 },
- { "cvtgq/sv", FP(0x15,0x5AF), BASE, ARG_FPZ1 },
-
- { "adds/c", FP(0x16,0x000), BASE, ARG_FP },
- { "subs/c", FP(0x16,0x001), BASE, ARG_FP },
- { "muls/c", FP(0x16,0x002), BASE, ARG_FP },
- { "divs/c", FP(0x16,0x003), BASE, ARG_FP },
- { "addt/c", FP(0x16,0x020), BASE, ARG_FP },
- { "subt/c", FP(0x16,0x021), BASE, ARG_FP },
- { "mult/c", FP(0x16,0x022), BASE, ARG_FP },
- { "divt/c", FP(0x16,0x023), BASE, ARG_FP },
- { "cvtts/c", FP(0x16,0x02C), BASE, ARG_FPZ1 },
- { "cvttq/c", FP(0x16,0x02F), BASE, ARG_FPZ1 },
- { "cvtqs/c", FP(0x16,0x03C), BASE, ARG_FPZ1 },
- { "cvtqt/c", FP(0x16,0x03E), BASE, ARG_FPZ1 },
- { "adds/m", FP(0x16,0x040), BASE, ARG_FP },
- { "subs/m", FP(0x16,0x041), BASE, ARG_FP },
- { "muls/m", FP(0x16,0x042), BASE, ARG_FP },
- { "divs/m", FP(0x16,0x043), BASE, ARG_FP },
- { "addt/m", FP(0x16,0x060), BASE, ARG_FP },
- { "subt/m", FP(0x16,0x061), BASE, ARG_FP },
- { "mult/m", FP(0x16,0x062), BASE, ARG_FP },
- { "divt/m", FP(0x16,0x063), BASE, ARG_FP },
- { "cvtts/m", FP(0x16,0x06C), BASE, ARG_FPZ1 },
- { "cvttq/m", FP(0x16,0x06F), BASE, ARG_FPZ1 },
- { "cvtqs/m", FP(0x16,0x07C), BASE, ARG_FPZ1 },
- { "cvtqt/m", FP(0x16,0x07E), BASE, ARG_FPZ1 },
- { "adds", FP(0x16,0x080), BASE, ARG_FP },
- { "negs", FP(0x16,0x081), BASE, ARG_FPZ1 }, /* pseudo */
- { "subs", FP(0x16,0x081), BASE, ARG_FP },
- { "muls", FP(0x16,0x082), BASE, ARG_FP },
- { "divs", FP(0x16,0x083), BASE, ARG_FP },
- { "addt", FP(0x16,0x0A0), BASE, ARG_FP },
- { "negt", FP(0x16,0x0A1), BASE, ARG_FPZ1 }, /* pseudo */
- { "subt", FP(0x16,0x0A1), BASE, ARG_FP },
- { "mult", FP(0x16,0x0A2), BASE, ARG_FP },
- { "divt", FP(0x16,0x0A3), BASE, ARG_FP },
- { "cmptun", FP(0x16,0x0A4), BASE, ARG_FP },
- { "cmpteq", FP(0x16,0x0A5), BASE, ARG_FP },
- { "cmptlt", FP(0x16,0x0A6), BASE, ARG_FP },
- { "cmptle", FP(0x16,0x0A7), BASE, ARG_FP },
- { "cvtts", FP(0x16,0x0AC), BASE, ARG_FPZ1 },
- { "cvttq", FP(0x16,0x0AF), BASE, ARG_FPZ1 },
- { "cvtqs", FP(0x16,0x0BC), BASE, ARG_FPZ1 },
- { "cvtqt", FP(0x16,0x0BE), BASE, ARG_FPZ1 },
- { "adds/d", FP(0x16,0x0C0), BASE, ARG_FP },
- { "subs/d", FP(0x16,0x0C1), BASE, ARG_FP },
- { "muls/d", FP(0x16,0x0C2), BASE, ARG_FP },
- { "divs/d", FP(0x16,0x0C3), BASE, ARG_FP },
- { "addt/d", FP(0x16,0x0E0), BASE, ARG_FP },
- { "subt/d", FP(0x16,0x0E1), BASE, ARG_FP },
- { "mult/d", FP(0x16,0x0E2), BASE, ARG_FP },
- { "divt/d", FP(0x16,0x0E3), BASE, ARG_FP },
- { "cvtts/d", FP(0x16,0x0EC), BASE, ARG_FPZ1 },
- { "cvttq/d", FP(0x16,0x0EF), BASE, ARG_FPZ1 },
- { "cvtqs/d", FP(0x16,0x0FC), BASE, ARG_FPZ1 },
- { "cvtqt/d", FP(0x16,0x0FE), BASE, ARG_FPZ1 },
- { "adds/uc", FP(0x16,0x100), BASE, ARG_FP },
- { "subs/uc", FP(0x16,0x101), BASE, ARG_FP },
- { "muls/uc", FP(0x16,0x102), BASE, ARG_FP },
- { "divs/uc", FP(0x16,0x103), BASE, ARG_FP },
- { "addt/uc", FP(0x16,0x120), BASE, ARG_FP },
- { "subt/uc", FP(0x16,0x121), BASE, ARG_FP },
- { "mult/uc", FP(0x16,0x122), BASE, ARG_FP },
- { "divt/uc", FP(0x16,0x123), BASE, ARG_FP },
- { "cvtts/uc", FP(0x16,0x12C), BASE, ARG_FPZ1 },
- { "cvttq/vc", FP(0x16,0x12F), BASE, ARG_FPZ1 },
- { "adds/um", FP(0x16,0x140), BASE, ARG_FP },
- { "subs/um", FP(0x16,0x141), BASE, ARG_FP },
- { "muls/um", FP(0x16,0x142), BASE, ARG_FP },
- { "divs/um", FP(0x16,0x143), BASE, ARG_FP },
- { "addt/um", FP(0x16,0x160), BASE, ARG_FP },
- { "subt/um", FP(0x16,0x161), BASE, ARG_FP },
- { "mult/um", FP(0x16,0x162), BASE, ARG_FP },
- { "divt/um", FP(0x16,0x163), BASE, ARG_FP },
- { "cvtts/um", FP(0x16,0x16C), BASE, ARG_FPZ1 },
- { "cvttq/vm", FP(0x16,0x16F), BASE, ARG_FPZ1 },
- { "adds/u", FP(0x16,0x180), BASE, ARG_FP },
- { "subs/u", FP(0x16,0x181), BASE, ARG_FP },
- { "muls/u", FP(0x16,0x182), BASE, ARG_FP },
- { "divs/u", FP(0x16,0x183), BASE, ARG_FP },
- { "addt/u", FP(0x16,0x1A0), BASE, ARG_FP },
- { "subt/u", FP(0x16,0x1A1), BASE, ARG_FP },
- { "mult/u", FP(0x16,0x1A2), BASE, ARG_FP },
- { "divt/u", FP(0x16,0x1A3), BASE, ARG_FP },
- { "cvtts/u", FP(0x16,0x1AC), BASE, ARG_FPZ1 },
- { "cvttq/v", FP(0x16,0x1AF), BASE, ARG_FPZ1 },
- { "adds/ud", FP(0x16,0x1C0), BASE, ARG_FP },
- { "subs/ud", FP(0x16,0x1C1), BASE, ARG_FP },
- { "muls/ud", FP(0x16,0x1C2), BASE, ARG_FP },
- { "divs/ud", FP(0x16,0x1C3), BASE, ARG_FP },
- { "addt/ud", FP(0x16,0x1E0), BASE, ARG_FP },
- { "subt/ud", FP(0x16,0x1E1), BASE, ARG_FP },
- { "mult/ud", FP(0x16,0x1E2), BASE, ARG_FP },
- { "divt/ud", FP(0x16,0x1E3), BASE, ARG_FP },
- { "cvtts/ud", FP(0x16,0x1EC), BASE, ARG_FPZ1 },
- { "cvttq/vd", FP(0x16,0x1EF), BASE, ARG_FPZ1 },
- { "cvtst", FP(0x16,0x2AC), BASE, ARG_FPZ1 },
- { "adds/suc", FP(0x16,0x500), BASE, ARG_FP },
- { "subs/suc", FP(0x16,0x501), BASE, ARG_FP },
- { "muls/suc", FP(0x16,0x502), BASE, ARG_FP },
- { "divs/suc", FP(0x16,0x503), BASE, ARG_FP },
- { "addt/suc", FP(0x16,0x520), BASE, ARG_FP },
- { "subt/suc", FP(0x16,0x521), BASE, ARG_FP },
- { "mult/suc", FP(0x16,0x522), BASE, ARG_FP },
- { "divt/suc", FP(0x16,0x523), BASE, ARG_FP },
- { "cvtts/suc", FP(0x16,0x52C), BASE, ARG_FPZ1 },
- { "cvttq/svc", FP(0x16,0x52F), BASE, ARG_FPZ1 },
- { "adds/sum", FP(0x16,0x540), BASE, ARG_FP },
- { "subs/sum", FP(0x16,0x541), BASE, ARG_FP },
- { "muls/sum", FP(0x16,0x542), BASE, ARG_FP },
- { "divs/sum", FP(0x16,0x543), BASE, ARG_FP },
- { "addt/sum", FP(0x16,0x560), BASE, ARG_FP },
- { "subt/sum", FP(0x16,0x561), BASE, ARG_FP },
- { "mult/sum", FP(0x16,0x562), BASE, ARG_FP },
- { "divt/sum", FP(0x16,0x563), BASE, ARG_FP },
- { "cvtts/sum", FP(0x16,0x56C), BASE, ARG_FPZ1 },
- { "cvttq/svm", FP(0x16,0x56F), BASE, ARG_FPZ1 },
- { "adds/su", FP(0x16,0x580), BASE, ARG_FP },
- { "negs/su", FP(0x16,0x581), BASE, ARG_FPZ1 }, /* pseudo */
- { "subs/su", FP(0x16,0x581), BASE, ARG_FP },
- { "muls/su", FP(0x16,0x582), BASE, ARG_FP },
- { "divs/su", FP(0x16,0x583), BASE, ARG_FP },
- { "addt/su", FP(0x16,0x5A0), BASE, ARG_FP },
- { "negt/su", FP(0x16,0x5A1), BASE, ARG_FPZ1 }, /* pseudo */
- { "subt/su", FP(0x16,0x5A1), BASE, ARG_FP },
- { "mult/su", FP(0x16,0x5A2), BASE, ARG_FP },
- { "divt/su", FP(0x16,0x5A3), BASE, ARG_FP },
- { "cmptun/su", FP(0x16,0x5A4), BASE, ARG_FP },
- { "cmpteq/su", FP(0x16,0x5A5), BASE, ARG_FP },
- { "cmptlt/su", FP(0x16,0x5A6), BASE, ARG_FP },
- { "cmptle/su", FP(0x16,0x5A7), BASE, ARG_FP },
- { "cvtts/su", FP(0x16,0x5AC), BASE, ARG_FPZ1 },
- { "cvttq/sv", FP(0x16,0x5AF), BASE, ARG_FPZ1 },
- { "adds/sud", FP(0x16,0x5C0), BASE, ARG_FP },
- { "subs/sud", FP(0x16,0x5C1), BASE, ARG_FP },
- { "muls/sud", FP(0x16,0x5C2), BASE, ARG_FP },
- { "divs/sud", FP(0x16,0x5C3), BASE, ARG_FP },
- { "addt/sud", FP(0x16,0x5E0), BASE, ARG_FP },
- { "subt/sud", FP(0x16,0x5E1), BASE, ARG_FP },
- { "mult/sud", FP(0x16,0x5E2), BASE, ARG_FP },
- { "divt/sud", FP(0x16,0x5E3), BASE, ARG_FP },
- { "cvtts/sud", FP(0x16,0x5EC), BASE, ARG_FPZ1 },
- { "cvttq/svd", FP(0x16,0x5EF), BASE, ARG_FPZ1 },
- { "cvtst/s", FP(0x16,0x6AC), BASE, ARG_FPZ1 },
- { "adds/suic", FP(0x16,0x700), BASE, ARG_FP },
- { "subs/suic", FP(0x16,0x701), BASE, ARG_FP },
- { "muls/suic", FP(0x16,0x702), BASE, ARG_FP },
- { "divs/suic", FP(0x16,0x703), BASE, ARG_FP },
- { "addt/suic", FP(0x16,0x720), BASE, ARG_FP },
- { "subt/suic", FP(0x16,0x721), BASE, ARG_FP },
- { "mult/suic", FP(0x16,0x722), BASE, ARG_FP },
- { "divt/suic", FP(0x16,0x723), BASE, ARG_FP },
- { "cvtts/suic", FP(0x16,0x72C), BASE, ARG_FPZ1 },
- { "cvttq/svic", FP(0x16,0x72F), BASE, ARG_FPZ1 },
- { "cvtqs/suic", FP(0x16,0x73C), BASE, ARG_FPZ1 },
- { "cvtqt/suic", FP(0x16,0x73E), BASE, ARG_FPZ1 },
- { "adds/suim", FP(0x16,0x740), BASE, ARG_FP },
- { "subs/suim", FP(0x16,0x741), BASE, ARG_FP },
- { "muls/suim", FP(0x16,0x742), BASE, ARG_FP },
- { "divs/suim", FP(0x16,0x743), BASE, ARG_FP },
- { "addt/suim", FP(0x16,0x760), BASE, ARG_FP },
- { "subt/suim", FP(0x16,0x761), BASE, ARG_FP },
- { "mult/suim", FP(0x16,0x762), BASE, ARG_FP },
- { "divt/suim", FP(0x16,0x763), BASE, ARG_FP },
- { "cvtts/suim", FP(0x16,0x76C), BASE, ARG_FPZ1 },
- { "cvttq/svim", FP(0x16,0x76F), BASE, ARG_FPZ1 },
- { "cvtqs/suim", FP(0x16,0x77C), BASE, ARG_FPZ1 },
- { "cvtqt/suim", FP(0x16,0x77E), BASE, ARG_FPZ1 },
- { "adds/sui", FP(0x16,0x780), BASE, ARG_FP },
- { "negs/sui", FP(0x16,0x781), BASE, ARG_FPZ1 }, /* pseudo */
- { "subs/sui", FP(0x16,0x781), BASE, ARG_FP },
- { "muls/sui", FP(0x16,0x782), BASE, ARG_FP },
- { "divs/sui", FP(0x16,0x783), BASE, ARG_FP },
- { "addt/sui", FP(0x16,0x7A0), BASE, ARG_FP },
- { "negt/sui", FP(0x16,0x7A1), BASE, ARG_FPZ1 }, /* pseudo */
- { "subt/sui", FP(0x16,0x7A1), BASE, ARG_FP },
- { "mult/sui", FP(0x16,0x7A2), BASE, ARG_FP },
- { "divt/sui", FP(0x16,0x7A3), BASE, ARG_FP },
- { "cvtts/sui", FP(0x16,0x7AC), BASE, ARG_FPZ1 },
- { "cvttq/svi", FP(0x16,0x7AF), BASE, ARG_FPZ1 },
- { "cvtqs/sui", FP(0x16,0x7BC), BASE, ARG_FPZ1 },
- { "cvtqt/sui", FP(0x16,0x7BE), BASE, ARG_FPZ1 },
- { "adds/suid", FP(0x16,0x7C0), BASE, ARG_FP },
- { "subs/suid", FP(0x16,0x7C1), BASE, ARG_FP },
- { "muls/suid", FP(0x16,0x7C2), BASE, ARG_FP },
- { "divs/suid", FP(0x16,0x7C3), BASE, ARG_FP },
- { "addt/suid", FP(0x16,0x7E0), BASE, ARG_FP },
- { "subt/suid", FP(0x16,0x7E1), BASE, ARG_FP },
- { "mult/suid", FP(0x16,0x7E2), BASE, ARG_FP },
- { "divt/suid", FP(0x16,0x7E3), BASE, ARG_FP },
- { "cvtts/suid", FP(0x16,0x7EC), BASE, ARG_FPZ1 },
- { "cvttq/svid", FP(0x16,0x7EF), BASE, ARG_FPZ1 },
- { "cvtqs/suid", FP(0x16,0x7FC), BASE, ARG_FPZ1 },
- { "cvtqt/suid", FP(0x16,0x7FE), BASE, ARG_FPZ1 },
-
- { "cvtlq", FP(0x17,0x010), BASE, ARG_FPZ1 },
- { "fnop", FP(0x17,0x020), BASE, { ZA, ZB, ZC } }, /* pseudo */
- { "fclr", FP(0x17,0x020), BASE, { ZA, ZB, FC } }, /* pseudo */
- { "fabs", FP(0x17,0x020), BASE, ARG_FPZ1 }, /* pseudo */
- { "fmov", FP(0x17,0x020), BASE, { FA, RBA, FC } }, /* pseudo */
- { "cpys", FP(0x17,0x020), BASE, ARG_FP },
- { "fneg", FP(0x17,0x021), BASE, { FA, RBA, FC } }, /* pseudo */
- { "cpysn", FP(0x17,0x021), BASE, ARG_FP },
- { "cpyse", FP(0x17,0x022), BASE, ARG_FP },
- { "mt_fpcr", FP(0x17,0x024), BASE, { FA, RBA, RCA } },
- { "mf_fpcr", FP(0x17,0x025), BASE, { FA, RBA, RCA } },
- { "fcmoveq", FP(0x17,0x02A), BASE, ARG_FP },
- { "fcmovne", FP(0x17,0x02B), BASE, ARG_FP },
- { "fcmovlt", FP(0x17,0x02C), BASE, ARG_FP },
- { "fcmovge", FP(0x17,0x02D), BASE, ARG_FP },
- { "fcmovle", FP(0x17,0x02E), BASE, ARG_FP },
- { "fcmovgt", FP(0x17,0x02F), BASE, ARG_FP },
- { "cvtql", FP(0x17,0x030), BASE, ARG_FPZ1 },
- { "cvtql/v", FP(0x17,0x130), BASE, ARG_FPZ1 },
- { "cvtql/sv", FP(0x17,0x530), BASE, ARG_FPZ1 },
-
- { "trapb", MFC(0x18,0x0000), BASE, ARG_NONE },
- { "draint", MFC(0x18,0x0000), BASE, ARG_NONE }, /* alias */
- { "excb", MFC(0x18,0x0400), BASE, ARG_NONE },
- { "mb", MFC(0x18,0x4000), BASE, ARG_NONE },
- { "wmb", MFC(0x18,0x4400), BASE, ARG_NONE },
- { "fetch", MFC(0x18,0x8000), BASE, { ZA, PRB } },
- { "fetch_m", MFC(0x18,0xA000), BASE, { ZA, PRB } },
- { "rpcc", MFC(0x18,0xC000), BASE, { RA } },
- { "rc", MFC(0x18,0xE000), BASE, { RA } },
- { "ecb", MFC(0x18,0xE800), BASE, { ZA, PRB } }, /* ev56 una */
- { "rs", MFC(0x18,0xF000), BASE, { RA } },
- { "wh64", MFC(0x18,0xF800), BASE, { ZA, PRB } }, /* ev56 una */
- { "wh64en", MFC(0x18,0xFC00), BASE, { ZA, PRB } }, /* ev7 una */
-
- { "hw_mfpr", OPR(0x19,0x00), EV4, { RA, RBA, EV4EXTHWINDEX } },
- { "hw_mfpr", OP(0x19), OP_MASK, EV5, { RA, RBA, EV5HWINDEX } },
- { "hw_mfpr", OP(0x19), OP_MASK, EV6, { RA, ZB, EV6HWINDEX } },
- { "hw_mfpr/i", OPR(0x19,0x01), EV4, ARG_EV4HWMPR },
- { "hw_mfpr/a", OPR(0x19,0x02), EV4, ARG_EV4HWMPR },
- { "hw_mfpr/ai", OPR(0x19,0x03), EV4, ARG_EV4HWMPR },
- { "hw_mfpr/p", OPR(0x19,0x04), EV4, ARG_EV4HWMPR },
- { "hw_mfpr/pi", OPR(0x19,0x05), EV4, ARG_EV4HWMPR },
- { "hw_mfpr/pa", OPR(0x19,0x06), EV4, ARG_EV4HWMPR },
- { "hw_mfpr/pai", OPR(0x19,0x07), EV4, ARG_EV4HWMPR },
- { "pal19", PCD(0x19), BASE, ARG_PCD },
-
- { "jmp", MBR_(0x1A,0), MBR_MASK | 0x3FFF, /* pseudo */
- BASE, { ZA, CPRB } },
- { "jmp", MBR(0x1A,0), BASE, { RA, CPRB, JMPHINT } },
- { "jsr", MBR(0x1A,1), BASE, { RA, CPRB, JMPHINT } },
- { "ret", MBR_(0x1A,2) | (31 << 21) | (26 << 16) | 1,/* pseudo */
- 0xFFFFFFFF, BASE, { 0 } },
- { "ret", MBR(0x1A,2), BASE, { RA, CPRB, RETHINT } },
- { "jcr", MBR(0x1A,3), BASE, { RA, CPRB, RETHINT } }, /* alias */
- { "jsr_coroutine", MBR(0x1A,3), BASE, { RA, CPRB, RETHINT } },
-
- { "hw_ldl", EV4HWMEM(0x1B,0x0), EV4, ARG_EV4HWMEM },
- { "hw_ldl", EV5HWMEM(0x1B,0x00), EV5, ARG_EV5HWMEM },
- { "hw_ldl", EV6HWMEM(0x1B,0x8), EV6, ARG_EV6HWMEM },
- { "hw_ldl/a", EV4HWMEM(0x1B,0x4), EV4, ARG_EV4HWMEM },
- { "hw_ldl/a", EV5HWMEM(0x1B,0x10), EV5, ARG_EV5HWMEM },
- { "hw_ldl/a", EV6HWMEM(0x1B,0xC), EV6, ARG_EV6HWMEM },
- { "hw_ldl/al", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM },
- { "hw_ldl/ar", EV4HWMEM(0x1B,0x6), EV4, ARG_EV4HWMEM },
- { "hw_ldl/av", EV5HWMEM(0x1B,0x12), EV5, ARG_EV5HWMEM },
- { "hw_ldl/avl", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM },
- { "hw_ldl/aw", EV5HWMEM(0x1B,0x18), EV5, ARG_EV5HWMEM },
- { "hw_ldl/awl", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM },
- { "hw_ldl/awv", EV5HWMEM(0x1B,0x1a), EV5, ARG_EV5HWMEM },
- { "hw_ldl/awvl", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM },
- { "hw_ldl/l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM },
- { "hw_ldl/p", EV4HWMEM(0x1B,0x8), EV4, ARG_EV4HWMEM },
- { "hw_ldl/p", EV5HWMEM(0x1B,0x20), EV5, ARG_EV5HWMEM },
- { "hw_ldl/p", EV6HWMEM(0x1B,0x0), EV6, ARG_EV6HWMEM },
- { "hw_ldl/pa", EV4HWMEM(0x1B,0xC), EV4, ARG_EV4HWMEM },
- { "hw_ldl/pa", EV5HWMEM(0x1B,0x30), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pal", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM },
- { "hw_ldl/par", EV4HWMEM(0x1B,0xE), EV4, ARG_EV4HWMEM },
- { "hw_ldl/pav", EV5HWMEM(0x1B,0x32), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pavl", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM },
- { "hw_ldl/paw", EV5HWMEM(0x1B,0x38), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pawl", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pawv", EV5HWMEM(0x1B,0x3a), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pawvl", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pl", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pr", EV4HWMEM(0x1B,0xA), EV4, ARG_EV4HWMEM },
- { "hw_ldl/pv", EV5HWMEM(0x1B,0x22), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pvl", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pw", EV5HWMEM(0x1B,0x28), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pwl", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pwv", EV5HWMEM(0x1B,0x2a), EV5, ARG_EV5HWMEM },
- { "hw_ldl/pwvl", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM },
- { "hw_ldl/r", EV4HWMEM(0x1B,0x2), EV4, ARG_EV4HWMEM },
- { "hw_ldl/v", EV5HWMEM(0x1B,0x02), EV5, ARG_EV5HWMEM },
- { "hw_ldl/v", EV6HWMEM(0x1B,0x4), EV6, ARG_EV6HWMEM },
- { "hw_ldl/vl", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM },
- { "hw_ldl/w", EV5HWMEM(0x1B,0x08), EV5, ARG_EV5HWMEM },
- { "hw_ldl/w", EV6HWMEM(0x1B,0xA), EV6, ARG_EV6HWMEM },
- { "hw_ldl/wa", EV6HWMEM(0x1B,0xE), EV6, ARG_EV6HWMEM },
- { "hw_ldl/wl", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM },
- { "hw_ldl/wv", EV5HWMEM(0x1B,0x0a), EV5, ARG_EV5HWMEM },
- { "hw_ldl/wvl", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/a", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/av", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/aw", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/awv", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/p", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/p", EV6HWMEM(0x1B,0x2), EV6, ARG_EV6HWMEM },
- { "hw_ldl_l/pa", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/pav", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/paw", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/pawv", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/pv", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/pw", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/pwv", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/v", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/w", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM },
- { "hw_ldl_l/wv", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM },
- { "hw_ldq", EV4HWMEM(0x1B,0x1), EV4, ARG_EV4HWMEM },
- { "hw_ldq", EV5HWMEM(0x1B,0x04), EV5, ARG_EV5HWMEM },
- { "hw_ldq", EV6HWMEM(0x1B,0x9), EV6, ARG_EV6HWMEM },
- { "hw_ldq/a", EV4HWMEM(0x1B,0x5), EV4, ARG_EV4HWMEM },
- { "hw_ldq/a", EV5HWMEM(0x1B,0x14), EV5, ARG_EV5HWMEM },
- { "hw_ldq/a", EV6HWMEM(0x1B,0xD), EV6, ARG_EV6HWMEM },
- { "hw_ldq/al", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM },
- { "hw_ldq/ar", EV4HWMEM(0x1B,0x7), EV4, ARG_EV4HWMEM },
- { "hw_ldq/av", EV5HWMEM(0x1B,0x16), EV5, ARG_EV5HWMEM },
- { "hw_ldq/avl", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM },
- { "hw_ldq/aw", EV5HWMEM(0x1B,0x1c), EV5, ARG_EV5HWMEM },
- { "hw_ldq/awl", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM },
- { "hw_ldq/awv", EV5HWMEM(0x1B,0x1e), EV5, ARG_EV5HWMEM },
- { "hw_ldq/awvl", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM },
- { "hw_ldq/l", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM },
- { "hw_ldq/p", EV4HWMEM(0x1B,0x9), EV4, ARG_EV4HWMEM },
- { "hw_ldq/p", EV5HWMEM(0x1B,0x24), EV5, ARG_EV5HWMEM },
- { "hw_ldq/p", EV6HWMEM(0x1B,0x1), EV6, ARG_EV6HWMEM },
- { "hw_ldq/pa", EV4HWMEM(0x1B,0xD), EV4, ARG_EV4HWMEM },
- { "hw_ldq/pa", EV5HWMEM(0x1B,0x34), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pal", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM },
- { "hw_ldq/par", EV4HWMEM(0x1B,0xF), EV4, ARG_EV4HWMEM },
- { "hw_ldq/pav", EV5HWMEM(0x1B,0x36), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pavl", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM },
- { "hw_ldq/paw", EV5HWMEM(0x1B,0x3c), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pawl", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pawv", EV5HWMEM(0x1B,0x3e), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pawvl", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pl", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pr", EV4HWMEM(0x1B,0xB), EV4, ARG_EV4HWMEM },
- { "hw_ldq/pv", EV5HWMEM(0x1B,0x26), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pvl", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pw", EV5HWMEM(0x1B,0x2c), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pwl", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pwv", EV5HWMEM(0x1B,0x2e), EV5, ARG_EV5HWMEM },
- { "hw_ldq/pwvl", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM },
- { "hw_ldq/r", EV4HWMEM(0x1B,0x3), EV4, ARG_EV4HWMEM },
- { "hw_ldq/v", EV5HWMEM(0x1B,0x06), EV5, ARG_EV5HWMEM },
- { "hw_ldq/v", EV6HWMEM(0x1B,0x5), EV6, ARG_EV6HWMEM },
- { "hw_ldq/vl", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM },
- { "hw_ldq/w", EV5HWMEM(0x1B,0x0c), EV5, ARG_EV5HWMEM },
- { "hw_ldq/w", EV6HWMEM(0x1B,0xB), EV6, ARG_EV6HWMEM },
- { "hw_ldq/wa", EV6HWMEM(0x1B,0xF), EV6, ARG_EV6HWMEM },
- { "hw_ldq/wl", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM },
- { "hw_ldq/wv", EV5HWMEM(0x1B,0x0e), EV5, ARG_EV5HWMEM },
- { "hw_ldq/wvl", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/a", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/av", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/aw", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/awv", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/p", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/p", EV6HWMEM(0x1B,0x3), EV6, ARG_EV6HWMEM },
- { "hw_ldq_l/pa", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/pav", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/paw", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/pawv", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/pv", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/pw", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/pwv", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/v", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/w", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM },
- { "hw_ldq_l/wv", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM },
- { "hw_ld", EV4HWMEM(0x1B,0x0), EV4, ARG_EV4HWMEM },
- { "hw_ld", EV5HWMEM(0x1B,0x00), EV5, ARG_EV5HWMEM },
- { "hw_ld/a", EV4HWMEM(0x1B,0x4), EV4, ARG_EV4HWMEM },
- { "hw_ld/a", EV5HWMEM(0x1B,0x10), EV5, ARG_EV5HWMEM },
- { "hw_ld/al", EV5HWMEM(0x1B,0x11), EV5, ARG_EV5HWMEM },
- { "hw_ld/aq", EV4HWMEM(0x1B,0x5), EV4, ARG_EV4HWMEM },
- { "hw_ld/aq", EV5HWMEM(0x1B,0x14), EV5, ARG_EV5HWMEM },
- { "hw_ld/aql", EV5HWMEM(0x1B,0x15), EV5, ARG_EV5HWMEM },
- { "hw_ld/aqv", EV5HWMEM(0x1B,0x16), EV5, ARG_EV5HWMEM },
- { "hw_ld/aqvl", EV5HWMEM(0x1B,0x17), EV5, ARG_EV5HWMEM },
- { "hw_ld/ar", EV4HWMEM(0x1B,0x6), EV4, ARG_EV4HWMEM },
- { "hw_ld/arq", EV4HWMEM(0x1B,0x7), EV4, ARG_EV4HWMEM },
- { "hw_ld/av", EV5HWMEM(0x1B,0x12), EV5, ARG_EV5HWMEM },
- { "hw_ld/avl", EV5HWMEM(0x1B,0x13), EV5, ARG_EV5HWMEM },
- { "hw_ld/aw", EV5HWMEM(0x1B,0x18), EV5, ARG_EV5HWMEM },
- { "hw_ld/awl", EV5HWMEM(0x1B,0x19), EV5, ARG_EV5HWMEM },
- { "hw_ld/awq", EV5HWMEM(0x1B,0x1c), EV5, ARG_EV5HWMEM },
- { "hw_ld/awql", EV5HWMEM(0x1B,0x1d), EV5, ARG_EV5HWMEM },
- { "hw_ld/awqv", EV5HWMEM(0x1B,0x1e), EV5, ARG_EV5HWMEM },
- { "hw_ld/awqvl", EV5HWMEM(0x1B,0x1f), EV5, ARG_EV5HWMEM },
- { "hw_ld/awv", EV5HWMEM(0x1B,0x1a), EV5, ARG_EV5HWMEM },
- { "hw_ld/awvl", EV5HWMEM(0x1B,0x1b), EV5, ARG_EV5HWMEM },
- { "hw_ld/l", EV5HWMEM(0x1B,0x01), EV5, ARG_EV5HWMEM },
- { "hw_ld/p", EV4HWMEM(0x1B,0x8), EV4, ARG_EV4HWMEM },
- { "hw_ld/p", EV5HWMEM(0x1B,0x20), EV5, ARG_EV5HWMEM },
- { "hw_ld/pa", EV4HWMEM(0x1B,0xC), EV4, ARG_EV4HWMEM },
- { "hw_ld/pa", EV5HWMEM(0x1B,0x30), EV5, ARG_EV5HWMEM },
- { "hw_ld/pal", EV5HWMEM(0x1B,0x31), EV5, ARG_EV5HWMEM },
- { "hw_ld/paq", EV4HWMEM(0x1B,0xD), EV4, ARG_EV4HWMEM },
- { "hw_ld/paq", EV5HWMEM(0x1B,0x34), EV5, ARG_EV5HWMEM },
- { "hw_ld/paql", EV5HWMEM(0x1B,0x35), EV5, ARG_EV5HWMEM },
- { "hw_ld/paqv", EV5HWMEM(0x1B,0x36), EV5, ARG_EV5HWMEM },
- { "hw_ld/paqvl", EV5HWMEM(0x1B,0x37), EV5, ARG_EV5HWMEM },
- { "hw_ld/par", EV4HWMEM(0x1B,0xE), EV4, ARG_EV4HWMEM },
- { "hw_ld/parq", EV4HWMEM(0x1B,0xF), EV4, ARG_EV4HWMEM },
- { "hw_ld/pav", EV5HWMEM(0x1B,0x32), EV5, ARG_EV5HWMEM },
- { "hw_ld/pavl", EV5HWMEM(0x1B,0x33), EV5, ARG_EV5HWMEM },
- { "hw_ld/paw", EV5HWMEM(0x1B,0x38), EV5, ARG_EV5HWMEM },
- { "hw_ld/pawl", EV5HWMEM(0x1B,0x39), EV5, ARG_EV5HWMEM },
- { "hw_ld/pawq", EV5HWMEM(0x1B,0x3c), EV5, ARG_EV5HWMEM },
- { "hw_ld/pawql", EV5HWMEM(0x1B,0x3d), EV5, ARG_EV5HWMEM },
- { "hw_ld/pawqv", EV5HWMEM(0x1B,0x3e), EV5, ARG_EV5HWMEM },
- { "hw_ld/pawqvl", EV5HWMEM(0x1B,0x3f), EV5, ARG_EV5HWMEM },
- { "hw_ld/pawv", EV5HWMEM(0x1B,0x3a), EV5, ARG_EV5HWMEM },
- { "hw_ld/pawvl", EV5HWMEM(0x1B,0x3b), EV5, ARG_EV5HWMEM },
- { "hw_ld/pl", EV5HWMEM(0x1B,0x21), EV5, ARG_EV5HWMEM },
- { "hw_ld/pq", EV4HWMEM(0x1B,0x9), EV4, ARG_EV4HWMEM },
- { "hw_ld/pq", EV5HWMEM(0x1B,0x24), EV5, ARG_EV5HWMEM },
- { "hw_ld/pql", EV5HWMEM(0x1B,0x25), EV5, ARG_EV5HWMEM },
- { "hw_ld/pqv", EV5HWMEM(0x1B,0x26), EV5, ARG_EV5HWMEM },
- { "hw_ld/pqvl", EV5HWMEM(0x1B,0x27), EV5, ARG_EV5HWMEM },
- { "hw_ld/pr", EV4HWMEM(0x1B,0xA), EV4, ARG_EV4HWMEM },
- { "hw_ld/prq", EV4HWMEM(0x1B,0xB), EV4, ARG_EV4HWMEM },
- { "hw_ld/pv", EV5HWMEM(0x1B,0x22), EV5, ARG_EV5HWMEM },
- { "hw_ld/pvl", EV5HWMEM(0x1B,0x23), EV5, ARG_EV5HWMEM },
- { "hw_ld/pw", EV5HWMEM(0x1B,0x28), EV5, ARG_EV5HWMEM },
- { "hw_ld/pwl", EV5HWMEM(0x1B,0x29), EV5, ARG_EV5HWMEM },
- { "hw_ld/pwq", EV5HWMEM(0x1B,0x2c), EV5, ARG_EV5HWMEM },
- { "hw_ld/pwql", EV5HWMEM(0x1B,0x2d), EV5, ARG_EV5HWMEM },
- { "hw_ld/pwqv", EV5HWMEM(0x1B,0x2e), EV5, ARG_EV5HWMEM },
- { "hw_ld/pwqvl", EV5HWMEM(0x1B,0x2f), EV5, ARG_EV5HWMEM },
- { "hw_ld/pwv", EV5HWMEM(0x1B,0x2a), EV5, ARG_EV5HWMEM },
- { "hw_ld/pwvl", EV5HWMEM(0x1B,0x2b), EV5, ARG_EV5HWMEM },
- { "hw_ld/q", EV4HWMEM(0x1B,0x1), EV4, ARG_EV4HWMEM },
- { "hw_ld/q", EV5HWMEM(0x1B,0x04), EV5, ARG_EV5HWMEM },
- { "hw_ld/ql", EV5HWMEM(0x1B,0x05), EV5, ARG_EV5HWMEM },
- { "hw_ld/qv", EV5HWMEM(0x1B,0x06), EV5, ARG_EV5HWMEM },
- { "hw_ld/qvl", EV5HWMEM(0x1B,0x07), EV5, ARG_EV5HWMEM },
- { "hw_ld/r", EV4HWMEM(0x1B,0x2), EV4, ARG_EV4HWMEM },
- { "hw_ld/rq", EV4HWMEM(0x1B,0x3), EV4, ARG_EV4HWMEM },
- { "hw_ld/v", EV5HWMEM(0x1B,0x02), EV5, ARG_EV5HWMEM },
- { "hw_ld/vl", EV5HWMEM(0x1B,0x03), EV5, ARG_EV5HWMEM },
- { "hw_ld/w", EV5HWMEM(0x1B,0x08), EV5, ARG_EV5HWMEM },
- { "hw_ld/wl", EV5HWMEM(0x1B,0x09), EV5, ARG_EV5HWMEM },
- { "hw_ld/wq", EV5HWMEM(0x1B,0x0c), EV5, ARG_EV5HWMEM },
- { "hw_ld/wql", EV5HWMEM(0x1B,0x0d), EV5, ARG_EV5HWMEM },
- { "hw_ld/wqv", EV5HWMEM(0x1B,0x0e), EV5, ARG_EV5HWMEM },
- { "hw_ld/wqvl", EV5HWMEM(0x1B,0x0f), EV5, ARG_EV5HWMEM },
- { "hw_ld/wv", EV5HWMEM(0x1B,0x0a), EV5, ARG_EV5HWMEM },
- { "hw_ld/wvl", EV5HWMEM(0x1B,0x0b), EV5, ARG_EV5HWMEM },
- { "pal1b", PCD(0x1B), BASE, ARG_PCD },
-
- { "sextb", OPR(0x1C, 0x00), BWX, ARG_OPRZ1 },
- { "sextw", OPR(0x1C, 0x01), BWX, ARG_OPRZ1 },
- { "ctpop", OPR(0x1C, 0x30), CIX, ARG_OPRZ1 },
- { "perr", OPR(0x1C, 0x31), MAX, ARG_OPR },
- { "ctlz", OPR(0x1C, 0x32), CIX, ARG_OPRZ1 },
- { "cttz", OPR(0x1C, 0x33), CIX, ARG_OPRZ1 },
- { "unpkbw", OPR(0x1C, 0x34), MAX, ARG_OPRZ1 },
- { "unpkbl", OPR(0x1C, 0x35), MAX, ARG_OPRZ1 },
- { "pkwb", OPR(0x1C, 0x36), MAX, ARG_OPRZ1 },
- { "pklb", OPR(0x1C, 0x37), MAX, ARG_OPRZ1 },
- { "minsb8", OPR(0x1C, 0x38), MAX, ARG_OPR },
- { "minsb8", OPRL(0x1C, 0x38), MAX, ARG_OPRL },
- { "minsw4", OPR(0x1C, 0x39), MAX, ARG_OPR },
- { "minsw4", OPRL(0x1C, 0x39), MAX, ARG_OPRL },
- { "minub8", OPR(0x1C, 0x3A), MAX, ARG_OPR },
- { "minub8", OPRL(0x1C, 0x3A), MAX, ARG_OPRL },
- { "minuw4", OPR(0x1C, 0x3B), MAX, ARG_OPR },
- { "minuw4", OPRL(0x1C, 0x3B), MAX, ARG_OPRL },
- { "maxub8", OPR(0x1C, 0x3C), MAX, ARG_OPR },
- { "maxub8", OPRL(0x1C, 0x3C), MAX, ARG_OPRL },
- { "maxuw4", OPR(0x1C, 0x3D), MAX, ARG_OPR },
- { "maxuw4", OPRL(0x1C, 0x3D), MAX, ARG_OPRL },
- { "maxsb8", OPR(0x1C, 0x3E), MAX, ARG_OPR },
- { "maxsb8", OPRL(0x1C, 0x3E), MAX, ARG_OPRL },
- { "maxsw4", OPR(0x1C, 0x3F), MAX, ARG_OPR },
- { "maxsw4", OPRL(0x1C, 0x3F), MAX, ARG_OPRL },
- { "ftoit", FP(0x1C, 0x70), CIX, { FA, ZB, RC } },
- { "ftois", FP(0x1C, 0x78), CIX, { FA, ZB, RC } },
-
- { "hw_mtpr", OPR(0x1D,0x00), EV4, { RA, RBA, EV4EXTHWINDEX } },
- { "hw_mtpr", OP(0x1D), OP_MASK, EV5, { RA, RBA, EV5HWINDEX } },
- { "hw_mtpr", OP(0x1D), OP_MASK, EV6, { ZA, RB, EV6HWINDEX } },
- { "hw_mtpr/i", OPR(0x1D,0x01), EV4, ARG_EV4HWMPR },
- { "hw_mtpr/a", OPR(0x1D,0x02), EV4, ARG_EV4HWMPR },
- { "hw_mtpr/ai", OPR(0x1D,0x03), EV4, ARG_EV4HWMPR },
- { "hw_mtpr/p", OPR(0x1D,0x04), EV4, ARG_EV4HWMPR },
- { "hw_mtpr/pi", OPR(0x1D,0x05), EV4, ARG_EV4HWMPR },
- { "hw_mtpr/pa", OPR(0x1D,0x06), EV4, ARG_EV4HWMPR },
- { "hw_mtpr/pai", OPR(0x1D,0x07), EV4, ARG_EV4HWMPR },
- { "pal1d", PCD(0x1D), BASE, ARG_PCD },
-
- { "hw_rei", SPCD(0x1E,0x3FF8000), EV4|EV5, ARG_NONE },
- { "hw_rei_stall", SPCD(0x1E,0x3FFC000), EV5, ARG_NONE },
- { "hw_jmp", EV6HWMBR(0x1E,0x0), EV6, { ZA, PRB, EV6HWJMPHINT } },
- { "hw_jsr", EV6HWMBR(0x1E,0x2), EV6, { ZA, PRB, EV6HWJMPHINT } },
- { "hw_ret", EV6HWMBR(0x1E,0x4), EV6, { ZA, PRB } },
- { "hw_jcr", EV6HWMBR(0x1E,0x6), EV6, { ZA, PRB } },
- { "hw_coroutine", EV6HWMBR(0x1E,0x6), EV6, { ZA, PRB } }, /* alias */
- { "hw_jmp/stall", EV6HWMBR(0x1E,0x1), EV6, { ZA, PRB, EV6HWJMPHINT } },
- { "hw_jsr/stall", EV6HWMBR(0x1E,0x3), EV6, { ZA, PRB, EV6HWJMPHINT } },
- { "hw_ret/stall", EV6HWMBR(0x1E,0x5), EV6, { ZA, PRB } },
- { "hw_jcr/stall", EV6HWMBR(0x1E,0x7), EV6, { ZA, PRB } },
- { "hw_coroutine/stall", EV6HWMBR(0x1E,0x7), EV6, { ZA, PRB } }, /* alias */
- { "pal1e", PCD(0x1E), BASE, ARG_PCD },
-
- { "hw_stl", EV4HWMEM(0x1F,0x0), EV4, ARG_EV4HWMEM },
- { "hw_stl", EV5HWMEM(0x1F,0x00), EV5, ARG_EV5HWMEM },
- { "hw_stl", EV6HWMEM(0x1F,0x4), EV6, ARG_EV6HWMEM }, /* ??? 8 */
- { "hw_stl/a", EV4HWMEM(0x1F,0x4), EV4, ARG_EV4HWMEM },
- { "hw_stl/a", EV5HWMEM(0x1F,0x10), EV5, ARG_EV5HWMEM },
- { "hw_stl/a", EV6HWMEM(0x1F,0xC), EV6, ARG_EV6HWMEM },
- { "hw_stl/ac", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM },
- { "hw_stl/ar", EV4HWMEM(0x1F,0x6), EV4, ARG_EV4HWMEM },
- { "hw_stl/av", EV5HWMEM(0x1F,0x12), EV5, ARG_EV5HWMEM },
- { "hw_stl/avc", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM },
- { "hw_stl/c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM },
- { "hw_stl/p", EV4HWMEM(0x1F,0x8), EV4, ARG_EV4HWMEM },
- { "hw_stl/p", EV5HWMEM(0x1F,0x20), EV5, ARG_EV5HWMEM },
- { "hw_stl/p", EV6HWMEM(0x1F,0x0), EV6, ARG_EV6HWMEM },
- { "hw_stl/pa", EV4HWMEM(0x1F,0xC), EV4, ARG_EV4HWMEM },
- { "hw_stl/pa", EV5HWMEM(0x1F,0x30), EV5, ARG_EV5HWMEM },
- { "hw_stl/pac", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM },
- { "hw_stl/pav", EV5HWMEM(0x1F,0x32), EV5, ARG_EV5HWMEM },
- { "hw_stl/pavc", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM },
- { "hw_stl/pc", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM },
- { "hw_stl/pr", EV4HWMEM(0x1F,0xA), EV4, ARG_EV4HWMEM },
- { "hw_stl/pv", EV5HWMEM(0x1F,0x22), EV5, ARG_EV5HWMEM },
- { "hw_stl/pvc", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM },
- { "hw_stl/r", EV4HWMEM(0x1F,0x2), EV4, ARG_EV4HWMEM },
- { "hw_stl/v", EV5HWMEM(0x1F,0x02), EV5, ARG_EV5HWMEM },
- { "hw_stl/vc", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM },
- { "hw_stl_c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM },
- { "hw_stl_c/a", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM },
- { "hw_stl_c/av", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM },
- { "hw_stl_c/p", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM },
- { "hw_stl_c/p", EV6HWMEM(0x1F,0x2), EV6, ARG_EV6HWMEM },
- { "hw_stl_c/pa", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM },
- { "hw_stl_c/pav", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM },
- { "hw_stl_c/pv", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM },
- { "hw_stl_c/v", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM },
- { "hw_stq", EV4HWMEM(0x1F,0x1), EV4, ARG_EV4HWMEM },
- { "hw_stq", EV5HWMEM(0x1F,0x04), EV5, ARG_EV5HWMEM },
- { "hw_stq", EV6HWMEM(0x1F,0x5), EV6, ARG_EV6HWMEM }, /* ??? 9 */
- { "hw_stq/a", EV4HWMEM(0x1F,0x5), EV4, ARG_EV4HWMEM },
- { "hw_stq/a", EV5HWMEM(0x1F,0x14), EV5, ARG_EV5HWMEM },
- { "hw_stq/a", EV6HWMEM(0x1F,0xD), EV6, ARG_EV6HWMEM },
- { "hw_stq/ac", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM },
- { "hw_stq/ar", EV4HWMEM(0x1F,0x7), EV4, ARG_EV4HWMEM },
- { "hw_stq/av", EV5HWMEM(0x1F,0x16), EV5, ARG_EV5HWMEM },
- { "hw_stq/avc", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM },
- { "hw_stq/c", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM },
- { "hw_stq/p", EV4HWMEM(0x1F,0x9), EV4, ARG_EV4HWMEM },
- { "hw_stq/p", EV5HWMEM(0x1F,0x24), EV5, ARG_EV5HWMEM },
- { "hw_stq/p", EV6HWMEM(0x1F,0x1), EV6, ARG_EV6HWMEM },
- { "hw_stq/pa", EV4HWMEM(0x1F,0xD), EV4, ARG_EV4HWMEM },
- { "hw_stq/pa", EV5HWMEM(0x1F,0x34), EV5, ARG_EV5HWMEM },
- { "hw_stq/pac", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM },
- { "hw_stq/par", EV4HWMEM(0x1F,0xE), EV4, ARG_EV4HWMEM },
- { "hw_stq/par", EV4HWMEM(0x1F,0xF), EV4, ARG_EV4HWMEM },
- { "hw_stq/pav", EV5HWMEM(0x1F,0x36), EV5, ARG_EV5HWMEM },
- { "hw_stq/pavc", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM },
- { "hw_stq/pc", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM },
- { "hw_stq/pr", EV4HWMEM(0x1F,0xB), EV4, ARG_EV4HWMEM },
- { "hw_stq/pv", EV5HWMEM(0x1F,0x26), EV5, ARG_EV5HWMEM },
- { "hw_stq/pvc", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM },
- { "hw_stq/r", EV4HWMEM(0x1F,0x3), EV4, ARG_EV4HWMEM },
- { "hw_stq/v", EV5HWMEM(0x1F,0x06), EV5, ARG_EV5HWMEM },
- { "hw_stq/vc", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM },
- { "hw_stq_c", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM },
- { "hw_stq_c/a", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM },
- { "hw_stq_c/av", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM },
- { "hw_stq_c/p", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM },
- { "hw_stq_c/p", EV6HWMEM(0x1F,0x3), EV6, ARG_EV6HWMEM },
- { "hw_stq_c/pa", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM },
- { "hw_stq_c/pav", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM },
- { "hw_stq_c/pv", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM },
- { "hw_stq_c/v", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM },
- { "hw_st", EV4HWMEM(0x1F,0x0), EV4, ARG_EV4HWMEM },
- { "hw_st", EV5HWMEM(0x1F,0x00), EV5, ARG_EV5HWMEM },
- { "hw_st/a", EV4HWMEM(0x1F,0x4), EV4, ARG_EV4HWMEM },
- { "hw_st/a", EV5HWMEM(0x1F,0x10), EV5, ARG_EV5HWMEM },
- { "hw_st/ac", EV5HWMEM(0x1F,0x11), EV5, ARG_EV5HWMEM },
- { "hw_st/aq", EV4HWMEM(0x1F,0x5), EV4, ARG_EV4HWMEM },
- { "hw_st/aq", EV5HWMEM(0x1F,0x14), EV5, ARG_EV5HWMEM },
- { "hw_st/aqc", EV5HWMEM(0x1F,0x15), EV5, ARG_EV5HWMEM },
- { "hw_st/aqv", EV5HWMEM(0x1F,0x16), EV5, ARG_EV5HWMEM },
- { "hw_st/aqvc", EV5HWMEM(0x1F,0x17), EV5, ARG_EV5HWMEM },
- { "hw_st/ar", EV4HWMEM(0x1F,0x6), EV4, ARG_EV4HWMEM },
- { "hw_st/arq", EV4HWMEM(0x1F,0x7), EV4, ARG_EV4HWMEM },
- { "hw_st/av", EV5HWMEM(0x1F,0x12), EV5, ARG_EV5HWMEM },
- { "hw_st/avc", EV5HWMEM(0x1F,0x13), EV5, ARG_EV5HWMEM },
- { "hw_st/c", EV5HWMEM(0x1F,0x01), EV5, ARG_EV5HWMEM },
- { "hw_st/p", EV4HWMEM(0x1F,0x8), EV4, ARG_EV4HWMEM },
- { "hw_st/p", EV5HWMEM(0x1F,0x20), EV5, ARG_EV5HWMEM },
- { "hw_st/pa", EV4HWMEM(0x1F,0xC), EV4, ARG_EV4HWMEM },
- { "hw_st/pa", EV5HWMEM(0x1F,0x30), EV5, ARG_EV5HWMEM },
- { "hw_st/pac", EV5HWMEM(0x1F,0x31), EV5, ARG_EV5HWMEM },
- { "hw_st/paq", EV4HWMEM(0x1F,0xD), EV4, ARG_EV4HWMEM },
- { "hw_st/paq", EV5HWMEM(0x1F,0x34), EV5, ARG_EV5HWMEM },
- { "hw_st/paqc", EV5HWMEM(0x1F,0x35), EV5, ARG_EV5HWMEM },
- { "hw_st/paqv", EV5HWMEM(0x1F,0x36), EV5, ARG_EV5HWMEM },
- { "hw_st/paqvc", EV5HWMEM(0x1F,0x37), EV5, ARG_EV5HWMEM },
- { "hw_st/par", EV4HWMEM(0x1F,0xE), EV4, ARG_EV4HWMEM },
- { "hw_st/parq", EV4HWMEM(0x1F,0xF), EV4, ARG_EV4HWMEM },
- { "hw_st/pav", EV5HWMEM(0x1F,0x32), EV5, ARG_EV5HWMEM },
- { "hw_st/pavc", EV5HWMEM(0x1F,0x33), EV5, ARG_EV5HWMEM },
- { "hw_st/pc", EV5HWMEM(0x1F,0x21), EV5, ARG_EV5HWMEM },
- { "hw_st/pq", EV4HWMEM(0x1F,0x9), EV4, ARG_EV4HWMEM },
- { "hw_st/pq", EV5HWMEM(0x1F,0x24), EV5, ARG_EV5HWMEM },
- { "hw_st/pqc", EV5HWMEM(0x1F,0x25), EV5, ARG_EV5HWMEM },
- { "hw_st/pqv", EV5HWMEM(0x1F,0x26), EV5, ARG_EV5HWMEM },
- { "hw_st/pqvc", EV5HWMEM(0x1F,0x27), EV5, ARG_EV5HWMEM },
- { "hw_st/pr", EV4HWMEM(0x1F,0xA), EV4, ARG_EV4HWMEM },
- { "hw_st/prq", EV4HWMEM(0x1F,0xB), EV4, ARG_EV4HWMEM },
- { "hw_st/pv", EV5HWMEM(0x1F,0x22), EV5, ARG_EV5HWMEM },
- { "hw_st/pvc", EV5HWMEM(0x1F,0x23), EV5, ARG_EV5HWMEM },
- { "hw_st/q", EV4HWMEM(0x1F,0x1), EV4, ARG_EV4HWMEM },
- { "hw_st/q", EV5HWMEM(0x1F,0x04), EV5, ARG_EV5HWMEM },
- { "hw_st/qc", EV5HWMEM(0x1F,0x05), EV5, ARG_EV5HWMEM },
- { "hw_st/qv", EV5HWMEM(0x1F,0x06), EV5, ARG_EV5HWMEM },
- { "hw_st/qvc", EV5HWMEM(0x1F,0x07), EV5, ARG_EV5HWMEM },
- { "hw_st/r", EV4HWMEM(0x1F,0x2), EV4, ARG_EV4HWMEM },
- { "hw_st/v", EV5HWMEM(0x1F,0x02), EV5, ARG_EV5HWMEM },
- { "hw_st/vc", EV5HWMEM(0x1F,0x03), EV5, ARG_EV5HWMEM },
- { "pal1f", PCD(0x1F), BASE, ARG_PCD },
-
- { "ldf", MEM(0x20), BASE, ARG_FMEM },
- { "ldg", MEM(0x21), BASE, ARG_FMEM },
- { "lds", MEM(0x22), BASE, ARG_FMEM },
- { "ldt", MEM(0x23), BASE, ARG_FMEM },
- { "stf", MEM(0x24), BASE, ARG_FMEM },
- { "stg", MEM(0x25), BASE, ARG_FMEM },
- { "sts", MEM(0x26), BASE, ARG_FMEM },
- { "stt", MEM(0x27), BASE, ARG_FMEM },
-
- { "ldl", MEM(0x28), BASE, ARG_MEM },
- { "ldq", MEM(0x29), BASE, ARG_MEM },
- { "ldl_l", MEM(0x2A), BASE, ARG_MEM },
- { "ldq_l", MEM(0x2B), BASE, ARG_MEM },
- { "stl", MEM(0x2C), BASE, ARG_MEM },
- { "stq", MEM(0x2D), BASE, ARG_MEM },
- { "stl_c", MEM(0x2E), BASE, ARG_MEM },
- { "stq_c", MEM(0x2F), BASE, ARG_MEM },
-
- { "br", BRA(0x30), BASE, { ZA, BDISP } }, /* pseudo */
- { "br", BRA(0x30), BASE, ARG_BRA },
- { "fbeq", BRA(0x31), BASE, ARG_FBRA },
- { "fblt", BRA(0x32), BASE, ARG_FBRA },
- { "fble", BRA(0x33), BASE, ARG_FBRA },
- { "bsr", BRA(0x34), BASE, ARG_BRA },
- { "fbne", BRA(0x35), BASE, ARG_FBRA },
- { "fbge", BRA(0x36), BASE, ARG_FBRA },
- { "fbgt", BRA(0x37), BASE, ARG_FBRA },
- { "blbc", BRA(0x38), BASE, ARG_BRA },
- { "beq", BRA(0x39), BASE, ARG_BRA },
- { "blt", BRA(0x3A), BASE, ARG_BRA },
- { "ble", BRA(0x3B), BASE, ARG_BRA },
- { "blbs", BRA(0x3C), BASE, ARG_BRA },
- { "bne", BRA(0x3D), BASE, ARG_BRA },
- { "bge", BRA(0x3E), BASE, ARG_BRA },
- { "bgt", BRA(0x3F), BASE, ARG_BRA },
-};
-
-const unsigned alpha_num_opcodes = sizeof(alpha_opcodes)/sizeof(*alpha_opcodes);
-
-/* OSF register names. */
-
-static const char * const osf_regnames[64] = {
- "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
- "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
- "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
- "t10", "t11", "ra", "t12", "at", "gp", "sp", "zero",
- "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
- "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
- "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
- "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
-};
-
-/* VMS register names. */
-
-static const char * const vms_regnames[64] = {
- "R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7",
- "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15",
- "R16", "R17", "R18", "R19", "R20", "R21", "R22", "R23",
- "R24", "AI", "RA", "PV", "AT", "FP", "SP", "RZ",
- "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7",
- "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15",
- "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23",
- "F24", "F25", "F26", "F27", "F28", "F29", "F30", "FZ"
-};
-
-/* Disassemble Alpha instructions. */
-
-int
-print_insn_alpha (memaddr, info)
- bfd_vma memaddr;
- struct disassemble_info *info;
-{
- static const struct alpha_opcode *opcode_index[AXP_NOPS+1];
- const char * const * regnames;
- const struct alpha_opcode *opcode, *opcode_end;
- const unsigned char *opindex;
- unsigned insn, op, isa_mask;
- int need_comma;
-
- /* Initialize the majorop table the first time through */
- if (!opcode_index[0])
- {
- opcode = alpha_opcodes;
- opcode_end = opcode + alpha_num_opcodes;
-
- for (op = 0; op < AXP_NOPS; ++op)
- {
- opcode_index[op] = opcode;
- while (opcode < opcode_end && op == AXP_OP (opcode->opcode))
- ++opcode;
- }
- opcode_index[op] = opcode;
- }
-
- if (info->flavour == bfd_target_evax_flavour)
- regnames = vms_regnames;
- else
- regnames = osf_regnames;
-
- isa_mask = AXP_OPCODE_NOPAL;
- switch (info->mach)
- {
- case bfd_mach_alpha_ev4:
- isa_mask |= AXP_OPCODE_EV4;
- break;
- case bfd_mach_alpha_ev5:
- isa_mask |= AXP_OPCODE_EV5;
- break;
- case bfd_mach_alpha_ev6:
- isa_mask |= AXP_OPCODE_EV6;
- break;
- }
-
- /* Read the insn into a host word */
- {
- bfd_byte buffer[4];
- int status = (*info->read_memory_func) (memaddr, buffer, 4, info);
- if (status != 0)
- {
- (*info->memory_error_func) (status, memaddr, info);
- return -1;
- }
- insn = bfd_getl32 (buffer);
- }
-
- /* Get the major opcode of the instruction. */
- op = AXP_OP (insn);
-
- /* Find the first match in the opcode table. */
- opcode_end = opcode_index[op + 1];
- for (opcode = opcode_index[op]; opcode < opcode_end; ++opcode)
- {
- if ((insn ^ opcode->opcode) & opcode->mask)
- continue;
-
- if (!(opcode->flags & isa_mask))
- continue;
-
- /* Make two passes over the operands. First see if any of them
- have extraction functions, and, if they do, make sure the
- instruction is valid. */
- {
- int invalid = 0;
- for (opindex = opcode->operands; *opindex != 0; opindex++)
- {
- const struct alpha_operand *operand = alpha_operands + *opindex;
- if (operand->extract)
- (*operand->extract) (insn, &invalid);
- }
- if (invalid)
- continue;
- }
-
- /* The instruction is valid. */
- goto found;
- }
-
- /* No instruction found */
- (*info->fprintf_func) (info->stream, ".long %#08x", insn);
-
- return 4;
-
-found:
- (*info->fprintf_func) (info->stream, "%s", opcode->name);
- if (opcode->operands[0] != 0)
- (*info->fprintf_func) (info->stream, "\t");
-
- /* Now extract and print the operands. */
- need_comma = 0;
- for (opindex = opcode->operands; *opindex != 0; opindex++)
- {
- const struct alpha_operand *operand = alpha_operands + *opindex;
- int value;
-
- /* Operands that are marked FAKE are simply ignored. We
- already made sure that the extract function considered
- the instruction to be valid. */
- if ((operand->flags & AXP_OPERAND_FAKE) != 0)
- continue;
-
- /* Extract the value from the instruction. */
- if (operand->extract)
- value = (*operand->extract) (insn, (int *) NULL);
- else
- {
- value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
- if (operand->flags & AXP_OPERAND_SIGNED)
- {
- int signbit = 1 << (operand->bits - 1);
- value = (value ^ signbit) - signbit;
- }
- }
-
- if (need_comma &&
- ((operand->flags & (AXP_OPERAND_PARENS | AXP_OPERAND_COMMA))
- != AXP_OPERAND_PARENS))
- {
- (*info->fprintf_func) (info->stream, ",");
- }
- if (operand->flags & AXP_OPERAND_PARENS)
- (*info->fprintf_func) (info->stream, "(");
-
- /* Print the operand as directed by the flags. */
- if (operand->flags & AXP_OPERAND_IR)
- (*info->fprintf_func) (info->stream, "%s", regnames[value]);
- else if (operand->flags & AXP_OPERAND_FPR)
- (*info->fprintf_func) (info->stream, "%s", regnames[value + 32]);
- else if (operand->flags & AXP_OPERAND_RELATIVE)
- (*info->print_address_func) (memaddr + 4 + value, info);
- else if (operand->flags & AXP_OPERAND_SIGNED)
- (*info->fprintf_func) (info->stream, "%d", value);
- else
- (*info->fprintf_func) (info->stream, "%#x", value);
-
- if (operand->flags & AXP_OPERAND_PARENS)
- (*info->fprintf_func) (info->stream, ")");
- need_comma = 1;
- }
-
- return 4;
-}
diff --git a/android-rebuild.sh b/android-rebuild.sh
new file mode 100755
index 0000000..443afca
--- /dev/null
+++ b/android-rebuild.sh
@@ -0,0 +1,265 @@
+#!/bin/bash
+#
+# this script is used to rebuild all QEMU binaries for the host
+# platforms.
+#
+# assume that the device tree is in TOP
+#
+
+cd `dirname $0`
+
+OS=`uname -s`
+EXE=""
+case "$OS" in
+ Darwin)
+ CPU=`uname -p`
+ if [ "$CPU" = "i386" ] ; then
+ OS=darwin-x86
+ else
+ OS=darwin-ppc
+ fi
+ ;;
+ *_NT-*)
+ OS=windows
+ EXE=.exe
+ ;;
+esac
+
+# select the compiler: on OS X PPC, we're forced to use gcc-3.3
+# also use ccache if we can
+CC=gcc
+HOSTCC=gcc
+cpu=$(uname -p)
+if [ "$cpu" = "powerpc" ] ; then
+ HOSTCC=gcc-3.3
+fi
+
+unset TOP
+# if ANDROID_PRODUCT_OUT is defined we maybe in an Android build
+if [ -n "$ANDROID_PRODUCT_OUT" ] ; then
+ TOP=$(cd $ANDROID_PRODUCT_OUT/../../../.. && pwd)
+ echo "TOP found at $TOP"
+ if [ ! -f "$TOP/config/envsetup.make" ] ; then
+ echo "Cannot find build system root (TOP)"
+ echo "defaulting to non-Android build"
+ unset TOP
+ fi
+fi
+
+# normalize the TOP variable, we don't want any trailing /
+IN_ANDROID_BUILD=
+if [ -n "$TOP" ] ; then
+ if [ ! "$(dirname $TOP)" = "." ] ; then
+ TOP=$(dirname $TOP)/$(basename $TOP)
+ fi
+ IN_ANDROID_BUILD=1
+ echo "In Android Build"
+fi
+
+TARGETS=
+DEBUG=no
+IGNORE_AUDIO=no
+for opt do
+ optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
+ case "$opt" in
+ --help|-h|-\?) show_help=yes
+ ;;
+ --install=*) TARGETS="$TARGETS $optarg";
+ ;;
+ --sdl-config=*) SDL_CONFIG=$optarg
+ ;;
+ --cc=*) CC="$optarg" ; HOSTCC=$CC
+ ;;
+ --no-strip) NOSTRIP=1
+ ;;
+ --no-android) IN_ANDROID_BUILD=
+ ;;
+ --debug) DEBUG=yes
+ ;;
+ --android-build) IN_ANDROID_BUILD=1
+ ;;
+ --ignore-audio) IGNORE_AUDIO=yes
+ ;;
+ esac
+done
+
+if test x"$show_help" = x"yes" ; then
+ cat << EOF
+
+Usage: android-rebuild.sh [options]
+Options: [defaults in brackets after descriptions]
+
+EOF
+ echo "Standard options:"
+ echo " --help print this message"
+ echo " --install=FILEPATH copy emulator executable to FILEPATH [$TARGETS]"
+ echo " --no-strip do not strip emulator executable"
+ echo " --sdl-config=FILE use specific sdl-config script [$SDL_CONFIG]"
+ echo " --debug enable debug (-O0 -g) build"
+ echo " --no-android perform clean build, without Android build tools & prebuilt"
+ echo " --ignore-audio ignore audio messages (may build sound-less emulator)"
+ echo " --cc=PATH specify C compiler [$CC]"
+ echo ""
+ exit 1
+fi
+
+if [ -n "$IN_ANDROID_BUILD" ] ; then
+ # Get the value of a build variable as an absolute path.
+ function get_abs_build_var()
+ {
+ (cd "$TOP" &&
+ CALLED_FROM_SETUP=true make -f config/envsetup.make dumpvar-abs-$1)
+ }
+
+ PREBUILT=$TOP/prebuilt/$OS
+ if [ ! -d $PREBUILT ] ; then
+ echo "Can't find the prebuilt directory $PREBUILT in Android build"
+ exit 1
+ fi
+ if [ -n "$USE_CCACHE" ] ; then
+ CCACHE="$TOP/prebuilt/$OS/ccache$EXE"
+ if [ -f $CCACHE ] ; then
+ CC="$TOP/prebuilt/$OS/ccache$EXE $CC"
+ HOSTCC="$CC"
+ fi
+ fi
+
+ if [ -z "$SDL_CONFIG" ] ; then
+ # always use our own static libSDL by default
+ SDL_CONFIG=$TOP/prebuilt/$OS/sdl/bin/sdl-config
+ fi
+ HOST_BIN=$(get_abs_build_var HOST_OUT_EXECUTABLES)
+ if [ -n "$HOST_BIN" ] ; then
+ TARGETS="$TARGETS $HOST_BIN/emulator$EXE"
+ fi
+else
+ # try to find sdl-config
+ if [ -z "$SDL_CONFIG" ] ; then
+ SDL_CONFIG=$(which sdl-config)
+ fi
+ if [ -z "$SDL_CONFIG" ] ; then
+ echo "Could not find the 'sdl-config' script"
+ echo "You need to have the development version of the SDL library on this machine to build this program"
+ echo "See (www.libsdl.org for details)"
+ if [ "$OS" = "Linux" ] ; then
+ echo "Try to install the 'libsdl-dev' package on this machine"
+ fi
+ exit 1
+ fi
+
+ # check that the static version is usable, this is performed by the configure script
+ # too, but we can be more informative when checking it here
+ TMPC=/tmp/android-qemu-sdl-check.c
+ TMPE=/tmp/android-qemu-sdl-check$EXE
+ TMPL=/tmp/android-qemu-sdl.log
+ cat > $TMPC << EOF
+#include <SDL.h>
+#undef main
+int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
+EOF
+ if $HOSTCC -o $TMPE $TMPC `$SDL_CONFIG --cflags` `$SDL_CONFIG --static-libs` 2> $TMPL; then
+ rm -f $TMPC $TMPE
+ else
+ echo "static linking with your installed SDL library doesn't work"
+ echo "please correct the following compilation/link error messages, then try again"
+ cat $TMPL
+ rm -f $TMPL $TMPC $TMPE
+ exit 1
+ fi
+fi
+
+# if we're in tools/qemu, we output the build commands to the standard outputs
+# if not, we hide them...
+if [ -n "$SHOW_COMMANDS" -o `dirname $0` = "." ] ; then
+ STDOUT=/dev/stdout
+ STDERR=/dev/stderr
+else
+ STDOUT=/dev/null
+ STDERR=/dev/null
+fi
+
+if ! [ -f $SDL_CONFIG ] ; then
+ echo "SDL_CONFIG is set to '$SDL_CONFIG' which doesn't exist"
+ exit 3
+fi
+
+use_sdl_config="--use-sdl-config=$SDL_CONFIG"
+
+# use Makefile.qemu if available
+#
+if [ -f Makefile.qemu ] ; then
+ MAKEFILE=Makefile.qemu
+else
+ MAKEFILE=Makefile
+fi
+
+# compute options for the 'configure' program
+CONFIGURE_OPTIONS="--disable-user --disable-kqemu --enable-trace --enable-shaper"
+CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS --enable-skins --enable-nand --enable-sdl $use_sdl_config"
+
+if [ "$OS" != "windows" ] ; then
+ # Windows doesn't have signals, so -nand-limits cannot work on this platform
+ CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS --enable-nand-limits"
+fi
+
+CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS --static-png --static-sdl --target-list=arm-softmmu"
+
+# we don't want to use the SDL audio driver when possible, since it doesn't support
+# audio input. select a platform-specific one instead...
+#
+AUDIO_OPTIONS=""
+case $OS in
+ darwin*) AUDIO_OPTIONS=" --enable-coreaudio"
+ ;;
+ windows) AUDIO_OPTIONS=" --enable-winaudio"
+ ;;
+ Linux)
+ if `pkg-config --exists alsa`; then
+ AUDIO_OPTIONS="$AUDIO_OPTIONS --enable-alsa"
+ else
+ if [ "$IGNORE_AUDIO" = "no" ] ; then
+ echo "please install the libasound2-dev package on this machine, or use the --ignore-audio option"
+ exit 3
+ fi
+ fi
+ if `pkg-config --exists esound`; then
+ AUDIO_OPTIONS="$AUDIO_OPTIONS --enable-esd"
+ else
+ if [ "$IGNORE_AUDIO" = "no" ] ; then
+ echo "please install the libesd0-dev package on this machine, or use the --ignore-audio option"
+ exit 3
+ fi
+ fi
+ AUDIO_OPTIONS="$AUDIO_OPTIONS --enable-oss"
+ ;;
+esac
+CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS$AUDIO_OPTIONS"
+
+if [ "$DEBUG" = "yes" ] ; then
+ CONFIGURE_OPTIONS="$CONFIGURE_OPTIONS --debug"
+fi
+
+export CC HOSTCC
+
+echo "rebuilding the emulator binary"
+if ! (
+ if [ -f arm-softmmu/Makefile ] ; then
+ make -f $MAKEFILE clean
+ fi
+ echo ./configure $CONFIGURE_OPTIONS &&
+ ./configure $CONFIGURE_OPTIONS &&
+ make -f $MAKEFILE -j4 ) 2>$STDERR >$STDOUT ; then
+ echo "Error while rebuilding the emulator. please check the sources"
+ exit 3
+fi
+
+for target in $TARGETS; do
+ ( echo "copying binary to $target" &&
+ cp -f arm-softmmu/qemu-system-arm$EXE $target &&
+ ( if [ -z "$NOSTRIP" ] ; then
+ echo "stripping $target"
+ strip $target ;
+ fi )
+ ) ;
+done
+
diff --git a/android.h b/android.h
new file mode 100644
index 0000000..8d304f5
--- /dev/null
+++ b/android.h
@@ -0,0 +1,105 @@
+/* Copyright (C) 2007 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _qemu_android_h
+#define _qemu_android_h
+
+#define ANDROID_VERSION_MAJOR 1
+#define ANDROID_VERSION_MINOR 7
+
+// Used to know where to store the user data image.
+// Note: this *must* match the similar-named constant in the ADT plugin,
+// defined in tools/androidprefs/src/com/android/prefs/AndroidLocation.java
+#define ANDROID_SDK_VERSION "SDK-1.0"
+
+#define CONFIG_SHAPER 1
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/** in vl.c */
+
+/* emulated network up/down speeds, expressed in bits/seconds */
+extern double qemu_net_upload_speed;
+extern double qemu_net_download_speed;
+
+/* emulated network min-max latency, expressed in ms */
+extern int qemu_net_min_latency;
+extern int qemu_net_max_latency;
+
+/* global flag, when true, network is disabled */
+extern int qemu_net_disable;
+
+/* list of supported network speed names and values in bits/seconds */
+typedef struct {
+ const char* name;
+ const char* display;
+ int upload;
+ int download;
+} NetworkSpeed;
+
+extern const NetworkSpeed android_netspeeds[];
+
+/* list of supported network latency names and min-max values in ms */
+typedef struct {
+ const char* name;
+ const char* display;
+ int min_ms;
+ int max_ms;
+} NetworkLatency;
+
+extern const NetworkLatency android_netdelays[];
+
+/* enable/disable interrupt polling mode. the emulator will always use 100%
+ * of host CPU time, but will get high-quality time measurments. this is
+ * required for the tracing mode unless you can bear 10ms granularities
+ */
+extern void qemu_polling_enable(void);
+extern void qemu_polling_disable(void);
+
+/**in hw/goldfish_fb.c */
+
+/* framebuffer dimensions in pixels, note these can change dynamically */
+extern int android_framebuffer_w;
+extern int android_framebuffer_h;
+/* framebuffer dimensions in mm */
+extern int android_framebuffer_phys_w;
+extern int android_framebuffer_phys_h;
+
+/* framebuffer rotation, relative to device */
+typedef enum {
+ ANDROID_ROTATION_0 = 0,
+ ANDROID_ROTATION_90,
+ ANDROID_ROTATION_180,
+ ANDROID_ROTATION_270
+} AndroidRotation;
+
+extern AndroidRotation android_framebuffer_rotation;
+
+/** in android_main.c */
+
+/* this is the port used for the control console in this emulator instance.
+ * starts at 5554, with increments of 2 */
+extern int android_base_port;
+
+/* parses a network speed parameter and sets qemu_net_upload_speed and
+ * qemu_net_download_speed accordingly. returns -1 on failure, 0 on success */
+extern int android_parse_network_speed(const char* speed);
+
+/* parse a network delay parameter and sets qemu_net_min/max_latency
+ * accordingly. returns -1 on error, 0 on success */
+extern int android_parse_network_latency(const char* delay);
+
+extern void android_emulation_setup( void );
+extern void android_emulation_teardown( void );
+
+#endif /* _qemu_android_h */
diff --git a/android/config/config.h b/android/config/config.h
new file mode 100644
index 0000000..be83607
--- /dev/null
+++ b/android/config/config.h
@@ -0,0 +1,14 @@
+/* Automatically generated by configure - do not modify */
+#include "config-host.h"
+#define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-arm"
+#define TARGET_ARCH "arm"
+#define TARGET_ARM 1
+#define CONFIG_TRACE 1
+#define CONFIG_NAND 1
+#define CONFIG_SHAPER 1
+#define CONFIG_SOFTMMU 1
+#define CONFIG_SOFTFLOAT 1
+#define CONFIG_SDL 1
+#ifndef _WIN32
+#define CONFIG_NAND_LIMITS 1
+#endif
diff --git a/android/config/darwin-ppc/config-host.h b/android/config/darwin-ppc/config-host.h
new file mode 100644
index 0000000..cbd43d1
--- /dev/null
+++ b/android/config/darwin-ppc/config-host.h
@@ -0,0 +1,13 @@
+/* Automatically generated by configure - do not modify */
+#define CONFIG_QEMU_SHAREDIR "/usr/local/share/qemu"
+#define HOST_PPC 1
+#define HOST_LONG_BITS 32
+#define CONFIG_DARWIN 1
+#define CONFIG_GDBSTUB 1
+#define CONFIG_SLIRP 1
+#define QEMU_VERSION "0.8.2"
+#define O_LARGEFILE 0
+#define MAP_ANONYMOUS MAP_ANON
+#define _BSD 1
+#define CONFIG_SKINS 1
+#define CONFIG_UNAME_RELEASE ""
diff --git a/android/config/darwin-x86/config-host.h b/android/config/darwin-x86/config-host.h
new file mode 100644
index 0000000..aaf0195
--- /dev/null
+++ b/android/config/darwin-x86/config-host.h
@@ -0,0 +1,13 @@
+/* Automatically generated by configure - do not modify */
+#define CONFIG_QEMU_SHAREDIR "/usr/local/share/qemu"
+#define HOST_I386 1
+#define HOST_LONG_BITS 32
+#define CONFIG_DARWIN 1
+#define CONFIG_GDBSTUB 1
+#define CONFIG_SLIRP 1
+#define QEMU_VERSION "0.8.2"
+#define O_LARGEFILE 0
+#define MAP_ANONYMOUS MAP_ANON
+#define _BSD 1
+#define CONFIG_SKINS 1
+#define CONFIG_UNAME_RELEASE ""
diff --git a/android/config/linux-x86/config-host.h b/android/config/linux-x86/config-host.h
new file mode 100644
index 0000000..90defbd
--- /dev/null
+++ b/android/config/linux-x86/config-host.h
@@ -0,0 +1,10 @@
+/* Automatically generated by configure - do not modify */
+#define CONFIG_QEMU_SHAREDIR "/usr/local/share/qemu"
+#define HOST_I386 1
+#define HOST_LONG_BITS 32
+#define HAVE_BYTESWAP_H 1
+#define CONFIG_GDBSTUB 1
+#define CONFIG_SLIRP 1
+#define QEMU_VERSION "0.8.2"
+#define CONFIG_SKINS 1
+#define CONFIG_UNAME_RELEASE ""
diff --git a/android/config/windows/config-host.h b/android/config/windows/config-host.h
new file mode 100644
index 0000000..8f9e0d9
--- /dev/null
+++ b/android/config/windows/config-host.h
@@ -0,0 +1,10 @@
+/* Automatically generated by configure - do not modify */
+#define CONFIG_QEMU_SHAREDIR "/usr/local/share/qemu"
+#define HOST_I386 1
+#define HOST_LONG_BITS 32
+#define CONFIG_WIN32 1
+#define CONFIG_GDBSTUB 1
+#define CONFIG_SLIRP 1
+#define QEMU_VERSION "0.8.2"
+#define CONFIG_SKINS 1
+#define CONFIG_UNAME_RELEASE ""
diff --git a/android_avm.c b/android_avm.c
new file mode 100644
index 0000000..277233f
--- /dev/null
+++ b/android_avm.c
@@ -0,0 +1,42 @@
+#include "android_avm.h"
+#include "android_utils.h"
+#include <string.h>
+
+int
+avm_check_name( const char* avm_name )
+{
+ static const char* goodchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789.";
+ int len = strlen(avm_name);
+ int slen = strspn(avm_name, goodchars);
+
+ return (len == slen);
+}
+
+
+char*
+avm_bufprint_default_root( char* p, char* end )
+{
+ /* at the moment, store in $CONFIG_PATH/VMs */
+ return bufprint_config_path(p, end, "VMs" );
+}
+
+char*
+avm_bufprint_avm_dir( char* p, char* end, const char* avm_name, const char* root_dir )
+{
+ if (root_dir) {
+ int len = strlen(root_dir);
+ /* get rid of trailing path separators */
+ while (len > 0 && root_dir[len-1] == PATH_SEP[0])
+ len -= 1;
+
+ p = bufprint( p, end, "%.*s", len, root_dir );
+ } else {
+ p = avm_bufprint_default_root( p, end );
+
+ p = bufprint( p, end, PATH_SEP "%s", avm_name );
+
+ return p;
+}
+
+
+
diff --git a/android_avm.h b/android_avm.h
new file mode 100644
index 0000000..24b7fa7
--- /dev/null
+++ b/android_avm.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef ANDROID_VIRTUAL_MACHINE_H
+#define ANDROID_VIRTUAL_MACHINE_H
+
+/* An Android Virtual Machine (AVM for short) corresponds to
+ * a directory containing all system + data disk images for a
+ * given virtual device, plus some AVM-specific configuration
+ * files.
+ */
+
+/* checks that the name of an AVM doesn't contain fancy characters
+ * returns 1 on success, 0 on failure
+ */
+extern int avm_check_name( const char* avm_name );
+
+/* bufprint the path of the default root directory where all AVMs are stored
+ * this is normally $HOME/.android/$SDK_VERSION/VMs on Unix
+ */
+extern char* avm_bufprint_default_root( char* p, char* end );
+
+/* bufprint the path of a given AVM's directory
+ * if 'root' is non NULL, this will be $root/$avm_name
+ * otherwise, it will be the result of avm_bufprint_defalt_root followed by avm_name
+ */
+extern char* avm_bufprint_avm_dir( char* p, char* end, const char* avm_name, const char* root_dir );
+
+
+
+#endif /* ANDROID_VIRTUAL_MACHINE_H */
diff --git a/android_charmap.c b/android_charmap.c
new file mode 100644
index 0000000..bd57bc0
--- /dev/null
+++ b/android_charmap.c
@@ -0,0 +1,148 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_charmap.h"
+
+/* the following is automatically generated by the 'gen-charmap.py' script
+ * do not touch. the generation command was:
+ * gen-charmap.py qwerty.kcm qwerty2.kcm
+ */
+
+static const AKeyEntry _qwerty_keys[] =
+{
+ /* keycode base caps fn caps+fn number */
+
+ { kKeyCodeA , 'a', 'A', '#', 0x00, '#' },
+ { kKeyCodeB , 'b', 'B', '<', 0x00, '<' },
+ { kKeyCodeC , 'c', 'C', '9', 0x00E7, '9' },
+ { kKeyCodeD , 'd', 'D', '5', 0x00, '5' },
+ { kKeyCodeE , 'e', 'E', '2', 0x0301, '2' },
+ { kKeyCodeF , 'f', 'F', '6', 0x00A5, '6' },
+ { kKeyCodeG , 'g', 'G', '-', '_', '-' },
+ { kKeyCodeH , 'h', 'H', '[', '{', '[' },
+ { kKeyCodeI , 'i', 'I', '$', 0x0302, '$' },
+ { kKeyCodeJ , 'j', 'J', ']', '}', ']' },
+ { kKeyCodeK , 'k', 'K', '"', '~', '"' },
+ { kKeyCodeL , 'l', 'L', '\'', '`', '\'' },
+ { kKeyCodeM , 'm', 'M', '!', 0x00, '!' },
+ { kKeyCodeN , 'n', 'N', '>', 0x0303, '>' },
+ { kKeyCodeO , 'o', 'O', '(', 0x00, '(' },
+ { kKeyCodeP , 'p', 'P', ')', 0x00, ')' },
+ { kKeyCodeQ , 'q', 'Q', '*', 0x0300, '*' },
+ { kKeyCodeR , 'r', 'R', '3', 0x20AC, '3' },
+ { kKeyCodeS , 's', 'S', '4', 0x00DF, '4' },
+ { kKeyCodeT , 't', 'T', '+', 0x00A3, '+' },
+ { kKeyCodeU , 'u', 'U', '&', 0x0308, '&' },
+ { kKeyCodeV , 'v', 'V', '=', '^', '=' },
+ { kKeyCodeW , 'w', 'W', '1', 0x00, '1' },
+ { kKeyCodeX , 'x', 'X', '8', 0x00, '8' },
+ { kKeyCodeY , 'y', 'Y', '%', 0x00A1, '%' },
+ { kKeyCodeZ , 'z', 'Z', '7', 0x00, '7' },
+ { kKeyCodeComma , ',', ';', ';', '|', ',' },
+ { kKeyCodePeriod , '.', ':', ':', 0x2026, '.' },
+ { kKeyCodeAt , '@', '0', '0', 0x2022, '0' },
+ { kKeyCodeSlash , '/', '?', '?', '\\', '/' },
+ { kKeyCodeSpace , 0x20, 0x20, 0x9, 0x9, 0x20 },
+ { kKeyCodeNewline , 0xa, 0xa, 0xa, 0xa, 0xa },
+ { kKeyCodeTab , 0x9, 0x9, 0x9, 0x9, 0x9 },
+ { kKeyCode0 , '0', ')', '0', ')', '0' },
+ { kKeyCode1 , '1', '!', '1', '!', '1' },
+ { kKeyCode2 , '2', '@', '2', '@', '2' },
+ { kKeyCode3 , '3', '#', '3', '#', '3' },
+ { kKeyCode4 , '4', '$', '4', '$', '4' },
+ { kKeyCode5 , '5', '%', '5', '%', '5' },
+ { kKeyCode6 , '6', '^', '6', '^', '6' },
+ { kKeyCode7 , '7', '&', '7', '&', '7' },
+ { kKeyCode8 , '8', '*', '8', '*', '8' },
+ { kKeyCode9 , '9', '(', '9', '(', '9' },
+ { kKeyCodeGrave , '`', '~', '`', '~', '`' },
+ { kKeyCodeMinus , '-', '_', '-', '_', '-' },
+ { kKeyCodeEquals , '=', '+', '=', '+', '=' },
+ { kKeyCodeLeftBracket , '[', '{', '[', '{', '[' },
+ { kKeyCodeRightBracket , ']', '}', ']', '}', ']' },
+ { kKeyCodeBackslash , '\\', '|', '\\', '|', '\\' },
+ { kKeyCodeSemicolon , ';', ':', ';', ':', ';' },
+ { kKeyCodeApostrophe , '\'', '"', '\'', '"', '\'' },
+};
+
+static const AKeyCharmap _qwerty_charmap =
+{
+ _qwerty_keys,
+ 51,
+ "qwerty"
+};
+
+static const AKeyEntry _qwerty2_keys[] =
+{
+ /* keycode base caps fn caps+fn number */
+
+ { kKeyCodeA , 'a', 'A', 'a', 'A', 'a' },
+ { kKeyCodeB , 'b', 'B', 'b', 'B', 'b' },
+ { kKeyCodeC , 'c', 'C', 0x00e7, 0x00E7, 'c' },
+ { kKeyCodeD , 'd', 'D', '\'', '\'', '\'' },
+ { kKeyCodeE , 'e', 'E', '"', 0x0301, '"' },
+ { kKeyCodeF , 'f', 'F', '[', '[', '[' },
+ { kKeyCodeG , 'g', 'G', ']', ']', ']' },
+ { kKeyCodeH , 'h', 'H', '<', '<', '<' },
+ { kKeyCodeI , 'i', 'I', '-', 0x0302, '-' },
+ { kKeyCodeJ , 'j', 'J', '>', '>', '>' },
+ { kKeyCodeK , 'k', 'K', ';', '~', ';' },
+ { kKeyCodeL , 'l', 'L', ':', '`', ':' },
+ { kKeyCodeM , 'm', 'M', '%', 0x00, '%' },
+ { kKeyCodeN , 'n', 'N', 0x00, 0x0303, 'n' },
+ { kKeyCodeO , 'o', 'O', '+', '+', '+' },
+ { kKeyCodeP , 'p', 'P', '=', 0x00A5, '=' },
+ { kKeyCodeQ , 'q', 'Q', '|', 0x0300, '|' },
+ { kKeyCodeR , 'r', 'R', '`', 0x20AC, '`' },
+ { kKeyCodeS , 's', 'S', '\\', 0x00DF, '\\' },
+ { kKeyCodeT , 't', 'T', '{', 0x00A3, '}' },
+ { kKeyCodeU , 'u', 'U', '_', 0x0308, '_' },
+ { kKeyCodeV , 'v', 'V', 'v', 'V', 'v' },
+ { kKeyCodeW , 'w', 'W', '~', '~', '~' },
+ { kKeyCodeX , 'x', 'X', 'x', 'X', 'x' },
+ { kKeyCodeY , 'y', 'Y', '}', 0x00A1, '}' },
+ { kKeyCodeZ , 'z', 'Z', 'z', 'Z', 'z' },
+ { kKeyCodeComma , ',', '<', ',', ',', ',' },
+ { kKeyCodePeriod , '.', '>', '.', 0x2026, '.' },
+ { kKeyCodeAt , '@', '@', '@', 0x2022, '@' },
+ { kKeyCodeSlash , '/', '?', '?', '?', '/' },
+ { kKeyCodeSpace , 0x20, 0x20, 0x9, 0x9, 0x20 },
+ { kKeyCodeNewline , 0xa, 0xa, 0xa, 0xa, 0xa },
+ { kKeyCode0 , '0', ')', ')', ')', '0' },
+ { kKeyCode1 , '1', '!', '!', '!', '1' },
+ { kKeyCode2 , '2', '@', '@', '@', '2' },
+ { kKeyCode3 , '3', '#', '#', '#', '3' },
+ { kKeyCode4 , '4', '$', '$', '$', '4' },
+ { kKeyCode5 , '5', '%', '%', '%', '5' },
+ { kKeyCode6 , '6', '^', '^', '^', '6' },
+ { kKeyCode7 , '7', '&', '&', '&', '7' },
+ { kKeyCode8 , '8', '*', '*', '*', '8' },
+ { kKeyCode9 , '9', '(', '(', '(', '9' },
+ { kKeyCodeTab , 0x9, 0x9, 0x9, 0x9, 0x9 },
+ { kKeyCodeGrave , '`', '~', '`', '~', '`' },
+ { kKeyCodeMinus , '-', '_', '-', '_', '-' },
+ { kKeyCodeEquals , '=', '+', '=', '+', '=' },
+ { kKeyCodeLeftBracket , '[', '{', '[', '{', '[' },
+ { kKeyCodeRightBracket , ']', '}', ']', '}', ']' },
+ { kKeyCodeBackslash , '\\', '|', '\\', '|', '\\' },
+ { kKeyCodeSemicolon , ';', ':', ';', ':', ';' },
+ { kKeyCodeApostrophe , '\'', '"', '\'', '"', '\'' },
+};
+
+static const AKeyCharmap _qwerty2_charmap =
+{
+ _qwerty2_keys,
+ 51,
+ "qwerty2"
+};
+
+const AKeyCharmap* android_charmaps[2] = { &_qwerty_charmap , &_qwerty2_charmap };
+const int android_charmap_count = 2;
diff --git a/android_charmap.h b/android_charmap.h
new file mode 100644
index 0000000..f300e68
--- /dev/null
+++ b/android_charmap.h
@@ -0,0 +1,133 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _android_charmap_h
+#define _android_charmap_h
+
+#include "linux_keycodes.h"
+
+/* Keep it consistent with linux/input.h */
+typedef enum {
+ kKeyCodeSoftLeft = KEY_SOFT1,
+ kKeyCodeSoftRight = KEY_SOFT2,
+ kKeyCodeHome = KEY_HOME,
+ kKeyCodeBack = KEY_BACK,
+ kKeyCodeCall = KEY_SEND,
+ kKeyCodeEndCall = KEY_END,
+ kKeyCode0 = KEY_0,
+ kKeyCode1 = KEY_1,
+ kKeyCode2 = KEY_2,
+ kKeyCode3 = KEY_3,
+ kKeyCode4 = KEY_4,
+ kKeyCode5 = KEY_5,
+ kKeyCode6 = KEY_6,
+ kKeyCode7 = KEY_7,
+ kKeyCode8 = KEY_8,
+ kKeyCode9 = KEY_9,
+ kKeyCodeStar = KEY_STAR,
+ kKeyCodePound = KEY_SHARP,
+ kKeyCodeDpadUp = KEY_UP,
+ kKeyCodeDpadDown = KEY_DOWN,
+ kKeyCodeDpadLeft = KEY_LEFT,
+ kKeyCodeDpadRight = KEY_RIGHT,
+ kKeyCodeDpadCenter = KEY_CENTER,
+ kKeyCodeVolumeUp = KEY_VOLUMEUP,
+ kKeyCodeVolumeDown = KEY_VOLUMEDOWN,
+ kKeyCodePower = KEY_POWER,
+ kKeyCodeCamera = KEY_CAMERA,
+ kKeyCodeClear = KEY_CLEAR,
+ kKeyCodeA = KEY_A,
+ kKeyCodeB = KEY_B,
+ kKeyCodeC = KEY_C,
+ kKeyCodeD = KEY_D,
+ kKeyCodeE = KEY_E,
+ kKeyCodeF = KEY_F,
+ kKeyCodeG = KEY_G,
+ kKeyCodeH = KEY_H,
+ kKeyCodeI = KEY_I,
+ kKeyCodeJ = KEY_J,
+ kKeyCodeK = KEY_K,
+ kKeyCodeL = KEY_L,
+ kKeyCodeM = KEY_M,
+ kKeyCodeN = KEY_N,
+ kKeyCodeO = KEY_O,
+ kKeyCodeP = KEY_P,
+ kKeyCodeQ = KEY_Q,
+ kKeyCodeR = KEY_R,
+ kKeyCodeS = KEY_S,
+ kKeyCodeT = KEY_T,
+ kKeyCodeU = KEY_U,
+ kKeyCodeV = KEY_V,
+ kKeyCodeW = KEY_W,
+ kKeyCodeX = KEY_X,
+ kKeyCodeY = KEY_Y,
+ kKeyCodeZ = KEY_Z,
+
+ kKeyCodeComma = KEY_COMMA,
+ kKeyCodePeriod = KEY_DOT,
+ kKeyCodeAltLeft = KEY_LEFTALT,
+ kKeyCodeAltRight = KEY_RIGHTALT,
+ kKeyCodeCapLeft = KEY_LEFTSHIFT,
+ kKeyCodeCapRight = KEY_RIGHTSHIFT,
+ kKeyCodeTab = KEY_TAB,
+ kKeyCodeSpace = KEY_SPACE,
+ kKeyCodeSym = KEY_COMPOSE,
+ kKeyCodeExplorer = KEY_WWW,
+ kKeyCodeEnvelope = KEY_MAIL,
+ kKeyCodeNewline = KEY_ENTER,
+ kKeyCodeDel = KEY_BACKSPACE,
+ kKeyCodeGrave = 399,
+ kKeyCodeMinus = KEY_MINUS,
+ kKeyCodeEquals = KEY_EQUAL,
+ kKeyCodeLeftBracket = KEY_LEFTBRACE,
+ kKeyCodeRightBracket = KEY_RIGHTBRACE,
+ kKeyCodeBackslash = KEY_BACKSLASH,
+ kKeyCodeSemicolon = KEY_SEMICOLON,
+ kKeyCodeApostrophe = KEY_APOSTROPHE,
+ kKeyCodeSlash = KEY_SLASH,
+ kKeyCodeAt = KEY_EMAIL,
+ kKeyCodeNum = KEY_NUM,
+ kKeyCodeHeadsetHook = KEY_HEADSETHOOK,
+ kKeyCodeFocus = KEY_FOCUS,
+ kKeyCodePlus = KEY_PLUS,
+ kKeyCodeMenu = KEY_MENU,
+ kKeyCodeNotification = KEY_NOTIFICATION,
+ kKeyCodeSearch = KEY_SEARCH,
+
+ kKeyCodeBtnMouse = BTN_MOUSE,
+
+ kKeyCodeOrientation0 = 77,
+ kKeyCodeOrientation90 = 78,
+ kKeyCodeOrientation180 = 79,
+ kKeyCodeOrientation270 = 80
+} AndroidKeyCode;
+
+
+/* this defines a structure used to describe an Android keyboard charmap */
+typedef struct AKeyEntry {
+ unsigned short code;
+ unsigned short base;
+ unsigned short caps;
+ unsigned short fn;
+ unsigned short caps_fn;
+ unsigned short number;
+} AKeyEntry;
+
+typedef struct {
+ const AKeyEntry* entries;
+ int num_entries;
+ char name[ 32 ];
+} AKeyCharmap;
+
+extern const int android_charmap_count;
+extern const AKeyCharmap* android_charmaps[];
+
+#endif /* _android_charmap_h */
diff --git a/android_config.c b/android_config.c
new file mode 100644
index 0000000..c90a219
--- /dev/null
+++ b/android_config.c
@@ -0,0 +1,471 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "android_config.h"
+#include "android_utils.h"
+
+#if !defined(_WIN23) && !defined(O_BINARY)
+# define O_BINARY 0
+#endif
+
+AConfig*
+aconfig_node(const char *name, const char *value)
+{
+ AConfig *n;
+
+ n = (AConfig*) calloc(sizeof(AConfig), 1);
+ n->name = name ? name : "";
+ n->value = value ? value : "";
+
+ return n;
+}
+
+static AConfig*
+_aconfig_find(AConfig *root, const char *name, int create)
+{
+ AConfig *node;
+
+ for(node = root->first_child; node; node = node->next) {
+ if(!strcmp(node->name, name)) return node;
+ }
+
+ if(create) {
+ node = (AConfig*) calloc(sizeof(AConfig), 1);
+ node->name = name;
+ node->value = "";
+
+ if(root->last_child) {
+ root->last_child->next = node;
+ } else {
+ root->first_child = node;
+ }
+ root->last_child = node;
+ }
+
+ return node;
+}
+
+AConfig*
+aconfig_find(AConfig *root, const char *name)
+{
+ return _aconfig_find(root, name, 0);
+}
+
+int
+aconfig_bool(AConfig *root, const char *name, int _default)
+{
+ AConfig *n = _aconfig_find(root, name, 0);
+ if(n == 0) {
+ return _default;
+ } else {
+ switch(n->value[0]){
+ case 'y':
+ case 'Y':
+ case '1':
+ return 1;
+ default:
+ return 0;
+ }
+ }
+}
+
+unsigned
+aconfig_unsigned(AConfig *root, const char *name, unsigned _default)
+{
+ AConfig *n = _aconfig_find(root, name, 0);
+ if(n == 0) {
+ return _default;
+ } else {
+ return strtoul(n->value, 0, 0);
+ }
+}
+
+int
+aconfig_int(AConfig *root, const char *name, int _default)
+{
+ AConfig *n = _aconfig_find(root, name, 0);
+ if(n == 0) {
+ return _default;
+ } else {
+ return strtol(n->value, 0, 0);
+ }
+}
+
+
+const char*
+aconfig_str(AConfig *root, const char *name, const char *_default)
+{
+ AConfig *n = _aconfig_find(root, name, 0);
+ if(n == 0) {
+ return _default;
+ } else {
+ return n->value;
+ }
+}
+
+void
+aconfig_set(AConfig *root, const char *name, const char *value)
+{
+ AConfig *node = _aconfig_find(root, name, 1);
+ node->value = value;
+}
+
+#define T_EOF 0
+#define T_TEXT 1
+#define T_DOT 2
+#define T_OBRACE 3
+#define T_CBRACE 4
+
+typedef struct
+{
+ char *data;
+ char *text;
+ int len;
+ char next;
+} cstate;
+
+
+static int _lex(cstate *cs, int value)
+{
+ char c;
+ char *s;
+ char *data;
+
+ data = cs->data;
+
+ if(cs->next != 0) {
+ c = cs->next;
+ cs->next = 0;
+ goto got_c;
+ }
+
+restart:
+ for(;;) {
+ c = *data++;
+ got_c:
+ if(isspace(c)) continue;
+
+ switch(c) {
+ case 0:
+ return T_EOF;
+
+ /* a sharp sign (#) starts a line comment and everything
+ * behind that is ignored until the end of line
+ */
+ case '#':
+ for(;;) {
+ switch(*data) {
+ case 0:
+ cs->data = data;
+ return T_EOF;
+ case '\n':
+ cs->data = data + 1;
+ goto restart;
+ default:
+ data++;
+ }
+ }
+ break;
+
+ case '.':
+ cs->data = data;
+ return T_DOT;
+
+ case '{':
+ cs->data = data;
+ return T_OBRACE;
+
+ case '}':
+ cs->data = data;
+ return T_CBRACE;
+
+ default:
+ s = data - 1;
+
+ if(value) {
+ /* if we're looking for a value, then take anything
+ * until the end of line. note that sharp signs do
+ * not start comments then. the result will be stripped
+ * from trailing whitespace.
+ */
+ for(;;) {
+ if(*data == 0) {
+ cs->data = data;
+ break;
+ }
+ if(*data == '\n') {
+ cs->data = data + 1;
+ *data-- = 0;
+ break;
+ }
+ data++;
+ }
+
+ /* strip trailing whitespace */
+ while(data > s){
+ if(!isspace(*data)) break;
+ *data-- = 0;
+ }
+
+ goto got_text;
+ } else {
+ /* looking for a key name. we stop at whitspace,
+ * EOF, of T_DOT/T_OBRACE/T_CBRACE characters.
+ * note that the name can include sharp signs
+ */
+ for(;;) {
+ if(isspace(*data)) {
+ *data = 0;
+ cs->data = data + 1;
+ goto got_text;
+ }
+ switch(*data) {
+ case 0:
+ cs->data = data;
+ goto got_text;
+ case '.':
+ case '{':
+ case '}':
+ cs->next = *data;
+ *data = 0;
+ cs->data = data + 1;
+ goto got_text;
+ default:
+ data++;
+ }
+ }
+ }
+ }
+ }
+
+got_text:
+ cs->text = s;
+ return T_TEXT;
+}
+
+#if 0
+char *TOKENNAMES[] = { "EOF", "TEXT", "DOT", "OBRACE", "CBRACE" };
+
+static int lex(cstate *cs, int value)
+{
+ int tok = _lex(cs, value);
+ printf("TOKEN(%d) %s %s\n", value, TOKENNAMES[tok],
+ tok == T_TEXT ? cs->text : "");
+ return tok;
+}
+#else
+#define lex(cs,v) _lex(cs,v)
+#endif
+
+static int parse_expr(cstate *cs, AConfig *node);
+
+static int
+parse_block(cstate *cs, AConfig *node)
+{
+ for(;;){
+ switch(lex(cs, 0)){
+ case T_TEXT:
+ if(parse_expr(cs, node)) return -1;
+ continue;
+
+ case T_CBRACE:
+ return 0;
+
+ default:
+ return -1;
+ }
+ }
+}
+
+static int
+parse_expr(cstate *cs, AConfig *node)
+{
+ /* last token was T_TEXT */
+ node = _aconfig_find(node, cs->text, 1);
+
+ for(;;) {
+ switch(lex(cs, 1)) {
+ case T_DOT:
+ if(lex(cs, 0) != T_TEXT) return -1;
+ node = _aconfig_find(node, cs->text, 1);
+ continue;
+
+ case T_TEXT:
+ node->value = cs->text;
+ return 0;
+
+ case T_OBRACE:
+ return parse_block(cs, node);
+
+ default:
+ return -1;
+ }
+ }
+}
+
+void
+aconfig_load(AConfig *root, char *data)
+{
+ if(data != 0) {
+ cstate cs;
+ cs.data = data;
+ cs.next = 0;
+
+ for(;;) {
+ switch(lex(&cs, 0)){
+ case T_TEXT:
+ if(parse_expr(&cs, root)) return;
+ break;
+ default:
+ return;
+ }
+ }
+ }
+}
+
+int
+aconfig_load_file(AConfig *root, const char *fn)
+{
+ char *data;
+ data = load_text_file(fn);
+ if (data == NULL)
+ return -1;
+
+ aconfig_load(root, data);
+ return 0;
+}
+
+
+typedef struct
+{
+ char buff[1024];
+ char* p;
+ char* end;
+ int fd;
+} Writer;
+
+static int
+writer_init( Writer* w, const char* fn )
+{
+ w->p = w->buff;
+ w->end = w->buff + sizeof(w->buff);
+
+ w->fd = creat( fn, 0755 );
+ if (w->fd < 0)
+ return -1;
+
+#ifdef _WIN32
+ _setmode( w->fd, _O_BINARY );
+#endif
+ return 0;
+}
+
+static void
+writer_write( Writer* w, const char* src, int len )
+{
+ while (len > 0) {
+ int avail = w->end - w->p;
+
+ if (avail > len)
+ avail = len;
+
+ memcpy( w->p, src, avail );
+ src += avail;
+ len -= avail;
+
+ w->p += avail;
+ if (w->p == w->end) {
+ write( w->fd, w->buff, w->p - w->buff );
+ w->p = w->buff;
+ }
+ }
+}
+
+static void
+writer_done( Writer* w )
+{
+ if (w->p > w->buff)
+ write( w->fd, w->buff, w->p - w->buff );
+ close( w->fd );
+}
+
+static void
+writer_margin( Writer* w, int margin)
+{
+ static const char spaces[10] = " ";
+ while (margin >= 10) {
+ writer_write(w,spaces,10);
+ margin -= 10;
+ }
+ if (margin > 0)
+ writer_write(w,spaces,margin);
+}
+
+static void
+writer_c(Writer* w, char c)
+{
+ writer_write(w, &c, 1);
+}
+
+static void
+writer_str(Writer* w, const char* str)
+{
+ writer_write(w, str, strlen(str));
+}
+
+static void
+writer_node(Writer* w, AConfig* node, int margin)
+{
+ writer_margin(w,margin);
+ writer_str(w, node->name);
+ writer_c(w,' ');
+
+ if (node->value[0]) {
+ writer_str(w, node->value);
+ writer_c(w,'\n');
+ }
+ else
+ {
+ AConfig* child;
+
+ writer_c(w, '{');
+ writer_c(w, '\n');
+
+ for (child = node->first_child; child; child = child->next)
+ writer_node(w,child,margin+4);
+
+ writer_margin(w,margin);
+ writer_c(w,'}');
+ writer_c(w,'\n');
+ }
+}
+
+int
+aconfig_save_file(AConfig *root, const char *fn)
+{
+ AConfig* child;
+ Writer w[1];
+
+ if (writer_init(w,fn) < 0)
+ return -1;
+
+ for (child = root->first_child; child; child = child->next)
+ writer_node(w,child,0);
+
+ writer_done(w);
+ return 0;
+}
diff --git a/android_config.h b/android_config.h
new file mode 100644
index 0000000..5e8b048
--- /dev/null
+++ b/android_config.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef ANDROID_CONFIG_H
+#define ANDROID_CONFIG_H
+
+/** ANDROID CONFIGURATION FILE SUPPORT
+ **
+ ** A configuration file is loaded as a simplre tree of (key,value)
+ ** pairs. keys and values are simple strings
+ **/
+typedef struct AConfig AConfig;
+
+struct AConfig
+{
+ AConfig* next;
+ AConfig* first_child;
+ AConfig* last_child;
+ const char* name;
+ const char* value;
+};
+
+/* parse a text string into a config node tree */
+extern void aconfig_load(AConfig* root, char* data);
+
+/* parse a file into a config node tree, return 0 in case of success, -1 otherwise */
+extern int aconfig_load_file(AConfig* root, const char* path);
+
+/* save a config node tree into a file, return 0 in case of success, -1 otherwise */
+extern int aconfig_save_file(AConfig* root, const char* path);
+
+/* create a single config node */
+extern AConfig* aconfig_node(const char *name, const char *value);
+
+/* locate a named child of a config node */
+extern AConfig* aconfig_find(AConfig *root, const char *name);
+
+/* add a named child to a config node (or modify it if it already exists) */
+extern void aconfig_set(AConfig *root, const char *name, const char *value);
+
+
+/* look up a child by name and return its value, eventually converted
+ * into a boolean or integer */
+extern int aconfig_bool (AConfig *root, const char *name, int _default);
+extern unsigned aconfig_unsigned(AConfig *root, const char *name, unsigned _default);
+extern int aconfig_int (AConfig *root, const char *name, int _default);
+extern const char* aconfig_str (AConfig *root, const char *name, const char *_default);
+
+#endif /* ANDROID_CONFIG_H */
diff --git a/android_console.c b/android_console.c
new file mode 100644
index 0000000..50af155
--- /dev/null
+++ b/android_console.c
@@ -0,0 +1,2134 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+/*
+ * Android emulator control console
+ *
+ * this console is enabled automatically at emulator startup, on port 5554 by default,
+ * unless some other emulator is already running. See (android_emulation_start in android_sdl.c
+ * for details)
+ *
+ * you can telnet to the console, then use commands like 'help' or others to dynamically
+ * change emulator settings.
+ *
+ */
+
+#include "sockets.h"
+#include "vl.h"
+#include "android.h"
+#include "sockets.h"
+#include "hw/goldfish_device.h"
+#include "hw/power_supply.h"
+#include "shaper.h"
+#include "modem_driver.h"
+#include "android_gps.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "android_events.h"
+#include "skin_keyboard.h"
+
+#if defined(CONFIG_SLIRP)
+#include "libslirp.h"
+#endif
+
+/* set to 1 to use the i/o and event functions
+ * defined in "telephony/sysdeps.h"
+ */
+#define USE_SYSDEPS 0
+
+#include "sysdeps.h"
+
+#define DEBUG 1
+
+#if 1
+# define D_ACTIVE VERBOSE_CHECK(console)
+#else
+# define D_ACTIVE DEBUG
+#endif
+
+#if DEBUG
+# define D(x) do { if (D_ACTIVE) ( printf x , fflush(stdout) ); } while (0)
+#else
+# define D(x) do{}while(0)
+#endif
+
+extern int slirp_inited; /* in vl.c */
+
+typedef struct ControlGlobalRec_* ControlGlobal;
+
+typedef struct ControlClientRec_* ControlClient;
+
+typedef struct {
+ int host_port;
+ int host_udp;
+ unsigned int guest_addr;
+ int guest_port;
+} RedirRec, *Redir;
+
+
+#if USE_SYSDEPS
+typedef SysChannel Socket;
+#else /* !USE_SYSDEPS */
+typedef int Socket;
+#endif /* !USE_SYSDEPS */
+
+
+typedef struct ControlClientRec_
+{
+ struct ControlClientRec_* next; /* next client in list */
+ Socket sock; /* socket used for communication */
+ ControlGlobal global;
+ char finished;
+ char buff[ 4096 ];
+ int buff_len;
+
+} ControlClientRec;
+
+
+typedef struct ControlGlobalRec_
+{
+ /* listening socket */
+ Socket listen_fd;
+
+ /* the list of current clients */
+ ControlClient clients;
+
+ /* the list of redirections currently active */
+ Redir redirs;
+ int num_redirs;
+ int max_redirs;
+
+} ControlGlobalRec;
+
+
+static int
+control_global_add_redir( ControlGlobal global,
+ int host_port,
+ int host_udp,
+ unsigned int guest_addr,
+ int guest_port )
+{
+ Redir redir;
+
+ if (global->num_redirs >= global->max_redirs)
+ {
+ int old_max = global->max_redirs;
+ int new_max = old_max + (old_max >> 1) + 4;
+
+ Redir new_redirs = realloc( global->redirs, new_max*sizeof(global->redirs[0]) );
+ if (new_redirs == NULL)
+ return -1;
+
+ global->redirs = new_redirs;
+ global->max_redirs = new_max;
+ }
+
+ redir = &global->redirs[ global->num_redirs++ ];
+
+ redir->host_port = host_port;
+ redir->host_udp = host_udp;
+ redir->guest_addr = guest_addr;
+ redir->guest_port = guest_port;
+
+ return 0;
+}
+
+static int
+control_global_del_redir( ControlGlobal global,
+ int host_port,
+ int host_udp )
+{
+ int nn;
+
+ for (nn = 0; nn < global->num_redirs; nn++)
+ {
+ Redir redir = &global->redirs[nn];
+
+ if ( redir->host_port == host_port &&
+ redir->host_udp == host_udp )
+ {
+ memmove( redir, redir + 1, ((global->num_redirs - nn)-1)*sizeof(*redir) );
+ global->num_redirs -= 1;
+ return 0;
+ }
+ }
+ /* we didn't find it */
+ return -1;
+}
+
+static void
+control_client_destroy( ControlClient client )
+{
+ ControlGlobal global = client->global;
+ ControlClient *pnode = &global->clients;
+
+ D(( "destroying control client %p\n", client ));
+
+#if USE_SYSDEPS
+ sys_channel_on( client->sock, 0, NULL, NULL );
+#else
+ qemu_set_fd_handler( client->sock, NULL, NULL, NULL );
+#endif
+
+ for ( ;; ) {
+ ControlClient node = *pnode;
+ if ( node == NULL )
+ break;
+ if ( node == client ) {
+ *pnode = node->next;
+ node->next = NULL;
+ break;
+ }
+ pnode = &node->next;
+ }
+
+#if USE_SYSDEPS
+ sys_channel_close( client->sock );
+ client->sock = NULL;
+#else
+ socket_close( client->sock );
+ client->sock = -1;
+#endif
+
+ free( client );
+}
+
+static void control_client_read( void* _client ); /* forward */
+
+
+static void control_control_write( ControlClient client, const char* buff, int len )
+{
+ int ret;
+
+ if (len < 0)
+ len = strlen(buff);
+
+ while (len > 0) {
+#if USE_SYSDEPS
+ ret = sys_channel_write( client->sock, buff, len );
+#else
+ ret = send( client->sock, buff, len, 0);
+#endif
+ if (ret < 0) {
+ if (socket_errno != EINTR && socket_errno != EWOULDBLOCK)
+ return;
+ } else {
+ buff += ret;
+ len -= ret;
+ }
+ }
+}
+
+static void control_write( ControlClient client, const char* format, ... )
+{
+ static char temp[1024];
+ va_list args;
+
+ va_start(args, format);
+ vsnprintf( temp, sizeof(temp), format, args );
+ va_end(args);
+
+ temp[ sizeof(temp)-1 ] = 0;
+
+ control_control_write( client, temp, -1 );
+}
+
+
+static ControlClient
+control_client_create( Socket socket,
+ ControlGlobal global )
+{
+ ControlClient client = calloc( sizeof(*client), 1 );
+
+ if (client) {
+#if !USE_SYSDEPS
+ socket_set_lowlatency( socket );
+ socket_set_nonblock( socket );
+#endif
+ client->finished = 0;
+ client->global = global;
+ client->sock = socket;
+ client->next = global->clients;
+ global->clients = client;
+
+#if USE_SYSDEPS
+ sys_channel_on( socket, SYS_EVENT_READ,
+ (SysChannelCallback) control_client_read,
+ client );
+#else
+ qemu_set_fd_handler( socket, control_client_read, NULL, client );
+#endif
+ }
+ return client;
+}
+
+typedef const struct CommandDefRec_ *CommandDef;
+
+typedef struct CommandDefRec_ {
+ const char* names;
+ const char* abstract;
+ const char* description;
+ void (*descriptor)( ControlClient client );
+ int (*handler)( ControlClient client, char* args );
+ CommandDef subcommands; /* if handler is NULL */
+
+} CommandDefRec;
+
+static const CommandDefRec main_commands[]; /* forward */
+
+static CommandDef
+find_command( char* input, CommandDef commands, char* *pend, char* *pargs )
+{
+ int nn;
+ char* args = strchr(input, ' ');
+
+ if (args != NULL) {
+ while (*args == ' ')
+ args++;
+
+ if (args[0] == 0)
+ args = NULL;
+ }
+
+ for (nn = 0; commands[nn].names != NULL; nn++)
+ {
+ const char* name = commands[nn].names;
+ const char* sep;
+
+ do {
+ int len, c;
+
+ sep = strchr( name, '|' );
+ if (sep)
+ len = sep - name;
+ else
+ len = strlen(name);
+
+ c = input[len];
+ if ( !memcmp( name, input, len ) && (c == ' ' || c == 0) ) {
+ *pend = input + len;
+ *pargs = args;
+ return &commands[nn];
+ }
+
+ if (sep)
+ name = sep + 1;
+
+ } while (sep != NULL && *name);
+ }
+ /* NOTE: don't touch *pend and *pargs if no command is found */
+ return NULL;
+}
+
+static void
+dump_help( ControlClient client,
+ CommandDef cmd,
+ const char* prefix )
+{
+ if (cmd->description) {
+ control_write( client, "%s", cmd->description );
+ } else if (cmd->descriptor) {
+ cmd->descriptor( client );
+ } else
+ control_write( client, "%s\r\n", cmd->abstract );
+
+ if (cmd->subcommands) {
+ cmd = cmd->subcommands;
+ control_write( client, "\r\navailable sub-commands:\r\n" );
+ for ( ; cmd->names != NULL; cmd++ ) {
+ control_write( client, " %s %-15s %s\r\n", prefix, cmd->names, cmd->abstract );
+ }
+ control_write( client, "\r\n" );
+ }
+}
+
+static void
+control_client_do_command( ControlClient client )
+{
+ char* line = client->buff;
+ char* args = NULL;
+ CommandDef commands = main_commands;
+ char* cmdend = client->buff;
+ CommandDef cmd = find_command( line, commands, &cmdend, &args );
+
+ if (cmd == NULL) {
+ control_write( client, "KO: unknown command, try 'help'\r\n" );
+ return;
+ }
+
+ for (;;) {
+ CommandDef subcmd;
+
+ if (cmd->handler) {
+ if ( !cmd->handler( client, args ) )
+ control_write( client, "OK\r\n" );
+ break;
+ }
+
+ /* no handler means we should have sub-commands */
+ if (cmd->subcommands == NULL) {
+ control_write( client, "KO: internal error: buggy command table for '%.*s'\r\n",
+ cmdend - client->buff, client->buff );
+ break;
+ }
+
+ /* we need a sub-command here */
+ if ( !args ) {
+ dump_help( client, cmd, "" );
+ control_write( client, "KO: missing sub-command\r\n" );
+ break;
+ }
+
+ line = args;
+ commands = cmd->subcommands;
+ subcmd = find_command( line, commands, &cmdend, &args );
+ if (subcmd == NULL) {
+ dump_help( client, cmd, "" );
+ control_write( client, "KO: bad sub-command\r\n" );
+ break;
+ }
+ cmd = subcmd;
+ }
+}
+
+/* implement the 'help' command */
+static int
+do_help( ControlClient client, char* args )
+{
+ char* line;
+ char* start = args;
+ char* end = start;
+ CommandDef cmd = main_commands;
+
+ /* without arguments, simply dump all commands */
+ if (args == NULL) {
+ control_write( client, "Android console command help:\r\n\r\n" );
+ for ( ; cmd->names != NULL; cmd++ ) {
+ control_write( client, " %-15s %s\r\n", cmd->names, cmd->abstract );
+ }
+ control_write( client, "\r\ntry 'help <command>' for command-specific help\r\n" );
+ return 0;
+ }
+
+ /* with an argument, find the corresponding command */
+ for (;;) {
+ CommandDef subcmd;
+
+ line = args;
+ subcmd = find_command( line, cmd, &end, &args );
+ if (subcmd == NULL) {
+ control_write( client, "try one of these instead:\r\n\r\n" );
+ for ( ; cmd->names != NULL; cmd++ ) {
+ control_write( client, " %.*s %s\r\n",
+ end - start, start, cmd->names );
+ }
+ control_write( client, "\r\nKO: unknown command\r\n" );
+ return -1;
+ }
+
+ if ( !args || !subcmd->subcommands ) {
+ dump_help( client, subcmd, start );
+ return 0;
+ }
+ cmd = subcmd->subcommands;
+ }
+}
+
+
+static void
+control_client_read_byte( ControlClient client, unsigned char ch )
+{
+ if (ch == '\r')
+ {
+ /* filter them out */
+ }
+ else if (ch == '\n')
+ {
+ client->buff[ client->buff_len ] = 0;
+ control_client_do_command( client );
+ if (client->finished)
+ return;
+
+ client->buff_len = 0;
+ }
+ else
+ {
+ if (client->buff_len >= sizeof(client->buff)-1)
+ client->buff_len = 0;
+
+ client->buff[ client->buff_len++ ] = ch;
+ }
+}
+
+static void
+control_client_read( void* _client )
+{
+ ControlClient client = _client;
+ unsigned char buf[4096];
+ int size;
+
+ D(( "in control_client read: " ));
+#if USE_SYSDEPS
+ size = sys_channel_read( client->sock, buf, sizeof(buf) );
+#else
+ size = recv( client->sock, buf, sizeof(buf), 0 );
+#endif
+ if (size < 0) {
+ D(( "size < 0, exiting with %d: %s\n", socket_errno, socket_errstr() ));
+ if (socket_errno != EWOULDBLOCK && socket_errno != EINTR)
+ control_client_destroy( client );
+ return;
+ }
+
+ if (size == 0) {
+ /* end of connection */
+ D(( "end of connection detected !!\n" ));
+ control_client_destroy( client );
+ }
+ else {
+ int nn;
+#ifdef _WIN32
+# if DEBUG
+ char temp[16];
+ int count = size > sizeof(temp)-1 ? sizeof(temp)-1 : size;
+ for (nn = 0; nn < count; nn++) {
+ int c = buf[nn];
+ if (c == '\n')
+ temp[nn] = '!';
+ else if (c < 32)
+ temp[nn] = '.';
+ else
+ temp[nn] = (char)c;
+ }
+ temp[nn] = 0;
+ D(( "received %d bytes: %s\n", size, temp ));
+# endif
+#else
+ D(( "received %.*s\n", size, buf ));
+#endif
+ for (nn = 0; nn < size; nn++) {
+ control_client_read_byte( client, buf[nn] );
+ if (client->finished) {
+ control_client_destroy(client);
+ return;
+ }
+ }
+ }
+}
+
+
+/* this function is called on each new client connection */
+static void
+control_global_accept( void* _global )
+{
+ ControlGlobal global = _global;
+ ControlClient client;
+ Socket fd;
+
+ D(( "control_global_accept: just in (fd=%p)\n", (void*)global->listen_fd ));
+
+#if USE_SYSDEPS
+ fd = sys_channel_create_tcp_handler( global->listen_fd );
+ if (fd == NULL) {
+ perror("accept");
+ return;
+ }
+#else
+ for(;;) {
+ struct sockaddr_in sockaddr;
+ socklen_t len = sizeof(sockaddr);
+
+ fd = accept( global->listen_fd, (struct sockaddr *)&sockaddr, &len);
+ if (fd < 0 && socket_errno != EINTR) {
+ D(( "problem in accept: %d: %s\n", socket_errno, socket_errstr() ));
+ perror("accept");
+ return;
+ } else if (fd >= 0) {
+ break;
+ }
+ D(( "relooping in accept()\n" ));
+ }
+
+ socket_set_xreuseaddr( fd );
+#endif
+
+ D(( "control_global_accept: creating new client\n" ));
+ client = control_client_create( fd, global );
+ if (client) {
+ D(( "control_global_accept: new client %p\n", client ));
+ control_write( client, "Android Console: type 'help' for a list of commands\r\n" );
+ control_write( client, "OK\r\n" );
+ }
+}
+
+
+static int
+control_global_init( ControlGlobal global,
+ int control_port )
+{
+ Socket fd;
+#if !USE_SYSDEPS
+ int ret;
+ struct sockaddr_in sockaddr;
+#endif
+
+ memset( global, 0, sizeof(*global) );
+
+ sys_main_init();
+
+#if USE_SYSDEPS
+ fd = sys_channel_create_tcp_server( control_port );
+ if (fd == NULL) {
+ return -1;
+ }
+
+ D(("global fd=%p\n", fd));
+
+ global->listen_fd = fd;
+ sys_channel_on( fd, SYS_EVENT_READ,
+ (SysChannelCallback) control_global_accept,
+ global );
+#else
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ socket_set_xreuseaddr( fd );
+
+ memset( &sockaddr, 0, sizeof(sockaddr) );
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_port = htons(control_port);
+ sockaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ ret = bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
+ if (ret < 0) {
+ perror("bind");
+ close( fd );
+ return -1;
+ }
+
+ ret = listen(fd, 0);
+ if (ret < 0) {
+ perror("listen");
+ close( fd );
+ return -1;
+ }
+
+ socket_set_nonblock(fd);
+
+ global->listen_fd = fd;
+
+ qemu_set_fd_handler( fd, control_global_accept, NULL, global );
+#endif
+ return 0;
+}
+
+
+
+static int
+do_quit( ControlClient client, char* args )
+{
+ client->finished = 1;
+ return -1;
+}
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** N E T W O R K S E T T I N G S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_network_status( ControlClient client, char* args )
+{
+ control_write( client, "Current network status:\r\n" );
+
+ control_write( client, " download speed: %8d bits/s (%.1f KB/s)\r\n",
+ (long)qemu_net_download_speed, qemu_net_download_speed/8192. );
+
+ control_write( client, " upload speed: %8d bits/s (%.1f KB/s)\r\n",
+ (long)qemu_net_upload_speed, qemu_net_upload_speed/8192. );
+
+ control_write( client, " minimum latency: %ld ms\r\n", qemu_net_min_latency );
+ control_write( client, " maximum latency: %ld ms\r\n", qemu_net_max_latency );
+ return 0;
+}
+
+static void
+dump_network_speeds( ControlClient client )
+{
+ const NetworkSpeed* speed = android_netspeeds;
+ const char* const format = " %-8s %s\r\n";
+ for ( ; speed->name; speed++ ) {
+ control_write( client, format, speed->name, speed->display );
+ }
+ control_write( client, format, "<num>", "selects both upload and download speed" );
+ control_write( client, format, "<up>:<down>", "select individual upload/download speeds" );
+}
+
+
+static int
+do_network_speed( ControlClient client, char* args )
+{
+ if ( !args ) {
+ control_write( client, "KO: missing <speed> argument, see 'help network speed'\r\n" );
+ return -1;
+ }
+ if ( android_parse_network_speed( args ) < 0 ) {
+ control_write( client, "KO: invalid <speed> argument, see 'help network speed' for valid values\r\n" );
+ return -1;
+ }
+
+ netshaper_set_rate( slirp_shaper_in, qemu_net_download_speed );
+ netshaper_set_rate( slirp_shaper_out, qemu_net_upload_speed );
+
+ if (android_modem) {
+ amodem_set_data_network_type( android_modem,
+ android_parse_network_type( args ) );
+ }
+ return 0;
+}
+
+static void
+describe_network_speed( ControlClient client )
+{
+ control_write( client,
+ "'network speed <speed>' allows you to dynamically change the speed of the emulated\r\n"
+ "network on the device, where <speed> is one of the following:\r\n\r\n" );
+ dump_network_speeds( client );
+}
+
+static int
+do_network_delay( ControlClient client, char* args )
+{
+ if ( !args ) {
+ control_write( client, "KO: missing <delay> argument, see 'help network delay'\r\n" );
+ return -1;
+ }
+ if ( android_parse_network_latency( args ) < 0 ) {
+ control_write( client, "KO: invalid <delay> argument, see 'help network delay' for valid values\r\n" );
+ return -1;
+ }
+ netdelay_set_latency( slirp_delay_in, qemu_net_min_latency, qemu_net_max_latency );
+ return 0;
+}
+
+static void
+describe_network_delay( ControlClient client )
+{
+ control_write( client,
+ "'network delay <latency>' allows you to dynamically change the latency of the emulated\r\n"
+ "network on the device, where <latency> is one of the following:\r\n\r\n" );
+ /* XXX: TODO */
+}
+
+static const CommandDefRec network_commands[] =
+{
+ { "status", "dump network status", NULL, NULL,
+ do_network_status, NULL },
+
+ { "speed", "change network speed", NULL, describe_network_speed,
+ do_network_speed, NULL },
+
+ { "delay", "change network latency", NULL, describe_network_delay,
+ do_network_delay, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** P O R T R E D I R E C T I O N S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_redir_list( ControlClient client, char* args )
+{
+ ControlGlobal global = client->global;
+
+ if (global->num_redirs == 0)
+ control_write( client, "no active redirections\r\n" );
+ else {
+ int nn;
+ for (nn = 0; nn < global->num_redirs; nn++) {
+ Redir redir = &global->redirs[nn];
+ control_write( client, "%s:%-5d => %-5d\r\n",
+ redir->host_udp ? "udp" : "tcp",
+ redir->host_port,
+ redir->guest_port );
+ }
+ }
+ return 0;
+}
+
+/* parse a protocol:port specification */
+static int
+redir_parse_proto_port( char* args, int *pport, int *pproto )
+{
+ int proto = -1;
+ int len = 0;
+ char* end;
+
+ if ( !memcmp( args, "tcp:", 4 ) ) {
+ proto = 0;
+ len = 4;
+ }
+ else if ( !memcmp( args, "udp:", 4 ) ) {
+ proto = 1;
+ len = 4;
+ }
+ else
+ return 0;
+
+ args += len;
+ *pproto = proto;
+ *pport = strtol( args, &end, 10 );
+ if (end == args)
+ return 0;
+
+ len += end - args;
+ return len;
+}
+
+static int
+redir_parse_guest_port( char* arg, int *pport )
+{
+ char* end;
+
+ *pport = strtoul( arg, &end, 10 );
+ if (end == arg)
+ return 0;
+
+ return end - arg;
+}
+
+static Redir
+redir_find( ControlGlobal global, int port, int isudp )
+{
+ int nn;
+
+ for (nn = 0; nn < global->num_redirs; nn++) {
+ Redir redir = &global->redirs[nn];
+
+ if (redir->host_port == port && redir->host_udp == isudp)
+ return redir;
+ }
+ return NULL;
+}
+
+
+static int
+do_redir_add( ControlClient client, char* args )
+{
+ int len, host_proto, host_port, guest_port;
+ struct in_addr guest_addr;
+ Redir redir;
+
+ if ( !args )
+ goto BadFormat;
+
+ if (!slirp_inited) {
+ slirp_inited = 1;
+ slirp_init();
+ }
+
+ len = redir_parse_proto_port( args, &host_port, &host_proto );
+ if (len == 0 || args[len] != ':')
+ goto BadFormat;
+
+ args += len + 1;
+ len = redir_parse_guest_port( args, &guest_port );
+ if (len == 0 || args[len] != 0)
+ goto BadFormat;
+
+ redir = redir_find( client->global, host_port, host_proto );
+ if ( redir != NULL ) {
+ control_write( client, "KO: host port already active, use 'redir del' to remove first\r\n" );
+ return -1;
+ }
+
+ if (!inet_aton("10.0.2.15", &guest_addr)) {
+ control_write( client, "KO: unexpected internal failure when resolving 10.0.2.15\r\n" );
+ return -1;
+ }
+
+ D(("pattern hport=%d gport=%d proto=%d\n", host_port, guest_port, host_proto ));
+ if ( control_global_add_redir( client->global, host_port, host_proto,
+ guest_addr.s_addr, guest_port ) < 0 )
+ {
+ control_write( client, "KO: not enough memory to allocate redirection\r\n" );
+ return -1;
+ }
+
+ if (slirp_redir(host_proto, host_port, guest_addr, guest_port) < 0) {
+ control_write( client, "KO: can't setup redirection, port probably used by another program on host\r\n" );
+ control_global_del_redir( client->global, host_port, host_proto );
+ return -1;
+ }
+
+ return 0;
+
+BadFormat:
+ control_write( client, "KO: bad redirection format, try (tcp|udp):hostport:guestport\r\n", -1 );
+ return -1;
+}
+
+
+static int
+do_redir_del( ControlClient client, char* args )
+{
+ int len, proto, port;
+ Redir redir;
+
+ if ( !args )
+ goto BadFormat;
+ len = redir_parse_proto_port( args, &port, &proto );
+ if ( len == 0 || args[len] != 0 )
+ goto BadFormat;
+
+ redir = redir_find( client->global, port, proto );
+ if (redir == NULL) {
+ control_write( client, "KO: can't remove unknown redirection (%s:%d)\r\n",
+ proto ? "udp" : "tcp", port );
+ return -1;
+ }
+
+ slirp_unredir( redir->host_udp, redir->host_port );
+ control_global_del_redir( client->global, port, proto );\
+
+ return 0;
+
+BadFormat:
+ control_write( client, "KO: bad redirection format, try (tcp|udp):hostport\r\n" );
+ return -1;
+}
+
+static const CommandDefRec redir_commands[] =
+{
+ { "list", "list current redirections",
+ "list current port redirections. use 'redir add' and 'redir del' to add and remove them\r\n", NULL,
+ do_redir_list, NULL },
+
+ { "add", "add new redirection",
+ "add a new port redirection, arguments must be:\r\n\r\n"
+ " redir add <protocol>:<host-port>:<guest-port>\r\n\r\n"
+ "where: <protocol> is either 'tcp' or 'udp'\r\n"
+ " <host-port> a number indicating which port on the host to open\r\n"
+ " <guest-port> a number indicating which port to route to on the device\r\n"
+ "\r\nas an example, 'redir tcp:5000:6000' will allow any packets sent to\r\n"
+ "the host's TCP port 5000 to be routed to TCP port 6000 of the emulated device\r\n", NULL,
+ do_redir_add, NULL },
+
+ { "del", "remove existing redirection",
+ "remove a port redirecion that was created with 'redir add', arguments must be:\r\n\r\n"
+ " redir del <protocol>:<host-port>\r\n\r\n"
+ "see the 'help redir add' for the meaning of <protocol> and <host-port>\r\n", NULL,
+ do_redir_del, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** G S M M O D E M ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static const struct {
+ const char* name;
+ const char* display;
+ ARegistrationState state;
+} _gsm_states[] = {
+ { "unregistered", "no network available", A_REGISTRATION_UNREGISTERED },
+ { "home", "on local network, non-roaming", A_REGISTRATION_HOME },
+ { "roaming", "on roaming network", A_REGISTRATION_ROAMING },
+ { "searching", "searching networks", A_REGISTRATION_SEARCHING },
+ { "denied", "emergency calls only", A_REGISTRATION_DENIED },
+ { "off", "same as 'unregistered'", A_REGISTRATION_UNREGISTERED },
+ { "on", "same as 'home'", A_REGISTRATION_HOME },
+ { NULL, NULL, A_REGISTRATION_UNREGISTERED }
+};
+
+static const char*
+gsm_state_to_string( ARegistrationState state )
+{
+ int nn;
+ for (nn = 0; _gsm_states[nn].name != NULL; nn++) {
+ if (state == _gsm_states[nn].state)
+ return _gsm_states[nn].name;
+ }
+ return "<unknown>";
+}
+
+static int
+do_gsm_status( ControlClient client, char* args )
+{
+ if (args) {
+ control_write( client, "KO: no argument required\r\n" );
+ return -1;
+ }
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+ control_write( client, "gsm voice state: %s\r\n",
+ gsm_state_to_string(
+ amodem_get_voice_registration(android_modem) ) );
+ control_write( client, "gsm data state: %s\r\n",
+ gsm_state_to_string(
+ amodem_get_data_registration(android_modem) ) );
+ return 0;
+}
+
+
+static void
+help_gsm_data( ControlClient client )
+{
+ int nn;
+ control_write( client,
+ "the 'gsm data <state>' allows you to change the state of your GPRS connection\r\n"
+ "valid values for <state> are the following:\r\n\r\n" );
+ for (nn = 0; ; nn++) {
+ const char* name = _gsm_states[nn].name;
+ const char* display = _gsm_states[nn].display;
+
+ if (!name)
+ break;
+
+ control_write( client, " %-15s %s\r\n", name, display );
+ }
+ control_write( client, "\r\n" );
+}
+
+
+static int
+do_gsm_data( ControlClient client, char* args )
+{
+ int nn;
+
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm data <state>'\r\n" );
+ return -1;
+ }
+
+ for (nn = 0; ; nn++) {
+ const char* name = _gsm_states[nn].name;
+ ARegistrationState state = _gsm_states[nn].state;
+
+ if (!name)
+ break;
+
+ if ( !strcmp( args, name ) ) {
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+ amodem_set_data_registration( android_modem, state );
+ qemu_net_disable = (state != A_REGISTRATION_HOME &&
+ state != A_REGISTRATION_ROAMING );
+ return 0;
+ }
+ }
+ control_write( client, "KO: bad GSM data state name, try 'help gsm data' for list of valid values\r\n" );
+ return -1;
+}
+
+static void
+help_gsm_voice( ControlClient client )
+{
+ int nn;
+ control_write( client,
+ "the 'gsm voice <state>' allows you to change the state of your GPRS connection\r\n"
+ "valid values for <state> are the following:\r\n\r\n" );
+ for (nn = 0; ; nn++) {
+ const char* name = _gsm_states[nn].name;
+ const char* display = _gsm_states[nn].display;
+
+ if (!name)
+ break;
+
+ control_write( client, " %-15s %s\r\n", name, display );
+ }
+ control_write( client, "\r\n" );
+}
+
+
+static int
+do_gsm_voice( ControlClient client, char* args )
+{
+ int nn;
+
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm voice <state>'\r\n" );
+ return -1;
+ }
+
+ for (nn = 0; ; nn++) {
+ const char* name = _gsm_states[nn].name;
+ ARegistrationState state = _gsm_states[nn].state;
+
+ if (!name)
+ break;
+
+ if ( !strcmp( args, name ) ) {
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+ amodem_set_voice_registration( android_modem, state );
+ return 0;
+ }
+ }
+ control_write( client, "KO: bad GSM data state name, try 'help gsm voice' for list of valid values\r\n" );
+ return -1;
+}
+
+
+static int
+gsm_check_number( char* args )
+{
+ int nn;
+
+ for (nn = 0; args[nn] != 0; nn++) {
+ int c = args[nn];
+ if ( !isdigit(c) && c != '+' && c != '#' ) {
+ return -1;
+ }
+ }
+ if (nn == 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+do_gsm_call( ControlClient client, char* args )
+{
+ /* check that we have a phone number made of digits */
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm call <phonenumber>'\r\n" );
+ return -1;
+ }
+
+ if (gsm_check_number(args)) {
+ control_write( client, "KO: bad phone number format, use digits, # and + only\r\n" );
+ return -1;
+ }
+
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+ amodem_add_inbound_call( android_modem, args );
+ return 0;
+}
+
+static int
+do_gsm_cancel( ControlClient client, char* args )
+{
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm call <phonenumber>'\r\n" );
+ return -1;
+ }
+ if (gsm_check_number(args)) {
+ control_write( client, "KO: bad phone number format, use digits, # and + only\r\n" );
+ return -1;
+ }
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+ if ( amodem_disconnect_call( android_modem, args ) < 0 ) {
+ control_write( client, "KO: could not cancel this number\r\n" );
+ return -1;
+ }
+ return 0;
+}
+
+
+static const char*
+call_state_to_string( ACallState state )
+{
+ switch (state) {
+ case A_CALL_ACTIVE: return "active";
+ case A_CALL_HELD: return "held";
+ case A_CALL_ALERTING: return "ringing";
+ case A_CALL_WAITING: return "waiting";
+ case A_CALL_INCOMING: return "incoming";
+ default: return "unknown";
+ }
+}
+
+static int
+do_gsm_list( ControlClient client, char* args )
+{
+ /* check that we have a phone number made of digits */
+ int count = amodem_get_call_count( android_modem );
+ int nn;
+ for (nn = 0; nn < count; nn++) {
+ ACall call = amodem_get_call( android_modem, nn );
+ const char* dir;
+
+ if (call == NULL)
+ continue;
+
+ if (call->dir == A_CALL_OUTBOUND)
+ dir = "outbound to ";
+ else
+ dir = "inbound from";
+
+ control_write( client, "%s %-10s : %s\r\n", dir,
+ call->number, call_state_to_string(call->state) );
+ }
+ return 0;
+}
+
+static int
+do_gsm_busy( ControlClient client, char* args )
+{
+ ACall call;
+
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm busy <phonenumber>'\r\n" );
+ return -1;
+ }
+ call = amodem_find_call_by_number( android_modem, args );
+ if (call == NULL || call->dir != A_CALL_OUTBOUND) {
+ control_write( client, "KO: no current outbound call to number '%s' (call %p)\r\n", args, call );
+ return -1;
+ }
+ if ( amodem_disconnect_call( android_modem, args ) < 0 ) {
+ control_write( client, "KO: could not cancel this number\r\n" );
+ return -1;
+ }
+ return 0;
+}
+
+static int
+do_gsm_hold( ControlClient client, char* args )
+{
+ ACall call;
+
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm out hold <phonenumber>'\r\n" );
+ return -1;
+ }
+ call = amodem_find_call_by_number( android_modem, args );
+ if (call == NULL) {
+ control_write( client, "KO: no current call to/from number '%s'\r\n", args );
+ return -1;
+ }
+ if ( amodem_update_call( android_modem, args, A_CALL_HELD ) < 0 ) {
+ control_write( client, "KO: could put this call on hold\r\n" );
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+do_gsm_accept( ControlClient client, char* args )
+{
+ ACall call;
+
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'gsm accept <phonenumber>'\r\n" );
+ return -1;
+ }
+ call = amodem_find_call_by_number( android_modem, args );
+ if (call == NULL) {
+ control_write( client, "KO: no current call to/from number '%s'\r\n", args );
+ return -1;
+ }
+ if ( amodem_update_call( android_modem, args, A_CALL_ACTIVE ) < 0 ) {
+ control_write( client, "KO: could not activate this call\r\n" );
+ return -1;
+ }
+ return 0;
+}
+
+
+#if 0
+static const CommandDefRec gsm_in_commands[] =
+{
+ { "new", "create a new 'waiting' inbound call",
+ "'gsm in create <phonenumber>' creates a new inbound phone call, placed in\r\n"
+ "the 'waiting' state by default, until the system answers/holds/closes it\r\n", NULL
+ do_gsm_in_create, NULL },
+
+ { "hold", "change the state of an oubtound call to 'held'",
+ "change the state of an outbound call to 'held'. this is only possible\r\n"
+ "if the call in the 'waiting' or 'active' state\r\n", NULL,
+ do_gsm_out_hold, NULL },
+
+ { "accept", "change the state of an outbound call to 'active'",
+ "change the state of an outbound call to 'active'. this is only possible\r\n"
+ "if the call is in the 'waiting' or 'held' state\r\n", NULL,
+ do_gsm_out_accept, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+#endif
+
+
+static const CommandDefRec gsm_commands[] =
+{
+ { "list", "list current phone calls",
+ "'gsm list' lists all inbound and outbound calls and their state\r\n", NULL,
+ do_gsm_list, NULL },
+
+ { "call", "create inbound phone call",
+ "'gsm call <phonenumber>' allows you to simulate a new inbound call\r\n", NULL,
+ do_gsm_call, NULL },
+
+ { "busy", "close waiting outbound call as busy",
+ "'gsm busy <remoteNumber>' closes an outbound call, reporting\r\n"
+ "the remote phone as busy. only possible if the call is 'waiting'.\r\n", NULL,
+ do_gsm_busy, NULL },
+
+ { "hold", "change the state of an oubtound call to 'held'",
+ "'gsm hold <remoteNumber>' change the state of a call to 'held'. this is only possible\r\n"
+ "if the call in the 'waiting' or 'active' state\r\n", NULL,
+ do_gsm_hold, NULL },
+
+ { "accept", "change the state of an outbound call to 'active'",
+ "'gsm accept <remoteNumber>' change the state of a call to 'active'. this is only possible\r\n"
+ "if the call is in the 'waiting' or 'held' state\r\n", NULL,
+ do_gsm_accept, NULL },
+
+ { "cancel", "disconnect an inbound or outbound phone call",
+ "'gsm cancel <phonenumber>' allows you to simulate the end of an inbound or outbound call\r\n", NULL,
+ do_gsm_cancel, NULL },
+
+ { "data", "modify data connection state", NULL, help_gsm_data,
+ do_gsm_data, NULL },
+
+ { "voice", "modify voice connection state", NULL, help_gsm_voice,
+ do_gsm_voice, NULL },
+
+ { "status", "display GSM status",
+ "'gsm status' displays the current state of the GSM emulation\r\n", NULL,
+ do_gsm_status, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** S M S C O M M A N D ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_sms_send( ControlClient client, char* args )
+{
+ char* p;
+ int textlen;
+ SmsAddressRec sender;
+ SmsPDU* pdus;
+ int nn;
+
+ /* check that we have a phone number made of digits */
+ if (!args) {
+ MissingArgument:
+ control_write( client, "KO: missing argument, try 'sms send <phonenumber> <text message>'\r\n" );
+ return -1;
+ }
+ p = strchr( args, ' ' );
+ if (!p) {
+ goto MissingArgument;
+ }
+
+ if ( sms_address_from_str( &sender, args, p - args ) < 0 ) {
+ control_write( client, "KO: bad phone number format, must be [+](0-9)*\r\n" );
+ return -1;
+ }
+
+
+ /* un-secape message text into proper utf-8 (conversion happens in-site) */
+ p += 1;
+ textlen = strlen(p);
+ textlen = sms_utf8_from_message_str( p, textlen, (unsigned char*)p, textlen );
+ if (textlen < 0) {
+ control_write( client, "message must be utf8 and can use the following escapes:\r\n"
+ " \\n for a newline\r\n"
+ " \\xNN where NN are two hexadecimal numbers\r\n"
+ " \\uNNNN where NNNN are four hexadecimal numbers\r\n"
+ " \\\\ to send a '\\' character\r\n\r\n"
+ " anything else is an error\r\n"
+ "KO: badly formatted text\r\n" );
+ return -1;
+ }
+
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+
+ /* create a list of SMS PDUs, then send them */
+ pdus = smspdu_create_deliver_utf8( (cbytes_t)p, textlen, &sender, NULL );
+ if (pdus == NULL) {
+ control_write( client, "KO: internal error when creating SMS-DELIVER PDUs\n" );
+ return -1;
+ }
+
+ for (nn = 0; pdus[nn] != NULL; nn++)
+ amodem_receive_sms( android_modem, pdus[nn] );
+
+ smspdu_free_list( pdus );
+ return 0;
+}
+
+static int
+do_sms_sendpdu( ControlClient client, char* args )
+{
+ SmsPDU pdu;
+
+ /* check that we have a phone number made of digits */
+ if (!args) {
+ control_write( client, "KO: missing argument, try 'sms sendpdu <hexstring>'\r\n" );
+ return -1;
+ }
+
+ if (!android_modem) {
+ control_write( client, "KO: modem emulation not running\r\n" );
+ return -1;
+ }
+
+ pdu = smspdu_create_from_hex( args, strlen(args) );
+ if (pdu == NULL) {
+ control_write( client, "KO: badly formatted <hexstring>\r\n" );
+ return -1;
+ }
+
+ amodem_receive_sms( android_modem, pdu );
+ smspdu_free( pdu );
+ return 0;
+}
+
+static const CommandDefRec sms_commands[] =
+{
+ { "send", "send inbound SMS text message",
+ "'sms send <phonenumber> <message>' allows you to simulate a new inbound sms message\r\n", NULL,
+ do_sms_send, NULL },
+
+ { "pdu", "send inbound SMS PDU",
+ "'sms pdu <hexstring>' allows you to simulate a new inbound sms PDU\r\n"
+ "(used internally when one emulator sends SMS messages to another instance).\r\n"
+ "you probably don't want to play with this at all\r\n", NULL,
+ do_sms_sendpdu, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+static void
+do_control_write(void* data, const char* string)
+{
+ control_write((ControlClient)data, string);
+}
+
+static int
+do_power_display( ControlClient client, char* args )
+{
+ goldfish_battery_display(do_control_write, client);
+ return 0;
+}
+
+static int
+do_ac_state( ControlClient client, char* args )
+{
+ if (args) {
+ if (strcasecmp(args, "on") == 0) {
+ goldfish_battery_set_prop(1, POWER_SUPPLY_PROP_ONLINE, 1);
+ return 0;
+ }
+ if (strcasecmp(args, "off") == 0) {
+ goldfish_battery_set_prop(1, POWER_SUPPLY_PROP_ONLINE, 0);
+ return 0;
+ }
+ }
+
+ control_write( client, "KO: Usage: \"ac on\" or \"ac off\"\n" );
+ return -1;
+}
+
+static int
+do_battery_status( ControlClient client, char* args )
+{
+ if (args) {
+ if (strcasecmp(args, "unknown") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_UNKNOWN);
+ return 0;
+ }
+ if (strcasecmp(args, "charging") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_CHARGING);
+ return 0;
+ }
+ if (strcasecmp(args, "discharging") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_DISCHARGING);
+ return 0;
+ }
+ if (strcasecmp(args, "not-charging") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_NOT_CHARGING);
+ return 0;
+ }
+ if (strcasecmp(args, "full") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_STATUS_FULL);
+ return 0;
+ }
+ }
+
+ control_write( client, "KO: Usage: \"status unknown|charging|discharging|not-charging|full\"\n" );
+ return -1;
+}
+
+static int
+do_battery_present( ControlClient client, char* args )
+{
+ if (args) {
+ if (strcasecmp(args, "true") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_PRESENT, 1);
+ return 0;
+ }
+ if (strcasecmp(args, "false") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_PRESENT, 0);
+ return 0;
+ }
+ }
+
+ control_write( client, "KO: Usage: \"present true\" or \"present false\"\n" );
+ return -1;
+}
+
+static int
+do_battery_health( ControlClient client, char* args )
+{
+ if (args) {
+ if (strcasecmp(args, "unknown") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_UNKNOWN);
+ return 0;
+ }
+ if (strcasecmp(args, "good") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_GOOD);
+ return 0;
+ }
+ if (strcasecmp(args, "overheat") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_OVERHEAT);
+ return 0;
+ }
+ if (strcasecmp(args, "dead") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_DEAD);
+ return 0;
+ }
+ if (strcasecmp(args, "overvoltage") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_OVERVOLTAGE);
+ return 0;
+ }
+ if (strcasecmp(args, "failure") == 0) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_HEALTH_UNSPEC_FAILURE);
+ return 0;
+ }
+ }
+
+ control_write( client, "KO: Usage: \"health unknown|good|overheat|dead|overvoltage|failure\"\n" );
+ return -1;
+}
+
+static int
+do_battery_capacity( ControlClient client, char* args )
+{
+ if (args) {
+ int capacity;
+
+ if (sscanf(args, "%d", &capacity) == 1 && capacity >= 0 && capacity <= 100) {
+ goldfish_battery_set_prop(0, POWER_SUPPLY_PROP_CAPACITY, capacity);
+ return 0;
+ }
+ }
+
+ control_write( client, "KO: Usage: \"capacity <percentage>\"\n" );
+ return -1;
+}
+
+
+static const CommandDefRec power_commands[] =
+{
+ { "display", "display battery and charger state",
+ "display battery and charger state\r\n", NULL,
+ do_power_display, NULL },
+
+ { "ac", "set AC charging state",
+ "'ac on|off' allows you to set the AC charging state to on or off\r\n", NULL,
+ do_ac_state, NULL },
+
+ { "status", "set battery status",
+ "'status unknown|charging|discharging|not-charging|full' allows you to set battery status\r\n", NULL,
+ do_battery_status, NULL },
+
+ { "present", "set battery present state",
+ "'present true|false' allows you to set battery present state to true or false\r\n", NULL,
+ do_battery_present, NULL },
+
+ { "health", "set battery health state",
+ "'health unknown|good|overheat|dead|overvoltage|failure' allows you to set battery health state\r\n", NULL,
+ do_battery_health, NULL },
+
+ { "capacity", "set battery capacity state",
+ "'capacity <percentage>' allows you to set battery capacity to a value 0 - 100\r\n", NULL,
+ do_battery_capacity, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** E V E N T C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+
+static int
+do_event_send( ControlClient client, char* args )
+{
+ char* p;
+
+ if (!args) {
+ control_write( client, "KO: Usage: event send <type>:<code>:<value> ...\r\n" );
+ return -1;
+ }
+
+ p = args;
+ while (*p) {
+ char* q;
+ int type, code, value, ret;
+
+ p += strspn( args, " \t" ); /* skip spaces */
+ if (*p == 0)
+ break;
+
+ q = p + strcspn( p, " \t" );
+
+ if (q == p)
+ break;
+
+ ret = android_event_from_str( p, &type, &code, &value );
+ if (ret < 0) {
+ if (ret == -1) {
+ control_write( client,
+ "KO: invalid event type in '%.*s', try 'event list types' for valid values\r\n",
+ q-p, p );
+ } else if (ret == -2) {
+ control_write( client,
+ "KO: invalid event code in '%.*s', try 'event list codes <type>' for valid values\r\n",
+ q-p, p );
+ } else {
+ control_write( client,
+ "KO: invalid event value in '%.*s', must be an integer\r\n",
+ q-p, p);
+ }
+ return -1;
+ }
+
+ kbd_generic_event( type, code, value );
+ p = q;
+ }
+ return 0;
+}
+
+static int
+do_event_types( ControlClient client, char* args )
+{
+ int count = android_event_get_type_count();
+ int nn;
+
+ control_write( client, "event <type> can be an integer or one of the following aliases\r\n" );
+ for (nn = 0; nn < count; nn++) {
+ char tmp[16];
+ char* p = tmp;
+ char* end = p + sizeof(tmp);
+ int count2 = android_event_get_code_count( nn );;
+
+ p = android_event_bufprint_type_str( p, end, nn );
+
+ control_write( client, " %-8s", tmp );
+ if (count2 > 0)
+ control_write( client, " (%d code aliases)", count2 );
+
+ control_write( client, "\r\n" );
+ }
+ return 0;
+}
+
+static int
+do_event_codes( ControlClient client, char* args )
+{
+ int count;
+ int nn, type, dummy;
+
+ if (!args) {
+ control_write( client, "KO: argument missing, try 'event codes <type>'\r\n" );
+ return -1;
+ }
+
+ if ( android_event_from_str( args, &type, &dummy, &dummy ) < 0 ) {
+ control_write( client, "KO: bad argument, see 'event types' for valid values\r\n" );
+ return -1;
+ }
+
+ count = android_event_get_code_count( type );
+ if (count == 0) {
+ control_write( client, "no code aliases defined for this type\r\n" );
+ } else {
+ control_write( client, "type '%s' accepts the following <code> aliases:\r\n",
+ args );
+ for (nn = 0; nn < count; nn++) {
+ char temp[20], *p = temp, *end = p + sizeof(temp);
+ android_event_bufprint_code_str( p, end, type, nn );
+ control_write( client, " %-12s\r\n", temp );
+ }
+ }
+
+ return 0;
+}
+
+static __inline__ int
+utf8_next( unsigned char* *pp, unsigned char* end )
+{
+ unsigned char* p = *pp;
+ int result = -1;
+
+ if (p < end) {
+ int c= *p++;
+ if (c >= 128) {
+ if ((c & 0xe0) == 0xc0)
+ c &= 0x1f;
+ else if ((c & 0xf0) == 0xe0)
+ c &= 0x0f;
+ else
+ c &= 0x07;
+
+ while (p < end && (p[0] & 0xc0) == 0x80) {
+ c = (c << 6) | (p[0] & 0x3f);
+ }
+ }
+ result = c;
+ *pp = p;
+ }
+ return result;
+}
+
+static int
+do_event_text( ControlClient client, char* args )
+{
+ SkinKeyboard* keyboard;
+ unsigned char* p = (unsigned char*) args;
+ unsigned char* end = p + strlen(args);
+ int textlen;
+
+ if (!args) {
+ control_write( client, "KO: argument missing, try 'event text <message>'\r\n" );
+ return -1;
+ }
+ keyboard = android_emulator_get_keyboard();
+ if (keyboard == NULL) {
+ control_write( client, "KO: no keyboard active in current device layout/config\r\n" );
+ return -1;
+ }
+
+ /* un-secape message text into proper utf-8 (conversion happens in-site) */
+ textlen = strlen((char*)p);
+ textlen = sms_utf8_from_message_str( args, textlen, (unsigned char*)p, textlen );
+ if (textlen < 0) {
+ control_write( client, "message must be utf8 and can use the following escapes:\r\n"
+ " \\n for a newline\r\n"
+ " \\xNN where NN are two hexadecimal numbers\r\n"
+ " \\uNNNN where NNNN are four hexadecimal numbers\r\n"
+ " \\\\ to send a '\\' character\r\n\r\n"
+ " anything else is an error\r\n"
+ "KO: badly formatted text\r\n" );
+ return -1;
+ }
+
+ end = p + textlen;
+ while (p < end) {
+ int c = utf8_next( &p, end );
+ if (c <= 0)
+ break;
+
+ skin_keyboard_process_unicode_event( keyboard, (unsigned)c, 1 );
+ skin_keyboard_process_unicode_event( keyboard, (unsigned)c, 0 );
+ skin_keyboard_flush( keyboard );
+ }
+
+ return 0;
+}
+
+static const CommandDefRec event_commands[] =
+{
+ { "send", "send a series of events to the kernel",
+ "'event send <type>:<code>:<value> ...' allows your to send one or more hardware events\r\n"
+ "to the Android kernel. you can use text names or integers for <type> and <code>\r\n", NULL,
+ do_event_send, NULL },
+
+ { "types", "list all <type> aliases",
+ "'event types' list all <type> string aliases supported by the 'event' subcommands\r\n",
+ NULL, do_event_types, NULL },
+
+ { "codes", "list all <code> aliases for a given <type>",
+ "'event codes <type>' lists all <code> string aliases for a given event <type>\r\n",
+ NULL, do_event_codes, NULL },
+
+ { "text", "simulate keystrokes from a given text",
+ "'event text <message>' allows you to simulate keypresses to generate a given text\r\n"
+ "message. <message> must be an utf-8 string. Unicode points will be reverse-mapped\r\n"
+ "according to the current device keyboard. unsupported characters will be discarded\r\n"
+ "silently\r\n", NULL, do_event_text, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** V M C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_vm_stop( ControlClient client, char* args )
+{
+ if (!vm_running) {
+ control_write( client, "KO: virtual machine already stopped\r\n" );
+ return -1;
+ }
+ vm_stop(EXCP_INTERRUPT);
+ return 0;
+}
+
+static int
+do_vm_start( ControlClient client, char* args )
+{
+ if (vm_running) {
+ control_write( client, "KO: virtual machine already running\r\n" );
+ return -1;
+ }
+ vm_start();
+ return 0;
+}
+
+static int
+do_vm_status( ControlClient client, char* args )
+{
+ control_write( client, "virtual machine is %s\r\n", vm_running ? "running" : "stopped" );
+ return 0;
+}
+
+static const CommandDefRec vm_commands[] =
+{
+ { "stop", "stop the virtual machine",
+ "'vm stop' stops the virtual machine immediately, use 'vm start' to continue execution\r\n",
+ NULL, do_vm_stop, NULL },
+
+ { "start", "start/restart the virtual machine",
+ "'vm start' will start or continue the virtual machine, use 'vm stop' to stop it\r\n",
+ NULL, do_vm_start, NULL },
+
+ { "status", "query virtual machine status",
+ "'vm status' will indicate wether the virtual machine is running or not\r\n",
+ NULL, do_vm_status, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** G E O C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_geo_nmea( ControlClient client, char* args )
+{
+ if (!args) {
+ control_write( client, "KO: NMEA sentence missing, try 'help geo nmea'\r\n" );
+ return -1;
+ }
+ if (!android_gps_cs) {
+ control_write( client, "KO: no GPS emulation in this virtual device\r\n" );
+ return -1;
+ }
+ android_gps_send_nmea( args );
+ return 0;
+}
+
+static int
+do_geo_fix( ControlClient client, char* args )
+{
+#define MAX_GEO_PARAMS 3
+ char* p = args;
+ int n_params = 0;
+ double params[ MAX_GEO_PARAMS ];
+
+ static int last_time = 0;
+ static double last_altitude = 0.;
+
+ if (!p)
+ p = "";
+
+ /* tokenize */
+ while (*p) {
+ char* end;
+ double val = strtod( p, &end );
+
+ if (end == p) {
+ control_write( client, "KO: argument '%s' is not a number\n", p );
+ return -1;
+ }
+
+ params[n_params++] = val;
+ if (n_params >= MAX_GEO_PARAMS)
+ break;
+
+ p = end;
+ while (*p && (p[0] == ' ' || p[0] == '\t'))
+ p += 1;
+ }
+
+ /* sanity check */
+ if (n_params < 2) {
+ control_write( client, "KO: not enough arguments: see 'help geo fix' for details\r\n" );
+ return -1;
+ }
+
+ /* generate an NMEA sentence for this fix */
+ {
+ STRALLOC_DEFINE(s);
+ double val;
+ int deg, min;
+ char hemi;
+
+ /* first, the time */
+ stralloc_add_format( s, "$GPGGA,%06d", last_time );
+ last_time ++;
+
+ /* then the latitude */
+ hemi = 'N';
+ val = params[1];
+ if (val < 0) {
+ hemi = 'S';
+ val = -val;
+ }
+ deg = (int) val;
+ min = 60*(val - deg);
+ val = val - min/60.;
+ stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)(val * 10000), hemi );
+
+ /* the longitude */
+ hemi = 'E';
+ val = params[0];
+ if (val < 0) {
+ hemi = 'W';
+ val = -val;
+ }
+ deg = (int) val;
+ min = 60*(val - deg);
+ val = val - min/60.;
+ stralloc_add_format( s, ",%02d%02d.%04d,%c", deg, min, (int)(val * 10000), hemi );
+
+ /* bogus fix quality, empty satellite count and dilutions */
+ stralloc_add_str( s, ",1,,,," );
+
+ /* optional altitude */
+ if (n_params >= 3) {
+ stralloc_add_format( s, "%.1g", params[2] );
+ last_altitude = params[2];
+ } else {
+ stralloc_add_str( s, "," );
+ }
+ /* bogus rest and checksum */
+ stralloc_add_str( s, ",,,*47" );
+
+ /* send it, then free */
+ android_gps_send_nmea( stralloc_cstr(s) );
+ stralloc_reset( s );
+ }
+ return 0;
+}
+
+static const CommandDefRec geo_commands[] =
+{
+ { "nmea", "send an GPS NMEA sentence",
+ "'geo nema <sentence>' sends a NMEA 0183 sentence to the emulated machine, as\r\n"
+ "if it came from an emulated GPS modem. <sentence> must begin with '$GP'. only\r\n"
+ "'$GPGGA' and '$GPRCM' sentences are supported at the moment.\r\n",
+ NULL, do_geo_nmea, NULL },
+
+ { "fix", "send a simple GPS fix",
+ "'geo fix <longitude> <latitude> [<altitude>]' allows you to send a\r\n"
+ "simple GPS fix to the emulated system. the parameters are:\r\n\r\n"
+ " <longitude> longitude, in decimal degrees\r\n"
+ " <latitude> latitude, in decimal degrees\r\n"
+ " <altitude> optional altitude in meters\r\n"
+ "\r\n",
+ NULL, do_geo_fix, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** M A I N C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+extern void android_emulator_set_window_scale( double, int );
+
+static int
+do_window_scale( ControlClient client, char* args )
+{
+ double scale;
+ int is_dpi = 0;
+ char* end;
+
+ if (!args) {
+ control_write( client, "KO: argument missing, try 'window scale <scale>'\r\n" );
+ return -1;
+ }
+
+ scale = strtol( args, &end, 10 );
+ if (end > args && !memcmp( end, "dpi", 4 )) {
+ is_dpi = 1;
+ }
+ else {
+ scale = strtod( args, &end );
+ if (end == args || end[0]) {
+ control_write( client, "KO: argument <scale> must be a real number, or an integer followed by 'dpi'\r\n" );
+ return -1;
+ }
+ }
+
+ android_emulator_set_window_scale( scale, is_dpi );
+ return 0;
+}
+
+static const CommandDefRec window_commands[] =
+{
+ { "scale", "change the window scale",
+ "'window scale <scale>' allows you to change the scale of the emulator window at runtime\r\n"
+ "<scale> must be either a real number between 0.1 and 3.0, or an integer followed by\r\n"
+ "the 'dpi' prefix (as in '120dpi')\r\n",
+ NULL, do_window_scale, NULL },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+/********************************************************************************************/
+/********************************************************************************************/
+/***** ******/
+/***** M A I N C O M M A N D S ******/
+/***** ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_kill( ControlClient client, char* args )
+{
+ control_write( client, "OK: killing emulator, bye bye\r\n" );
+ exit(0);
+}
+
+static const CommandDefRec main_commands[] =
+{
+ { "help|h|?", "print a list of commands", NULL, NULL, do_help, NULL },
+
+ { "event", "simulate hardware events",
+ "allows you to send fake hardware events to the kernel\r\n", NULL,
+ NULL, event_commands },
+
+ { "geo", "Geo-location commands",
+ "allows you to change Geo-related settings, or to send GPS NMEA sentences\r\n", NULL,
+ NULL, geo_commands },
+
+ { "gsm", "GSM related commands",
+ "allows you to change GSM-related settings, or to make a new inbound phone call\r\n", NULL,
+ NULL, gsm_commands },
+
+ { "kill", "kill the emulator instance", NULL, NULL,
+ do_kill, NULL },
+
+ { "network", "manage network settings",
+ "allows you to manage the settings related to the network data connection of the\r\n"
+ "emulated device.\r\n", NULL,
+ NULL, network_commands },
+
+ { "power", "power related commands",
+ "allows change battery and AC power status\r\n", NULL,
+ NULL, power_commands },
+
+ { "quit|exit", "quit control session", NULL, NULL,
+ do_quit, NULL },
+
+ { "redir", "manage port redirections",
+ "allows you to add, list and remove UDP and/or PORT redirection from the host to the device\r\n"
+ "as an example, 'redir tcp:5000:6000' will route any packet sent to the host's TCP port 5000\r\n"
+ "to TCP port 6000 of the emulated device\r\n", NULL,
+ NULL, redir_commands },
+
+ { "sms", "SMS related commands",
+ "allows you to simulate an inbound SMS\r\n", NULL,
+ NULL, sms_commands },
+
+ { "vm", "manager virtual machine state",
+ "allows to change (e.g. start/stop) the virtual machine state\r\n", NULL,
+ NULL, vm_commands },
+
+ { "window", "manage emulator window",
+ "allows you to modify the emulator window\r\n", NULL,
+ NULL, window_commands },
+
+ { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+static ControlGlobalRec _g_global;
+
+int
+control_console_start( int port )
+{
+ return control_global_init( &_g_global, port );
+}
diff --git a/android_debug.c b/android_debug.c
new file mode 100644
index 0000000..8ec1d67
--- /dev/null
+++ b/android_debug.c
@@ -0,0 +1,141 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_debug.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+void
+dprint( const char* format, ... )
+{
+ va_list args;
+ va_start( args, format );
+ fprintf( stdout, "emulator: ");
+ vfprintf( stdout, format, args );
+ fprintf( stdout, "\n" );
+ va_end( args );
+}
+
+void
+dprintn( const char* format, ... )
+{
+ va_list args;
+ va_start( args, format );
+ vfprintf( stdout, format, args );
+ va_end( args );
+}
+
+void
+dprintnv( const char* format, va_list args )
+{
+ vfprintf( stdout, format, args );
+}
+
+
+void
+dwarning( const char* format, ... )
+{
+ va_list args;
+ va_start( args, format );
+ dprintn( "emulator: WARNING: " );
+ dprintnv( format, args );
+ dprintn( "\n" );
+ va_end( args );
+}
+
+
+void
+derror( const char* format, ... )
+{
+ va_list args;
+ va_start( args, format );
+ dprintn( "emulator: ERROR: " );
+ dprintnv( format, args );
+ dprintn( "\n" );
+ va_end( args );
+}
+
+/** STDOUT/STDERR REDIRECTION
+ **
+ ** allows you to shut temporarily shutdown stdout/stderr
+ ** this is useful to get rid of debug messages from ALSA and esd
+ ** on Linux.
+ **/
+static int stdio_disable_count;
+static int stdio_save_out_fd;
+static int stdio_save_err_fd;
+
+#ifdef _WIN32
+extern void
+stdio_disable( void )
+{
+ if (++stdio_disable_count == 1) {
+ int null_fd, out_fd, err_fd;
+ fflush(stdout);
+ out_fd = _fileno(stdout);
+ err_fd = _fileno(stderr);
+ stdio_save_out_fd = _dup(out_fd);
+ stdio_save_err_fd = _dup(err_fd);
+ null_fd = _open( "NUL", _O_WRONLY );
+ _dup2(null_fd, out_fd);
+ _dup2(null_fd, err_fd);
+ close(null_fd);
+ }
+}
+
+extern void
+stdio_enable( void )
+{
+ if (--stdio_disable_count == 0) {
+ int out_fd, err_fd;
+ fflush(stdout);
+ out_fd = _fileno(stdout);
+ err_fd = _fileno(stderr);
+ _dup2(stdio_save_out_fd, out_fd);
+ _dup2(stdio_save_err_fd, err_fd);
+ _close(stdio_save_out_fd);
+ _close(stdio_save_err_fd);
+ }
+}
+#else
+extern void
+stdio_disable( void )
+{
+ if (++stdio_disable_count == 1) {
+ int null_fd, out_fd, err_fd;
+ fflush(stdout);
+ out_fd = fileno(stdout);
+ err_fd = fileno(stderr);
+ stdio_save_out_fd = dup(out_fd);
+ stdio_save_err_fd = dup(err_fd);
+ null_fd = open( "/dev/null", O_WRONLY );
+ dup2(null_fd, out_fd);
+ dup2(null_fd, err_fd);
+ close(null_fd);
+ }
+}
+
+extern void
+stdio_enable( void )
+{
+ if (--stdio_disable_count == 0) {
+ int out_fd, err_fd;
+ fflush(stdout);
+ out_fd = fileno(stdout);
+ err_fd = fileno(stderr);
+ dup2(stdio_save_out_fd, out_fd);
+ dup2(stdio_save_err_fd, err_fd);
+ close(stdio_save_out_fd);
+ close(stdio_save_err_fd);
+ }
+}
+#endif
diff --git a/android_debug.h b/android_debug.h
new file mode 100644
index 0000000..14e962f
--- /dev/null
+++ b/android_debug.h
@@ -0,0 +1,89 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_DEBUG_H
+#define _ANDROID_DEBUG_H
+
+#include <stdarg.h>
+
+#define VERBOSE_TAG_LIST \
+ _VERBOSE_TAG(init, "emulator initialization") \
+ _VERBOSE_TAG(console, "control console") \
+ _VERBOSE_TAG(modem, "emulated GSM modem") \
+ _VERBOSE_TAG(radio, "emulated GSM AT Command channel") \
+ _VERBOSE_TAG(keys, "key bindings & presses") \
+ _VERBOSE_TAG(slirp, "internal router/firewall") \
+ _VERBOSE_TAG(timezone, "host timezone detection" ) \
+ _VERBOSE_TAG(socket, "network sockets") \
+ _VERBOSE_TAG(proxy, "network proxy support") \
+ _VERBOSE_TAG(audio, "audio sub-system") \
+ _VERBOSE_TAG(audioin, "audio input backend") \
+ _VERBOSE_TAG(audioout, "audio output backend") \
+ _VERBOSE_TAG(surface, "video surface support") \
+ _VERBOSE_TAG(qemud, "qemud multiplexer daemon") \
+ _VERBOSE_TAG(gps, "emulated GPS") \
+ _VERBOSE_TAG(nand_limits, "nand/flash read/write thresholding") \
+
+#define _VERBOSE_TAG(x,y) VERBOSE_##x,
+typedef enum {
+ VERBOSE_TAG_LIST
+ VERBOSE_MAX /* do not remove */
+} VerboseTag;
+#undef _VERBOSE_TAG
+
+/* defined in android_main.c */
+extern unsigned long android_verbose;
+
+#define VERBOSE_ENABLE(tag) \
+ android_verbose |= (1 << VERBOSE_##tag)
+
+#define VERBOSE_DISABLE(tag) \
+ android_verbose &= (1 << VERBOSE_##tag)
+
+#define VERBOSE_CHECK(tag) \
+ ((android_verbose & (1 << VERBOSE_##tag)) != 0)
+
+#define VERBOSE_CHECK_ANY() \
+ (android_verbose != 0)
+
+#define VERBOSE_PRINT(tag,...) \
+ do { if (VERBOSE_CHECK(tag)) dprint(__VA_ARGS__); } while (0)
+
+/** DEBUG TRACE SUPPORT
+ **
+ ** debug messages can be sent by calling these function
+ **
+ ** 'dprint' prints the message, then appends a '\n\
+ ** 'dprintn' simply prints the message as is
+ ** 'dprintnv' allows you to use a va_list argument
+ ** 'dwarning' prints a warning message, then appends a '\n'
+ ** 'derror' prints a severe error message, then appends a '\n'
+ */
+
+extern void dprint( const char* format, ... );
+extern void dprintn( const char* format, ... );
+extern void dprintnv( const char* format, va_list args );
+extern void dwarning( const char* format, ... );
+extern void derror( const char* format, ... );
+
+/** STDOUT/STDERR REDIRECTION
+ **
+ ** allows you to shut temporarily shutdown stdout/stderr
+ ** this is useful to get rid of debug messages from ALSA and esd
+ ** on Linux.
+ **/
+
+extern void stdio_disable( void );
+extern void stdio_enable( void );
+
+/* */
+
+#endif /* _ANDROID_DEBUG_H */
diff --git a/android_events.c b/android_events.c
new file mode 100644
index 0000000..b69e0fe
--- /dev/null
+++ b/android_events.c
@@ -0,0 +1,222 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_events.h"
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ const char* name;
+ int value;
+} PairRec;
+
+#define EV_TYPE(n,v) { STRINGIFY(n), (v) },
+#define BTN_CODE(n,v) { STRINGIFY(n), (v) },
+#define REL_CODE(n,v) { STRINGIFY(n), (v) },
+#define ABS_CODE(n,v) { STRINGIFY(n), (v) },
+
+static const PairRec _ev_types_tab[] =
+{
+ EVENT_TYPE_LIST
+ { NULL, 0 }
+};
+
+static const PairRec _btn_codes_list[] =
+{
+ EVENT_BTN_LIST
+ { NULL, 0 }
+};
+
+static const PairRec _rel_codes_list[] =
+{
+ EVENT_REL_LIST
+ { NULL, 0 }
+};
+
+static const PairRec _abs_codes_list[] =
+{
+ EVENT_ABS_LIST
+ { NULL, 0 }
+};
+
+#undef EV_TYPE
+#undef BTN_CODE
+#undef REL_CODE
+#undef ABS_CODE
+
+static int
+count_list( const PairRec* list )
+{
+ int nn = 0;
+ while (list[nn].name != NULL)
+ nn += 1;
+
+ return nn;
+}
+
+static int
+scan_list( const PairRec* list,
+ const char* prefix,
+ const char* name,
+ int namelen )
+{
+ int len;
+
+ if (namelen <= 0)
+ return -1;
+
+ len = strlen(prefix);
+ if (namelen <= len)
+ return -1;
+ if ( memcmp( name, prefix, len ) != 0 )
+ return -1;
+
+ name += len;
+ namelen -= len;
+
+ for ( ; list->name != NULL; list += 1 )
+ {
+ if ( memcmp( list->name, name, namelen ) == 0 && list->name[namelen] == 0 )
+ return list->value;
+ }
+ return -1;
+}
+
+
+typedef struct {
+ int type;
+ const char* prefix;
+ const PairRec* pairs;
+} TypeListRec;
+
+typedef const TypeListRec* TypeList;
+
+static const TypeListRec _types_list[] =
+{
+ { EV_KEY, "BTN_", _btn_codes_list },
+ { EV_REL, "REL_", _rel_codes_list },
+ { EV_ABS, "ABS_", _abs_codes_list },
+ { -1, NULL, NULL }
+};
+
+
+static TypeList
+find_type_list( int type )
+{
+ TypeList list = _types_list;
+
+ for ( ; list->type >= 0; list += 1 )
+ if (list->type == type)
+ return list;
+
+ return NULL;
+}
+
+
+int
+android_event_from_str( const char* name,
+ int *ptype,
+ int *pcode,
+ int *pvalue )
+{
+ const char* p;
+ const char* pend;
+ const char* q;
+ TypeList list;
+ char* end;
+
+ *ptype = 0;
+ *pcode = 0;
+ *pvalue = 0;
+
+ p = name;
+ pend = p + strcspn(p, " \t");
+ q = strchr(p, ':');
+ if (q == NULL || q > pend)
+ q = pend;
+
+ *ptype = scan_list( _ev_types_tab, "EV_", p, q-p );
+ if (*ptype < 0) {
+ *ptype = (int) strtol( p, &end, 0 );
+ if (end != q)
+ return -1;
+ }
+
+ if (*q != ':')
+ return 0;
+
+ p = q + 1;
+ q = strchr(p, ':');
+ if (q == NULL || q > pend)
+ q = pend;
+
+ list = find_type_list( *ptype );
+
+ *pcode = -1;
+ if (list != NULL) {
+ *pcode = scan_list( list->pairs, list->prefix, p, q-p );
+ }
+ if (*pcode < 0) {
+ *pcode = (int) strtol( p, &end, 0 );
+ if (end != q)
+ return -2;
+ }
+
+ if (*q != ':')
+ return 0;
+
+ p = q + 1;
+ q = strchr(p, ':');
+ if (q == NULL || q > pend)
+ q = pend;
+
+ *pvalue = (int)strtol( p, &end, 0 );
+ if (end != q)
+ return -3;
+
+ return 0;
+}
+
+int
+android_event_get_type_count( void )
+{
+ return count_list( _ev_types_tab );
+}
+
+char*
+android_event_bufprint_type_str( char* buff, char* end, int type_index )
+{
+ return bufprint( buff, end, "EV_%s", _ev_types_tab[type_index].name );
+}
+
+/* returns the list of valid event code string aliases for a given event type */
+int
+android_event_get_code_count( int type )
+{
+ TypeList list = find_type_list(type);
+
+ if (list == NULL)
+ return 0;
+
+ return count_list( list->pairs );
+}
+
+char*
+android_event_bufprint_code_str( char* buff, char* end, int type, int code_index )
+{
+ TypeList list = find_type_list(type);
+
+ if (list == NULL)
+ return buff;
+
+ return bufprint( buff, end, "%s%s", list->prefix, list->pairs[code_index].name );
+}
+
diff --git a/android_events.h b/android_events.h
new file mode 100644
index 0000000..b3d69b6
--- /dev/null
+++ b/android_events.h
@@ -0,0 +1,184 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_EVENTS_H
+#define _ANDROID_EVENTS_H
+
+#include "android_utils.h"
+
+/* from the Linux kernel */
+
+#define EVENT_TYPE_LIST \
+ EV_TYPE(SYN,0x00) \
+ EV_TYPE(KEY,0x01) \
+ EV_TYPE(REL,0x02) \
+ EV_TYPE(ABS,0x03) \
+ EV_TYPE(MSC,0x04) \
+ EV_TYPE(SW, 0x05) \
+ EV_TYPE(LED,0x11) \
+ EV_TYPE(SND,0x12) \
+ EV_TYPE(REP,0x14) \
+ EV_TYPE(FF, 0x15) \
+ EV_TYPE(PWR,0x16) \
+ EV_TYPE(FF_STATUS,0x17) \
+ EV_TYPE(MAX,0x1f)
+
+#undef EV_TYPE
+#define EV_TYPE(n,v) GLUE(EV_,n) = v,
+typedef enum {
+ EVENT_TYPE_LIST
+} EventType;
+#undef EV_TYPE
+
+#define EVENT_BTN_LIST \
+ BTN_CODE(MISC,0x100) \
+ BTN_CODE(0,0x100) \
+ BTN_CODE(1,0x101) \
+ BTN_CODE(2,0x102) \
+ BTN_CODE(3,0x103) \
+ BTN_CODE(4,0x104) \
+ BTN_CODE(5,0x105) \
+ BTN_CODE(6,0x106) \
+ BTN_CODE(7,0x107) \
+ BTN_CODE(8,0x108) \
+ BTN_CODE(9,0x109) \
+ \
+ BTN_CODE(MOUSE, 0x110) \
+ BTN_CODE(LEFT, 0x110) \
+ BTN_CODE(RIGHT, 0x111) \
+ BTN_CODE(MIDDLE, 0x112) \
+ BTN_CODE(SIDE, 0x113) \
+ BTN_CODE(EXTRA, 0x114) \
+ BTN_CODE(FORWARD,0x115) \
+ BTN_CODE(BACK, 0x116) \
+ BTN_CODE(TASK, 0x117) \
+ \
+ BTN_CODE(JOYSTICK,0x120) \
+ BTN_CODE(TRIGGER, 0x120) \
+ BTN_CODE(THUMB, 0x121) \
+ BTN_CODE(THUMB2, 0x122) \
+ BTN_CODE(TOP, 0x123) \
+ BTN_CODE(TOP2, 0x124) \
+ BTN_CODE(PINKIE, 0x125) \
+ BTN_CODE(BASE, 0x126) \
+ BTN_CODE(BASE2, 0x127) \
+ BTN_CODE(BASE3, 0x128) \
+ BTN_CODE(BASE4, 0x129) \
+ BTN_CODE(BASE5, 0x12a) \
+ BTN_CODE(BASE6, 0x12b) \
+ BTN_CODE(DEAD, 0x12f) \
+ \
+ BTN_CODE(GAMEPAD, 0x130) \
+ BTN_CODE(A, 0x130) \
+ BTN_CODE(B, 0x131) \
+ BTN_CODE(C, 0x132) \
+ BTN_CODE(X, 0x133) \
+ BTN_CODE(Y, 0x134) \
+ BTN_CODE(Z, 0x135) \
+ BTN_CODE(TL, 0x136) \
+ BTN_CODE(TR, 0x137) \
+ BTN_CODE(TL2, 0x138) \
+ BTN_CODE(TR2, 0x139) \
+ BTN_CODE(SELECT, 0x13a) \
+ BTN_CODE(START, 0x13b) \
+ BTN_CODE(MODE, 0x13c) \
+ BTN_CODE(THUMBL, 0x13d) \
+ BTN_CODE(THUMBR, 0x13e) \
+ \
+ BTN_CODE(DIGI, 0x140) \
+ BTN_CODE(TOOL_PEN, 0x140) \
+ BTN_CODE(TOOL_RUBBER, 0x141) \
+ BTN_CODE(TOOL_BRUSH, 0x142) \
+ BTN_CODE(TOOL_PENCIL, 0x143) \
+ BTN_CODE(TOOL_AIRBRUSH, 0x144) \
+ BTN_CODE(TOOL_FINGER, 0x145) \
+ BTN_CODE(TOOL_MOUSE, 0x146) \
+ BTN_CODE(TOOL_LENS, 0x147) \
+ BTN_CODE(TOUCH, 0x14a) \
+ BTN_CODE(STYLUS, 0x14b) \
+ BTN_CODE(STYLUS2, 0x14c) \
+ BTN_CODE(TOOL_DOUBLETAP, 0x14d) \
+ BTN_CODE(TOOL_TRIPLETAP, 0x14e) \
+ \
+ BTN_CODE(WHEEL, 0x150) \
+ BTN_CODE(GEAR_DOWN, 0x150) \
+ BTN_CODE(GEAR_UP, 0x150)
+
+#undef BTN_CODE
+#define BTN_CODE(n,v) GLUE(BTN_,n) = v,
+typedef enum {
+ EVENT_BTN_LIST
+} EventBtnCode;
+#undef BTN_CODE
+
+#define EVENT_REL_LIST \
+ REL_CODE(X, 0x00) \
+ REL_CODE(Y, 0x01)
+
+#define REL_CODE(n,v) GLUE(REL_,n) = v,
+typedef enum {
+ EVENT_REL_LIST
+} EventRelCode;
+#undef REL_CODE
+
+#define EVENT_ABS_LIST \
+ ABS_CODE(X, 0x00) \
+ ABS_CODE(Y, 0x01) \
+ ABS_CODE(Z, 0x02) \
+ ABS_CODE(RX, 0x03) \
+ ABS_CODE(RY, 0x04) \
+ ABS_CODE(RZ, 0x05) \
+ ABS_CODE(THROTTLE, 0x06) \
+ ABS_CODE(RUDDER, 0x07) \
+ ABS_CODE(WHEEL, 0x08) \
+ ABS_CODE(GAS, 0x09) \
+ ABS_CODE(BRAKE, 0x0a) \
+ ABS_CODE(HAT0X, 0x10) \
+ ABS_CODE(HAT0Y, 0x11) \
+ ABS_CODE(HAT1X, 0x12) \
+ ABS_CODE(HAT1Y, 0x13) \
+ ABS_CODE(HAT2X, 0x14) \
+ ABS_CODE(HAT2Y, 0x15) \
+ ABS_CODE(HAT3X, 0x16) \
+ ABS_CODE(HAT3Y, 0x17) \
+ ABS_CODE(PRESSURE, 0x18) \
+ ABS_CODE(DISTANCE, 0x19) \
+ ABS_CODE(TILT_X, 0x1a) \
+ ABS_CODE(TILT_Y, 0x1b) \
+ ABS_CODE(TOOL_WIDTH, 0x1c) \
+ ABS_CODE(VOLUME, 0x20) \
+ ABS_CODE(MISC, 0x28) \
+ ABS_CODE(MAX, 0x3f)
+
+#define ABS_CODE(n,v) GLUE(ABS_,n) = v,
+
+typedef enum {
+ EVENT_ABS_LIST
+} EventAbsCode;
+#undef ABS_CODE
+
+/* convert an event string specification like <type>:<code>:<value>
+ * into three integers. returns 0 on success, or -1 in case of error
+ */
+extern int android_event_from_str( const char* name,
+ int *ptype,
+ int *pcode,
+ int *pvalue );
+
+/* returns the list of valid event type string aliases */
+extern int android_event_get_type_count( void );
+extern char* android_event_bufprint_type_str( char* buff, char* end, int type_index );
+
+/* returns the list of valid event code string aliases for a given event type */
+extern int android_event_get_code_count( int type );
+extern char* android_event_bufprint_code_str( char* buff, char* end, int type, int code_index );
+
+#endif /* _ANDROID_EVENTS_H */
diff --git a/android_gps.c b/android_gps.c
new file mode 100644
index 0000000..219c178
--- /dev/null
+++ b/android_gps.c
@@ -0,0 +1,36 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_gps.h"
+#include "android_debug.h"
+
+CharDriverState* android_gps_cs;
+
+#define D(...) VERBOSE_PRINT(gps,__VA_ARGS__)
+
+void
+android_gps_send_nmea( const char* sentence )
+{
+ if (sentence == NULL)
+ return;
+
+ D("sending '%s'", sentence);
+
+ if (android_gps_cs == NULL) {
+ D("missing GPS channel, ignored");
+ return;
+ }
+
+ qemu_chr_write( android_gps_cs, (const void*)sentence, strlen(sentence) );
+ qemu_chr_write( android_gps_cs, "\n", 1 );
+}
+
+
diff --git a/android_gps.h b/android_gps.h
new file mode 100644
index 0000000..d51d8f3
--- /dev/null
+++ b/android_gps.h
@@ -0,0 +1,23 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _android_gps_h
+#define _android_gps_h
+
+#include "vl.h"
+
+/* this is the internal character driver used to communicate with the
+ * emulated GPS unit. see qemu_chr_open() in vl.c */
+extern CharDriverState* android_gps_cs;
+
+extern void android_gps_send_nmea( const char* sentence );
+
+#endif /* _android_gps_h */
diff --git a/android_help.c b/android_help.c
new file mode 100644
index 0000000..25ff36a
--- /dev/null
+++ b/android_help.c
@@ -0,0 +1,1246 @@
+#include "android_help.h"
+#include "android_option.h"
+#include "skins/skin_keyset.h"
+#include "android.h"
+#include <stdint.h>
+#include "audio/audio.h"
+#include <string.h>
+#include <stdlib.h>
+#include "vl.h" /* for pstrcpy */
+
+/* XXX: TODO: put most of the help stuff in auto-generated files */
+
+#define PRINTF(...) stralloc_add_format(out,__VA_ARGS__)
+
+static void
+help_disk_images( stralloc_t* out )
+{
+ char datadir[256];
+
+ bufprint_config_path( datadir, datadir + sizeof(datadir) );
+
+ PRINTF(
+ " the emulator needs several key read-only image files to run appropriately.\n"
+ " they are normally searched in 'lib/images' under the emulator's program\n"
+ " location, but you can also use '-system <dir>' to specify a different\n"
+ " directory\n\n"
+
+ " the files that are looked up in the system directory are, by default:\n\n"
+
+ " kernel-qemu the emulator-specific Linux kernel image\n"
+ " ramdisk.img the ramdisk image used to boot the system\n"
+ " system.img the *initial* system image\n"
+ " userdata.img the *initial* data partition image\n\n"
+
+ " use '-kernel <file>', '-ramdisk <file>', '-image <file>' and\n"
+ " '-initdata <file>' respectively if you want to override these.\n\n"
+
+ " several *writable* files are also used at runtime. they are searched\n"
+ " in a specific data directory, which is, on this system:\n\n"
+
+ " %s\n\n"
+
+ " you can use the '-datadir <dir>' option to use another directory.\n"
+ " the writable image files there are:\n\n"
+
+ " userdata-qemu.img the persistent /data partition image\n"
+ " sdcard.img an *optional* SD Card partition image file\n\n"
+
+ " use '-data <file>' to specify an alternative /data partition image. if\n"
+ " <file> does not exist, it will be created with a copy of the initial\n"
+ " userdata.img file.\n\n"
+
+ " use '-wipe-data' to copy the initial data partition image into your\n"
+ " data image. this has the effect of resetting everything in /data to the\n"
+ " 'factory defaults', wiping all installed applications and settings.\n\n"
+
+ " use '-sdcard <file>' to specify a different SD Card partition image. these\n"
+ " are simple FAT32 image disks that can be used with the 'mksdcard' tool that\n"
+ " comes with the Android SDK. If <file> does not exist, the option is ignored\n"
+ " and the emulator will start without an attached SD Card.\n\n"
+
+ " finally, some *writable* *temporary* files are used at runtime:\n\n"
+
+ " the *writable* system image\n"
+ " the /cache partition image\n\n"
+
+ " the writable system image is initialized on startup with the read-only\n"
+ " system.img file. it is always deleted on exit, and there is currently no\n"
+ " way to make changes in there persistent\n\n"
+
+ " the /cache partition image is initially empty, and is used by the browser\n"
+ " to cache downloaded web pages and images. you can use '-cache <file>' to\n"
+ " make it persistent. if <file> does not exist, it will be created empty.\n"
+ " another option is to disable the cache partition with '-nocache'\n\n",
+
+ datadir );
+}
+
+static void
+help_keys(stralloc_t* out)
+{
+ int pass, maxw = 0;
+
+ stralloc_add_str( out, " When running the emulator, use the following keypresses:\n\n");
+
+ if (!android_keyset)
+ android_keyset = skin_keyset_new_from_text( skin_keyset_get_default() );
+
+ for (pass = 0; pass < 2; pass++) {
+ SkinKeyCommand cmd;
+
+ for (cmd = SKIN_KEY_COMMAND_NONE+1; cmd < SKIN_KEY_COMMAND_MAX; cmd++)
+ {
+ SkinKeyBinding bindings[ SKIN_KEY_COMMAND_MAX_BINDINGS ];
+ int n, count, len;
+ char temp[32], *p = temp, *end = p + sizeof(temp);
+
+ count = skin_keyset_get_bindings( android_keyset, cmd, bindings );
+ if (count <= 0)
+ continue;
+
+ for (n = 0; n < count; n++) {
+ p = bufprint(p, end, "%s%s", (n == 0) ? "" : ", ",
+ skin_key_symmod_to_str( bindings[n].sym, bindings[n].mod ) );
+ }
+
+ if (pass == 0) {
+ len = strlen(temp);
+ if (len > maxw)
+ maxw = len;
+ } else {
+ PRINTF( " %-*s %s\n", maxw, temp, skin_key_command_description(cmd) );
+ }
+ }
+ }
+ PRINTF( "\n" );
+ PRINTF( " note that NumLock must be deactivated for keypad keys to work\n\n" );
+}
+
+
+static void
+help_environment(stralloc_t* out)
+{
+ PRINTF(
+ " the Android emulator looks at various environment variables when it starts:\n\n"
+
+ " if ANDROID_LOG_TAGS is defined, it will be used as in '-logcat <tags>'\n\n"
+
+ " if 'http_proxy' is defined, it will be used as in '-http-proxy <proxy>'\n\n"
+
+ " If ANDROID_VERBOSE is defined, it can contain a comma-separated list of\n"
+ " verbose items. for example:\n\n"
+
+ " ANDROID_VERBOSE=socket,radio\n\n"
+
+ " is equivalent to using the '-verbose -verbose-socket -verbose-radio'\n"
+ " options together. unsupported items will be ignored\n\n"
+
+ );
+}
+
+
+static void
+help_keyset_file(stralloc_t* out)
+{
+ int n, count;
+ const char** strings;
+ char temp[MAX_PATH];
+
+ PRINTF(
+ " on startup, the emulator looks for 'keyset' file that contains the\n"
+ " configuration of key-bindings to use. the default location on this\n"
+ " system is:\n\n"
+ );
+
+ bufprint_config_file( temp, temp+sizeof(temp), KEYSET_FILE );
+ PRINTF( " %s\n\n", temp );
+
+ PRINTF(
+ " if the file doesn't exist, the emulator writes one containing factory\n"
+ " defaults. you are then free to modify it to suit specific needs.\n\n"
+ " this file shall contain a list of text lines in the following format:\n\n"
+
+ " <command> [<modifiers>]<key>\n\n"
+
+ " where <command> is an emulator-specific command name, i.e. one of:\n\n"
+ );
+
+ count = SKIN_KEY_COMMAND_MAX-1;
+ strings = calloc( count, sizeof(char*) );
+ for (n = 0; n < count; n++)
+ strings[n] = skin_key_command_to_str(n+1);
+
+ stralloc_tabular( out, strings, count, " ", 80-8 );
+ free(strings);
+
+ PRINTF(
+ "\n"
+ " <modifers> is an optional list of <modifier> elements (without separators)\n"
+ " which can be one of:\n\n"
+
+ " Ctrl- Left Control Key\n"
+ " Shift- Left Shift Key\n"
+ " Alt- Left Alt key\n"
+ " RCtrl- Right Control Key\n"
+ " RShift- Right Shift Key\n"
+ " RAlt- Right Alt key (a.k.a AltGr)\n"
+ "\n"
+ " finally <key> is a QWERTY-specific keyboard symbol which can be one of:\n\n"
+ );
+ count = skin_keysym_str_count();
+ strings = calloc( count, sizeof(char*) );
+ for (n = 0; n < count; n++)
+ strings[n] = skin_keysym_str(n);
+
+ stralloc_tabular( out, strings, count, " ", 80-8 );
+ free(strings);
+
+ PRINTF(
+ "\n"
+ " case is not significant, and a single command can be associated to up\n"
+ " to %d different keys. to bind a command to multiple keys, use commas to\n"
+ " separate them. here are some examples:\n\n",
+ SKIN_KEY_COMMAND_MAX_BINDINGS );
+
+ PRINTF(
+ " TOGGLE_NETWORK F8 # toggle the network on/off\n"
+ " CHANGE_LAYOUT_PREV Keypad_7,Ctrl-J # switch to a previous skin layout\n"
+ "\n"
+ );
+}
+
+
+static void
+help_debug_tags(stralloc_t* out)
+{
+ int n;
+
+#define _VERBOSE_TAG(x,y) { #x, VERBOSE_##x, y },
+ static const struct { const char* name; int flag; const char* text; }
+ verbose_options[] = {
+ VERBOSE_TAG_LIST
+ { 0, 0, 0 }
+ };
+#undef _VERBOSE_TAG
+
+ PRINTF(
+ " the '-debug <tags>' option can be used to enable or disable debug\n"
+ " messages from specific parts of the emulator. <tags> must be a list\n"
+ " (separated by space/comma/column) of <component> names, which can be one of:\n\n"
+ );
+
+ for (n = 0; n < VERBOSE_MAX; n++)
+ PRINTF( " %-12s %s\n", verbose_options[n].name, verbose_options[n].text );
+ PRINTF( " %-12s %s\n", "all", "all components together\n" );
+
+ PRINTF(
+ "\n"
+ " each <component> can be prefixed with a single '-' to indicate the disabling\n"
+ " of its debug messages. for example:\n\n"
+
+ " -debug all,-socket,-keys\n\n"
+
+ " enables all debug messages, except the ones related to network sockets\n"
+ " and key bindings/presses\n\n"
+ );
+}
+
+static void
+help_char_devices(stralloc_t* out)
+{
+ PRINTF(
+ " various emulation options take a <device> specification that can be used to\n"
+ " specify something to hook to an emulated device or communication channel.\n"
+ " here is the list of supported <device> specifications:\n\n"
+
+ " stdio\n"
+ " standard input/output. this may be subject to character\n"
+ " translation (e.g. LN <=> CR/LF)\n\n"
+
+ " COM<n> [Windows only]\n"
+ " where <n> is a digit. host serial communication port.\n\n"
+
+ " pipe:<filename>\n"
+ " named pipe <filename>\n\n"
+
+ " file:<filename>\n"
+ " write output to <filename>, no input can be read\n\n"
+
+ " pty [Linux only]\n"
+ " pseudo TTY (a new PTY is automatically allocated)\n\n"
+
+ " /dev/<file> [Unix only]\n"
+ " host char device file, e.g. /dev/ttyS0. may require root access\n\n"
+
+ " /dev/parport<N> [Linux only]\n"
+ " use host parallel port. may require root access\n\n"
+
+ " unix:<path>[,server][,nowait]] [Unix only]\n"
+ " use a Unix domain socket. if you use the 'server' option, then\n"
+ " the emulator will create the socket and wait for a client to\n"
+ " connect before continuing, unless you also use 'nowait'\n\n"
+
+ " tcp:[<host>]:<port>[,server][,nowait][,nodelay]\n"
+ " use a TCP socket. 'host' is set to localhost by default. if you\n"
+ " use the 'server' option will bind the port and wait for a client\n"
+ " to connect before continuing, unless you also use 'nowait'. the\n"
+ " 'nodelay' option disables the TCP Nagle algorithm\n\n"
+
+ " telnet:[<host>]:<port>[,server][,nowait][,nodelay]\n"
+ " similar to 'tcp:' but uses the telnet protocol instead of raw TCP\n\n"
+
+ " udp:[<remote_host>]:<remote_port>[@[<src_ip>]:<src_port>]\n"
+ " send output to a remote UDP server. if 'remote_host' is no\n"
+ " specified it will default to '0.0.0.0'. you can also receive input\n"
+ " through UDP by specifying a source address after the optional '@'.\n\n"
+
+ " fdpair:<fd1>,<fd2> [Unix only]\n"
+ " redirection input and output to a pair of pre-opened file\n"
+ " descriptors. this is mostly useful for scripts and other\n"
+ " programmatic launches of the emulator.\n\n"
+
+ " none\n"
+ " no device connected\n\n"
+
+ " null\n"
+ " the null device (a.k.a /dev/null on Unix, or NUL on Win32)\n\n"
+
+ " NOTE: these correspond to the <device> parameter of the QEMU -serial option\n"
+ " as described on http://bellard.org/qemu/qemu-doc.html#SEC10\n\n"
+ );
+}
+
+static const struct { const char* name; const char* descr; void (*help_func)(stralloc_t* out); } help_topics[] =
+{
+ { "disk-images", "about disk images", help_disk_images },
+ { "keys", "supported key bindings", help_keys },
+ { "debug-tags", "debug tags for -debug <tags>", help_debug_tags },
+ { "char-devices", "character <device> specification", help_char_devices },
+ { "environment", "environment variables", help_environment },
+ { "keyset-file", "key bindings configuration file", help_keyset_file },
+ { NULL, NULL }
+};
+
+
+static void
+help_system(stralloc_t* out)
+{
+ char systemdir[MAX_PATH];
+ char *p = systemdir, *end = p + sizeof(systemdir);
+
+ p = bufprint_app_dir( p, end );
+ p = bufprint( p, end, PATH_SEP "lib" PATH_SEP "images" );
+
+ PRINTF(
+ " use '-system <dir>' to specify a directory where system read-only\n"
+ " image files will be searched. on this system, the default directory is:\n\n"
+ " %s\n\n", systemdir );
+
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_datadir(stralloc_t* out)
+{
+ char datadir[MAX_PATH];
+
+ bufprint_config_path(datadir, datadir + sizeof(datadir));
+
+ PRINTF(
+ " use '-datadir <dir>' to specify a directory where writable image files\n"
+ " will be searched. on this system, the default directory is:\n\n"
+ " %s\n\n", datadir );
+
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_kernel(stralloc_t* out)
+{
+ PRINTF(
+ " use '-kernel <file>' to specify a Linux kernel image to be run.\n"
+ " the default image is 'kernel-qemu' from the system directory.\n\n" );
+ PRINTF(
+ " you can use '-debug-kernel' to send debug messages from the kernel\n"
+ " to the terminal\n\n" );
+
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_ramdisk(stralloc_t* out)
+{
+ PRINTF(
+ " use '-ramdisk <file>' to specify a Linux ramdisk boot image to be run in\n"
+ " the emulator. the default image is 'ramdisk.img' from the system directory.\n\n" );
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_image(stralloc_t* out)
+{
+ PRINTF(
+ " use '-image <file>' to specify the intial system image that will be loaded.\n"
+ " the default image is 'system.img' from the system directory.\n\n");
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_initdata(stralloc_t* out)
+{
+ PRINTF(
+ " use '-initdata <file>' to specify an *init* /data partition file.\n"
+ " it is only used when creating a new writable /data image file, or\n"
+ " when you use '-wipe-data' to reset it. the default is 'userdata.img'\n"
+ " from the system directory.\n\n" );
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_data(stralloc_t* out)
+{
+ char file[MAX_PATH];
+
+ bufprint_config_file( file, file+sizeof(file), "userdata-qemu.img" );
+
+ PRINTF(
+ " use '-data <file>' to specify a different /data partition image file.\n"
+ " the default, on this system is the following:\n\n"
+ " %s\n\n", file );
+
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_wipe_data(stralloc_t* out)
+{
+ PRINTF(
+ " use '-wipe-data' to reset your /data partition image to its factory\n"
+ " defaults. this removes all installed applications and settings.\n\n" );
+
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_cache(stralloc_t* out)
+{
+ PRINTF(
+ " use '-cache <file>' to specify a /cache partition image. if <file> does\n"
+ " not exist, it will be created empty. by default, the cache partition is\n"
+ " backed by a temporary file that is deleted when the emulator exits.\n"
+ " using the -cache option allows it to be persistent.\n\n" );
+
+ PRINTF(
+ " the '-nocache' option can be used to disable the cache partition.\n\n" );
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_nocache(stralloc_t* out)
+{
+ PRINTF(
+ " use '-nocache' to disable the cache partition in the emulated system.\n"
+ " the cache partition is optional, but when available, is used by the browser\n"
+ " to cache web pages and images\n\n" );
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_sdcard(stralloc_t* out)
+{
+ char file[MAX_PATH];
+
+ bufprint_config_file( file, file+sizeof(file), "sdcard.img" );
+
+ PRINTF(
+ " use '-sdcard <file>' to specify a SD Card image file that will be attached\n"
+ " to the emulator. By default, the following file is searched:\n\n"
+ " %s\n\n", file );
+ PRINTF(
+ " if the file does not exist, the emulator will still start, but without an\n"
+ " attached SD Card.\n\n");
+ PRINTF(
+ " see '-help-disk-images' for more information about disk image files\n\n" );
+}
+
+static void
+help_skindir(stralloc_t* out)
+{
+ PRINTF(
+ " use '-skindir <dir>' to specify a directory that will be used to search\n"
+ " for emulator skins. each skin must be a subdirectory of <dir>. by default\n"
+ " the emulator will look in the 'skins' sub-directory of the system directory\n\n" );
+}
+
+static void
+help_skin(stralloc_t* out)
+{
+ PRINTF(
+ " use '-skin <skin>' to specify an emulator skin, each skin corresponds to\n"
+ " the visual appearance of a given device, including buttons and keyboards,\n"
+ " and is stored as subdirectory <skin> of the skin root directory\n"
+ " (see '-help-skindir')\n\n" );
+
+ PRINTF(
+ " note that <skin> can also be '<width>x<height>' (e.g. '320x480') to\n"
+ " specify an exact framebuffer size, without any visual ornaments.\n\n" );
+}
+
+/* default network settings for emulator */
+#define DEFAULT_NETSPEED "full"
+#define DEFAULT_NETDELAY "none"
+
+static void
+help_shaper(stralloc_t* out)
+{
+ int n;
+
+ PRINTF(
+ " the Android emulator supports network throttling, i.e. slower network\n"
+ " bandwidth as well as higher connection latencies. this is done either through\n"
+ " skin configuration, or with '-netspeed <speed>' and '-netdelay <delay>'.\n\n"
+
+ " the format of -netspeed is one of the following (numbers are kbits/s):\n\n" );
+
+ for (n = 0; android_netspeeds[n].name != NULL; n++) {
+ PRINTF( " -netspeed %-12s %-15s (up: %.1f, down: %.1f)\n",
+ android_netspeeds[n].name,
+ android_netspeeds[n].display,
+ android_netspeeds[n].upload/1000.,
+ android_netspeeds[n].download/1000. );
+ }
+ PRINTF( "\n" );
+ PRINTF( " -netspeed %-12s %s", "<num>", "select both upload and download speed\n");
+ PRINTF( " -netspeed %-12s %s", "<up>:<down>", "select individual up and down speed\n");
+
+ PRINTF( "\n The format of -netdelay is one of the following (numbers are msec):\n\n" );
+ for (n = 0; android_netdelays[n].name != NULL; n++) {
+ PRINTF( " -netdelay %-10s %-15s (min %d, max %d)\n",
+ android_netdelays[n].name, android_netdelays[n].display,
+ android_netdelays[n].min_ms, android_netdelays[n].max_ms );
+ }
+ PRINTF( " -netdelay %-10s %s", "<num>", "select exact latency\n");
+ PRINTF( " -netdelay %-10s %s", "<min>:<max>", "select min and max latencies\n\n");
+
+ PRINTF( " the emulator uses the following defaults:\n\n" );
+ PRINTF( " Default network speed is '%s'\n", DEFAULT_NETSPEED);
+ PRINTF( " Default network latency is '%s'\n\n", DEFAULT_NETDELAY);
+}
+
+static void
+help_http_proxy(stralloc_t* out)
+{
+ PRINTF(
+ " the Android emulator allows you to redirect all TCP connections through\n"
+ " a HTTP/HTTPS proxy. this can be enabled by using the '-http-proxy <proxy>'\n"
+ " option, or by defining the 'http_proxy' environment variable.\n\n"
+
+ " <proxy> can be one of the following:\n\n"
+ " http://<server>:<port>\n"
+ " http://<username>:<password>@<server>:<port>\n\n"
+
+ " the 'http://' prefix can be omitted. If '-http-proxy <proxy>' is not used,\n"
+ " the 'http_proxy' environment variable is looked up and any value matching\n"
+ " the <proxy> format will be used automatically\n\n" );
+}
+
+static void
+help_report_console(stralloc_t* out)
+{
+ PRINTF(
+ " the '-report-console <socket>' option can be used to report the\n"
+ " automatically-assigned console port number to a remote third-party\n"
+ " before starting the emulation. <socket> must be in one of these\n"
+ " formats:\n\n"
+
+ " tcp:<port>[,server][,max=<seconds>]\n"
+ " unix:<path>[,server][,max=<seconds>]\n"
+ "\n"
+ " if the 'server' option is used, the emulator opens a server socket\n"
+ " and waits for an incoming connection to it. by default, it will instead\n"
+ " try to make a normal client connection to the socket, and, in case of\n"
+ " failure, will repeat this operation every second for 10 seconds.\n"
+ " the 'max=<seconds>' option can be used to modify the timeout\n\n"
+
+ " when the connection is established, the emulator sends its console port\n"
+ " number as text to the remote third-party, then closes the connection and\n"
+ " starts the emulation as usual. *any* failure in the process described here\n"
+ " will result in the emulator aborting immediately\n\n"
+
+ " as an example, here's a small Unix shell script that starts the emulator in\n"
+ " the background and waits for its port number with the help of the 'netcat'\n"
+ " utility:\n\n"
+
+ " MYPORT=5000\n"
+ " emulator -no-window -report-console tcp:$MYPORT &\n"
+ " CONSOLEPORT=`nc -l localhost $MYPORT`\n"
+ "\n"
+ );
+}
+
+static void
+help_dpi_device(stralloc_t* out)
+{
+ PRINTF(
+ " use '-dpi-device <dpi>' to specify the screen resolution of the emulated\n"
+ " device. <dpi> must be an integer between 72 and 1000. the default is taken\n"
+ " from the skin, if available, or uses the contant value %d (an average of\n"
+ " several prototypes used during Android development).\n\n", DEFAULT_DEVICE_DPI );
+
+ PRINTF(
+ " the device resolution can also used to rescale the emulator window with\n"
+ " the '-scale' option (see -help-scale)\n\n"
+ );
+}
+
+static void
+help_audio(stralloc_t* out)
+{
+ PRINTF(
+ " the '-audio <backend>' option allows you to select a specific backend\n"
+ " to be used to both play and record audio in the Android emulator.\n\n"
+
+ " this is equivalent to calling both '-audio-in <backend>' and\n"
+ " '-audio-out <backend>' at the same time.\n\n"
+
+ " use '-help-audio-out' to see a list of valid output <backend> values.\n"
+ " use '-help-audio-in' to see a list of valid input <backend> values.\n"
+ " use '-audio none' to disable audio completely.\n\n"
+ );
+}
+
+static void
+help_audio_out(stralloc_t* out)
+{
+ int nn;
+
+ PRINTF(
+ " the '-audio-out <backend>' option allows you to select a specific\n"
+ " backend to play audio in the Android emulator. this is mostly useful\n"
+ " on Linux\n\n"
+
+ " on this system, output <backend> can be one of the following:\n\n"
+ );
+ for ( nn = 0; ; nn++ ) {
+ const char* descr;
+ const char* name = audio_get_backend_name( 0, nn, &descr );
+ if (name == NULL)
+ break;
+ PRINTF( " %-10s %s\n", name, descr );
+ }
+ PRINTF( "\n" );
+}
+
+static void
+help_audio_in(stralloc_t* out)
+{
+ int nn;
+
+ PRINTF(
+ " the '-audio-in <backend>' option allows you to select a specific\n"
+ " backend to play audio in the Android emulator. this is mostly useful\n"
+ " on Linux\n\n"
+
+ " IMPORTANT NOTE:\n"
+ " on some Linux systems, broken Esd/ALSA/driver implementations will\n"
+ " make your emulator freeze and become totally unresponsive when\n"
+ " using audio recording. the only way to avoid this is to use\n"
+ " '-audio-in none' to disable it\n\n"
+
+ " on this system, input <backend> can be one of:\n\n"
+ );
+ for ( nn = 0; ; nn++ ) {
+ const char* descr;
+ const char* name = audio_get_backend_name( 1, nn, &descr );
+ if (name == NULL)
+ break;
+ PRINTF( " %-10s %s\n", name, descr );
+ }
+ PRINTF( "\n" );
+}
+
+
+static void
+help_scale(stralloc_t* out)
+{
+ PRINTF(
+ " the '-scale <scale>' option is used to scale the emulator window to\n"
+ " something that better fits the physical dimensions of a real device. this\n"
+ " can be *very* useful to check that your UI isn't too small to be usable\n"
+ " on a real device.\n\n"
+
+ " there are three supported formats for <scale>:\n\n"
+
+ " * if <scale> is a real number (between 0.1 and 3.0) it is used as a\n"
+ " scaling factor for the emulator's window.\n\n"
+
+ " * if <scale> is an integer followed by the suffix 'dpi' (e.g. '110dpi'),\n"
+ " then it is interpreted as the resolution of your monitor screen. this\n"
+ " will be divided by the emulated device's resolution to get an absolute\n"
+ " scale. (see -help-dpi-device for details).\n\n"
+
+ " * finally, if <scale> is the keyword 'auto', the emulator tries to guess\n"
+ " your monitor's resolution and automatically adjusts its window\n"
+ " accordingly\n\n"
+
+ " NOTE: this process is *very* unreliable, depending on your OS, video\n"
+ " driver issues and other random system parameters\n\n"
+
+ " the emulator's scale can be changed anytime at runtime through the control\n"
+ " console. see the help for the 'window scale' command for details\n\n" );
+}
+
+static void
+help_trace(stralloc_t* out)
+{
+ PRINTF(
+ " use '-trace <name>' to start the emulator with runtime code profiling support\n"
+ " profiling itself will not be enabled unless you press F9 to activate it, or\n"
+ " the executed code turns it on programmatically.\n\n"
+
+ " trace information is stored in directory <name>, several files are created\n"
+ " there, that can later be used with the 'traceview' program that comes with\n"
+ " the Android SDK for analysis.\n\n"
+
+ " note that execution will be slightly slower when enabling code profiling,\n"
+ " this is a necessary requirement of the operations being performed to record\n"
+ " the execution trace. this slowdown should not affect your system until you\n"
+ " enable the profiling though...\n\n"
+ );
+}
+
+static void
+help_show_kernel(stralloc_t* out)
+{
+ PRINTF(
+ " use '-show-kernel' to redirect debug messages from the kernel to the current\n"
+ " terminal. this is useful to check that the boot process works correctly.\n\n"
+ );
+}
+
+static void
+help_shell(stralloc_t* out)
+{
+ PRINTF(
+ " use '-shell' to create a root shell console on the current terminal.\n"
+ " this is unlike the 'adb shell' command for the following reasons:\n\n"
+
+ " * this is a *root* shell that allows you to modify many parts of the system\n"
+ " * this works even if the ADB daemon in the emulated system is broken\n"
+ " * pressing Ctrl-C will stop the emulator, instead of the shell.\n\n"
+ " See also '-shell-serial'.\n\n" );
+}
+
+static void
+help_shell_serial(stralloc_t* out)
+{
+ PRINTF(
+ " use '-shell-serial <device>' instead of '-shell' to open a root shell\n"
+ " to the emulated system, while specifying an external communication\n"
+ " channel / host device.\n\n"
+
+ " '-shell-serial stdio' is identical to '-shell', while you can use\n"
+ " '-shell-serial tcp::4444,server,nowait' to talk to the shell over local\n"
+ " TCP port 4444. '-shell-serial fdpair:3:6' would let a parent process\n"
+ " talk to the shell using fds 3 and 6.\n\n"
+
+ " see -help-char-devices for a list of available <device> specifications.\n\n"
+ " NOTE: you can have only one shell per emulator instance at the moment\n\n"
+ );
+}
+
+static void
+help_logcat(stralloc_t* out)
+{
+ PRINTF(
+ " use '-logcat <tags>' to redirect log messages from the emulated system to\n"
+ " the current terminal. <tags> is a list of space/comma-separated log filters\n"
+ " where each filter has the following format:\n\n"
+
+ " <componentName>:<logLevel>\n\n"
+
+ " where <componentName> is either '*' or the name of a given component,\n"
+ " and <logLevel> is one of the following letters:\n\n"
+
+ " v verbose level\n"
+ " d debug level\n"
+ " i informative log level\n"
+ " w warning log level\n"
+ " e error log level\n"
+ " s silent log level\n\n"
+
+ " for example, the following only displays messages from the 'GSM' component\n"
+ " that are at least at the informative level:\n\n"
+
+ " -logcat '*:s GSM:i'\n\n"
+
+ " if '-logcat <tags>' is not used, the emulator looks for ANDROID_LOG_TAGS\n"
+ " in the environment. if it is defined, its value must match the <tags>\n"
+ " format and will be used to redirect log messages to the terminal.\n\n"
+
+ " note that this doesn't prevent you from redirecting the same, or other,\n"
+ " log messages through the ADB or DDMS tools too.\n\n");
+}
+
+static void
+help_noaudio(stralloc_t* out)
+{
+ PRINTF(
+ " use '-noaudio' to disable all audio support in the emulator. this may be\n"
+ " unfortunately be necessary in some cases:\n\n"
+
+ " * at least two users have reported that their Windows machine rebooted\n"
+ " instantly unless they used this option when starting the emulator.\n"
+ " it is very likely that the problem comes from buggy audio drivers.\n\n"
+
+ " * on some Linux machines, the emulator might get stuck at startup with\n"
+ " audio support enabled. this problem is hard to reproduce, but seems to\n"
+ " be related too to flaky ALSA / audio driver support.\n\n"
+
+ " on Linux, another option is to try to change the default audio backend\n"
+ " used by the emulator. you can do that by setting the QEMU_AUDIO_DRV\n"
+ " environment variables to one of the following values:\n\n"
+
+ " alsa (use the ALSA backend)\n"
+ " esd (use the EsounD backend)\n"
+ " sdl (use the SDL audio backend, no audio input supported)\n"
+ " oss (use the OSS backend)\n"
+ " none (do not support audio)\n"
+ "\n"
+ " the very brave can also try to use distinct backends for audio input\n"
+ " and audio outputs, this is possible by selecting one of the above values\n"
+ " into the QEMU_AUDIO_OUT_DRV and QEMU_AUDIO_IN_DRV environment variables.\n\n"
+ );
+}
+
+static void
+help_raw_keys(stralloc_t* out)
+{
+ PRINTF(
+ " this option is deprecated because one can do the same using Ctrl-K\n"
+ " at runtime (this keypress toggles between unicode/raw keyboard modes)\n\n"
+
+ " by default, the emulator tries to reverse-map the characters you type on\n"
+ " your keyboard to device-specific key presses whenever possible. this is\n"
+ " done to make the emulator usable with a non-QWERTY keyboard.\n\n"
+
+ " however, this also means that single keypresses like Shift or Alt are not\n"
+ " passed to the emulated device. the '-raw-keys' option disables the reverse\n"
+ " mapping. it should only be used when using a QWERTY keyboard on your machine\n"
+
+ " (should only be useful to Android system hackers, e.g. when implementing a\n"
+ " new input method).\n\n"
+ );
+}
+
+static void
+help_radio(stralloc_t* out)
+{
+ PRINTF(
+ " use '-radio <device>' to redirect the GSM modem emulation to an external\n"
+ " character device or program. this bypasses the emulator's internal modem\n"
+ " and should only be used for testing.\n\n"
+
+ " see '-help-char-devices' for the format of <device>\n\n"
+
+ " the data exchanged with the external device/program are GSM AT commands\n\n"
+
+ " note that, when running in the emulator, the Android GSM stack only supports\n"
+ " a *very* basic subset of the GSM protocol. trying to link the emulator to\n"
+ " a real GSM modem is very likely to not work properly.\n\n"
+ );
+}
+
+
+static void
+help_port(stralloc_t* out)
+{
+ PRINTF(
+ " at startup, the emulator tries to bind its control console at a free port\n"
+ " starting from 5554, in increments of two (i.e. 5554, then 5556, 5558, etc..)\n"
+ " this allows several emulator instances to run concurrently on the same\n"
+ " machine, each one using a different console port number.\n\n"
+
+ " use '-port <port>' to force an emulator instance to use a given console port\n\n"
+
+ " note that <port> must be an *even* integer between 5554 and 5584 included.\n"
+ " <port>+1 must also be free and will be reserved for ADB. if any of these\n"
+ " ports is already used, the emulator will fail to start.\n\n" );
+}
+
+static void
+help_onion(stralloc_t* out)
+{
+ PRINTF(
+ " use '-onion <file>' to specify a PNG image file that will be displayed on\n"
+ " top of the emulated framebuffer with translucency. this can be useful to\n"
+ " check that UI elements are correctly positioned with regards to a reference\n"
+ " graphics specification.\n\n"
+
+ " the default translucency is 50%%, but you can use '-onion-alpha <%%age>' to\n"
+ " select a different one, or even use keypresses at runtime to alter it\n"
+ " (see -help-keys for details)\n\n"
+
+ " finally, the onion image can be rotated (see -help-onion-rotate)\n\n"
+ );
+}
+
+static void
+help_onion_alpha(stralloc_t* out)
+{
+ PRINTF(
+ " use '-onion-alpha <percent>' to change the translucency level of the onion\n"
+ " image that is going to be displayed on top of the framebuffer (see also\n"
+ " -help-onion). the default is 50%%.\n\n"
+
+ " <percent> must be an integer between 0 and 100.\n\n"
+
+ " you can also change the translucency dynamically (see -help-keys)\n\n"
+ );
+}
+
+static void
+help_onion_rotation(stralloc_t* out)
+{
+ PRINTF(
+ " use '-onion-rotation <rotation>' to change the rotation of the onion\n"
+ " image loaded through '-onion <file>'. valid values for <rotation> are:\n\n"
+
+ " 0 no rotation\n"
+ " 1 90 degrees clockwise\n"
+ " 2 180 degrees\n"
+ " 3 270 degrees clockwise\n\n"
+ );
+}
+
+
+static void
+help_timezone(stralloc_t* out)
+{
+ PRINTF(
+ " by default, the emulator tries to detect your current timezone to report\n"
+ " it to the emulated system. use the '-timezone <timezone>' option to choose\n"
+ " a different timezone, or if the automatic detection doesn't work correctly.\n\n"
+
+ " VERY IMPORTANT NOTE:\n\n"
+ " the <timezone> value must be in zoneinfo format, i.e. it should look like\n"
+ " Area/Location or even Area/SubArea/Location. valid examples are:\n\n"
+
+ " America/Los_Angeles\n"
+ " Europe/Paris\n\n"
+
+ " using a human-friendly abbreviation like 'PST' or 'CET' will not work, as\n"
+ " well as using values that are not defined by the zoneinfo database.\n\n"
+
+ " NOTE: unfortunately, this will not work on M5 and older SDK releases\n\n"
+ );
+}
+
+
+static void
+help_dns_server(stralloc_t* out)
+{
+ PRINTF(
+ " by default, the emulator tries to detect the DNS servers you're using and\n"
+ " will setup special aliases in the emulated firewall network to allow the\n"
+ " Android system to connect directly to them. use '-dns-server <servers>' to\n"
+ " select a different list of DNS servers to be used.\n\n"
+
+ " <servers> must be a comma-separated list of up to 4 DNS server names or\n"
+ " IP addresses.\n\n"
+
+ " NOTE: on M5 and older SDK releases, only the first server in the list will\n"
+ " be used.\n\n"
+ );
+}
+
+
+static void
+help_cpu_delay(stralloc_t* out)
+{
+ PRINTF(
+ " this option is purely experimental, probably doesn't work as you would\n"
+ " expect, and may even disappear in a later emulator release.\n\n"
+
+ " use '-cpu-delay <delay>' to throttle CPU emulation. this may be useful\n"
+ " to detect weird race conditions that only happen on 'lower' CPUs. note\n"
+ " that <delay> is a unit-less integer that doesn't even scale linearly\n"
+ " to observable slowdowns. use trial and error to find something that\n"
+ " suits you, the 'correct' machine is very probably dependent on your\n"
+ " host CPU and memory anyway...\n\n"
+ );
+}
+
+
+static void
+help_no_boot_anim(stralloc_t* out)
+{
+ PRINTF(
+ " use '-no-boot-anim' to disable the boot animation (red bouncing ball) when\n"
+ " starting the emulator. on slow machines, this can surprisingly speed up the\n"
+ " boot sequence in tremendous ways.\n\n"
+
+ " NOTE: unfortunately, this will not work on M5 and older SDK releases\n\n"
+ );
+}
+
+
+static void
+help_gps(stralloc_t* out)
+{
+ PRINTF(
+ " use '-gps <device>' to emulate an NMEA-compatible GPS unit connected to\n"
+ " an external character device or socket. the format of <device> is the same\n"
+ " than the one used for '-radio <device>' (see -help-char-devices for details)\n\n"
+ );
+}
+
+
+static void
+help_keyset(stralloc_t* out)
+{
+ char temp[256];
+
+ PRINTF(
+ " use '-keyset <name>' to specify a different keyset file name to use when\n"
+ " starting the emulator. a keyset file contains a list of key bindings used\n"
+ " to control the emulator with the host keyboard.\n\n"
+
+ " by default, the emulator looks for the following file:\n\n"
+ );
+
+ bufprint_config_file(temp, temp+sizeof(temp), KEYSET_FILE);
+ PRINTF(
+ " %s\n\n", temp );
+
+ bufprint_config_path(temp, temp+sizeof(temp));
+ PRINTF(
+ " however, if -keyset is used, then the emulator does the following:\n\n"
+ " - first, if <name> doesn't have an extension, then the '.keyset' suffix\n"
+ " is appended to it (e.g. \"foo\" => \"foo.keyset\"),\n\n"
+
+ " - then, the emulator searches for a file named <name> in the following\n"
+ " directories:\n\n"
+
+ " * the emulator configuration directory: %s\n"
+ " * the 'keysets' subdirectory of <systemdir>, if any\n"
+ " * the 'keysets' subdirectory of the program location, if any\n\n",
+ temp );
+
+ PRINTF(
+ " if no corresponding file is found, a default set of key bindings is used.\n\n"
+ " use '-help-keys' to list the default key bindings.\n"
+ " use '-help-keyset-file' to learn more about the format of keyset files.\n"
+ "\n"
+ );
+}
+
+static void
+help_old_system(stralloc_t* out)
+{
+ PRINTF(
+ " use '-old-system' if you want to use a recent emulator binary to run\n"
+ " an old version of the Android SDK system images. Here, 'old' means anything\n"
+ " older than version 1.4 of the emulator.\n\n"
+
+ " NOTE: using '-old-system' with recent system images is likely to not work\n"
+ " properly, though you may not notice it immediately (e.g. failure to\n"
+ " start the emulated GPS hardware)\n\n"
+ );
+}
+
+#ifdef CONFIG_NAND_LIMITS
+static void
+help_nand_limits(stralloc_t* out)
+{
+ PRINTF(
+ " use '-nand-limits <limits>' to enable a debugging feature that sends a\n"
+ " signal to an external process once a read and/or write limit is achieved\n"
+ " in the emulated system. the format of <limits> is the following:\n\n"
+
+ " pid=<number>,signal=<number>,[reads=<threshold>][,writes=<threshold>]\n\n"
+
+ " where 'pid' is the target process identifier, 'signal' the number of the\n"
+ " target signal. the read and/or write threshold'reads' are a number optionally\n"
+ " followed by a K, M or G suffix, corresponding to the number of bytes to be\n"
+ " read or written before the signal is sent.\n\n"
+ );
+}
+#endif /* CONFIG_NAND_LIMITS */
+
+#define help_noskin NULL
+#define help_netspeed help_shaper
+#define help_netdelay help_shaper
+#define help_netfast help_shaper
+
+#define help_nojni NULL
+#define help_no_window NULL
+#define help_version NULL
+
+
+typedef struct {
+ const char* name;
+ const char* template;
+ const char* descr;
+ void (*func)(stralloc_t*);
+} OptionHelp;
+
+static const OptionHelp option_help[] = {
+#define OPT_FLAG(_name,_descr) { STRINGIFY(_name), NULL, _descr, help_##_name },
+#define OPT_PARAM(_name,_template,_descr) { STRINGIFY(_name), _template, _descr, help_##_name },
+#include "android_options.h"
+ { NULL, NULL, NULL, NULL }
+};
+
+typedef struct {
+ const char* name;
+ const char* desc;
+ void (*func)(stralloc_t*);
+} TopicHelp;
+
+
+static const TopicHelp topic_help[] = {
+ { "disk-images", "about disk images", help_disk_images },
+ { "keys", "supported key bindings", help_keys },
+ { "debug-tags", "debug tags for -debug <tags>", help_debug_tags },
+ { "char-devices", "character <device> specification", help_char_devices },
+ { "environment", "environment variables", help_environment },
+ { "keyset-file", "key bindings configuration file", help_keyset_file },
+ { NULL, NULL, NULL }
+};
+
+int
+android_help_for_option( const char* option, stralloc_t* out )
+{
+ OptionHelp const* oo;
+ char temp[32];
+
+ /* the names in the option_help table use underscore instead
+ * of dashes, so create a tranlated copy of the option name
+ * before scanning the table for matches
+ */
+ pstrcpy(temp, sizeof temp, option);
+ buffer_translate_char( temp, sizeof temp, '-', '_' );
+
+ for ( oo = option_help; oo->name != NULL; oo++ ) {
+ if ( !strcmp(oo->name, temp) ) {
+ if (oo->func)
+ oo->func(out);
+ else
+ stralloc_add_str(out, oo->descr);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+int
+android_help_for_topic( const char* topic, stralloc_t* out )
+{
+ const TopicHelp* tt;
+
+ for ( tt = topic_help; tt->name != NULL; tt++ ) {
+ if ( !strcmp(tt->name, topic) ) {
+ tt->func(out);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+extern void
+android_help_list_options( stralloc_t* out )
+{
+ const OptionHelp* oo;
+ const TopicHelp* tt;
+ int maxwidth = 0;
+
+ for ( oo = option_help; oo->name != NULL; oo++ ) {
+ int width = strlen(oo->name);
+ if (oo->template != NULL)
+ width += strlen(oo->template);
+ if (width > maxwidth)
+ maxwidth = width;
+ }
+
+ for (oo = option_help; oo->name != NULL; oo++) {
+ char temp[32];
+ /* the names in the option_help table use underscores instead
+ * of dashes, so create a translated copy of the option's name
+ */
+ pstrcpy(temp, sizeof temp, oo->name);
+ buffer_translate_char(temp, sizeof temp, '_', '-');
+
+ stralloc_add_format( out, " -%s %-*s %s\n",
+ temp,
+ (int)(maxwidth - strlen(oo->name)),
+ oo->template ? oo->template : "",
+ oo->descr );
+ }
+
+ PRINTF( "\n" );
+ PRINTF( " %-*s %s\n", maxwidth, "-qemu args...", "pass arguments to qemu");
+ PRINTF( " %-*s %s\n", maxwidth, "-qemu -h", "display qemu help");
+ PRINTF( "\n" );
+ PRINTF( " %-*s %s\n", maxwidth, "-verbose", "same as '-debug-init'");
+ PRINTF( " %-*s %s\n", maxwidth, "-debug <tags>", "enable/disable debug messages");
+ PRINTF( " %-*s %s\n", maxwidth, "-debug-<tag>", "enable specific debug messages");
+ PRINTF( " %-*s %s\n", maxwidth, "-debug-no-<tag>","disable specific debug messages");
+ PRINTF( "\n" );
+ PRINTF( " %-*s %s\n", maxwidth, "-help", "print this help");
+ PRINTF( " %-*s %s\n", maxwidth, "-help-<option>", "print option-specific help");
+ PRINTF( "\n" );
+
+ for (tt = topic_help; tt->name != NULL; tt += 1) {
+ char help[32];
+ snprintf(help, sizeof(help), "-help-%s", tt->name);
+ PRINTF( " %-*s %s\n", maxwidth, help, tt->desc );
+ }
+ PRINTF( " %-*s %s\n", maxwidth, "-help-all", "prints all help content");
+ PRINTF( "\n");
+}
+
+
+void
+android_help_main( stralloc_t* out )
+{
+ stralloc_add_str(out, "Android Emulator usage: emulator [options] [-qemu args]\n");
+ stralloc_add_str(out, " options:\n" );
+
+ android_help_list_options(out);
+
+ /*printf( "%.*s", out->n, out->s );*/
+}
+
+
+void
+android_help_all( stralloc_t* out )
+{
+ const OptionHelp* oo;
+ const TopicHelp* tt;
+
+ for (oo = option_help; oo->name != NULL; oo++) {
+ PRINTF( "========= help for option -%s:\n\n", oo->name );
+ android_help_for_option( oo->name, out );
+ }
+
+ for (tt = topic_help; tt->name != NULL; tt++) {
+ PRINTF( "========= help for -help-%s\n\n", tt->name );
+ android_help_for_topic( tt->name, out );
+ }
+ PRINTF( "========= top-level help\n\n" );
+ android_help_main(out);
+}
diff --git a/android_help.h b/android_help.h
new file mode 100644
index 0000000..30c907b
--- /dev/null
+++ b/android_help.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_HELP_H
+#define _ANDROID_HELP_H
+
+#include "android_utils.h"
+
+/* appends the list of options with a small description to a dynamic string */
+extern void android_help_list_options( stralloc_t* out );
+
+/* output main help screen into a single dynamic string */
+extern void android_help_main( stralloc_t* out );
+
+/* output all help into a single dynamic string */
+extern void android_help_all( stralloc_t* out );
+
+/* appends the help for a given command-line option into a dynamic string
+ * returns 0 on success, or -1 on error (i.e. unknown option)
+ */
+extern int android_help_for_option( const char* option, stralloc_t* out );
+
+/* appends the help for a given help topic into a dynamic string
+ * returns 0 on success, or -1 on error (i.e. unknown topic)
+ */
+extern int android_help_for_topic( const char* topic, stralloc_t* out );
+
+#endif /* _ANDROID_HELP_H */
diff --git a/android_icons.h b/android_icons.h
new file mode 100644
index 0000000..e4ec861
--- /dev/null
+++ b/android_icons.h
@@ -0,0 +1,984 @@
+/* Copyright (C) 2007 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+/* automatically generated, do not touch */
+
+static const unsigned char _data_android_icon_16_png[460] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 16, 0, 0, 0, 16, 8, 6, 0, 0, 0, 31,243,255,
+ 97, 0, 0, 1,147, 73, 68, 65, 84, 56,141,173, 82, 77, 75, 66,
+ 65, 20, 61, 79,173,199,148,125, 64,209, 35,112, 97,145, 84,219,
+ 30,210, 7,173,162, 64,168, 77,235, 8,132, 86,110,251, 39,109,
+ 94,109, 10,177, 40,104, 47, 73, 59,169, 80,136, 90, 68,144,182,
+ 8, 18,162, 44, 42,165,184,111, 20,229,182,200, 39,126,188,146,
+ 160, 3, 3,119,152,115,207, 61, 51,115,192,204,104, 92, 68, 82,
+ 39,146, 61, 53,123, 65, 36,167,237,184,182,205,145,228, 12,231,
+ 62, 94,152, 72,222, 17,201,251,143,207, 28, 71,146, 51,108, 39,
+ 226, 66, 51, 2,139,227,135, 56, 78,175, 65,150,222,134,152,203,
+ 80, 93,189, 8,140, 70, 0, 32, 0, 32, 81,199,110,152, 62,250,
+ 244,126,203,225,196, 36, 19, 73, 54,226, 94, 54,226, 94, 38,146,
+ 188,115, 54,193, 15,175, 87, 77, 46, 28,150,144,105, 22,102, 1,
+ 132, 82,217, 61, 80, 49,139,240,249, 88,117, 72,248,124, 12,178,
+ 244,134,235,199,109, 0, 8,153,102, 97,193, 58, 83,152, 25,166,
+ 89,152,205,126, 94,156,104,110,221,230, 70, 63, 98, 73, 8, 53,
+ 106,189, 65, 40,253,124,128,163,155, 21, 4,253,169,186,233,181,
+ 8,250, 83,216,191,244, 99,160, 75,199,188,111, 43, 4, 32,234,
+ 176,101,254, 1,255, 38, 80, 86,224,132,162, 56, 91, 54, 40,138,
+ 3,202,119, 91, 25, 64, 53, 7,155,186,103,125,117,164,127,185,
+ 165,192,156,207, 64,103,155, 6, 0,155, 85, 7, 66,168,137,142,
+ 118,205, 51,216, 61,181,209, 74, 64,115,235,187,110,213, 51, 44,
+ 132, 26, 3,208, 28, 36, 34,105,228,205, 12, 27,113, 47,231,205,
+ 12,215,214, 68, 50,242, 99,144, 42, 78,210, 0,162,191, 24,136,
+ 9,161,214, 69,217,238, 23, 46, 74, 69, 7,134,251,150, 80,144,
+ 69, 0,168,173, 19,141,100,133,153,155, 20,172, 88,163,242, 80,
+ 86, 45,132,122,218,200,253, 2, 34,145, 32,131,249,218,106,138,
+ 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+#ifdef CONFIG_DARWIN
+static const unsigned char _data_android_icon_256_png[13369] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 1, 0, 0, 0, 1, 0, 8, 6, 0, 0, 0, 92,114,168,
+ 102, 0, 0, 32, 0, 73, 68, 65, 84,120,156,237,157,119,124, 84,
+ 85,222,255, 63, 51,119,122, 50,105, 36,164,144, 10, 36, 4,144,
+ 162, 16, 69, 17, 68, 4, 17, 69,220, 93, 5,101,125,118,117,197,
+ 125, 22,244,121, 30, 93, 86,244,167,235,174,143,186,174,171,176,
+ 214, 69,121,118,215,222,176, 23,176, 32,138, 65,164, 8, 2, 73,
+ 32, 16,106,122, 47,147, 73,153,126,231,254,254,184,153,100,106,
+ 114,238,100,250, 61,239,215,107, 94, 19,134,115,238, 57,183,124,
+ 63,247,123,234, 87,194,113, 28, 40, 20,138, 56,145,134,187, 2,
+ 20, 10, 37,124, 80, 1,160, 80, 68,140, 44,208, 7, 52, 26,205,
+ 129, 62,100,196,163,209,168, 36,129, 56,142,193, 96, 18, 85,123,
+ 140, 94, 55,255, 81,171,149, 1, 57,142, 36,208,125, 0, 98, 18,
+ 128, 97, 30, 96, 41,120,113,101, 6,190, 37, 0,216,129,143, 13,
+ 128, 29, 0, 55,240,241, 74,172, 62,212,195, 92, 51, 9,134,174,
+ 23, 51,240,225,192, 95, 47,199,181,115, 92, 55,175,196,234, 53,
+ 243, 70,160, 4,128, 54, 1,252, 64,163, 81, 73,188, 60,200, 12,
+ 0, 21,128,132, 39,159,220, 48,169,186,186,230,209,174, 46,221,
+ 238,254,126, 67,131,193, 96,234,236,233,233, 61,209,210,210,250,
+ 246,161, 67,135, 86, 1, 72, 4,160, 1, 32, 7,127, 15, 36, 3,
+ 31,151, 50, 66,112, 42, 33,197,203, 57, 73,193, 95, 3, 13,128,
+ 196, 67,135, 14,173,106,105,105,125,187,167,167,247,132,193, 96,
+ 234,236,239, 55, 52,116,117,233,118, 87, 87,215, 60,250,228,147,
+ 27,138, 0, 36, 0, 80,131,191,214, 94,175, 89, 44, 94,183, 96,
+ 66, 61, 0,129,120,121,192, 36,224,223, 90,154,150,150,214,151,
+ 180,218,132,107, 36, 18,201, 72,242,204,153,205,166,170,147, 39,
+ 79, 62, 60,103,206, 69,219, 0, 88,192,191,225, 6,255,223,241,
+ 71,172,188,213,220,174,155, 4,188,241, 43,203,202,202, 87,228,
+ 231, 23, 60,160, 80, 40, 38,194,205,160,221,225, 56,206,220,219,
+ 219,243,121, 70, 70,250,237, 0, 12,224,189, 3,199,245,113,185,
+ 78,177,114,221,124, 65,155, 0, 97,192,199, 27, 76,249,209, 71,
+ 31, 95,176,120,241,226, 15, 25, 70, 54, 86,232, 49,219,219,219,
+ 62,202,203,203, 93, 13,192, 8, 31, 15,116,180, 63,204, 94,140,
+ 159, 1,160,105,110,110,125, 45, 49, 49,241, 58,161,199,179, 90,
+ 45,237, 95,127,189,253,250, 21, 43, 86, 28, 6, 96,198, 80,115,
+ 74, 52, 34, 64, 5, 32, 12,184, 61,200, 82, 0,170,250,250,134,
+ 39,198,140, 73, 93,139, 81, 52,167,140, 70, 99,237,152, 49,201,
+ 179, 0,244,129, 23, 1,192,237,129,142,214,135,217,139,241,203,
+ 0,196,245,244,244,150,203,100,242, 28,255,143,204,217, 91, 90,
+ 90,254, 57,126,124,193,122, 0, 38,120, 17,129,104,189,102, 36,
+ 208, 62,128, 16,227,229, 65,150,151,151, 87,220, 54,102, 76,234,
+ 157, 24,229,117, 84,171,213,121,157,157, 93, 21, 0,226,192,191,
+ 29, 29,101, 12,150, 25,141,109, 91, 31,111,126,245,232,141, 31,
+ 0, 36,210,140,140,204, 53,223,125, 87,122, 39, 0, 5,134,174,
+ 87, 84, 95,179, 80, 67, 5, 64, 56,142,246,107,220,196,137,133,
+ 79, 4,234,160,106,181, 38,235,228,201, 83,239, 98,168,147,203,
+ 81, 86, 44, 60,196,131,109,254,166,166,230,215, 71,111,252, 67,
+ 204,158, 61,251, 97, 0,169,112,125,150, 99,225,154,133, 4, 42,
+ 0,194,145, 0, 80,233,116,221,223, 75, 36, 18,117, 32, 15,156,
+ 147,147,187,232,163,143, 62, 94, 13,222, 77,246,120,160,163,233,
+ 141,230, 84, 87,199, 55,115,224,192,193, 27,147,146,146,151, 7,
+ 178, 28,134,145, 41,155,155, 91,118,130, 31,129,113,140,168, 80,
+ 8,161, 2, 32, 28,201,182,109,159,207, 82, 42, 85, 83,130,113,
+ 240,203, 47,191,252,127,193,191,209,124, 14,117, 5,163,220, 64,
+ 226, 99,136, 52,110,242,228, 41, 27,131, 81, 94, 98, 98,210,132,
+ 135, 31,126,100, 41,232,243, 44,152,128,207, 4, 20,202,171, 7,
+ 139,195, 93, 5, 33, 72, 0,200,166, 79,159,113,115,176, 10, 80,
+ 42, 85,218,234,234,154,207, 10, 10,242, 47, 7, 63,212,229, 49,
+ 60, 24, 69,215,204,225,250,171,218,219, 59,183, 49, 12,147, 20,
+ 172,130, 22, 45, 90,180,234,161,135,254,188, 29,124, 71,170, 3,
+ 46,210,175,213,173, 37, 85, 97, 45,159, 42,166,112,100, 90,109,
+ 252,165,193, 44, 32, 61, 61, 99,198, 7, 31,124,176, 22, 67,179,
+ 8, 93, 58,184,238,184,172, 38, 98,189, 0,167,186, 57,234, 43,
+ 59,120,240,167,155,227,226,226, 46, 14,102,185,121,121,249, 51,
+ 192, 79,176,138,216,107, 19,137, 80, 1, 16,142, 76,161, 80, 20,
+ 144, 36,236,232,175,192, 87, 85,191,194, 7, 21,139,112,164,241,
+ 121, 65,133, 44, 92,184,232,255,129,111, 10, 56, 68,192,133, 72,
+ 20, 1, 47,117,146, 2,136, 47, 46, 46,126, 92,200,113, 14, 53,
+ 60,133, 15, 42, 22,225,171,170, 95,161,163,191,130, 40, 79, 66,
+ 66, 66, 38,128,160,121, 24,177, 74,216,155, 0,209,128,243, 91,
+ 237, 79,127,250, 83,186, 68, 34, 85,141,148,135,181,155,240,205,
+ 169, 53, 48,217,186, 0, 0,229, 77,155, 96,231,172,152,149,189,
+ 142,168, 76,149, 74,165,173,174,174,249,180, 96,168, 41,224, 60,
+ 166,205, 57,234,245,194,174,252,193,223, 67, 45, 10,195,148,237,
+ 236,250,127,198, 48, 50, 98,195, 60,212,240, 20,142, 54,255, 19,
+ 0,208,103,110,192, 55,167,214, 96,197,140,157, 96, 70,184,228,
+ 50,153, 76,185, 96,193,130,156,210,210,210, 42, 56,205, 7,112,
+ 191, 70, 20, 87,168, 0, 8, 67,114,227,141, 55, 93, 78,146, 80,
+ 111,170, 30, 52,126, 7,199, 90, 94, 66,110,210, 66,164,197,207,
+ 36, 42,204,209, 20,184,225,134, 27,158, 3,255, 64,219,157,254,
+ 123,240, 1,119,175,163,151,127, 15,247,113, 28,203,125, 34,141,
+ 163, 60, 95,198,195,249, 16, 28,191, 93,255,246,190, 50, 28,107,
+ 121,201,229, 55,147,173, 11,122, 83, 53, 82, 52,147, 71,204,127,
+ 235,173,183, 94, 90, 90, 90,186, 19,174,253, 38,148, 97,160, 2,
+ 32, 12,238,221,119,183,124,119,255,253,127, 28, 49, 97,162,170,
+ 0, 10, 70, 11, 11,219, 59,148,153, 99,241, 67,245,253,184,238,
+ 188,207, 32,149,200,137, 10, 28,104, 10,188, 13,160, 13, 67, 43,
+ 9, 1,222,200, 56,167,191, 25,240,111, 93, 41,134, 86,211, 73,
+ 211,210,210,228,159,127,254,197, 34,133, 66,145,234, 56,102,124,
+ 124,124,102, 92, 92,156, 75,239, 88,127,127,127, 85, 95, 95, 95,
+ 179,227,223, 70,163,177, 99,249,242,107,191,109,111,111,183, 12,
+ 148,105,135,235,170, 60,111, 43, 26, 7,135,252, 0,104, 39, 77,
+ 34,119,253,237,156, 21, 63, 84,223, 15,142,115,181, 93, 5,163,
+ 69,162,138,168,197,133,205,155,255,239, 16, 0, 37,248,181, 21,
+ 20, 2,168, 0, 8,131,123,244,209, 71,219,238,187,239,126,147,
+ 84, 58,188, 79,202, 72, 85,152,157,179, 30,123,107,254,236,242,
+ 187,222, 84,141,195, 13,207, 96,118,206,122,162, 2, 85, 42,149,
+ 246,220,185,234, 79,198,143, 47,184, 2,124, 83, 96,176, 8,167,
+ 143,124,223,190,125, 87,101,103,231, 92,166, 80, 40,115,149, 74,
+ 197, 68,153, 76,150, 42,145, 72, 53, 18,137,132,232, 30, 39, 38,
+ 38,121,204,201,175,173,173, 7,199,113, 54,187,221,110, 96, 89,
+ 91,135,201,100, 58,107, 54,155,235,154,154, 26, 75, 47,190,248,
+ 226,237, 0,172,224, 69,201,177,100, 23,224, 69, 64,221,214,214,
+ 254,153, 76, 70,238,250, 31,110,120, 6,122, 83,181,199,239,179,
+ 115,214,143,232,254, 3,128,213,106,181,236,223,191, 79, 7,126,
+ 77, 5,133, 16, 42, 0,194,177, 89,173,150,106,165, 82, 53,162,
+ 79, 90,148,182, 18, 53, 93, 95,161,169,103,175,203,239,149,173,
+ 175, 34, 47,121, 49,113, 83, 32, 35, 35,115,198,150, 45,239,174,
+ 189,233,166, 27,255, 9, 0,119,223,253,251,180,223,253,238,119,
+ 191, 76, 77, 77, 93,160, 84,170,138,101, 50, 89, 50,130,212,251,
+ 45,145, 72,100, 12,195, 36, 48, 12,147,160, 80, 40,199, 3, 64,
+ 90,218,216,213, 6,131,137,179,217,108, 58,179,217, 84,213,209,
+ 209, 81,250,210, 75,255,126,107,227,198,141,109, 0,240,195, 15,
+ 123,110,140,143,215,206, 33, 45,163,189,175, 12,149,173,175,122,
+ 252,158,149,112, 9,138,210, 86, 18, 29, 67,175,215, 55,129, 31,
+ 2,180,143,148,150, 50, 68,216, 23, 3, 69,250, 56, 45,224, 49,
+ 180,165,172,169,169,125,110,236,216,244,219, 73,242,246, 91,154,
+ 241,201,209,107, 96,181, 27, 92,126, 79, 84, 21, 8,106, 10, 24,
+ 141,134, 62,171,213,218, 28, 23, 23,159,195, 48,204,200,175,196,
+ 48,192,178,172,201,100, 50,214,202,229,138, 12,133, 66,145, 72,
+ 146,199,206, 89,241,233,177,229, 30,111,127,185, 84,131,159, 77,
+ 251, 28,113,138, 76,162,178, 15, 30, 60,240,217,101,151,205,255,
+ 127, 0,206,194,181,137,130, 72,238, 4,244,119, 30, 0, 93, 12,
+ 20, 62,216,159,126, 58,248, 14,105,226, 56, 69, 38, 46,204,125,
+ 192,227,119, 71, 83,128, 20,181, 90, 19,159,144,144, 88, 24,169,
+ 198, 15, 0, 12,195,168,226,226,226, 39,145, 26, 63,224,219,245,
+ 191, 48,247, 1, 98,227, 7,128, 45, 91,222,249, 26, 64, 15,113,
+ 6, 10, 0, 42, 0, 68,184,189, 65,236, 55,220,112,195, 97,163,
+ 209,120,134, 52,127, 97,218, 13,200, 74,184,196,227,247,202,214,
+ 87,209,222, 87, 22,136, 42, 70, 37, 29,253, 21, 62, 93,255,194,
+ 180, 27,136,143,211,213,213, 89,255,226,139, 47, 86, 1,112,244,
+ 184, 14,222,175, 72,126,251, 71, 2, 84, 0,132,195, 1, 48,109,
+ 216,240,228,207,237,118, 59,241,112,211,220,130,199,160, 96,180,
+ 174, 7, 26, 24, 21,176,115,214, 64,215, 49,226,177,115, 86,236,
+ 62,119,159,215, 94,255,185, 5,143, 17, 31,135,101, 89,118,197,
+ 138, 27,238, 7,208, 2,190,247,159, 26,188, 0,168, 0,248, 7,
+ 251,183,191, 61, 94,215,209,209,254, 17,105,134, 56, 69, 38, 74,
+ 114,238,243,248, 93,104, 83, 32, 86,240,229,250,151,228,220, 39,
+ 200,245, 63,118,236,104,233,190,125,251,106, 1,212,130, 26,191,
+ 96,168, 0, 8,195,121,178,140, 37, 63, 63,239,206,254,254,190,
+ 58,210,204,180, 41,192, 19, 40,215,191,179,179,179,249,226,139,
+ 231,252, 29, 64, 3,248, 97, 72,111, 19,154, 40,195, 64, 5,192,
+ 63, 56,240, 15,156, 97,221,186,223, 47,181,219,237,182,145, 50,
+ 56,184,180,224,113, 81, 55, 5, 2,229,250,219,108, 54,246,170,
+ 171,174,188, 7, 64, 35,128,118, 80,195,247, 11, 58, 15, 96,116,
+ 216,222,120,227,141,166,135, 31,126,228,227,140,140,204, 21, 36,
+ 25, 52,138,116,148,228,220,135, 61, 53, 15,186,252, 46,116,130,
+ 144, 16,244,166,106,216,216,161, 97, 72, 51,171, 71,159,185,193,
+ 37, 77,188, 50, 27, 74,102,168,243, 94,198,104,136,103,224, 9,
+ 33, 80,174,255,209,163, 21,223, 87, 86, 86, 54,129,119,253,135,
+ 141, 23, 64,241, 13, 21, 0,255,112,105, 10,140, 31, 95,240, 95,
+ 109,109,237, 23,197,199,107,115, 73, 50, 23,166,221,128, 26,221,
+ 118, 52,234,119,187,252, 46,116,130,144, 51,122, 83, 53,116,198,
+ 83, 48, 88, 90,209,109, 60,131, 94,115, 29, 12,150, 86,175,198,
+ 38,132, 68, 85, 1, 52,138,116,104,149,185, 72, 82, 79,132, 70,
+ 145,142,100,117,145, 95,226, 16, 40,215,191,163,163,189,121,238,
+ 220, 75,158, 2, 80,143,161,157,148,169, 7,224, 7,116, 34,144,
+ 0,188,172,117,119,204,189, 87,172, 88,177, 50,255,229,151, 95,
+ 57,204, 48, 12,145,168, 26, 44,173,248,228,216, 50,151,181, 2,
+ 0,217, 4, 33,214,110, 66, 91, 95, 25,218,251,202,208,214, 95,
+ 134,246,190, 35, 48,219,244,126,157,147,191, 40,101,137, 72,139,
+ 63, 31, 99,227,102, 34, 45,126, 38,198,198,207, 28,118,202,174,
+ 175, 9, 63, 10, 70,139,159,157,183, 13, 26, 69, 58, 81,185, 86,
+ 171,149,189,232,162, 11,127, 83, 85,117,162, 18,192, 25, 12, 77,
+ 67,246, 88,159, 16, 13, 67,128,225,158, 8, 68, 61,128,192,192,
+ 189,255,254,123,157, 15, 61,244,208, 23,227,199, 79, 32,218,243,
+ 78,163, 72,199,133,185, 15,224,135,234,251, 93,126,247,213, 20,
+ 232, 50,156, 64,125,247, 78, 52,232,119, 71, 68,135,161,217,166,
+ 71, 67,119, 41, 26,186, 75, 7,127, 75,139,159,137,236,196,121,
+ 200, 73, 90,232,177,122,111, 56,215,159,212,248, 1,224,208,161,
+ 159,246, 86, 85,157,232, 4,223,241, 23,241, 6, 30,233, 80, 15,
+ 128, 16, 47,235,221, 29, 30,128, 28, 64,252,185,115,213,255, 72,
+ 79,207,184, 65, 34,145, 8,154,147,191,227,212,111, 61,154, 2,
+ 18, 9,131,107, 38,191, 3,169, 68,142,234,174, 47,113,182,243,
+ 83, 24, 44,173,163, 61,133,144,162, 81,164, 99,194,152,235, 80,
+ 144,178, 20, 28,103,199,182, 19, 43, 61, 58,254,198, 37,206,195,
+ 226,162,127, 9, 58, 46,199,113, 56,115,230,244, 87, 51,102, 76,
+ 255, 45,248,185,255,142,168, 74, 94, 87, 40, 70,186, 23, 16,110,
+ 15,128, 10, 0, 1, 94,140, 31, 24, 88,133,119,193, 5, 23,140,
+ 249,230,155,157,187, 84, 42,255,122,204,124, 53, 5, 24,169, 10,
+ 172,221,228, 95,133, 35, 12,111,231, 34,212,245,119,167,183,183,
+ 167,225,150, 91,110, 89,252,213, 87, 95, 54,131,143, 14,228, 24,
+ 6,116, 44, 6,138, 10, 17, 8,183, 0,208, 97,192, 17, 24,198,
+ 248, 85, 71,142,148,221,182,123,247,158, 51,254, 26, 63, 48,212,
+ 20,112, 39, 86,140, 31,240,126, 46, 23,230, 62,224,183,241, 3,
+ 128, 86,155,144,253,254,251, 31, 28,221,187,119,223,111,224, 25,
+ 75,193,249, 59, 34,183, 79,139, 20,168, 0, 12,195, 48,198,175,
+ 169,171,171,223, 60,105, 82,241,243, 18,137, 68, 49,154, 50,186,
+ 12, 39, 80,215,189,115, 52,135,136, 74,234,186,119,162,203,112,
+ 98, 84,199, 96, 24, 70, 54,115,230,249, 79,159, 62,125,102, 51,
+ 248, 8,195,206,155,168, 2, 84, 4, 70,132, 54, 1,124,224,195,
+ 248,101, 0,226, 58, 59,117,223,170,213,234,243, 71,115,252, 46,
+ 195, 9,148, 53,189,128, 58,221,142,209, 28, 38,234,201, 77, 94,
+ 140,153, 89,119, 16,109,249, 53, 28, 61, 61,250,163, 25, 25,233,
+ 87,128,239, 23,176,194,115,123, 51, 0,145,215, 28, 8,119, 19,
+ 128, 10,128, 23,124,116,248,201, 0,104,245,250,222, 50,185, 92,
+ 62,206,223, 99,155,109,122,252,212,176, 1,167,219, 63, 24,109,
+ 53, 99,138,194,180, 27, 48, 59,123, 61,148, 50,226,149,196, 30,
+ 152, 76,198,214,148,148,228, 25,224, 87, 5, 90,225, 58, 65, 40,
+ 34, 69, 32,220, 2, 64,155, 0,110,248, 48,126,121,105,233,174,
+ 43,251,250, 12,213,254, 26, 63,199,177,168,108,121, 5, 31, 86,
+ 44,162,198,239,133,211,237, 31,224,195,138, 69,168,108,121,197,
+ 99,180,128, 20,149, 74,157,222,211,211,123,110,251,246,175,175,
+ 4, 31, 48,212, 57, 84, 24,109, 14,120,129, 10,128, 19,195, 24,
+ 255,226,217,179, 75,182, 72,165,210,120,127,142,171, 55, 85,227,
+ 243, 19,171,112,176,254, 9,143,222,126,202, 16, 22,182, 23, 7,
+ 235,159,192,231, 39, 86,249, 61,131, 81, 38,147,107, 46,185,228,
+ 146, 45, 31,126,248,209,213,160, 34, 48, 34, 84, 0, 6,240,213,
+ 230, 47, 45,221,181,184,164,164,228, 93,169, 84,170,241,231,184,
+ 21, 77,155,241,233,177,229,196, 1, 46, 40,252,148,225, 79,143,
+ 45, 71, 69,211,102,191,242, 51,140, 76,121,229,149, 75,222,252,
+ 248,227, 79,150,130,159,167, 65, 59, 6,125, 64, 5,192, 19,231,
+ 14, 63,237,236,217,179,223,146, 72,164,130,163, 0, 27,173, 29,
+ 248,250,228,109, 56,220,248,140, 40, 86,249, 5, 26, 59,103,197,
+ 225,198,103,176,253,228,173, 48, 90, 59, 4,231,103, 24, 70,177,
+ 112,225,194, 87, 1,140,193, 48, 34, 32,118,168, 0,192,235,155,
+ 128, 1, 16,175,215,247,150, 75,165,110,107,119, 9,104,238,217,
+ 143,207, 42,127,230,177, 27, 48, 69, 56,142,107,217,220,179, 95,
+ 112, 94,185, 92, 17,215,209,209,121, 8,128, 22,158, 67,132, 0,
+ 168, 23, 32,122, 1,240, 17,210, 74,211,213,165,219, 41,151,203,
+ 179,132, 30,239, 68,219, 91,248,250,212,106,191,222, 90, 20,239,
+ 24,173, 29,248,250,212,106,156,104,123, 75,112, 94,141, 38, 46,
+ 173,161,161,105, 23,128, 56,184,134, 92,167, 77, 1,136, 92, 0,
+ 124,197,179,171,173,173,123, 90,165, 82,207, 16,122,188,159,234,
+ 55,224,199,218, 71,253,238,197,166,248,134,227, 88,252, 88,251,
+ 40, 14,214, 63, 33, 56,111, 74, 74, 74,113, 89, 89,249, 11, 0,
+ 84, 24,234, 20,164, 34, 0,145, 11,128, 19,142,155, 47, 63,114,
+ 164,236,214,180,180,177,191, 17,146,217,206, 89,177,235,236, 58,
+ 143,184,118,148,192, 83,217,242, 10,118,157, 93, 39,184, 95,165,
+ 168,104,210,202,175,190,218,190, 22,252,200, 0,237, 15, 24, 64,
+ 180, 2,224,171,221, 95, 84, 52,105,163,144,227,216, 57, 43, 74,
+ 207,174, 67,117,215, 23,129,171, 28,101, 88,170,187,190,192,119,
+ 103,238, 18, 44, 2,115,231, 94,250, 72, 97, 97, 97, 54, 60, 59,
+ 5, 1,136,211, 11, 16,165, 0,120,113,253, 25, 0,113, 58,157,
+ 126,175, 68, 34, 33,158, 98,101,231,172,248,238,204, 93, 1,157,
+ 206, 27,175,204, 70,126,242, 18,140,137,155, 26,176, 99,134,155,
+ 49,113, 83,145,159,188, 4,241,202,236,128, 29,179,190,123, 39,
+ 190, 61,125,135, 32, 17, 96, 24, 70,190,123,247,158, 29,160,253,
+ 1,131,136,125, 67, 16,199,205, 87, 52, 52, 52,254, 67,169, 84,
+ 78, 20,146,249,135,234,251, 81, 31,160,133, 60, 83, 51,126,131,
+ 233,153,107, 60,166,194,158,235,220,134, 3,117,127,245, 8, 53,
+ 30,233,168,100, 41,184, 48,247, 1,140, 31,179,204,229,119,179,
+ 77,143,138,230,205,168,108,121,101,212,101, 52,234,119,227,135,
+ 234,251, 49,127, 60,185,211,150,144,144,144,125,236, 88,229, 43,
+ 231,157, 55,245,102,120,134, 17,143,152, 41,194,161, 66,116, 30,
+ 128, 55,215,255,142, 59,238,200, 74, 78, 78,185, 81,200,113, 14,
+ 214, 63,129,115,157,219, 70, 93, 31,149, 44, 5,215, 76,222,130,
+ 146,156,251,188,206,131, 31, 63,102, 25,126, 62,237, 75,140, 75,
+ 156, 55,234,178, 66,197,184,196,121,248,217,180,109, 30,198, 15,
+ 240, 91,137,149,228,220,135,107, 38,111,129, 74,150, 50,234,178,
+ 206,117,110, 19,220, 49,152,159, 95,112,213,162, 69,139, 39, 99,
+ 168, 41,224,130,152,188, 0,209, 9,128, 19, 14,215, 95,243,216,
+ 99,143,127, 73, 26, 70, 27, 0,142,183,190, 30,144, 55, 24, 0,
+ 44,152,248,236,136,155,128, 42,101,137, 88, 56,241,121, 36, 40,
+ 137,246, 28, 13, 43, 9,202, 92, 44,152,248,236,136,198,157, 22,
+ 63, 19,151, 23, 62, 31,144, 50, 43, 91, 94,193,241,214,215,137,
+ 211, 75,165, 82,230,205, 55,223,124, 15,252,252, 0,175, 77, 1,
+ 177, 32, 42, 1,112,219,212, 19, 0,228,245,245,141,207, 40,149,
+ 202, 9,164,199,104,237, 59,132,159,234, 55, 4,164, 62, 5, 41,
+ 87, 35, 67, 91, 66,148,150,145,170,130,178,101,120,160,153,157,
+ 179, 30,114,194, 89,211,233,241,179, 80,144,114,117, 64,202,253,
+ 169,126, 3, 90,251, 14, 17,167, 79, 72, 72,204, 41, 47,175,120,
+ 1, 62, 70, 5,196,226, 5,136, 74, 0,220, 96, 0,104,146,147,
+ 147,174, 39,205, 96,180,118,160,212,143,222,103, 95, 76, 24, 67,
+ 180,127,232, 32, 57, 73, 11, 71,181, 92, 54,216, 40,101,137,200,
+ 73, 90, 40, 40,143,208,107,224, 11, 59,103, 69,233,153,187, 4,
+ 77,192,202,203,203, 95, 10, 32, 11, 62,102, 9,138, 1,209, 8,
+ 128,151, 45,189,149,237,237, 29,159, 72,165, 12,241, 10,191, 31,
+ 170,239, 15,232, 12,191,100,205, 36, 65,233, 37, 18, 6, 73, 42,
+ 65,253,148, 33, 37, 73, 53, 17, 18, 9, 51,114, 66, 39,132, 94,
+ 131,225, 48, 90, 59,176,251,220,189,196,233, 21, 10,133,250,220,
+ 185,234,183, 0, 40,225,218, 12, 16,141, 23, 32, 26, 1,112,131,
+ 249,247,191,255, 61, 53, 46, 46,126, 46,105,134,211,237, 31,120,
+ 236,222, 59, 90,100,126, 44, 48,148, 49,126, 45, 74, 12, 9,254,
+ 212,205,159,107, 48, 28, 77, 61,123, 5,237,183,144,145,145,121,
+ 193, 93,119,221, 53, 15, 67, 94,128,168, 16,133, 0,120,121,251,
+ 43,174,189,118,249,227,164,249,251, 45,205, 56, 80,247,215,128,
+ 215,203,104,109,247, 35, 79,228,174, 49,240,167,110,254, 92,131,
+ 145, 56, 80,247, 87,244, 91,154,137,211,175, 89,179,246, 33,240,
+ 115, 3, 68,231, 5,136, 66, 0,220,144, 2, 80,199,199,107,231,
+ 147,102,216, 87,251, 48,172,118,195,200, 9, 5, 34,116,181, 96,
+ 191,165,121,212, 27,105, 6,147, 46,195, 9, 65,134, 7, 8,191,
+ 6, 36, 88,237, 6,236,171,125,152, 56,125, 78, 78,238, 76,240,
+ 125, 1,142, 17, 1,209, 32, 70, 1,144,215,215, 55,108,148, 16,
+ 54, 86,221,163,223, 4,146,227,173,175, 11,234, 80, 20, 50,212,
+ 21, 46,132,212,209,206, 89,131,118, 78, 66,238,155, 84, 42,101,
+ 14, 28, 56,248, 24, 60, 71, 4, 98,158,152, 23, 0, 55,247, 95,
+ 10, 64,149,156,156,242, 11,146,188, 28,199,226,112,227,179, 65,
+ 171, 91,159,185,129,184,105,209,220,179, 31, 39, 90,223, 12, 90,
+ 93, 2,197,137,214, 55,137,215,238, 31,168,251,171, 71,148,226,
+ 64,114,184,241, 89,226,149,153, 69, 69, 69, 11, 1,100,192,203,
+ 106,193, 88,110, 6,196,188, 0,184, 33,219,187,119,223,114,210,
+ 189,253,106,187,191, 9,186,203, 93,213,246, 14,246,214,252,121,
+ 216, 64, 32, 53,186,237,216, 41,112,222,123,184,176,115, 86,236,
+ 60,125,199,176,139,163, 88,187, 9,123,107,254,140,170,182,119,
+ 130, 90,151, 46,195, 9,212,118,127, 67,148, 86,161, 80,170, 55,
+ 111,254,191, 21, 16,217,144,160, 88,214, 2, 12,110,240, 89, 84,
+ 52,233, 46,210, 76,254,238, 73, 39,148, 83,237,239,161, 81,191,
+ 27, 69,105, 55, 32, 43, 97, 46,100,140, 6,118,187, 21,221,166,
+ 51, 56,219,241,105,212,237, 44,100,181, 27,176,235,236, 58,156,
+ 110,255, 0, 19, 82,175, 67,146,106, 34,164, 82, 57,108,172, 1,
+ 77, 61,123,112,170,253, 3,193,125, 5,254, 82,209,180, 25,249,
+ 201, 75,136,210, 46, 93,186,244, 22, 0, 47, 3,232, 28,248,201,
+ 33, 2, 49,187, 70, 32,166,227, 2,120,113,255,147,250,251,141,
+ 45, 36,237,255,134,238, 82,124,115,122, 77,208,234, 70, 9, 29,
+ 139, 10, 55, 35, 59,105,193,136,233,236,118,187, 61, 62, 94, 83,
+ 2,224, 4,248,176,227, 65, 15, 55, 78,227, 2,132, 14, 89, 89,
+ 89,249, 42,210,206,191,170,246, 45,193,174, 15, 37, 68,144,222,
+ 75,169, 84, 42,125,227,141, 55,110,130,136,154, 1, 98, 17, 0,
+ 9, 0, 89, 86, 86,214, 10,146,196, 6, 75,107,192, 39,253, 80,
+ 194, 71,163,126, 55,113,120,245,146,146, 11, 23, 3, 72,128, 72,
+ 118, 12, 18,131, 0, 12, 46,252, 81,171,201,246,249, 59,219,249,
+ 41,221,215, 47,134,224, 56, 22,103, 58, 62, 38, 74,155,158,158,
+ 94, 8, 32, 25, 34,217, 54, 76, 12, 2, 0,240,231,169, 96, 24,
+ 89, 2, 73,226, 64,172,243,167, 68, 22,164, 91,182, 41,149,170,
+ 56, 0, 41,112, 29, 14,140, 89, 98, 86, 0,220,198,110,153,178,
+ 178,242,255, 32,201,215, 99,174,131,206,120, 42, 72,181,162,132,
+ 11,157,241, 20,122,204,117, 68,105, 95,127,253,141,235,225,101,
+ 109, 64, 44,206, 7,136, 89, 1,112, 66, 2, 64,150,153,153, 73,
+ 180,240,188, 73,191, 39,200,213,161,132, 11,210,123, 59,107,214,
+ 172,185,224,251, 1,128, 24,247, 2, 98, 93, 0, 6,195,124,169,
+ 213,234,105, 36, 25,162,109,204,157, 66, 14,233,189, 29, 59, 54,
+ 125, 2,128, 68,184, 26,126, 76,138, 64,172, 11, 0,192,159,163,
+ 92, 38,147,141, 33, 73,220,222,119, 36,200,213,161,132, 11,210,
+ 123,171,209,168, 19, 1, 36, 65, 4,253, 0, 98, 16, 0,201,103,
+ 159,109,157, 13, 72, 70, 60, 87,131,165, 53,162,151,219, 82, 70,
+ 135,209,218, 65, 52, 28, 40,145, 72, 37,235,215,223, 59, 11, 34,
+ 176,143,168,154, 10,236,103, 39, 12,115,222,121,231,121,110, 79,
+ 235,133, 78, 67,165, 31,135,167, 68, 19,157,134, 74,104, 20,233,
+ 35,166, 91,178,100,201,101, 27, 54, 60,249, 14, 0,151, 5, 24,
+ 66,158,193, 96,204, 28, 12, 52, 17, 41, 0, 2, 46,178,123, 58,
+ 206,237,255, 36, 0, 24,141, 70,115, 30,201,193,244,166,106,194,
+ 98, 41,209,138,222, 84,141, 28,130,116, 89, 89, 89,227, 1,196,
+ 3,232,133,107, 51,192,253, 25,115,198,197,224,125, 61,199,145,
+ 36, 12, 17, 35, 0,195, 24,189,227,226, 75,193,215, 87, 6,126,
+ 227, 6,105, 70, 70, 6, 3, 0, 45, 45, 45,142,121,219, 54,240,
+ 193, 30,216,129,127, 75, 1, 48, 10,133, 34,147,164, 14,253,230,
+ 166,209,156, 2, 37, 10, 32,189,199, 90,173,118, 12, 0, 13,134,
+ 158, 63,199,176, 32, 51,240,183, 52, 35, 35, 67, 6, 0, 45, 45,
+ 45,142,231,205,241,236, 57,158, 67,103, 67, 31,252,219,249, 89,
+ 191,213, 16,222,133, 70, 97, 23, 0, 47,134,239,188, 22, 91, 62,
+ 240, 81, 28, 57, 82,118,195,184,113,227,150,171, 84,234,153, 12,
+ 35, 77,150, 72,164,170,161, 44,156,205,110,231,140,102,179,233,
+ 116,119,119,247,206,119,223,125,247,213, 7, 30,184,191, 25,252,
+ 77, 80, 49,140, 44,149,164, 46,189,150,198, 64,156, 18, 37,130,
+ 33,189,199,106,181, 58, 9,188, 7, 16, 7, 64,242,151,191, 60,
+ 150,190,106,213,170, 91,146,146,146, 22, 42,149,170, 66,169, 84,
+ 162, 6,134, 98, 73,112,156,221,196,178,108,151,193, 96, 56, 82,
+ 95, 95,255, 73, 73,201,236, 79,192, 55, 31, 28, 31, 14,188, 72,
+ 12,102, 1, 0,141, 70, 37, 1, 0,131,193, 20, 22, 33, 8,219,
+ 106, 64,199,137, 59,215, 5, 67, 10,171,250,234,171,237, 23, 77,
+ 159, 62,125,181, 86,155,112, 37,195, 48,201, 66,235,193,113,118,
+ 179,209,104, 60,117,252,248,241, 45,231,159,127,254, 31, 25, 70,
+ 54,226,238,147,159,159,184, 9,237,125,101, 66,139,162, 68, 17,
+ 105,241, 51,113,205,228,145, 23, 7,153,205,102,243,231,159,111,
+ 125,241,202, 43,151, 92,161,209,196, 21, 73,165, 82,161,203,239,
+ 56,155,205,166,235,233,209,127, 83, 94, 94,254,210, 53,215, 92,
+ 253, 35, 0, 51,134, 86, 25, 14,166,115,206, 68, 42, 4,129, 90,
+ 13, 24, 22, 1,112, 51,126,199,223, 12, 0, 85,101,229,241,223,
+ 101,103,103,223, 37,151, 43, 2, 22, 73,146,101, 89, 43,195, 48,
+ 242,145,210,125,122,108, 57,157, 5, 24,227, 36,171,139,112,221,
+ 121,159,141,152,206,106,181,218,228,114,121,192, 60,100,139,197,
+ 220, 80, 95, 95,247,220,180,105,211,254, 9,192,136,161,184,132,
+ 156,219, 55,145, 8, 4, 74, 0, 66,222, 4,240, 98,252, 14, 87,
+ 63, 94,167,211,239, 86, 42,149, 1,223, 32,128,196,248, 1, 4,
+ 101,227, 79, 74,100, 65,122,143, 3,105,252, 0,160, 80, 40,179,
+ 39, 76, 40,124,178,179,179,235,246, 49, 99, 82,230, 1,232, 3,
+ 223, 52,112,236, 57, 32,129, 83,179, 32, 84, 77,130,144,142,115,
+ 122, 49,126, 6,128,250,216,177,202,181,253,253,134,250, 96, 24,
+ 191, 16,130,185, 63, 29, 37, 50, 8,247, 61, 86,171, 53, 69,189,
+ 189,253,117,101,101,229,107, 1,168,225, 35, 54,161,151, 38,114,
+ 80, 8, 89, 19,192,139,241,203, 0,104,154,154,154, 95, 79, 74,
+ 74,190, 54,160,149,160, 80,162,128,246,246,182, 47,243,242,114,
+ 255, 3,128, 1,124,223, 0,231,244, 1,224,187, 57, 16, 85,125,
+ 0, 62,222,252,241,221,221, 61, 7, 20, 10, 69,228,198,186,162,
+ 80,130,140,193,208, 95,147,154, 58,166, 4,252,124, 3,199,208,
+ 225,136, 34, 16, 53, 91,130,249, 48,254, 56,157,174,251, 7,106,
+ 252, 20,177,163,209,196,229,183,182,182, 31, 4, 63,220, 24,242,
+ 230, 64, 40,251, 0, 6,247,229,111,108,108,126, 69,169, 84, 77,
+ 9, 97,217, 20, 74,196,162,213,106,243, 79,159, 62,243, 33, 0,
+ 21,188,196, 37, 8, 38, 65, 21, 0, 39,229, 26, 92,150, 91, 81,
+ 113,244,183,201,201,201, 63, 11,102,185, 20, 74,180, 49,110, 92,
+ 246,130, 29, 59,118,220, 13,126, 68,204, 99,152, 60, 88, 94, 64,
+ 80,251, 0,220, 4,128, 1,144,216,223,111,168,119,157,197, 71,
+ 134,213,110, 64,179,126, 15,170,187,190, 68,143,185, 22, 58,195,
+ 169,193, 64, 25, 9,202, 92,104, 20,233,200, 74,152,139,188,148,
+ 37, 72, 84, 21,248, 85,247, 96,110, 81, 78,137, 28,252,221,138,
+ 91,111,170, 70,109,215,118, 52,245,236,129,193,210, 58,184,195,
+ 144, 84, 34, 71,178,166, 8,137,170, 2,228, 39, 47, 65,102,226,
+ 92,200,253,136,122,204,178, 54,139, 86, 27, 95, 12,160, 25, 94,
+ 58, 5,157,251, 2, 34,190, 19,208,205,248,165, 0, 52, 58,157,
+ 254, 71,161, 67,125, 22,182, 23, 71, 26,158,193,169,142, 15,135,
+ 141,158,227, 76, 90,252, 76, 92, 48,238,110,100, 38,204, 17, 82,
+ 20, 21, 0,145, 32, 84, 0,154,123,246,227,112,227, 51,196,179,
+ 68, 25,169, 10, 69,169,215,227,252,236,187,161, 96,180,130,202,
+ 210,235,187,171, 51, 51, 51,102, 1,232,135,107, 92, 2, 23, 17,
+ 136,154, 78,192, 1,152,242,242,138,219,132, 26,127,125,247, 78,
+ 124, 88,177, 8, 39,218,222, 34, 54,126, 0,104,239, 43,195,246,
+ 147,183,226,251,115,247,208,201, 61, 20,191,177,218, 13,248,254,
+ 220, 61,216,126,242, 86, 65, 83,196, 89,187, 9, 39,218,222,194,
+ 135, 21,139, 80,223,189, 83, 80,153,137,137, 73, 5, 91,183,110,
+ 93, 7,207,166, 64, 80, 8,182, 0, 12,118,252,229,229,229,253,
+ 94, 72,198,242,166, 77,248,246,244, 29, 48,219,244,126, 23,126,
+ 174,115, 27,182, 85, 94, 31,178, 48, 84,148,216,161,223,210,140,
+ 109,149,215,143,106,135,104,179, 77,143,111, 79,223,129,242,166,
+ 77,130,242, 93,120,225, 69,183,195,115,103,226,160,136, 65, 80,
+ 4,192,173,195, 66,250,221,119,165,151, 43, 20,202, 92,210,252,
+ 199, 90, 94,194,145,198,231, 3, 82, 23,189,169, 26,219,171,110,
+ 129,133,237, 13,200,241, 40,177,143,133,237,197,246,170, 91, 2,
+ 182, 63,196,145,198,231, 5,197,153,212,106, 19, 50,158,121,230,
+ 217,101, 24, 26, 22, 28, 36,208,157,129,161,104, 2,200,167, 78,
+ 157, 74, 28,144,179,161,187, 20,135, 26,158, 10,104, 5,122,204,
+ 117, 40, 61,115, 23, 13,246, 65, 25, 17,142, 99, 81,122,230, 46,
+ 226, 45,196, 73, 57,220,248, 12,234,116, 59,136,211, 47, 93,186,
+ 244,118,240,203,145,131, 58, 28, 24, 76, 1, 24, 92,232,163, 86,
+ 107, 46, 32,201, 96,182,233,177,187,250,190,160, 24,106, 83,207,
+ 94, 28,107,121, 41,224,199,165,196, 22,199, 90, 94, 10,218,206,
+ 208,123,106, 30, 36,110,210,166,167,167, 23, 3, 72,133,107,116,
+ 162,128, 11, 65, 40,250, 0, 20, 12,195, 16, 69,228, 41,111,218,
+ 52,170, 54,255, 72, 84, 52,109,134,201,214, 21,180,227, 83,162,
+ 27,147,173, 43,168, 33,225,205, 54, 61,113,127,128, 66,161,212,
+ 0, 24,131,161,126,128,160, 16,108, 1,144, 85, 84, 28, 37,138,
+ 200, 99,182,233,113,178,253,189,160, 86,198,106, 55,224, 68,235,
+ 91, 65, 45,131, 18,189,156,104,125, 43,232,163, 70, 39,219,223,
+ 35,126,201,109,217,242,238,141, 8,114,164,226,128, 11,128, 91,
+ 39, 5,147,158,158,126, 13, 73,190, 90,221,118, 65, 67,125,254,
+ 114,182,243,211,160,151, 65,137, 78, 66,241,108,176,118, 19,106,
+ 117,219,137,210,206,152, 49,227, 18,184, 70, 42, 6, 16,216,142,
+ 192, 96,247, 1,200, 73, 35,242, 52,132, 40, 28,119,159,185,129,
+ 238,254, 75,241,160,219,120, 38,100,123, 5,212,119,151, 18,165,
+ 75, 75, 27, 59, 30,124,164, 98, 32,202,250, 0, 6,183,249, 34,
+ 141,200,211,209, 95, 17,164,170,132,183, 44, 74,116, 16,202,152,
+ 16,164,101,169, 84, 42, 45, 60, 61,128,168, 25, 6,148,252,230,
+ 55,183, 37,145, 68,228,177,115, 86,162,136, 45,129, 34,220,187,
+ 194, 80, 34,143, 80, 62, 19, 6, 75,235,224, 58,150,225,144, 74,
+ 165,210,169, 83,167,166, 33,136, 29,129, 65, 21,128, 37, 75,174,
+ 28, 71,146, 48,212,147,116, 44,108, 95, 72,203,163, 68, 62, 86,
+ 54,180, 83,198, 73,159,249,139, 46,186, 40, 11,174, 67,129, 1,
+ 37,168, 2,144,144,144, 64,180,157, 55,107, 39,219, 74, 60, 80,
+ 132,162,179,145, 18, 93,216, 66,188,102,132,244,153, 79, 79, 79,
+ 215, 34,136,235, 2, 98, 62,248, 33,133, 18,205,216,237,156, 99,
+ 61, 77, 80,160, 2, 64,161, 68, 62, 81, 57, 17, 40,102, 99,170,
+ 83, 40,161,195,101,191,142,168,234, 3, 64,128,247, 26,161, 80,
+ 196, 76, 84,245, 1,208,183, 63,133, 18, 56,162,114, 30, 0,133,
+ 66,137,112,168, 0, 80, 40, 34,134, 10, 0,133, 18,193,112, 28,
+ 23,212,230, 52, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21,
+ 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80,
+ 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12,
+ 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196,
+ 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68,
+ 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,
+ 196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80,
+ 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10,
+ 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160,
+ 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0,
+ 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,
+ 160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21,
+ 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80,
+ 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12,
+ 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 37,130,
+ 145, 72, 36, 92, 48,143, 79, 5,128, 66, 17, 49, 84, 0, 40, 20,
+ 17, 19, 44, 1, 8,170,219, 66,161,136, 12,206,199,223,163, 38,
+ 152, 30, 0,215,210,210,220, 78,146, 80, 38,213, 4,177, 26,225,
+ 47,143, 18,249, 68,234, 51, 88, 91, 91,219, 5,222,232,131,242,
+ 82, 13,170, 0,124,255,253,247,109, 36, 9,229, 76,104, 47,190,
+ 130,209,134,180, 60, 74,228, 19,234,103,144,180,188,178,178, 50,
+ 61, 0,251,192, 63, 3, 46, 2, 65, 21,128,215, 94,123, 77,207,
+ 113, 28, 59, 98, 37, 36,114,196, 43,179,131, 88, 21, 87,180,170,
+ 220,144,149, 69,137, 14, 18, 84, 5, 33, 43, 43, 94,153, 13,169,
+ 68, 62, 98, 58,150,101,237, 85, 85, 85,189, 0,172,193,170, 75,
+ 176, 59, 1,109, 86,171,181,147, 36, 97,170,102,106,144,171, 50,
+ 68, 90,220,244,144,149, 69,137, 14, 66,249, 76,144, 62,235, 6,
+ 131, 65, 15,192,132, 40,109, 2, 0,128,205, 96,232,175, 32, 73,
+ 56, 46,113, 94,144,171,194,147,160,204, 13,169,183, 65,137, 14,
+ 226,149,217, 72, 80,134,198, 51, 36,125,214, 91, 91, 91,206, 0,
+ 232, 65, 16, 59,213,131,218, 4, 0, 96,107,104,104,248,156, 36,
+ 113, 94,202, 18,200, 67,208, 17, 51, 49,245, 23, 65, 47,131, 18,
+ 157,132,226,217,144, 75, 53,200, 75, 89, 66,148,246,199, 31,247,
+ 239, 5,160,119,250, 41,170,250, 0, 0,128,189,240,194,146,119,
+ 72, 18, 42, 24, 45,166,101,254,103, 80, 43,163, 81,164, 99,114,
+ 198,175,131, 90, 6, 37,122,153,156,241,107,104, 20,233, 65, 45,
+ 99, 90,230,127, 18,117, 66,115, 28,135,223,254,246,183,223, 96,
+ 200, 3,136,170, 38, 0,231,244,109,179,217,172,250,225, 18, 59,
+ 8,246, 13,152,158,185, 38, 36, 94, 6, 37, 58,145, 75, 53,152,
+ 158,185, 38,104,199, 23,242, 2, 50,153,140,125,224, 59,255,250,
+ 17,173,243, 0, 6, 62,214,190,190,190, 67, 36, 25,228, 82, 13,
+ 230,143,223, 72,212, 67, 42,148,156,164,133, 40, 30,187, 42,224,
+ 199,165,196, 22,197, 99, 87, 33, 39,105, 97,192,143, 43,145, 48,
+ 152,155,255, 23,226, 23, 80, 83, 83,211, 73, 0, 58,184,190, 76,
+ 35,191, 9, 96, 48,152,220, 43,105, 61,120,240,192,115,164,249,
+ 51,180, 37,152,147,247,167,128,214, 41, 89, 93,132,249, 19, 54,
+ 6,244,152,148,216,101,254,132,141, 72, 86, 23, 5,244,152, 37,
+ 57,247, 9,234,232,126,253,245,215,223,197,144, 0,184,216,148,
+ 23, 27,243,155, 96,247, 1,112, 0,216,235,174,187,110,183,209,
+ 104, 56, 71,154,169, 40,109, 37, 46, 45,120, 60, 32,158, 64,134,
+ 182, 4, 87, 21,191, 65, 93,127, 10, 49,114,169, 6, 87, 21,191,
+ 129, 12,109,201,168,143, 37,149,200,113,105,193,227,152,146, 78,
+ 222,247,212,217,217,217,184, 97,195,147,229, 0, 58, 49, 36, 0,
+ 81,213, 7,224,140, 29,128,121,223,190,125,235,133,100,154,152,
+ 250,115, 44, 41,126,213,239, 33, 59,137,132,193,121, 25,171,113,
+ 229,164,151,161,148, 37,250,117, 12,138,120, 81,202, 18,113,229,
+ 164,151,113, 94,198,106, 72, 36,140, 95,199,136, 87,102,227,202,
+ 73, 47, 99, 98,234,207, 5,229,219,180,233,249, 77, 0,154, 1,
+ 24, 17, 68,227, 7, 0, 9,199, 5,246,216, 70,163, 25, 26,141,
+ 74,226, 56, 62,120,145, 97, 0,104,218,218,218,119,197,199,107,
+ 167, 9, 57,158,157,179,226,100,251,123, 40,107,124, 14,102, 27,
+ 81, 95, 34,114,147, 23,227,130,113,119, 33, 73, 61, 81, 80,221,
+ 95, 61, 88, 44, 40, 61, 37, 58,185,181,164, 74, 80,122,189,169,
+ 26,135, 26,158, 66,157,110, 7, 81,122,165, 44, 17, 51,199,253,
+ 15, 38,165,173, 20,236,197, 54, 55, 55,157,157, 48, 97,252, 29,
+ 0,126, 2, 96, 0,255, 2,117,124, 56,128,111, 2,168,213, 74,
+ 65,199,245, 69, 40, 4,192, 33, 2, 50, 0, 9,122,125,239, 57,
+ 185, 92,238,151, 63,222,212,179, 23, 77,250, 61,104,238,221, 15,
+ 0,232,236,175, 68,156, 34, 19, 42,121, 10, 52,242,116,228, 37,
+ 47,198,184,196,121, 80,203, 83,253, 92,168,210,238, 0, 0, 19,
+ 244, 73, 68, 65, 84,170, 59, 21, 0,113, 32, 84, 0, 28,152,108,
+ 93,104,232,222,133, 90,221, 14, 24,172,173, 48, 89,187,208,111,
+ 105,198,152, 56,126,102, 95,166,118, 14,178, 18,231, 34, 43,225,
+ 18,191,142,111, 54,155,140,201,201, 73, 43, 0,156, 3, 80, 3,
+ 79,227, 15,184, 0,200, 2,114, 20, 55, 12, 6, 19,231, 36, 2,
+ 142,138,179, 0, 12,229,229,101,235,102,207, 46,217,236,207,113,
+ 179, 18, 46,241,251,226, 82, 40,163, 69, 37, 75,193,196,212,159,
+ 11,118,233, 73,121,237,181,215,254, 1,160, 3, 64, 29,124,180,
+ 253, 3,217, 1, 8,132,166, 19,208,241,205, 1,176,206,159, 63,
+ 239,189,186,186, 90,162,201, 65, 20,138, 88,168,168, 40,223,117,
+ 247,221,119,125, 3,160, 26,174,111,252,168,239, 4, 4, 92,189,
+ 0, 83,113,241,164,187,116,186,174, 35, 33, 42,155, 66,137,104,
+ 154,155,155,206,206,153,115,209,223, 0,156, 6,208, 7, 47,110,
+ 127,176, 8,154, 0, 56,185, 42,238, 94, 0, 11,160,127,220,184,
+ 172,171,218,218, 90,127, 10, 86,249, 20, 74, 52, 80, 83, 83,125,
+ 116,194,132,241,255, 13,160, 22, 64, 43, 60,223,254,128, 83,219,
+ 63,208,229,135,218, 3,112,124,108, 0,250,242,243,243,174, 62,
+ 121,178,234,189, 16,213,129, 66,137, 40, 14, 30, 60,176,125,202,
+ 148,201,247, 2, 56, 11, 94, 0,220,223,252,209,235, 1, 0, 94,
+ 21,203, 67, 4,206, 63,127,230,218,143, 63,254,240,191,204,102,
+ 147, 33,152,117,161, 80, 34, 5,163,209,104,120,250,233,167,254,
+ 114,217,101,243, 55, 2,168, 2,208, 0,239,198, 63, 72, 48,222,
+ 254, 64,144, 70, 1,124,192,129, 31, 18,116, 62, 17, 22,128,241,
+ 230,155,111,126, 3,192,151,213,213,181, 91,211,211,211,167,132,
+ 176, 78, 20, 74, 72,105,108,108, 56, 89, 88, 56,113, 61,120,119,
+ 191, 26,252, 98, 31, 95,198, 31,244,205,117,131,222, 4,112, 83,
+ 46,111, 61,155, 44, 0, 11,128,182,130,130,188, 5,127,252,227,
+ 253, 55,117,116,116,212, 5,178, 14, 54,155,205, 62,114, 42, 10,
+ 101, 8,155,205, 26,208,103,166,173,173,173,238,246,219,111,251,
+ 239,194,194,137,255, 3,190,179,239, 56,124, 27,191,139, 7, 16,
+ 172,183, 63, 16,162, 62,128, 97, 68,192,238,244,109, 5,208,247,
+ 244,211, 79,127,153,155,155,125,145, 70,163,186,248,199, 31,247,
+ 111,237,234,234,108, 98, 89,118,196,125, 5,221, 49, 26,141,134,
+ 170,170, 19, 63, 61,246,216,163,127,151, 72, 36, 35,103,160, 80,
+ 92,144,224,207,127,254,211, 19,199,143, 87, 30, 50, 26, 13,130,
+ 155,167, 54,155,141,237,232,232,104,218,183,111,239, 54,141, 70,
+ 117, 93,126,126,238,237,111,191,253,118, 41,128, 3, 0,234,193,
+ 191,248, 88,184,218, 64, 72,141, 31, 8,210, 76, 64, 95, 56, 77,
+ 14, 2,248,230,128,227,219,249, 35, 29,248,102, 0,200, 1,140,
+ 5,144,188,102,205,154, 11, 86,174,188,113,233,132, 9, 19,166,
+ 39, 37, 37,101,112, 28,160, 80, 40, 20, 44,203,218, 89,150,181,
+ 89,173, 22, 99, 75, 75, 75,205,225,195,135,247,223,114,203,175,
+ 191, 2, 47, 40, 61, 0,108,125,125,253, 63, 72,165,204,136, 98,
+ 71,103, 2,138, 3,146,153,128, 44,107,179,107,181,241,215, 3,
+ 168, 4,144, 8, 32,233,245,215,223,184,254,130, 11, 46,152,147,
+ 158,158, 94, 32,151, 43,212, 12,195,200, 24,134,145, 90, 44, 22,
+ 11, 0,116,119,235, 90,206,156, 57,115,244,237,183,223,250,246,
+ 229,151, 95, 62, 13,126, 42,175, 14, 64, 23,134, 22,246,248, 50,
+ 120, 15,183,127, 56,227,143,232,169,192,195, 65, 40, 2,238, 31,
+ 6,188, 48,168, 0, 36, 1, 72, 0,160, 85,169, 84,140,201,100,
+ 82,128,111, 66, 88,192,111,160,216, 3,126, 27,165,254,129,188,
+ 137,125,125,134,179, 82,169,116,196, 21, 29, 84, 0,196, 1,153,
+ 0,176,118,173, 54,238, 58, 0,251, 49,100,172, 82, 0, 90,240,
+ 130,160, 5,160, 80, 42,149, 10,179,217,204, 96,200,157,239, 6,
+ 208, 59,240, 49,195,183,177,251,109,252, 64,224, 4, 32,148,157,
+ 128, 0,188, 78, 19,134,211,223,206, 70, 15,167,191,237, 3,223,
+ 86,240, 19, 37, 0, 64, 98, 50,153,220, 15,239,126,209,164,224,
+ 221, 44, 10,197, 31, 28, 46,186,227,219, 14,254, 37,227, 8,120,
+ 35, 49,155, 61, 94,120,238,243, 94,124, 25,186,207,206,190, 96,
+ 187,253,206,132, 92, 0, 0, 15, 17, 0, 92, 71, 8,156,133,192,
+ 241, 55,224, 41, 12,190,112,206,195, 1, 96,105, 23, 0,197, 79,
+ 28,157,212,206, 2,224,248,125,164,103,208,241,237,107, 66,156,
+ 123, 90, 0,161, 53,126, 32, 76, 2, 0, 12,157,168, 15,111,192,
+ 241,111,231, 97, 67, 18,227,119,198,145,206, 78,158,133, 66,113,
+ 193,238,229, 67,106,160,222,222,238, 62,135,247, 66,109,248, 14,
+ 194, 38, 0, 14, 94,216,149,207, 1,192, 29,151,213,184,123, 4,
+ 142,111,119,129, 16, 42, 0, 20,138,191,184,143, 88,249, 35, 0,
+ 190,254, 13, 32,124,134,239, 32,236, 2,224,192, 33, 4,128, 79,
+ 49,240,245,111,111,184, 47, 69,166, 80, 0, 0,113,138, 76,162,
+ 116, 78,205,198,225,218,242,126,225,252,172,135,155,136, 17, 0,
+ 103,134,187, 64,110,226,224, 11, 95,237, 45, 10,133,144,193,199,
+ 204, 47,227,143, 36, 35, 31,142,136, 20,128,225, 32,185,176,110,
+ 34, 65,236,182, 37, 40,115,209, 99, 14,232, 36, 68, 74,132,193,
+ 16,110,209,197,241,227,227, 94,163,242, 70,139,113,147, 16,170,
+ 213,128,225,196,206,178,108,223,200,201, 0,173, 42, 47,216,117,
+ 161,132, 25,210,123,108,177,152, 13,224, 23,172,197,140,177,123,
+ 35,214, 5,128, 3,192,154, 76,198,179, 36,137, 83,105,212,224,
+ 152,135,244, 30,119,117,117, 53,130, 31,243,119, 16,147, 66, 16,
+ 235, 2, 0, 0, 86,157, 78,247, 45, 73,194,188,228, 69,193,174,
+ 11, 37,204,144,222,227,227,199,143, 31, 70,144,227,242, 69, 2,
+ 177, 44, 0,142,155,102,127,246,217,103, 95, 37,201,144,162,153,
+ 140,236,164, 5, 65,171, 16, 37,188,100, 39, 45, 64,138,102, 50,
+ 81,218,135, 30,122,104, 27, 92, 35,243, 2, 49, 40, 4,177, 44,
+ 0, 14,236, 47,188,176,169,157,101, 89,143,121,195,222,152,149,
+ 189,206,239, 64, 16,148,200, 69, 34, 97, 48, 43,123, 29, 81, 90,
+ 139,197, 98, 41, 43, 59,162, 3, 63,159, 63,230,140,222,153,152,
+ 20, 0,167, 94, 90,135,251,102,179, 88,204, 53, 36,121,147,213,
+ 69,184, 40,247,193, 96, 85,141, 18, 38, 46,202,125,144, 56,222,
+ 159, 94,223,221, 12,126,205,137, 99, 29,201, 96, 51, 32,150, 70,
+ 0,128, 24, 21, 0, 47, 88,154,154,154,136,247, 30, 44, 30,187,
+ 10,211, 50,255, 51,152,245,161,132,144,233, 89,107, 4, 69,134,
+ 254,241,199, 31,191,133,143,192,156,177,134, 24, 4,128, 3, 96,
+ 155, 54,237,188, 77, 54,155,173,159, 52,211,172,236,117,184,180,
+ 224,113, 26, 84, 52,138,145, 75, 53,184,180,224,113, 92, 48,238,
+ 110,226, 60,102,179,201,184,114,229,138, 15, 16,130,192,156,145,
+ 128, 24, 4, 0,224, 39,116, 24,187,186, 58, 63, 20,146,105, 98,
+ 234,207,241,139,233, 95,163,120,236, 42, 42, 4, 81,132, 92,170,
+ 65,241,216, 85,248,197,244,175, 5, 71,241, 57,118,236,216, 46,
+ 240, 27,120,232, 17,227,198, 15, 68,225, 76, 64,129, 56, 47, 32,
+ 178,230,231,231,253,161,171, 75,183, 88,165, 82,147, 77, 8, 7,
+ 160,150,167, 98, 78,222, 67,184, 48,247, 1, 52,233,247, 64,103,
+ 60,133, 67, 13, 79, 5,167,182,148, 81, 49, 43,123, 29,146,213,
+ 69,200, 74,156,235, 87,104,121,189,190,187, 99,222,188, 75,159,
+ 5, 31,153,215,219,250,253,152, 35,214, 5,192,129, 99, 93,183,
+ 225,249,231,159, 91,254,135, 63,172,223, 79,178, 67,144, 51, 82,
+ 137, 28,217, 73, 11,144,157,180, 64,112,255, 64,168,119, 26,242,
+ 55,248,229, 72,196,202,121,120,131,101, 89,251,175,127,253,171,
+ 245,224,141,191, 3, 34,112,255, 1,241, 52, 1,128,129,190,128,
+ 135, 30,122,232, 84,117,245,185, 77,225,174, 12, 37,178,216,181,
+ 171,244,253, 29, 59,118,156,133,103,108,190,152, 38,102, 5,192,
+ 203, 80,160,227, 99,153, 54,237,188, 71,116, 58, 93,121,216, 42,
+ 71,137, 40, 26, 27, 27, 79, 46, 91,118,205, 43,224,195,114, 91,
+ 225, 99, 5, 96,172, 13, 1, 2, 49, 44, 0, 62, 24,108, 10,140,
+ 27,151,121,165,193,208,223, 20,238, 10, 81,194,139, 78,167,107,
+ 41, 44,156,240,123, 0, 53,224,135,254,132,110,252, 17,213,196,
+ 180, 0, 12,227, 5,176, 0,250, 83, 83,199,156,223,210,210,114,
+ 40, 92,245,163,132,151,154,154,234,163,227,198,101,222, 6,160,
+ 17,252, 94,253, 62, 3,116,196,226,219, 31,136,113, 1,240,130,
+ 243, 77,181, 2,232, 27, 63, 62,255,170,253,251,247, 61,203,178,
+ 54, 91,120,171, 70, 9, 21, 54,155,205,182,109,219,214, 87,167,
+ 76,153,188, 30,124, 96,206, 51, 24, 33, 54, 95,172, 34, 38, 1,
+ 112,223,156,145, 3,191,222,187,127,225,194,203,255,119,193,130,
+ 203,102,119,119,235, 26,194, 83, 53, 74,168,232,232,232,104,154,
+ 50,165,248,151, 43, 87,174,120, 9, 64, 5,188, 7,230,116, 16,
+ 243, 34, 16,243, 2,224,230,186,121,115,239, 88, 0,166, 67,135,
+ 14,157,203,202,202,156,189,115,231,183,127,239,233,209,119,132,
+ 161,170,148, 32,162,215,119,119,124,252,241, 71,255,204,205,205,
+ 94,221,208,208, 80, 5,160, 28,252,100,159, 17, 99,243,197,170,
+ 251, 15,136,100, 30,192, 11,187,242, 57,167,109,194,188,221, 76,
+ 59,248,200, 66,236,178,101,215,252, 5,192,166, 59,239,188,115,
+ 238, 47,127,121,243,205,185,185,185,231, 37, 36, 36,166,203,229,
+ 114,225, 51, 75, 40, 97,195,106,181, 88,187,187,245,109,117,117,
+ 53,199, 94,124,241,197,173,111,191,253,246, 89,240, 17,121,155,
+ 193,175,242, 27,206,240, 69, 97,252,128, 72, 4, 0, 24, 86, 4,
+ 56,184, 6, 34,177, 3,104,217,180,105,211,167,155, 54,109,250,
+ 26, 64, 10,128,132,107,175, 93, 94,116,199, 29,107,175,203,205,
+ 205,155,164,213,106, 83,237,118, 78, 18, 31, 31,151,164,209,196,
+ 169, 66,122, 34, 1,194,110,183,163,185,185,169, 13, 0, 50, 51,
+ 179,198, 74,165,209,233, 12,246,245,245,153,123,123,123,186,165,
+ 82, 41,215,219,219,219, 81, 87, 87,119,234,217,103,159,217,190,
+ 99,199,142, 70,240,225,186,186,193,191,233,117,224,251,125,134,
+ 11,198, 41, 42,227, 7, 68, 36, 0, 0,145, 39, 0,184,134, 33,
+ 179,129, 95, 22, 42,217,186,245,179,147, 91,183,126,246, 53,248,
+ 216,132,113, 0, 82,186,186,186,183, 6,187,206,193,164,176,112,
+ 226, 61, 0,244,125,125,134, 79,195, 93, 23,127,145, 72, 36,220,
+ 132, 9,227,127, 7,126,254,190, 13,188,209, 59,226, 67,218, 64,
+ 22,151,207, 89, 0, 0,136,195,248, 1, 17,244, 1,184,227,165,
+ 79,192,241,237, 30, 1,134,117,251, 88,192,139, 65, 19,248, 9,
+ 35,167, 24, 70, 26,208, 24,242, 97,192, 8,224,156, 68, 34,137,
+ 218,135,125, 32,244,187, 17,192,201,129, 79, 45,248,169,188,102,
+ 240, 2,224,126, 31,125, 69,250, 17,157,241, 3, 34, 20, 0,192,
+ 103,199,160,227,111,231, 7,195,151, 24,216,248, 79,244, 6, 31,
+ 26, 8,124,225, 56,151,168,101, 64, 0,236, 24,188, 39,195, 26,
+ 189,251,253, 5, 68,232,246, 59, 35,170, 38,128, 51, 94, 66,146,
+ 185,223,120,231,149,132,142,111,231, 88,133,118, 73, 84, 71, 29,
+ 149, 0, 67, 6, 17,237,184, 27, 58,139, 97,220,123,120,222,107,
+ 209, 25,190, 3,209, 10,128,131, 17, 98, 19,194,237, 55,231,240,
+ 229,177,240,192, 56, 71,188,141, 74, 6, 52,216, 91, 19,142,104,
+ 76, 95,172,134,239, 64,244, 2,224,224,133, 93,249,220,218,249,
+ 213, 0, 0,137,235,171,221,215,176, 97,148,123, 0, 0, 98,192,
+ 3, 24,232,191,240,230,222,251,156,205, 39,118,163,119, 70,148,
+ 125, 0, 35,193,249, 0, 62,198,138,163,152, 88, 59, 15,151,207,
+ 48,247,145, 50, 0, 21, 0,113, 67,141, 65,228, 80, 1,160, 80,
+ 68, 12, 21, 0, 10, 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10,
+ 69,196, 80, 1,160, 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160,
+ 80, 68, 12, 21, 0, 10, 69,196, 80, 1,160,196,202,100,160, 88,
+ 57,143,144, 66, 5,128, 66, 17, 49, 84, 0, 40, 81,206,224,178,
+ 102,138, 31, 80, 1,160, 80,227, 17, 49, 84, 0,252,135,227, 56,
+ 46,138,119,211,137,141, 85,113,118,187,221,121, 57,115, 76,156,
+ 83, 40,161,251, 1, 56,241,226,247, 5, 66,146,115, 28,199, 89,
+ 72, 18,230, 38, 47, 70,157,110,135,127,149, 18, 72,130, 50,151,
+ 40,221,128,225,176, 0,236, 28,199,177, 18,137,100,196,103, 33,
+ 65,153,139, 30,115,221, 40,107, 72, 70,110,242, 98,162,116,118,
+ 59,107,197,208, 14, 64, 46, 8,188,159,162,132,122, 0,254,193,
+ 1, 96,173, 86, 11, 81,112,209, 68, 85,232, 30, 68,173, 42,143,
+ 40,157,217,108, 49, 98, 32, 22,130,205,102,235, 11,228,177, 3,
+ 65,146,122, 2, 81, 58,189, 94,223, 6,215,125, 13,169, 23, 32,
+ 0, 42, 0,254, 99,211,233,116,123, 73, 18,142,141,159, 25,236,
+ 186, 8, 46,171,163,163,189, 30,252,110,186,172,193,208,127, 58,
+ 144,199, 14, 4,105,113,211,137,210, 85, 87,159,171, 4,191, 21,
+ 56, 64,141, 95, 48, 84, 0,132,227,120,200,216,111,190,249,230,
+ 109,146, 12,233,218, 18, 48,210,208,196, 15, 25,151, 56,143, 40,
+ 221,241,227,149, 63,129,223, 59,223,218,222,222,190, 51,144,199,
+ 30, 45,140, 84,133,116,109, 9, 81,218,127,253,235, 95,219,193,
+ 71,250, 17, 85, 76,191, 64, 65, 5,192,127,236,107,215,174, 57,
+ 105,183,219,173, 35, 37, 84, 48, 90,228, 39, 47, 9,122,133,146,
+ 213, 69, 72, 37,124,115,222,115,207, 61, 91, 49, 16, 60,227,222,
+ 123,215,191, 70,146, 39, 53,110, 58,146,213, 69,163,168, 33, 25,
+ 249,201, 75,160, 96,180, 35,166,179,217,172,182,247,222,123,175,
+ 14,124, 32, 16,106,244,126, 64, 5, 64, 0, 78,155, 73, 14, 70,
+ 23,182, 88, 44,245, 36,121,103,140,187, 19, 82, 73,112,195, 11,
+ 206,202, 94, 71,148,206, 98, 49,155,207,157, 59,215,135,129, 24,
+ 121,219,183,111,215,177, 44,107, 12,100, 25,254, 34,149,200, 49,
+ 99,220,157, 68,105,245,250,158, 54,240,238,191, 67,132, 7,247,
+ 56,164, 27,127,146, 65, 5, 96,116, 88,123,122,244, 7, 72, 18,
+ 38, 40,115, 49, 41,109,101,208, 42,146, 30, 63, 11,217, 73, 11,
+ 136,210,234,116,221, 77, 24, 10,144,201, 1,176,153, 76,198,106,
+ 146,188,217, 73, 11,144, 65,232,158,251,195,164,180,149,196, 35,
+ 25, 13, 13,245,149,224,189,152, 88,217,220, 52,228, 80, 1,240,
+ 31, 14, 0,123,244,232,209,119, 72, 51,204,206, 89,143, 20,205,
+ 228,128, 87, 68, 37, 75,193,101, 19,158, 34, 78, 95, 81, 81,190,
+ 7,124,176, 76,135,225, 88,218,218,218, 62, 39,205, 63,127,252,
+ 70,168,100, 41,130,235, 57, 18, 41,154,201,152,157,179,158, 56,
+ 253, 71, 31,125,180, 3,174,238, 63, 21, 1,129, 80, 1, 24, 29,
+ 236,181,215, 46,219, 99,177, 88, 58, 73, 18, 51, 82, 21, 22, 21,
+ 110, 14,168,241, 72, 37,114, 92, 81,248, 2, 52,138,116,162,244,
+ 44,203,218,175,187,110,249, 59, 24, 18, 0, 59, 0,235,212,169,
+ 83,158,226, 56,142, 37, 57,134, 70,145,142, 43, 10, 95, 8,104,
+ 147, 70, 37, 75,193,162,194,205,196,157,165,125,125,125,250, 13,
+ 27,158, 60, 10,234, 1,140, 10, 42, 0,254, 49, 24, 30, 12,128,
+ 185,185,185,233, 85,210,140, 26, 69, 58,150, 77,121, 47, 32,157,
+ 105,106,121, 42,150, 20,191,138, 52, 1,195,115,245,245,117, 71,
+ 193, 7, 57,213,195, 53,160,134,177,167, 71, 79, 52,172, 9, 0,
+ 105,241, 51,177,180,248, 13,168,229,169, 2,107,237, 73,178,186,
+ 8, 87, 79,217, 66, 44, 98, 0,176,127,255,190, 47, 0,180,129,
+ 31,202, 4,168, 23,224, 23, 84, 0,252,199,241,160, 89, 39, 79,
+ 46,254,155,209,104, 36,154, 20, 4, 0,241,202,108, 92, 61,101,
+ 11,198,143, 89,230,119,225, 25,218, 18, 44,155,242, 62,210,227,
+ 103, 17,231,177, 90,173,214, 41, 83, 38, 63, 8,160, 25,158, 17,
+ 116, 44,153,153, 25, 43, 89,150, 37,154,221, 8,240, 34,176,108,
+ 202,251,163,234, 19, 24, 63,102, 25,174,158,178,133,184,221, 15,
+ 0,221,221,186,246,229,203,175,125, 29,252,121,248,138,255, 71,
+ 33,128, 10,192,232, 24,124,123,214,212, 84, 63, 39, 36,163, 92,
+ 170,193,252,241, 27,113,237,148, 15,145,153, 48,135, 56, 95,178,
+ 186, 8,139, 10, 55,227,170,226, 55, 16,167,200, 20, 84,217, 51,
+ 103, 78, 31, 0,239,250, 55,193, 51,146, 14, 11,192,168,215,119,
+ 127, 33,228,152,113,138, 76, 92, 85,252, 6, 22, 21,110, 22,228,
+ 213,100, 38,204,193,178, 41,239, 97,254,248,141,144, 75, 53, 66,
+ 138,196,142, 29, 59, 62, 0,127, 14,206,238, 63, 53,126, 63,144,
+ 4, 58, 82,146,209,104, 22,148,254,213,131,197, 1, 45, 63, 20,
+ 12, 4, 18,117,254, 48, 0,226,154,154,154,119, 36, 37, 37, 95,
+ 224,207, 49, 13,150, 86,212,117,239, 68,107,239, 65,244,152,107,
+ 97,182,233,193,218, 77,208, 40,210,161,145,167, 35, 45,110, 58,
+ 242, 82,150,248, 61,173,184,187,187,187, 61, 43, 43,227, 22, 0,
+ 39, 49,228, 1, 56,135,201,150,128, 95, 27, 18,223,209,209,121,
+ 68,163,137, 27,231, 79, 57,122, 83, 53,106,187,182,163,189,191,
+ 2, 6,107, 43, 12,150, 86, 48, 82, 21,148,178, 68, 36, 40,243,
+ 48, 86, 59, 11,121, 73,139, 4,185,251,206, 52, 52,212,159, 40,
+ 42, 42,252, 61,128, 35,224, 59, 0, 61,226, 1, 70,211, 16,224,
+ 173, 37, 85,126,229, 83,171,149, 1, 41,159, 46, 6,242, 31,231,
+ 135,204, 14,192,152,149,149,121,117,119,119,207, 41,133, 66,145,
+ 32,244, 96, 26, 69, 58,138,199,174, 66,241,216, 85,129,171,225,
+ 0, 44,203,178, 55,222,184,226, 30,240,111,205, 22,248,142,160,
+ 107, 3,208,255,224,131,127,188,114,227,198,167,202,165, 82,169,
+ 224,231, 35, 81, 85,128,233, 89,107, 2, 81,109, 15,140, 70, 67,
+ 95, 81, 81,225, 61, 0,106,193,247, 99,196, 98,188,198,144, 18,
+ 118, 15, 32, 26,209,104, 84,142,176,192,206, 94,128, 20,128,226,
+ 139, 47,190, 92,118,217,101, 11,222,150, 68, 80,232,224,119,222,
+ 121,251,249,213,171,111,123, 15, 64, 57,248, 73, 51,238,111,127,
+ 7,142,243, 80,238,221,187,111,237,204,153,231, 63, 17,218,154,
+ 250,198,110,183,115, 79, 62,249,196, 67,143, 60,242,240,151, 0,
+ 78, 96, 96, 37, 35,188, 68, 3, 54, 24, 76, 49, 47, 4,129,242,
+ 0,168, 0,248,137, 23, 17,144, 14,124,212,223,127,191,123,205,
+ 236,217, 37,143,135,173,114, 78,236,219,183,119,235, 21, 87, 44,
+ 124, 30, 64, 5,124,184,204, 3, 73,221,155, 52,234,163, 71, 43,
+ 159,153, 48, 97,194,175, 67, 95,107, 79, 6, 68,236, 35, 0, 71,
+ 1, 24, 48,180, 4,216,197,147, 17,131,241, 3,129, 19, 0,218,
+ 9, 24, 56, 28, 15,163,105,254,252,121,255,119,232,208, 79,127,
+ 9,119, 40,234, 31,127,220,255,197, 21, 87, 44,252, 7,128, 42,
+ 12,205,252,243,102,252,112,251,141, 5, 96,156, 54,109,234,186,
+ 211,167, 79,189, 25,218, 90,187,194,113, 28,247,233,167,159,188,
+ 188,122,245,109, 91,193,191,249, 13,240,222,124,161,248, 1, 21,
+ 0, 63,113,122,211,184,183, 65,237, 0,140,243,230, 93,250,247,
+ 47,190,216,246, 59,179,217,108, 8,117,221,108, 54, 27,251,238,
+ 187, 91, 54, 95,126,249,130,103,193, 27, 77, 39, 60, 13,127,164,
+ 143, 29,128, 97,198,140,233,119,237,221,187,231, 17,150,101,137,
+ 38, 9, 5, 18,163,209,104,120,250,233,191, 63,186,106,213, 77,
+ 111,130,127,243, 59, 60, 24,175,109,127,177,188,253, 3, 9,109,
+ 2,140, 2,167,102, 0,224,217, 31, 32, 5, 32, 7,144, 86, 83,
+ 83,187,109,236,216,244,192,207, 1,246, 66,119,183,174,117,233,
+ 210,171,254, 80, 94, 94, 94, 7,224, 20, 60,223,252,206,109,127,
+ 111,125, 0,142,111, 41,134,154, 3,202,235,175,191,126,226,166,
+ 77, 47,110, 77, 72, 72,200, 8,246, 57, 0, 64, 99, 99,195,233,
+ 194,194,137,235,192, 79,246,169, 6,191,232,199,155,219, 63,120,
+ 14, 98, 18, 0,218, 7, 16, 33,184,245, 5, 56,190,157, 13, 72,
+ 6, 32,110,207,158,189,127,157, 52,169,120,133, 70,163, 17, 60,
+ 66, 64,130,197, 98,177,158, 58,117,114,255,133, 23,150,252, 13,
+ 64, 35,120,163,177,129,220,248, 29,120, 19, 1,135,152,197, 31,
+ 59, 86,249,122, 78, 78,238,124,185, 92,174, 8,198,121,244,247,
+ 247,245, 28, 56,112,224,171,107,174,185,250, 21,240,189,253,117,
+ 62,206,193,229, 60,196,100,252, 0, 21,128,136,193,139, 23,224,
+ 248,118,127,139, 42, 0,100,148,149,149, 63, 91, 80, 80,176, 64,
+ 46, 87, 4,196,128, 88,150,181,215,213,213, 30,157, 58,117,202,
+ 159, 48, 52,201,167, 21,158,237,125,199,230,153, 94,223,154, 62,
+ 188, 25, 56,157,131, 67,204,148, 0,178, 79,157, 58,253,114, 86,
+ 214,184,243,165, 82,105, 64,154,145, 22,139,197, 82, 85,117, 98,
+ 223,156, 57, 23,109, 0,255,214,111, 30, 56,159, 17,141,223,249,
+ 60,196, 2, 21,128, 8, 98, 4, 17,112,247, 6, 20, 0, 50, 55,
+ 109,218,116,253,194,133, 87,252, 34, 45,109,236,120,181, 90,173,
+ 21, 50,106,104, 54,155, 76, 93, 93, 93, 77,165,165,223,125,181,
+ 122,245,234,175,192,187,249,205,224,223,252,190, 12,102, 68,163,
+ 17,120, 30, 74, 0,121,111,190,249,230,175, 46,185,100,238,181,
+ 201,201, 41,227,148, 74, 37,241,182, 71, 28,199,193,104, 52,244,
+ 182,181,181,215,110,219,246,217,231,247,222,123,239,247, 0,186,
+ 193,207, 83,104, 27,205,121,136, 1, 42, 0, 17, 6,129,241,184,
+ 247, 15,200, 0,196, 3, 72, 3,144,244,194, 11, 47, 46,187,248,
+ 226,139,231,101,102,102, 77, 84,169, 84,241, 12,195,200, 36, 18,
+ 137,196,102,179, 89,173, 86,139,177,189,189,163,161,188,188,236,
+ 224,218,181,107,182,117,119,119,155,192,119,136,117, 3,232,128,
+ 235,218,126,159,157,100, 32, 48, 26, 63,206, 67, 14, 32, 9, 64,
+ 90, 90, 90, 90,202, 63,254,177,233,198, 25, 51,102,148,140, 25,
+ 51, 38, 71, 46, 87,168,101, 50,153,156,227, 56,142,101, 89,155,
+ 201,100,236,107,106,106, 58,179,111,223,190,125,119,222,121,199,
+ 78,240,115, 18,116,224,167,244,118,194,181,135,127, 84,231, 17,
+ 235, 80, 1,136, 64,220,140, 7,112,117,165,125, 25,145,227,155,
+ 1,144,224,244, 81, 13,252, 6,240,187,247,154,193, 27,189, 30,
+ 174, 6,239,236,226, 15,103, 44,196, 70, 51,140, 8,120, 59, 15,
+ 169,219,223, 14, 65, 72, 0, 47,112,138,129,243,224, 6,206,195,
+ 232,116, 30,253, 4,231,224,247,121,196, 50, 84, 0, 34, 20, 31,
+ 34,224,254,237,237, 3, 47,127, 59,227,205, 16,134, 51, 22,175,
+ 157,125,164, 70, 51,194,121,144,158,203, 72,231, 65,122, 46,126,
+ 159, 71,172, 66, 5, 32,194, 33, 20, 2,199,247, 72, 70,227,192,
+ 151, 81,140,104, 48,128,112,163,241,114, 14,222,234, 56, 92,253,
+ 133,156,199,112,231, 54,136,216, 13,223, 1, 21,128, 40, 96, 4,
+ 3,114,254,219,219,111,190,224,188,252,237,237,183, 65, 70,107,
+ 52,177,114, 30,177, 4, 21,128, 40,131,192,136,134,251,205, 25,
+ 111, 55,204,235, 77, 12,180,193,248, 56, 7, 32,136,231, 65,141,
+ 222, 59, 84, 0,162,152, 97, 12,105,212,132,202, 96, 98,225, 28,
+ 162, 25, 42, 0, 49,202, 72,134, 21, 45,198, 17, 43,231, 17,169,
+ 4, 74, 0,254, 63, 34, 58,182, 52, 79,174,223,189, 0, 0, 0,
+ 0, 73, 69, 78, 68,174, 66, 96,130
+};
+#endif /* CONFIG_DARWIN */
+
+static const unsigned char _data_android_icon_32_png[1321] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 32, 0, 0, 0, 32, 8, 6, 0, 0, 0,115,122,122,
+ 244, 0, 0, 4,240, 73, 68, 65, 84, 88,133,237, 87, 91,108, 20,
+ 85, 24,254,102,167, 51,237,238, 78,183,237,178,180,182,213,165,
+ 110, 98, 35, 18,181, 41, 41, 18,185, 52, 1,251,162, 4, 98,212,
+ 180, 38, 74,170,132, 7,170, 38, 26, 31, 20,130, 24,130,196,128,
+ 190, 24,181, 38,120, 71,177, 82,110,106,212, 4,154, 0, 69,170,
+ 98, 85,104,161, 8,180,118,183, 40,236,165,179,219,153,189,204,
+ 206,238,204,244,248, 80,102,178,211,237,110,161, 53,242,226,151,
+ 76,246, 59,255,249,207,255,127,123,230,159,115,161, 8, 33, 0,
+ 0,138,162,144, 7, 84, 40,196, 47,103, 89,118,105, 58,157, 62,
+ 89, 94,238, 58, 33, 73, 50,201,116,176,217,138, 44, 60, 31,121,
+ 154, 97,152, 37,138,162,244,184, 92,206,143, 36, 73, 30,159, 28,
+ 200,102, 43, 50, 56, 33, 4,212,117, 8,160, 68, 49,246, 5,195,
+ 48, 45, 25, 3,131,137, 68,226, 89,139,197, 82, 14, 0,170,170,
+ 122,237,118,251, 86,154,166, 27,116, 31, 77,211,122,139,139,237,
+ 139,219,187,107, 76, 34,218, 26,125, 55, 38, 32, 20,226, 27, 57,
+ 142, 59,158, 75, 93, 62, 72,146,180,190,115,160,254,131,124, 2,
+ 44,211, 5, 97, 89,118,169,206,207,250,119, 33,154,186,156,215,
+ 191,199,183,217,224,170,170,172,152, 46,254,180, 2,100, 89,246,
+ 233,252,206,138, 39,208,119,229, 93, 16,162,129, 79,244,227,210,
+ 104, 39, 46,141,118,226,106,244, 71,164, 84, 17,231,131,187,225,
+ 113,174, 50,198,198,227, 9,170,173,209,151,183,184, 10,242,117,
+ 242,124,228, 65,155,205,246,185,222, 38, 68, 67, 74, 19,241,217,
+ 111,117, 24, 39, 74,150, 63, 87,120, 43, 86,222,209,110,180,171,
+ 170,170, 90, 4, 33, 58, 84, 90,234,216,210,222, 93, 67,178, 6,
+ 32,255, 12, 80, 69, 69, 69, 70, 52, 33, 57,132,175,206,173,194,
+ 85,177, 7, 52,197, 76, 57, 64,213, 36,124, 51,240, 48, 46,132,
+ 58, 12, 27,203,178,155, 71, 71,195, 15,228, 74, 50,165, 0, 66,
+ 8, 34, 17,225,113,139,197, 50, 15, 0,164,116, 16,135, 47,182,
+ 66, 74, 7,177,110, 73, 63,230, 87, 54,103,141,185,171, 98, 45,
+ 30,187,247, 40, 8,209,240,243,200, 86,248,198, 14, 27,125,133,
+ 133,133,175,111, 88,238,197,134,229,222,172,113, 89,175, 96,120,
+ 216,231, 22,132,104, 27, 77,211,166,226, 75, 42, 60, 0,224,148,
+ 119, 39, 46, 6, 15,101, 5,250, 51,252, 53, 34,210, 31, 70,251,
+ 212,200, 54,184, 75, 87,192, 66, 49, 40, 40, 40, 88, 40, 8,209,
+ 183,210,233,116, 23,128,239, 0, 24,175,195,244, 25, 10, 66,116,
+ 19,203,178,219, 39, 7,239,236,107,132,148, 14, 78, 53, 89,121,
+ 241,208,252, 47, 49,151,171, 51,217, 84, 85,253,214,225,224, 86,
+ 3, 32,166,117, 32, 28, 30,107,176,217,108,191,220,112,150, 25,
+ 64,150,229, 86,167,179,244, 83,147,128,104, 52,254, 49,195, 48,
+ 173, 0,240,183,112, 28,231, 2, 31,162,204, 90,139, 6,247,203,
+ 216,253,235,221, 51, 74,212,218,112, 1,222,200,247, 24, 8,124,
+ 130,170,146,251, 81, 95,253, 60, 0,128, 16,146,176,219,173,197,
+ 132, 16, 98, 20, 33, 77,211, 75,116,222,251,215, 14, 4, 98,189,
+ 240,199,126,130, 37, 71,197, 95, 47,250,174,190, 3, 62,209,143,
+ 203, 99, 71, 12, 27, 69, 81,246, 64, 32, 88, 15,152,191, 2,171,
+ 78, 68,121,162, 90,133,228,240,172,146,103,198,152, 28,203,239,
+ 15,184, 38, 11,248, 79,145, 74,201,244, 77, 21,160,105, 26,117,
+ 83, 5,232,248, 95, 64,166,128,164, 78, 74,173, 30,211,239,108,
+ 144, 43,150, 36, 37,227, 38, 1,154,166,245,232,188,225,182,141,
+ 168,116, 44, 70,117, 73, 35, 8,209,102, 37,160,190,250, 5, 84,
+ 112, 11,225,113,174, 54,108,170,170,202, 77, 77, 43, 79, 3, 25,
+ 155,145,162, 40,237,250, 74, 88, 93,178, 12,213, 37,203,102,149,
+ 88,135,187,172, 9,238,178, 38,147,237,216,177,163, 59, 0,152,
+ 103,192,229,114,246,170,170,250,210,191,146, 53, 15,188, 94,239,
+ 137, 53,107, 86,191,135,107, 59,162,169, 8, 29, 14,110,231,249,
+ 243, 3,110, 65, 24,123, 67, 16,198,250,117,251, 76,102,195,237,
+ 108, 52,181,207,156, 57,189,119,207,158, 61,235, 23, 44,152,223,
+ 12, 32,172,219,167, 58, 21, 83,152,184, 7,188,202,113,220, 22,
+ 221, 40,202, 94, 12,241,135,112,214,191, 11, 0, 96,101, 92,104,
+ 174, 59, 9, 0, 56,233,221,136, 33,126,226,140, 80,193, 45,196,
+ 34,247, 38,148,217,106,141,125, 36,153, 76,134,231,204, 41,171,
+ 5, 16, 3, 48,126,237, 33,185, 78,197, 4,192,120, 60, 30,127,
+ 155, 16,114, 69, 55,150, 20,221, 14, 59, 91,105, 56,101,110, 82,
+ 86,102,174,193,153,130, 98,204,177, 47, 48,245,119,117, 29,217,
+ 14, 64,108,239,174, 81, 0,104,200, 56,144,228, 92, 7, 60,158,
+ 26, 62, 24, 12,214,137,162,240, 90, 46,159,233, 16, 10,133,134,
+ 59, 58, 58,158,107,105,105,126, 31, 19,255, 58, 11,121, 23, 34,
+ 143,167,134,103, 24,214,111, 56, 83,180,209, 71,153,120,206, 48,
+ 193,117,235,158,218, 5, 64,154,201,169, 24, 0, 64, 8, 49,214,
+ 135,185, 92, 29,104,203,196,221,174,210,177,216,240,185,165,120,
+ 145,193, 43,139,239, 51,120, 32,224,255, 29,128, 50,249,122,150,
+ 137,235,186, 27, 38, 18, 73,129,162, 40, 7, 0,164, 84, 17,177,
+ 212, 8, 92,246,123, 76, 78, 73,133,135,172, 70, 80,102,173, 53,
+ 108,251,247,239,123, 36, 62,239,149,131,153,126, 55,124, 53, 3,
+ 64, 82,169,212, 51,122,163,176,160, 36, 43, 57, 48,241, 85,100,
+ 38, 31, 28, 28,236, 90,187,246,201,227,211, 71, 39, 4,250, 44,
+ 228, 1, 21, 14,143, 61, 42,138,177,139,146, 36, 19, 73,146, 73,
+ 60, 46, 41, 7, 14, 28,124,179,187,251,135, 23, 5, 33,234,211,
+ 237,162, 24, 75,236,221,219,185, 13, 64, 57, 0, 90,146,100,100,
+ 62,147,115,255, 3, 56,204, 60,122,104, 43, 57,236, 0, 0, 0,
+ 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+
+static const FileEntry _file_entries[] =
+{
+
+ { "android_icon_16.png", _data_android_icon_16_png, 460 },
+#ifdef CONFIG_DARWIN
+ { "android_icon_256.png", _data_android_icon_256_png, 13369 },
+#endif
+ { "android_icon_32.png", _data_android_icon_32_png, 1321 },
+ { NULL, NULL, 0 }
+};
diff --git a/android_kmsg.c b/android_kmsg.c
new file mode 100644
index 0000000..f6261b3
--- /dev/null
+++ b/android_kmsg.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_kmsg.h"
+#include "charpipe.h"
+#include "android_debug.h"
+
+static CharDriverState* android_kmsg_cs;
+
+typedef struct {
+ CharDriverState* cs;
+ AndroidKmsgFlags flags;
+} KernelLog;
+
+static int
+kernel_log_can_read( void* opaque )
+{
+ return 1024;
+}
+
+static void
+kernel_log_read( void* opaque, const uint8_t* from, int len )
+{
+ KernelLog* k = opaque;
+
+ if (k->flags & ANDROID_KMSG_PRINT_MESSAGES)
+ printf( "%.*s", len, (const char*)from );
+
+ /* XXXX: TODO: save messages into in-memory buffer for later retrieval */
+}
+
+static void
+kernel_log_init( KernelLog* k, AndroidKmsgFlags flags )
+{
+ if ( qemu_chr_open_charpipe( &k->cs, &android_kmsg_cs ) < 0 ) {
+ derror( "could not create kernel log charpipe" );
+ exit(1);
+ }
+
+ qemu_chr_add_read_handler( k->cs, kernel_log_can_read, kernel_log_read, k );
+
+ k->flags = flags;
+}
+
+static KernelLog _kernel_log[1];
+
+void
+android_kmsg_init( AndroidKmsgFlags flags )
+{
+ if (_kernel_log->cs == NULL)
+ kernel_log_init( _kernel_log, flags );
+}
+
+
+CharDriverState* android_kmsg_get_cs( void )
+{
+ if (android_kmsg_cs == NULL) {
+ android_kmsg_init(0);
+ }
+ return android_kmsg_cs;
+}
diff --git a/android_kmsg.h b/android_kmsg.h
new file mode 100644
index 0000000..4419282
--- /dev/null
+++ b/android_kmsg.h
@@ -0,0 +1,31 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _android_kmsg_h
+#define _android_kmsg_h
+
+#include "vl.h"
+
+/* this chardriver is used to read the kernel messages coming
+ * from the first serial port (i.e. /dev/ttyS0) and store them
+ * in memory for later...
+ */
+
+typedef enum {
+ ANDROID_KMSG_SAVE_MESSAGES = (1 << 0),
+ ANDROID_KMSG_PRINT_MESSAGES = (1 << 1),
+} AndroidKmsgFlags;
+
+extern void android_kmsg_init( AndroidKmsgFlags flags );
+
+extern CharDriverState* android_kmsg_get_cs( void );
+
+#endif /* _android_kmsg_h */
diff --git a/android_main.c b/android_main.c
new file mode 100644
index 0000000..72c9ef6
--- /dev/null
+++ b/android_main.c
@@ -0,0 +1,2620 @@
+/* Copyright (C) 2006-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#else
+#include <winsock2.h>
+#include <process.h>
+#endif
+#include "libslirp.h"
+#include "sockets.h"
+
+#include "android.h"
+#include "vl.h"
+
+#include <SDL.h>
+#include <SDL_syswm.h>
+
+#include "math.h"
+
+#include "android.h"
+#include "android_charmap.h"
+#include "modem_driver.h"
+#include "shaper.h"
+#include "proxy_http.h"
+
+#include "android_utils.h"
+#include "android_resource.h"
+#include "android_config.h"
+
+#include "skin_image.h"
+#include "skin_trackball.h"
+#include "skin_keyboard.h"
+#include "skin_file.h"
+#include "skin_window.h"
+#include "skin_keyset.h"
+
+#include "android_timezone.h"
+#include "android_gps.h"
+#include "android_qemud.h"
+#include "android_kmsg.h"
+
+#include "android_option.h"
+#include "android_help.h"
+#include "hw/goldfish_nand.h"
+
+#include "framebuffer.h"
+AndroidRotation android_framebuffer_rotation;
+
+#define STRINGIFY(x) _STRINGIFY(x)
+#define _STRINGIFY(x) #x
+
+#define VERSION_STRING STRINGIFY(ANDROID_VERSION_MAJOR)"."STRINGIFY(ANDROID_VERSION_MINOR)
+
+#define KEYSET_FILE "default.keyset"
+SkinKeyset* android_keyset;
+
+#define D(...) do { if (VERBOSE_CHECK(init)) dprint(__VA_ARGS__); } while (0)
+
+extern int control_console_start( int port ); /* in control.c */
+
+extern int qemu_milli_needed;
+
+/* the default device DPI if none is specified by the skin
+ */
+#define DEFAULT_DEVICE_DPI 165
+
+static const AKeyCharmap* android_charmap;
+
+int android_base_port;
+
+#if 0
+static int opts->flashkeys; /* forward */
+#endif
+
+static void handle_key_command( void* opaque, SkinKeyCommand command, int param );
+
+#ifdef CONFIG_TRACE
+extern void start_tracing(void);
+extern void stop_tracing(void);
+#endif
+
+unsigned long android_verbose;
+
+int qemu_cpu_delay = 0;
+int qemu_cpu_delay_count;
+
+/***********************************************************************/
+/***********************************************************************/
+/***** *****/
+/***** U T I L I T Y R O U T I N E S *****/
+/***** *****/
+/***********************************************************************/
+/***********************************************************************/
+
+/*** APPLICATION DIRECTORY
+ *** Where are we ?
+ ***/
+
+const char* get_app_dir(void)
+{
+ char buffer[1024];
+ char* p = buffer;
+ char* end = p + sizeof(buffer);
+ p = bufprint_app_dir(p, end);
+ if (p >= end)
+ return NULL;
+
+ return strdup(buffer);
+}
+
+/*** CONFIGURATION
+ ***/
+
+static AConfig* emulator_config;
+static int emulator_config_found;
+static char emulator_configpath[256];
+
+void
+emulator_config_init( void )
+{
+ char* end = emulator_configpath + sizeof(emulator_configpath);
+ char* p;
+ void* config;
+
+ emulator_config = aconfig_node("","");
+
+ p = bufprint_config_file(emulator_configpath, end, "emulator.cfg");
+ if (p >= end) {
+ dwarning( "emulator configuration path too long" );
+ emulator_configpath[0] = 0;
+ return;
+ }
+
+ config = load_text_file( emulator_configpath );
+ if (config == NULL)
+ D( "cannot load emulator configuration at '%s'\n",
+ emulator_configpath );
+ else {
+ aconfig_load( emulator_config, config );
+ emulator_config_found = 1;
+ }
+}
+
+/* only call this function on normal exits, so that ^C doesn't save the configuration */
+void
+emulator_config_done( void )
+{
+ int save = 0; /* only save config if we see changes */
+ AConfig* guid_node;
+ char guid_value[32];
+ AConfig* window_node;
+ int prev_x, prev_y, win_x, win_y;
+
+ if (!emulator_configpath[0]) {
+ D("no config path ?");
+ return;
+ }
+
+ /* compare window positions */
+ {
+ SDL_WM_GetPos( &win_x, &win_y );
+ prev_x = win_x - 1;
+ prev_y = win_y - 1;
+
+ window_node = aconfig_find( emulator_config, "window" );
+ if (window_node == NULL) {
+ aconfig_set( emulator_config, "window", "" );
+ window_node = aconfig_find( emulator_config, "window" );
+ save = 1;
+ }
+
+ prev_x = (int)aconfig_unsigned( window_node, "x", 0 );
+ prev_y = (int)aconfig_unsigned( window_node, "y", 0 );
+
+ save = (prev_x != win_x) || (prev_y != win_y);
+
+ /* Beware: If the new window position is definitely off-screen,
+ * we don't want to save it in the configuration file. This can
+ * happen for example on Linux where certain window managers
+ * will 'minimize' a window by moving it to coordinates like
+ * (-5000,-5000)
+ */
+ if ( !SDL_WM_IsFullyVisible(0) ) {
+ D( "not saving new emulator window position since it is not fully visible" );
+ save = 0;
+ }
+ else if (save)
+ D( "emulator window position changed and will be saved as (%d, %d)", win_x, win_y );
+ }
+
+ /* If there is no guid node, create one with the current time in
+ * milliseconds. Thus, the value doesn't correspond to any system or
+ * user-specific data
+ */
+#define GUID_NAME "unique-id"
+
+ guid_node = aconfig_find( emulator_config, GUID_NAME );
+ if (!guid_node) {
+ struct timeval tm;
+ gettimeofday( &tm, NULL );
+ sprintf( guid_value, "%lld", (long long)tm.tv_sec*1000 + tm.tv_usec/1000 );
+ save = 1;
+ aconfig_set( emulator_config, GUID_NAME, guid_value );
+ }
+
+ if (save) {
+ char xbuf[16], ybuf[16];
+
+ sprintf( xbuf, "%d", win_x );
+ sprintf( ybuf, "%d", win_y );
+
+ aconfig_set( window_node, "x", xbuf );
+ aconfig_set( window_node, "y", ybuf );
+
+ /* do we need to create the $HOME/.android directory ? */
+ if ( !path_exists(emulator_configpath) ) {
+ char* dir = path_parent(emulator_configpath, 1);
+ if (dir == NULL) {
+ D("invalid user-specific config directory: '%s'", emulator_configpath);
+ return;
+ }
+ if ( path_mkdir_if_needed(dir, 0755) < 0 ) {
+ D("cannot create directory '%s', configuration lost", dir);
+ free(dir);
+ return;
+ }
+ free(dir);
+ }
+ if ( aconfig_save_file( emulator_config, emulator_configpath ) < 0 ) {
+ D( "cannot save configuration to %s", emulator_configpath);
+ } else
+ D( "configuration saved to %s", emulator_configpath );
+ }
+}
+
+void *loadpng(const char *fn, unsigned *_width, unsigned *_height);
+void *readpng(const unsigned char* base, size_t size, unsigned *_width, unsigned *_height);
+
+#ifdef CONFIG_DARWIN
+# define ANDROID_ICON_PNG "android_icon_256.png"
+#else
+# define ANDROID_ICON_PNG "android_icon_16.png"
+#endif
+
+static void
+sdl_set_window_icon( void )
+{
+ static int window_icon_set;
+
+ if (!window_icon_set)
+ {
+#ifdef _WIN32
+ HANDLE handle = GetModuleHandle( NULL );
+ HICON icon = LoadIcon( handle, MAKEINTRESOURCE(1) );
+ SDL_SysWMinfo wminfo;
+
+ SDL_GetWMInfo(&wminfo);
+
+ SetClassLong( wminfo.window, GCL_HICON, (LONG)icon );
+#else /* !_WIN32 */
+ unsigned icon_w, icon_h;
+ size_t icon_bytes;
+ const unsigned char* icon_data;
+ void* icon_pixels;
+
+ window_icon_set = 1;
+
+ icon_data = android_icon_find( ANDROID_ICON_PNG, &icon_bytes );
+ if ( !icon_data )
+ return;
+
+ icon_pixels = readpng( icon_data, icon_bytes, &icon_w, &icon_h );
+ if ( !icon_pixels )
+ return;
+
+ /* the data is loaded into memory as RGBA bytes by libpng. we want to manage
+ * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending
+ * on our CPU endianess
+ */
+ {
+ unsigned* d = icon_pixels;
+ unsigned* d_end = d + icon_w*icon_h;
+
+ for ( ; d < d_end; d++ ) {
+ unsigned pix = d[0];
+#if WORDS_BIGENDIAN
+ /* R,G,B,A read as RGBA => ARGB */
+ pix = ((pix >> 8) & 0xffffff) | (pix << 24);
+#else
+ /* R,G,B,A read as ABGR => ARGB */
+ pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16);
+#endif
+ d[0] = pix;
+ }
+ }
+
+ SDL_Surface* icon = sdl_surface_from_argb32( icon_pixels, icon_w, icon_h );
+ if (icon != NULL) {
+ SDL_WM_SetIcon(icon, NULL);
+ SDL_FreeSurface(icon);
+ free( icon_pixels );
+ }
+#endif /* !_WIN32 */
+ }
+}
+
+
+/***********************************************************************/
+/***********************************************************************/
+/***** *****/
+/***** S K I N I M A G E S *****/
+/***** *****/
+/***********************************************************************/
+/***********************************************************************/
+
+void send_key_event(unsigned code, unsigned down)
+{
+ if(code == 0) {
+ return;
+ }
+ if (VERBOSE_CHECK(keys))
+ printf(">> KEY [0x%03x,%s]\n", (code & 0x1ff), down ? "down" : " up " );
+ kbd_put_keycode((code & 0x1ff) | (down ? 0x200 : 0));
+}
+
+
+
+typedef struct {
+ AConfig* aconfig;
+ SkinFile* layout_file;
+ SkinLayout* layout;
+ SkinKeyboard* keyboard;
+ SkinWindow* window;
+ int win_x;
+ int win_y;
+ int show_trackball;
+ SkinTrackBall* trackball;
+ SkinImage* onion;
+ SkinRotation onion_rotation;
+ int onion_alpha;
+
+ AndroidOptions opts[1]; /* copy of options */
+} QEmulator;
+
+static QEmulator qemulator[1];
+
+static void
+qemulator_done( QEmulator* emulator )
+{
+ if (emulator->window) {
+ skin_window_free(emulator->window);
+ emulator->window = NULL;
+ }
+ if (emulator->trackball) {
+ skin_trackball_destroy(emulator->trackball);
+ emulator->trackball = NULL;
+ }
+ if (emulator->keyboard) {
+ skin_keyboard_free(emulator->keyboard);
+ emulator->keyboard = NULL;
+ }
+ emulator->layout = NULL;
+ if (emulator->layout_file) {
+ skin_file_free(emulator->layout_file);
+ emulator->layout_file = NULL;
+ }
+}
+
+
+static void
+qemulator_setup( QEmulator* emulator );
+
+static void
+qemulator_fb_update( void* _emulator, int x, int y, int w, int h )
+{
+ QEmulator* emulator = _emulator;
+
+ if (emulator->window)
+ skin_window_update_display( emulator->window, x, y, w, h );
+}
+
+static void
+qemulator_fb_rotate( void* _emulator, int rotation )
+{
+ QEmulator* emulator = _emulator;
+
+ qemulator_setup( emulator );
+}
+
+
+
+static int
+qemulator_init( QEmulator* emulator,
+ AConfig* aconfig,
+ const char* basepath,
+ int x,
+ int y,
+ AndroidOptions* opts )
+{
+ emulator->aconfig = aconfig;
+ emulator->layout_file = skin_file_create_from_aconfig(aconfig, basepath);
+ emulator->layout = emulator->layout_file->layouts;
+ emulator->keyboard = skin_keyboard_create_from_aconfig(aconfig, opts->raw_keys);
+ emulator->window = NULL;
+ emulator->win_x = x;
+ emulator->win_y = y;
+ emulator->opts[0] = opts[0];
+
+ /* register as a framebuffer clients for all displays defined in the skin file */
+ SKIN_FILE_LOOP_PARTS( emulator->layout_file, part )
+ SkinDisplay* disp = part->display;
+ if (disp->valid) {
+ qframebuffer_add_client( disp->qfbuff,
+ emulator,
+ qemulator_fb_update,
+ qemulator_fb_rotate,
+ NULL );
+ }
+ SKIN_FILE_LOOP_END_PARTS
+ return 0;
+}
+
+
+static AndroidKeyCode
+qemulator_rotate_keycode( QEmulator* emulator,
+ AndroidKeyCode sym )
+{
+ switch (skin_layout_get_dpad_rotation(emulator->layout)) {
+ case SKIN_ROTATION_90:
+ switch (sym) {
+ case kKeyCodeDpadLeft: sym = kKeyCodeDpadDown; break;
+ case kKeyCodeDpadRight: sym = kKeyCodeDpadUp; break;
+ case kKeyCodeDpadUp: sym = kKeyCodeDpadLeft; break;
+ case kKeyCodeDpadDown: sym = kKeyCodeDpadRight; break;
+ default: ;
+ }
+ break;
+
+ case SKIN_ROTATION_180:
+ switch (sym) {
+ case kKeyCodeDpadLeft: sym = kKeyCodeDpadRight; break;
+ case kKeyCodeDpadRight: sym = kKeyCodeDpadLeft; break;
+ case kKeyCodeDpadUp: sym = kKeyCodeDpadDown; break;
+ case kKeyCodeDpadDown: sym = kKeyCodeDpadUp; break;
+ default: ;
+ }
+ break;
+
+ case SKIN_ROTATION_270:
+ switch (sym) {
+ case kKeyCodeDpadLeft: sym = kKeyCodeDpadUp; break;
+ case kKeyCodeDpadRight: sym = kKeyCodeDpadDown; break;
+ case kKeyCodeDpadUp: sym = kKeyCodeDpadRight; break;
+ case kKeyCodeDpadDown: sym = kKeyCodeDpadLeft; break;
+ default: ;
+ }
+ break;
+
+ default: ;
+ }
+ return sym;
+}
+
+static int
+get_device_dpi( AndroidOptions* opts )
+{
+ int dpi_device = DEFAULT_DEVICE_DPI;
+
+ if (opts->dpi_device != NULL) {
+ char* end;
+ dpi_device = strtol( opts->dpi_device, &end, 0 );
+ if (end == NULL || *end != 0 || dpi_device <= 0) {
+ fprintf(stderr, "argument for -dpi-device must be a positive integer. Aborting\n" );
+ exit(1);
+ }
+ }
+ return dpi_device;
+}
+
+static double
+get_default_scale( AndroidOptions* opts )
+{
+ int dpi_device = get_device_dpi( opts );
+ int dpi_monitor = -1;
+ double scale = 0.0;
+
+ /* possible values for the 'scale' option are
+ * 'auto' : try to determine the scale automatically
+ * '<number>dpi' : indicates the host monitor dpi, compute scale accordingly
+ * '<fraction>' : use direct scale coefficient
+ */
+
+ if (opts->scale) {
+ if (!strcmp(opts->scale, "auto"))
+ {
+ /* we need to get the host dpi resolution ? */
+ int xdpi, ydpi;
+
+ if ( get_monitor_resolution( &xdpi, &ydpi ) < 0 ) {
+ fprintf(stderr, "could not get monitor DPI resolution from system. please use -dpi-monitor to specify one\n" );
+ exit(1);
+ }
+ D( "system reported monitor resolutions: xdpi=%d ydpi=%d\n", xdpi, ydpi);
+ dpi_monitor = (xdpi + ydpi+1)/2;
+ }
+ else
+ {
+ char* end;
+ scale = strtod( opts->scale, &end );
+
+ if (end && end[0] == 'd' && end[1] == 'p' && end[2] == 'i' && end[3] == 0) {
+ if ( scale < 20 || scale > 1000 ) {
+ fprintf(stderr, "emulator: ignoring bad -scale argument '%s': %s\n", opts->scale,
+ "host dpi number must be between 20 and 1000" );
+ exit(1);
+ }
+ dpi_monitor = scale;
+ scale = 0.0;
+ }
+ else if (end == NULL || *end != 0) {
+ fprintf(stderr, "emulator: ignoring bad -scale argument '%s': %s\n", opts->scale,
+ "not a number or the 'auto' keyword" );
+ exit(1);
+ }
+ else if ( scale < 0.1 || scale > 3. ) {
+ fprintf(stderr, "emulator: ignoring bad -window-scale argument '%s': %s\n", opts->scale,
+ "must be between 0.1 and 3.0" );
+ exit(1);
+ }
+ }
+ }
+
+ if (scale == 0.0 && dpi_monitor > 0)
+ scale = dpi_monitor*1.0/dpi_device;
+
+ if (scale == 0.0)
+ scale = 1.0;
+
+ return scale;
+}
+
+void
+android_emulator_set_window_scale( double scale, int is_dpi )
+{
+ QEmulator* emulator = qemulator;
+
+ if (is_dpi)
+ scale /= get_device_dpi( emulator->opts );
+
+ if (emulator->window)
+ skin_window_set_scale( emulator->window, scale );
+}
+
+
+static void
+qemulator_set_title( QEmulator* emulator )
+{
+ char temp[64];
+
+ if (emulator->window == NULL)
+ return;
+
+ snprintf( temp, sizeof(temp), "Android Emulator (%d)", android_base_port );
+ skin_window_set_title( emulator->window, temp );
+}
+
+/* called by the emulated framebuffer device each time the content of the
+ * framebuffer has changed. the rectangle is the bounding box of all changes
+ */
+static void
+sdl_update(DisplayState *ds, int x, int y, int w, int h)
+{
+ /* this function is being called from the console code that is currently inactive
+ ** simple totally ignore it...
+ */
+ (void)ds;
+ (void)x;
+ (void)y;
+ (void)w;
+ (void)h;
+}
+
+
+
+static void
+qemulator_setup( QEmulator* emulator )
+{
+ AndroidOptions* opts = emulator->opts;
+
+ if ( !emulator->window && !opts->no_window ) {
+ SkinLayout* layout = emulator->layout;
+ double scale = get_default_scale(emulator->opts);
+
+ emulator->window = skin_window_create( layout, emulator->win_x, emulator->win_y, scale, 0);
+ if (emulator->window == NULL)
+ return;
+
+ {
+ SkinTrackBall* ball;
+ SkinTrackBallParameters params;
+
+ params.diameter = 30;
+ params.ring = 2;
+ params.ball_color = 0xffe0e0e0;
+ params.dot_color = 0xff202020;
+ params.ring_color = 0xff000000;
+
+ ball = skin_trackball_create( &params );
+ emulator->trackball = ball;
+ skin_window_set_trackball( emulator->window, ball );
+ }
+
+ if ( emulator->onion != NULL )
+ skin_window_set_onion( emulator->window,
+ emulator->onion,
+ emulator->onion_rotation,
+ emulator->onion_alpha );
+
+ qemulator_set_title( emulator );
+ }
+}
+
+
+/* called by the emulated framebuffer device each time the framebuffer
+ * is resized or rotated */
+static void
+sdl_resize(DisplayState *ds, int w, int h, int rotation)
+{
+ fprintf(stderr, "weird, sdl_resize being called with framebuffer interface\n");
+ exit(1);
+}
+
+
+static void sdl_refresh(DisplayState *ds)
+{
+ QEmulator* emulator = ds->opaque;
+ SDL_Event ev;
+ SkinWindow* window = emulator->window;
+ SkinKeyboard* keyboard = emulator->keyboard;
+
+ /* this will eventually call sdl_update if the content of the VGA framebuffer
+ * has changed */
+ qframebuffer_check_updates();
+
+ if (window == NULL)
+ return;
+
+ while(SDL_PollEvent(&ev)){
+ switch(ev.type){
+ case SDL_VIDEOEXPOSE:
+ skin_window_redraw( window, NULL );
+ break;
+
+ case SDL_KEYDOWN:
+#ifdef _WIN32
+ /* special code to deal with Alt-F4 properly */
+ if (ev.key.keysym.sym == SDLK_F4 &&
+ ev.key.keysym.mod & KMOD_ALT) {
+ goto CleanExit;
+ }
+#endif
+#ifdef __APPLE__
+ /* special code to deal with Command-Q properly */
+ if (ev.key.keysym.sym == SDLK_q &&
+ ev.key.keysym.mod & KMOD_META) {
+ goto CleanExit;
+ }
+#endif
+ skin_keyboard_process_event( keyboard, &ev, 1 );
+ break;
+
+ case SDL_KEYUP:
+ skin_keyboard_process_event( keyboard, &ev, 0 );
+ break;
+
+ case SDL_MOUSEMOTION:
+ skin_window_process_event( window, &ev );
+ break;
+
+ case SDL_MOUSEBUTTONDOWN:
+ case SDL_MOUSEBUTTONUP:
+ {
+ int down = (ev.type == SDL_MOUSEBUTTONDOWN);
+ if (ev.button.button == 4)
+ {
+ /* scroll-wheel simulates DPad up */
+ AndroidKeyCode kcode;
+
+ kcode = qemulator_rotate_keycode(emulator, kKeyCodeDpadUp);
+ send_key_event( kcode, down );
+ }
+ else if (ev.button.button == 5)
+ {
+ /* scroll-wheel simulates DPad down */
+ AndroidKeyCode kcode;
+
+ kcode = qemulator_rotate_keycode(emulator, kKeyCodeDpadDown);
+ send_key_event( kcode, down );
+ }
+ else if (ev.button.button == SDL_BUTTON_LEFT) {
+ skin_window_process_event( window, &ev );
+ }
+#if 0
+ else {
+ fprintf(stderr, "... mouse button %s: button=%d state=%04x x=%d y=%d\n",
+ down ? "down" : "up ",
+ ev.button.button, ev.button.state, ev.button.x, ev.button.y);
+ }
+#endif
+ }
+ break;
+
+ case SDL_QUIT:
+#if defined _WIN32 || defined __APPLE__
+ CleanExit:
+#endif
+ /* only save emulator config through clean exit */
+ qemulator_done( emulator );
+ qemu_system_shutdown_request();
+ return;
+ }
+ }
+
+ skin_keyboard_flush( keyboard );
+}
+
+
+/* used to respond to a given keyboard command shortcut
+ */
+static void
+handle_key_command( void* opaque, SkinKeyCommand command, int down )
+{
+ static const struct { SkinKeyCommand cmd; AndroidKeyCode kcode; } keycodes[] =
+ {
+ { SKIN_KEY_COMMAND_BUTTON_CALL, kKeyCodeCall },
+ { SKIN_KEY_COMMAND_BUTTON_HOME, kKeyCodeHome },
+ { SKIN_KEY_COMMAND_BUTTON_BACK, kKeyCodeBack },
+ { SKIN_KEY_COMMAND_BUTTON_HANGUP, kKeyCodeEndCall },
+ { SKIN_KEY_COMMAND_BUTTON_POWER, kKeyCodePower },
+ { SKIN_KEY_COMMAND_BUTTON_SEARCH, kKeyCodeSearch },
+ { SKIN_KEY_COMMAND_BUTTON_MENU, kKeyCodeMenu },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_UP, kKeyCodeDpadUp },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_LEFT, kKeyCodeDpadLeft },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_RIGHT, kKeyCodeDpadRight },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_DOWN, kKeyCodeDpadDown },
+ { SKIN_KEY_COMMAND_BUTTON_DPAD_CENTER, kKeyCodeDpadCenter },
+ { SKIN_KEY_COMMAND_BUTTON_VOLUME_UP, kKeyCodeVolumeUp },
+ { SKIN_KEY_COMMAND_BUTTON_VOLUME_DOWN, kKeyCodeVolumeDown },
+ { SKIN_KEY_COMMAND_NONE, 0 }
+ };
+ int nn;
+ static int tracing = 0;
+ QEmulator* emulator = opaque;
+
+
+ for (nn = 0; keycodes[nn].kcode != 0; nn++) {
+ if (command == keycodes[nn].cmd) {
+ unsigned code = keycodes[nn].kcode;
+ if (down)
+ code |= 0x200;
+ kbd_put_keycode( code );
+ return;
+ }
+ }
+
+ // for the trackball command, handle down events to enable, and
+ // up events to disable
+ if (command == SKIN_KEY_COMMAND_TOGGLE_TRACKBALL) {
+ skin_window_toggle_trackball( emulator->window );
+ emulator->show_trackball = !emulator->show_trackball;
+ //qemulator_set_title( emulator );
+ return;
+ }
+
+ // only handle down events for the rest
+ if (down == 0)
+ return;
+
+ switch (command)
+ {
+ case SKIN_KEY_COMMAND_TOGGLE_NETWORK:
+ {
+ qemu_net_disable = !qemu_net_disable;
+ if (android_modem) {
+ amodem_set_data_registration(
+ android_modem,
+ qemu_net_disable ? A_REGISTRATION_UNREGISTERED
+ : A_REGISTRATION_HOME);
+ }
+ D( "network is now %s", qemu_net_disable ? "disconnected" : "connected" );
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_TOGGLE_FULLSCREEN:
+ if (emulator->window) {
+ skin_window_toggle_fullscreen(emulator->window);
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_TOGGLE_TRACING:
+ {
+#ifdef CONFIG_TRACE
+ tracing = !tracing;
+ if (tracing)
+ start_tracing();
+ else
+ stop_tracing();
+#endif
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_ONION_ALPHA_UP:
+ case SKIN_KEY_COMMAND_ONION_ALPHA_DOWN:
+ if (emulator->onion)
+ {
+ int alpha = emulator->onion_alpha;
+
+ if (command == SKIN_KEY_COMMAND_ONION_ALPHA_UP)
+ alpha += 16;
+ else
+ alpha -= 16;
+
+ if (alpha > 256)
+ alpha = 256;
+ else if (alpha < 0)
+ alpha = 0;
+
+ emulator->onion_alpha = alpha;
+ skin_window_set_onion( emulator->window, emulator->onion, emulator->onion_rotation, alpha );
+ skin_window_redraw( emulator->window, NULL );
+ //dprint( "onion alpha set to %d (%.f %%)", alpha, alpha/2.56 );
+ }
+ break;
+
+ case SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV:
+ case SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT:
+ {
+ SkinLayout* layout = NULL;
+
+ if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT) {
+ layout = emulator->layout->next;
+ if (layout == NULL)
+ layout = emulator->layout_file->layouts;
+ }
+ else if (command == SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV) {
+ layout = emulator->layout_file->layouts;
+ while (layout->next && layout->next != emulator->layout)
+ layout = layout->next;
+ }
+ if (layout != NULL) {
+ emulator->layout = layout;
+ skin_window_reset( emulator->window, layout );
+
+ if (emulator->keyboard)
+ skin_keyboard_set_rotation( emulator->keyboard,
+ skin_layout_get_dpad_rotation( layout ) );
+ if (emulator->trackball)
+ skin_window_set_trackball( emulator->window, emulator->trackball );
+
+ qframebuffer_invalidate_all();
+ qframebuffer_check_updates();
+ }
+ }
+ break;
+
+ default:
+ /* XXX: TODO ? */
+ ;
+ }
+}
+
+
+static void sdl_at_exit(void)
+{
+ emulator_config_done();
+ qemulator_done( qemulator );
+ SDL_Quit();
+}
+
+
+void sdl_display_init(DisplayState *ds, int full_screen)
+{
+ QEmulator* emulator = qemulator;
+ SkinDisplay* disp = skin_layout_get_display(emulator->layout);
+
+// fprintf(stderr,"*** sdl_display_init ***\n");
+ ds->opaque = emulator;
+
+ if (disp->rotation & 1) {
+ ds->width = disp->rect.size.h;
+ ds->height = disp->rect.size.w;
+ } else {
+ ds->width = disp->rect.size.w;
+ ds->height = disp->rect.size.h;
+ }
+
+ ds->dpy_update = sdl_update;
+ ds->dpy_resize = sdl_resize;
+ ds->dpy_refresh = sdl_refresh;
+
+ skin_keyboard_enable( emulator->keyboard, 1 );
+ skin_keyboard_on_command( emulator->keyboard, handle_key_command, emulator );
+}
+
+
+extern SkinKeyboard* android_emulator_get_keyboard(void)
+{
+ return qemulator->keyboard;
+}
+
+static const char* skin_network_speed = NULL;
+static const char* skin_network_delay = NULL;
+
+/* list of skin aliases */
+static const struct {
+ const char* name;
+ const char* alias;
+} skin_aliases[] = {
+ { "QVGA-L", "320x240" },
+ { "QVGA-P", "240x320" },
+ { "HVGA-L", "480x320" },
+ { "HVGA-P", "320x480" },
+ { "QVGA", "320x240" },
+ { "HVGA", "320x480" },
+ { NULL, NULL }
+};
+
+/* this is used by hw/events_device.c to send the charmap name to the system */
+const char* android_skin_keycharmap = NULL;
+
+void init_skinned_ui(const char *path, const char *name, AndroidOptions* opts)
+{
+ char tmp[1024];
+ AConfig* root;
+ AConfig* n;
+ int win_x, win_y, flags;
+
+ signal(SIGINT, SIG_DFL);
+#ifndef _WIN32
+ signal(SIGQUIT, SIG_DFL);
+#endif
+
+ /* we're not a game, so allow the screensaver to run */
+ putenv("SDL_VIDEO_ALLOW_SCREENSAVER=1");
+
+ flags = SDL_INIT_NOPARACHUTE;
+ if (!opts->no_window)
+ flags |= SDL_INIT_VIDEO;
+
+ if(SDL_Init(flags)){
+ fprintf(stderr, "SDL init failure, reason is: %s\n", SDL_GetError() );
+ exit(1);
+ }
+
+ if (!opts->no_window) {
+ SDL_EnableUNICODE(!opts->raw_keys);
+ SDL_EnableKeyRepeat(0,0);
+
+ sdl_set_window_icon();
+ }
+ else
+ {
+#ifndef _WIN32
+ /* prevent SIGTTIN and SIGTTOUT from stopping us. this is necessary to be
+ * able to run the emulator in the background (e.g. "emulator &").
+ * despite the fact that the emulator should not grab input or try to
+ * write to the output in normal cases, we're stopped on some systems
+ * (e.g. OS X)
+ */
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+#endif
+ }
+ atexit(sdl_at_exit);
+
+ root = aconfig_node("", "");
+
+ if(name) {
+ /* Support skin aliases like QVGA-H QVGA-P, etc...
+ But first we check if it's a directory that exist before applyin the alias */
+ sprintf(tmp, "%s/%s", path, name);
+ if (!path_exists(tmp)) {
+ /* directory is invalid, apply alias */
+ int nn;
+ for (nn = 0; ; nn++ ) {
+ const char* skin_name = skin_aliases[nn].name;
+ const char* skin_alias = skin_aliases[nn].alias;
+
+ if ( !skin_name )
+ break;
+
+ if ( !strcasecmp( skin_name, name ) ) {
+ name = skin_alias;
+ break;
+ }
+ }
+ }
+
+ /* Magically support skins like "320x240" */
+ if(isdigit(name[0])) {
+ char *x = strchr(name, 'x');
+ if(x && isdigit(x[1])) {
+ int width = atoi(name);
+ int height = atoi(x + 1);
+ sprintf(tmp,"display {\n width %d\n height %d\n}\n", width, height);
+ aconfig_load(root, strdup(tmp));
+ path = ":";
+ goto found_a_skin;
+ }
+ }
+
+ sprintf(tmp, "%s/%s/layout", path, name);
+ D("trying to load skin file '%s'", tmp);
+
+ if(aconfig_load_file(root, tmp) >= 0) {
+ sprintf(tmp, "%s/%s/", path, name);
+ path = tmp;
+ goto found_a_skin;
+ } else {
+ fprintf(stderr, "### WARNING: could not load skin file '%s', using built-in one\n", tmp);
+ }
+ }
+
+ {
+ const unsigned char* layout_base;
+ size_t layout_size;
+
+ name = "<builtin>";
+
+ layout_base = android_resource_find( "layout", &layout_size );
+ if (layout_base != NULL) {
+ char* base = malloc( layout_size+1 );
+ memcpy( base, layout_base, layout_size );
+ base[layout_size] = 0;
+
+ D("parsing built-in skin layout file (size=%d)", (int)layout_size);
+ aconfig_load(root, base);
+ path = ":";
+ } else {
+ fprintf(stderr, "Couldn't load builtin skin\n");
+ exit(1);
+ }
+ }
+
+found_a_skin:
+ {
+ AConfig* node = aconfig_find( emulator_config, "window" );
+
+ win_x = 10;
+ win_y = 10;
+
+ if (node == NULL) {
+ if (emulator_config_found)
+ dwarning( "broken configuration file doesn't have 'window' element" );
+ } else {
+ win_x = aconfig_int( node, "x", win_x );
+ win_y = aconfig_int( node, "y", win_y );
+ }
+ }
+ if ( qemulator_init( qemulator, root, path, win_x, win_y, opts ) < 0 ) {
+ fprintf(stderr, "### Error: could not load emulator skin '%s'\n", name);
+ exit(1);
+ }
+
+ android_skin_keycharmap = skin_keyboard_charmap_name(qemulator->keyboard);
+
+ /* the default network speed and latency can now be specified by the device skin */
+ n = aconfig_find(root, "network");
+ if (n != NULL) {
+ skin_network_speed = aconfig_str(n, "speed", 0);
+ skin_network_delay = aconfig_str(n, "delay", 0);
+ }
+
+#if 0
+ /* create a trackball if needed */
+ n = aconfig_find(root, "trackball");
+ if (n != NULL) {
+ SkinTrackBallParameters params;
+
+ params.x = aconfig_unsigned(n, "x", 0);
+ params.y = aconfig_unsigned(n, "y", 0);
+ params.diameter = aconfig_unsigned(n, "diameter", 20);
+ params.ring = aconfig_unsigned(n, "ring", 1);
+
+ params.ball_color = aconfig_unsigned(n, "ball-color", 0xffe0e0e0);
+ params.dot_color = aconfig_unsigned(n, "dot-color", 0xff202020 );
+ params.ring_color = aconfig_unsigned(n, "ring-color", 0xff000000 );
+
+ qemu_disp->trackball = skin_trackball_create( &params );
+ skin_trackball_refresh( qemu_disp->trackball );
+ }
+#endif
+
+ /* add an onion overlay image if needed */
+ if (opts->onion) {
+ SkinImage* onion = skin_image_find_simple( opts->onion );
+ int alpha, rotate;
+
+ if ( opts->onion_alpha && 1 == sscanf( opts->onion_alpha, "%d", &alpha ) ) {
+ alpha = (256*alpha)/100;
+ } else
+ alpha = 128;
+
+ if ( opts->onion_rotation && 1 == sscanf( opts->onion_rotation, "%d", &rotate ) ) {
+ rotate &= 3;
+ } else
+ rotate = SKIN_ROTATION_0;
+
+ qemulator->onion = onion;
+ qemulator->onion_alpha = alpha;
+ qemulator->onion_rotation = rotate;
+ }
+}
+
+/* where to look relative to appdir for system.img and friends */
+const char *sysdir_paths[] = {
+ "%s/lib/images/%s", /* emulator in <sdk>, images in <sdk>/lib/images */
+ "%s/%s", /* emulator and images in the same directory */
+ "%s/../%s",
+ "%s/../../%s", /* emulator in <build>/host/bin, images in <build> */
+ 0
+};
+
+int qemu_main(int argc, char **argv);
+
+/* this function dumps the QEMU help */
+extern void help( void );
+extern void emulator_help( void );
+
+#define VERBOSE_OPT(str,var) { str, &var }
+
+#define _VERBOSE_TAG(x,y) { #x, VERBOSE_##x, y },
+static const struct { const char* name; int flag; const char* text; }
+verbose_options[] = {
+ VERBOSE_TAG_LIST
+ { 0, 0, 0 }
+};
+
+int
+android_parse_network_speed(const char* speed)
+{
+ int n;
+ char* end;
+ double sp;
+
+ if (speed == NULL || speed[0] == 0) {
+ speed = DEFAULT_NETSPEED;
+ }
+
+ for (n = 0; android_netspeeds[n].name != NULL; n++) {
+ if (!strcmp(android_netspeeds[n].name, speed)) {
+ qemu_net_download_speed = android_netspeeds[n].download;
+ qemu_net_upload_speed = android_netspeeds[n].upload;
+ return 0;
+ }
+ }
+
+ /* is this a number ? */
+ sp = strtod(speed, &end);
+ if (end == speed) {
+ return -1;
+ }
+
+ qemu_net_download_speed = qemu_net_upload_speed = sp*1000.;
+ if (*end == ':') {
+ speed = end+1;
+ sp = strtod(speed, &end);
+ if (end > speed) {
+ qemu_net_download_speed = sp*1000.;
+ }
+ }
+
+ if (android_modem)
+ amodem_set_data_network_type( android_modem,
+ android_parse_network_type(speed) );
+ return 0;
+}
+
+
+int
+android_parse_network_latency(const char* delay)
+{
+ int n;
+ char* end;
+ double sp;
+
+ if (delay == NULL || delay[0] == 0)
+ delay = DEFAULT_NETDELAY;
+
+ for (n = 0; android_netdelays[n].name != NULL; n++) {
+ if ( !strcmp( android_netdelays[n].name, delay ) ) {
+ qemu_net_min_latency = android_netdelays[n].min_ms;
+ qemu_net_max_latency = android_netdelays[n].max_ms;
+ return 0;
+ }
+ }
+
+ /* is this a number ? */
+ sp = strtod(delay, &end);
+ if (end == delay) {
+ return -1;
+ }
+
+ qemu_net_min_latency = qemu_net_max_latency = (int)sp;
+ if (*end == ':') {
+ delay = (const char*)end+1;
+ sp = strtod(delay, &end);
+ if (end > delay) {
+ qemu_net_max_latency = (int)sp;
+ }
+ }
+ return 0;
+}
+
+
+static int
+load_keyset(const char* path)
+{
+ if (path_can_read(path)) {
+ AConfig* root = aconfig_node("","");
+ if (!aconfig_load_file(root, path)) {
+ android_keyset = skin_keyset_new(root);
+ if (android_keyset != NULL) {
+ D( "keyset loaded from: %s", path);
+ return 0;
+ }
+ }
+ }
+ return -1;
+}
+
+static void
+parse_keyset(const char* keyset, AndroidOptions* opts)
+{
+ char kname[MAX_PATH];
+ char temp[MAX_PATH];
+ char* p;
+ char* end;
+
+ /* append .keyset suffix if needed */
+ if (strchr(keyset, '.') == NULL) {
+ p = kname;
+ end = p + sizeof(kname);
+ p = bufprint(p, end, "%s.keyset", keyset);
+ if (p >= end) {
+ derror( "keyset name too long: '%s'\n", keyset);
+ exit(1);
+ }
+ keyset = kname;
+ }
+
+ /* look for a the keyset file */
+ p = temp;
+ end = p + sizeof(temp);
+ p = bufprint_config_file(p, end, keyset);
+ if (p < end && load_keyset(temp) == 0)
+ return;
+
+ p = temp;
+ p = bufprint(p, end, "%s" PATH_SEP "keysets" PATH_SEP "%s", opts->system, keyset);
+ if (p < end && load_keyset(temp) == 0)
+ return;
+
+ p = temp;
+ p = bufprint_app_dir(p, end);
+ p = bufprint(p, end, PATH_SEP "keysets" PATH_SEP "%s", keyset);
+ if (p < end && load_keyset(temp) == 0)
+ return;
+
+ return;
+}
+
+static void
+write_default_keyset( void )
+{
+ char path[MAX_PATH];
+
+ bufprint_config_file( path, path+sizeof(path), KEYSET_FILE );
+
+ /* only write if there is no file here */
+ if ( !path_exists(path) ) {
+ int fd = open( path, O_WRONLY | O_CREAT, 0666 );
+ int ret;
+ const char* ks = skin_keyset_get_default();
+
+
+ D( "writing default keyset file to %s", path );
+
+ if (fd < 0) {
+ D( "%s: could not create file: %s", __FUNCTION__, strerror(errno) );
+ return;
+ }
+ CHECKED(ret, write(fd, ks, strlen(ks)));
+ close(fd);
+ }
+}
+
+#ifdef CONFIG_NAND_LIMITS
+
+static uint64_t
+parse_nand_rw_limit( const char* value )
+{
+ char* end;
+ uint64_t val = strtoul( value, &end, 0 );
+
+ if (end == value) {
+ derror( "bad parameter value '%s': expecting unsigned integer", value );
+ exit(1);
+ }
+
+ switch (end[0]) {
+ case 'K': val <<= 10; break;
+ case 'M': val <<= 20; break;
+ case 'G': val <<= 30; break;
+ case 0: break;
+ default:
+ derror( "bad read/write limit suffix: use K, M or G" );
+ exit(1);
+ }
+ return val;
+}
+
+static void
+parse_nand_limits(char* limits)
+{
+ int pid = -1, signal = -1;
+ int64_t reads = 0, writes = 0;
+ char* item = limits;
+
+ /* parse over comma-separated items */
+ while (item && *item) {
+ char* next = strchr(item, ',');
+ char* end;
+
+ if (next == NULL) {
+ next = item + strlen(item);
+ } else {
+ *next++ = 0;
+ }
+
+ if ( !memcmp(item, "pid=", 4) ) {
+ pid = strtol(item+4, &end, 10);
+ if (end == NULL || *end) {
+ derror( "bad parameter, expecting pid=<number>, got '%s'",
+ item );
+ exit(1);
+ }
+ if (pid <= 0) {
+ derror( "bad parameter: process identifier must be > 0" );
+ exit(1);
+ }
+ }
+ else if ( !memcmp(item, "signal=", 7) ) {
+ signal = strtol(item+7,&end, 10);
+ if (end == NULL || *end) {
+ derror( "bad parameter: expecting signal=<number>, got '%s'",
+ item );
+ exit(1);
+ }
+ if (signal <= 0) {
+ derror( "bad parameter: signal number must be > 0" );
+ exit(1);
+ }
+ }
+ else if ( !memcmp(item, "reads=", 6) ) {
+ reads = parse_nand_rw_limit(item+6);
+ }
+ else if ( !memcmp(item, "writes=", 7) ) {
+ writes = parse_nand_rw_limit(item+7);
+ }
+ else {
+ derror( "bad parameter '%s' (see -help-nand-limits)", item );
+ exit(1);
+ }
+ item = next;
+ }
+ if (pid < 0) {
+ derror( "bad paramater: missing pid=<number>" );
+ exit(1);
+ }
+ else if (signal < 0) {
+ derror( "bad parameter: missing signal=<number>" );
+ exit(1);
+ }
+ else if (reads == 0 && writes == 0) {
+ dwarning( "no read or write limit specified. ignoring -nand-limits" );
+ } else {
+ nand_threshold* t;
+
+ t = &android_nand_read_threshold;
+ t->pid = pid;
+ t->signal = signal;
+ t->counter = 0;
+ t->limit = reads;
+
+ t = &android_nand_write_threshold;
+ t->pid = pid;
+ t->signal = signal;
+ t->counter = 0;
+ t->limit = writes;
+ }
+}
+#endif /* CONFIG_NAND_LIMITS */
+
+/* If *arg isn't already set, and <dir>/<file> exists, use it. */
+static void default_file(char **arg, const char* option, const char *dir, const char *file) {
+ if (*arg == NULL || (*arg)[0] == '\0') {
+ *arg = malloc(strlen(dir) + strlen(PATH_SEP) + strlen(file) + 1);
+ sprintf(*arg, "%s%s%s", dir, PATH_SEP, file);
+ if (option)
+ D("autoconfig: -%s %s", option, *arg);
+ }
+}
+
+
+/* Call default_file() and also exit if the file doesn't exist. */
+static void require_file(char **arg, const char* option, const char *dir, const char *file) {
+ default_file(arg, option, dir, file);
+ if (!path_exists(*arg)) {
+ fprintf(stderr, "Cannot find file: %s\n", *arg);
+ if (option != NULL)
+ fprintf(stderr, "Please specify a valid -%s file\n", option);
+ exit(1);
+ }
+}
+
+
+/* If *arg is set, require it to exist, else use the default if it exists. */
+static void optional_file(char **arg, const char* option, const char *dir, const char *file) {
+ if (*arg == NULL) {
+ default_file(arg, option, dir, file);
+ if (!path_exists(*arg))
+ *arg = NULL;
+ } else {
+ /* If it's supplied explciitly, it better be there. */
+ require_file(arg, option, dir, file);
+ }
+}
+
+void emulator_help( void )
+{
+ STRALLOC_DEFINE(out);
+ android_help_main(out);
+ printf( "%.*s", out->n, out->s );
+ stralloc_reset(out);
+ exit(1);
+}
+
+static int
+add_dns_server( const char* server_name )
+{
+ struct in_addr dns1;
+ struct hostent* host = gethostbyname(server_name);
+
+ if (host == NULL) {
+ fprintf(stderr,
+ "### WARNING: can't resolve DNS server name '%s'\n",
+ server_name );
+ return -1;
+ }
+
+ dns1 = *(struct in_addr*)host->h_addr;
+ D( "DNS server name '%s' resolved to %s", server_name, inet_ntoa(dns1) );
+
+ if ( slirp_add_dns_server( dns1 ) < 0 ) {
+ fprintf(stderr,
+ "### WARNING: could not add DNS server '%s' to the network stack\n", server_name);
+ return -1;
+ }
+ return 0;
+}
+
+
+enum {
+ REPORT_CONSOLE_SERVER = (1 << 0),
+ REPORT_CONSOLE_MAX = (1 << 1)
+};
+
+static int
+get_report_console_options( char* end, int *maxtries )
+{
+ int flags = 0;
+
+ if (end == NULL || *end == 0)
+ return 0;
+
+ if (end[0] != ',') {
+ derror( "socket port/path can be followed by [,<option>]+ only\n");
+ exit(3);
+ }
+ end += 1;
+ while (*end) {
+ char* p = strchr(end, ',');
+ if (p == NULL)
+ p = end + strlen(end);
+
+ if (memcmp( end, "server", p-end ) == 0)
+ flags |= REPORT_CONSOLE_SERVER;
+ else if (memcmp( end, "max=", 4) == 0) {
+ end += 4;
+ *maxtries = strtol( end, NULL, 10 );
+ flags |= REPORT_CONSOLE_MAX;
+ } else {
+ derror( "socket port/path can be followed by [,server][,max=<count>] only\n");
+ exit(3);
+ }
+
+ end = p;
+ if (*end)
+ end += 1;
+ }
+ return flags;
+}
+
+static void
+report_console( const char* proto_port, int console_port )
+{
+ int s = -1, s2, ret;
+ int maxtries = 10;
+ int flags = 0;
+ signal_state_t sigstate;
+
+ disable_sigalrm( &sigstate );
+
+ if ( !strncmp( proto_port, "tcp:", 4) ) {
+ char* end;
+ long port = strtol(proto_port + 4, &end, 10);
+
+ flags = get_report_console_options( end, &maxtries );
+
+ if (flags & REPORT_CONSOLE_SERVER) {
+ s = socket_loopback_server( port, SOCK_STREAM );
+ if (s < 0) {
+ fprintf(stderr, "could not create server socket on TCP:%ld: %s\n",
+ port, socket_errstr());
+ exit(3);
+ }
+ } else {
+ for ( ; maxtries > 0; maxtries-- ) {
+ D("trying to find console-report client on tcp:%d", port);
+ s = socket_loopback_client( port, SOCK_STREAM );
+ if (s >= 0)
+ break;
+
+ sleep_ms(1000);
+ }
+ if (s < 0) {
+ fprintf(stderr, "could not connect to server on TCP:%ld: %s\n",
+ port, socket_errstr());
+ exit(3);
+ }
+ }
+ } else if ( !strncmp( proto_port, "unix:", 5) ) {
+#ifdef _WIN32
+ fprintf(stderr, "sorry, the unix: protocol is not supported on Win32\n");
+ exit(3);
+#else
+ char* path = strdup(proto_port+5);
+ char* end = strchr(path, ',');
+ if (end != NULL) {
+ flags = get_report_console_options( end, &maxtries );
+ *end = 0;
+ }
+ if (flags & REPORT_CONSOLE_SERVER) {
+ s = socket_unix_server( path, SOCK_STREAM );
+ if (s < 0) {
+ fprintf(stderr, "could not bind unix socket on '%s': %s\n",
+ proto_port+5, socket_errstr());
+ exit(3);
+ }
+ } else {
+ for ( ; maxtries > 0; maxtries-- ) {
+ s = socket_unix_client( path, SOCK_STREAM );
+ if (s >= 0)
+ break;
+
+ sleep_ms(1000);
+ }
+ if (s < 0) {
+ fprintf(stderr, "could not connect to unix socket on '%s': %s\n",
+ path, socket_errstr());
+ exit(3);
+ }
+ }
+ free(path);
+#endif
+ } else {
+ fprintf(stderr, "-report-console must be followed by a 'tcp:<port>' or 'unix:<path>'\n");
+ exit(3);
+ }
+
+ if (flags & REPORT_CONSOLE_SERVER) {
+ int tries = 3;
+ D( "waiting for console-reporting client" );
+ do {
+ s2 = accept( s, NULL, NULL );
+ } while (s2 < 0 && socket_errno == EINTR && --tries > 0);
+
+ if (s2 < 0) {
+ fprintf(stderr, "could not accept console-reporting client connection: %s\n",
+ socket_errstr());
+ exit(3);
+ }
+
+ socket_close(s);
+ s = s2;
+ }
+
+ /* simply send the console port in text */
+ {
+ char temp[12];
+ snprintf( temp, sizeof(temp), "%d", console_port );
+ do {
+ ret = send( s, temp, strlen(temp), 0 );
+ } while (ret < 0 && socket_errno == EINTR);
+
+ if (ret < 0) {
+ fprintf(stderr, "could not send console number report: %d: %s\n",
+ socket_errno, socket_errstr() );
+ exit(3);
+ }
+ socket_close(s);
+ }
+ D( "console port number sent to remote. resuming boot" );
+
+ restore_sigalrm (&sigstate);
+}
+
+#ifdef _WIN32
+#undef main /* we don't want SDL to define main */
+#endif
+
+int main(int argc, char **argv)
+{
+ char tmp[MAX_PATH];
+ char* tmpend = tmp + sizeof(tmp);
+ char* args[128];
+ int n;
+ char* opt;
+ int use_sdcard_img = 0;
+ int serial = 0;
+ int gps_serial = 0;
+ int radio_serial = 0;
+ int qemud_serial = 0;
+ int shell_serial = 0;
+ int dns_count = 0;
+
+ const char *appdir = get_app_dir();
+ char* android_build_root = NULL;
+ char* android_build_out = NULL;
+
+ AndroidOptions opts[1];
+
+ args[0] = argv[0];
+
+ if ( android_parse_options( &argc, &argv, opts ) < 0 ) {
+ exit(1);
+ }
+
+ while (argc-- > 1) {
+ opt = (++argv)[0];
+
+ if(!strcmp(opt, "-qemu")) {
+ break;
+ }
+
+ if (!strcmp(opt, "-help")) {
+ emulator_help();
+ }
+
+ if (!strncmp(opt, "-help-",6)) {
+ STRALLOC_DEFINE(out);
+ opt += 6;
+
+ if (!strcmp(opt, "all")) {
+ android_help_all(out);
+ }
+ else if (android_help_for_option(opt, out) == 0) {
+ /* ok */
+ }
+ else if (android_help_for_topic(opt, out) == 0) {
+ /* ok */
+ }
+ if (out->n > 0) {
+ printf("\n%.*s", out->n, out->s);
+ exit(0);
+ }
+
+ fprintf(stderr, "unknown option: -%s\n", opt);
+ emulator_help();
+ }
+
+ if (opt[0] == '-') {
+ fprintf(stderr, "unknown option: %s\n", opt);
+ emulator_help();
+ }
+
+ fprintf(stderr, "invalid command-line parameter: %s\n", opt);
+ emulator_help();
+ }
+
+ android_charmap = android_charmaps[0];
+
+ if (opts->version) {
+ printf("Android emulator version %s\n"
+ "Copyright (C) 2006-2008 The Android Open Source Project and many others.\n"
+ "This program is a derivative of the QEMU CPU emulator (www.qemu.org).\n\n",
+#if defined ANDROID_BUILD_ID
+ VERSION_STRING " (build_id " STRINGIFY(ANDROID_BUILD_ID) ")" );
+#else
+ VERSION_STRING);
+#endif
+ printf(" This software is licensed under the terms of the GNU General Public\n"
+ " License version 2, as published by the Free Software Foundation, and\n"
+ " may be copied, distributed, and modified under those terms.\n\n"
+ " This program is distributed in the hope that it will be useful,\n"
+ " but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ " GNU General Public License for more details.\n\n");
+
+ exit(0);
+ }
+
+ if (opts->timezone) {
+ if ( timezone_set(opts->timezone) < 0 ) {
+ fprintf(stderr, "emulator: it seems the timezone '%s' is not in zoneinfo format\n", opts->timezone);
+ }
+ }
+
+ //if(opts->nopoll) qemu_milli_needed = 0;
+
+ /* try to find the top of the Android build tree */
+ do {
+ char* out = getenv("ANDROID_PRODUCT_OUT");
+
+ if (out == NULL || out[0] == 0)
+ break;
+
+ if (!path_exists(out)) {
+ dprint("### Weird, can't access ANDROID_PRODUCT_OUT as '%s'", out);
+ break;
+ }
+
+ android_build_root = path_parent( out, 4 );
+ if (android_build_root == NULL) {
+ break;
+ }
+ if (!path_exists(android_build_root)) {
+ dprint("### Weird, can't access build root as '%s'", android_build_root);
+ free(android_build_root);
+ android_build_root = NULL;
+ break;
+ }
+ android_build_out = out;
+ D( "found Android build root: %s", android_build_root );
+ D( "found Android build out: %s", android_build_out );
+ } while (0);
+
+ /* if no opts->system was specified, try to find one */
+ if (opts->system == NULL) {
+ for (n = 0; sysdir_paths[n]; n++) {
+ sprintf(tmp, sysdir_paths[n], appdir, "system.img");
+ if (path_exists(tmp)) {
+ sprintf(tmp, sysdir_paths[n], appdir, "");
+ opts->system = strdup(tmp);
+ break;
+ }
+ }
+
+ if (opts->system == NULL && android_build_out) {
+ sprintf(tmp, "%s/%s", android_build_out, "system.img");
+ if (path_exists(tmp))
+ opts->system = android_build_out;
+ }
+
+ if (opts->system == NULL) {
+ fprintf(stderr,
+ "Cannot locate system directory, which "
+ "contains 'system.img' and other\n"
+ "system files. Please specify one by "
+ "using '-system <directory>' or by\n"
+ "defining the environment variable ANDROID_PRODUCT_OUT.\n");
+ exit(1);
+ }
+
+ D("autoconfig: -system %s", opts->system);
+ }
+
+ if (opts->datadir == NULL) {
+ if (android_build_out)
+ opts->datadir = android_build_out;
+ else {
+ bufprint_config_path( tmp, tmpend );
+ opts->datadir = strdup(tmp);
+ }
+ D("autoconfig: -datadir %s", opts->datadir);
+ }
+
+ sprintf(tmp, "%s%s.", opts->datadir, PATH_SEP);
+ if (!path_can_write(tmp)) {
+ if (path_mkdir_if_needed(opts->datadir, 0755) != 0) {
+ fprintf(stderr,
+ "Cannot create data directory: %s\n"
+ "Please specify a writable directory with -datadir.\n", opts->datadir);
+ exit(1);
+ }
+ }
+
+ /* try to find the qemu kernel in the system directory,
+ * otherwise, try to get it in the prebuilt directory */
+ optional_file(&opts->kernel, "kernel", opts->system, "kernel-qemu");
+ if (!opts->kernel && android_build_root) {
+ sprintf(tmp, "%s/prebuilt/android-arm/kernel", android_build_root);
+ optional_file(&opts->kernel, "kernel", tmp, "kernel-qemu");
+ }
+
+ /* similar hack for emulator skins */
+ if (!opts->noskin && opts->skindir == NULL) {
+ if (android_build_root) {
+ sprintf(tmp, "%s/development/emulator", android_build_root);
+ optional_file(&opts->skindir, "skindir", tmp, "skins");
+ }
+ }
+
+ require_file(&opts->kernel, "kernel", opts->system, "kernel-qemu");
+ require_file(&opts->ramdisk, "ramdisk", opts->system, "ramdisk.img");
+ require_file(&opts->image, "image", opts->system, "system.img");
+ require_file(&opts->initdata, "initdata", opts->system, "userdata.img");
+
+ if (!opts->skindir)
+ optional_file(&opts->skindir, "skindir", opts->system, "skins");
+
+ optional_file(&opts->sdcard, "sdcard", opts->datadir, "sdcard.img");
+
+ if (opts->data == NULL) {
+ if (strcmp(opts->datadir, opts->system) != 0) {
+ /* in the past, the writable image was called "userdata.img" */
+ optional_file(&opts->data, "data", opts->datadir, "userdata.img");
+ }
+ default_file(&opts->data, "data", opts->datadir, "userdata-qemu.img");
+
+ if ( !path_exists(opts->data) ) {
+ /* if the file does not exist, imply a -wipe-data */
+ opts->wipe_data = 1;
+ }
+ } else if ( !path_exists(opts->data) ) {
+ /* if -data is used with a non-existent data file */
+ opts->wipe_data = 1;
+ }
+
+ {
+ FileLock* data_lock = filelock_create(opts->data);
+ if (data_lock == NULL) {
+ fprintf(stderr, "Cannot create /data image file lock\n");
+ exit(2);
+ }
+ /* if the file is already used, use a temporary file instead */
+ if (filelock_lock(data_lock) < 0) {
+ TempFile* data_tmp;
+ fprintf(stderr,
+ "### WARNING: Another emulator is running with our data file\n");
+
+ data_tmp = tempfile_create();
+ if (data_tmp == NULL) {
+ fprintf(stderr, "annot create a new temporary user data file.\n" );
+ exit(2);
+ }
+ fprintf(stderr, "### WARNING: User data changes will NOT be saved!\n");
+ opts->data = (char*) tempfile_path(data_tmp);
+ opts->wipe_data = 1;
+ }
+ }
+
+
+ /* wipe the data file if necessary */
+ if (opts->wipe_data || !path_exists(opts->data)) {
+ if (copy_file(opts->data, opts->initdata) >= 0) {
+ D("copied file '%s' from '%s'", opts->data, opts->initdata);
+ } else {
+ fprintf(stderr,
+ "### WARNING: Cannot write user data file '%s': %s\n",
+ opts->data, strerror(errno));
+ exit(3);
+ }
+ }
+
+ /* lock the SD card image file */
+ if (opts->sdcard != NULL) {
+ FileLock* sdcard_lock = filelock_create( opts->sdcard );
+ int free_sdcard = (sdcard_lock == NULL);
+
+ if (sdcard_lock && filelock_lock(sdcard_lock) < 0) {
+ fprintf( stderr, "#### WARNING: SD Card emulation disabled. '%s' already in use\n", opts->sdcard );
+ free_sdcard = 1;
+ }
+
+ if (free_sdcard) {
+ opts->sdcard = NULL;
+ }
+ }
+
+#ifdef CONFIG_NAND_LIMITS
+ if (opts->nand_limits)
+ parse_nand_limits(opts->nand_limits);
+#endif
+
+ if (opts->keyset) {
+ parse_keyset(opts->keyset, opts);
+ if (!android_keyset) {
+ fprintf(stderr,
+ "emulator: WARNING: could not find keyset file named '%s', using defaults instead\n",
+ opts->keyset);
+ }
+ }
+ if (!android_keyset) {
+ android_keyset = skin_keyset_new_from_text( skin_keyset_get_default() );
+ if (!android_keyset) {
+ fprintf(stderr, "PANIC: default keyset file is corrupted !!\n" );
+ fprintf(stderr, "PANIC: please update the code in skins/skin_keyset.c\n" );
+ exit(1);
+ }
+ if (!opts->keyset)
+ write_default_keyset();
+ }
+
+ if (opts->audio) {
+ if (opts->audio_in || opts->audio_out) {
+ derror( "you can't use -audio with -audio-in or -audio-out\n" );
+ exit(1);
+ }
+ if ( !audio_check_backend_name( 0, opts->audio ) ) {
+ derror( "'%s' is not a valid audio output backend. see -help-audio-out\n",
+ opts->audio);
+ exit(1);
+ }
+ opts->audio_out = opts->audio;
+ opts->audio_in = opts->audio;
+
+ if ( !audio_check_backend_name( 1, opts->audio ) ) {
+ fprintf(stderr,
+ "emulator: warning: '%s' is not a valid audio input backend. audio record disabled\n",
+ opts->audio);
+ opts->audio_in = "none";
+ }
+ }
+
+ if (opts->audio_in) {
+ static char env[64]; /* note: putenv needs a static unique string buffer */
+ if ( !audio_check_backend_name( 1, opts->audio_in ) ) {
+ derror( "'%s' is not a valid audio input backend. see -help-audio-in\n",
+ opts->audio_in);
+ exit(1);
+ }
+ bufprint( env, env+sizeof(env), "QEMU_AUDIO_IN_DRV=%s", opts->audio_in );
+ putenv( env );
+ }
+ if (opts->audio_out) {
+ static char env[64]; /* note: putenv needs a static unique string buffer */
+ if ( !audio_check_backend_name( 0, opts->audio_out ) ) {
+ derror( "'%s' is not a valid audio output backend. see -help-audio-out\n",
+ opts->audio_out);
+ exit(1);
+ }
+ bufprint( env, env+sizeof(env), "QEMU_AUDIO_OUT_DRV=%s", opts->audio_out );
+ putenv( env );
+ }
+
+ if (opts->noskin) {
+ opts->skin = "320x240";
+ opts->skindir = NULL;
+ } else if (opts->skin == NULL) {
+ /* select default skin based on product type */
+ const char* env = getenv("ANDROID_PRODUCT_OUT");
+ if (env) {
+ const char* p = strrchr(env,'/');
+ if (p) {
+ if (p[1] == 's') {
+ opts->skin = "QVGA-L";
+ } else if (p[1] == 'd') {
+ opts->skin = "HVGA";
+ }
+ }
+ }
+ if (opts->skin) {
+ D("autoconfig: -skin %s", opts->skin);
+ }
+ }
+
+ if (opts->cpu_delay) {
+ char* end;
+ long delay = strtol(opts->cpu_delay, &end, 0);
+ if (end == NULL || *end || delay < 0 || delay > 1000 ) {
+ fprintf(stderr, "option -cpu-delay must be an integer between 0 and 1000\n" );
+ exit(1);
+ }
+ if (delay > 0)
+ delay = (1000-delay);
+
+ qemu_cpu_delay = (int) delay;
+ }
+
+ emulator_config_init();
+ init_skinned_ui(opts->skindir, opts->skin, opts);
+
+ if (!opts->netspeed) {
+ if (skin_network_speed)
+ D("skin network speed: '%s'", skin_network_speed);
+ opts->netspeed = (char*)skin_network_speed;
+ }
+ if (!opts->netdelay) {
+ if (skin_network_delay)
+ D("skin network delay: '%s'", skin_network_delay);
+ opts->netdelay = (char*)skin_network_delay;
+ }
+
+ if ( android_parse_network_speed(opts->netspeed) < 0 ) {
+ fprintf(stderr, "invalid -netspeed parameter '%s', see emulator -usage\n", opts->netspeed);
+ emulator_help();
+ }
+
+ if ( android_parse_network_latency(opts->netdelay) < 0 ) {
+ fprintf(stderr, "invalid -netdelay parameter '%s', see emulator -usage\n", opts->netdelay);
+ emulator_help();
+ }
+
+ if (opts->netfast) {
+ qemu_net_download_speed = 0;
+ qemu_net_upload_speed = 0;
+ qemu_net_min_latency = 0;
+ qemu_net_max_latency = 0;
+ }
+
+ if (opts->trace) {
+ int ret;
+ sprintf(tmp, "%s/traces", opts->system);
+ ret = path_mkdir_if_needed( tmp, 0755 );
+ if (ret < 0) {
+ fprintf(stderr, "could not create directory '%s'\n", tmp);
+ exit(2);
+ }
+ sprintf(tmp, "%s/traces/%s", opts->system, opts->trace);
+ opts->trace = strdup(tmp);
+ }
+
+ if (opts->nocache)
+ opts->cache = 0;
+
+ if (opts->cache) {
+ FileLock* cache_lock = filelock_create(opts->cache);
+ if (cache_lock == NULL) {
+ fprintf(stderr, "Could not create cache image file lock\n" );
+ exit(2);
+ }
+ if ( filelock_lock( cache_lock ) < 0 ) {
+ fprintf(stderr, "### WARNING: Another emulator instance is using our cache file. using temp file\n");
+ opts->cache = NULL;
+ }
+ else if ( !path_exists(opts->cache) ) {
+ /* -cache <file> where <file> does not exit, we simply */
+ /* create an empty file then */
+ if ( make_empty_file( opts->cache ) < 0 ) {
+ fprintf(stderr, "could not create cache file '%s'\n", opts->cache);
+ exit(2);
+ }
+ D( "created non-existent cache image file: %s\n", opts->cache );
+ }
+ }
+
+ if (opts->dns_server) {
+ char* x = strchr(opts->dns_server, ',');
+ dns_count = 0;
+ if (x == NULL)
+ {
+ if ( add_dns_server( opts->dns_server ) == 0 )
+ dns_count = 1;
+ }
+ else
+ {
+ x = strdup(opts->dns_server);
+ while (*x) {
+ char* y = strchr(x, ',');
+
+ if (y != NULL)
+ *y = 0;
+
+ if (y == NULL || y > x) {
+ if ( add_dns_server( x ) == 0 )
+ dns_count += 1;
+ }
+
+ if (y == NULL)
+ break;
+
+ x = y+1;
+ }
+ }
+ if (dns_count == 0)
+ fprintf( stderr, "### WARNING: will use system default DNS server\n" );
+ }
+
+ if (dns_count == 0)
+ dns_count = slirp_get_system_dns_servers();
+
+ n = 1;
+ /* generate arguments for the underlying qemu main() */
+ if(opts->kernel) {
+ args[n++] = "-kernel";
+ args[n++] = opts->kernel;
+ }
+ if(opts->ramdisk) {
+ args[n++] = "-initrd";
+ args[n++] = opts->ramdisk;
+ }
+ if(opts->image) {
+ sprintf(tmp, "system,size=0x4200000,initfile=%s", opts->image);
+ args[n++] = "-nand";
+ args[n++] = strdup(tmp);
+ }
+ if(opts->data) {
+ sprintf(tmp, "userdata,size=0x4200000,file=%s", opts->data);
+ args[n++] = "-nand";
+ args[n++] = strdup(tmp);
+ }
+ if (opts->cache) {
+ sprintf(tmp, "cache,size=0x4200000,file=%s", opts->cache);
+ args[n++] = "-nand";
+ args[n++] = strdup(tmp);
+ } else if(!opts->nocache) {
+ sprintf(tmp, "cache,size=0x4200000");
+ args[n++] = "-nand";
+ args[n++] = strdup(tmp);
+ }
+ if(opts->sdcard) {
+ uint64_t size;
+ if (path_get_size(opts->sdcard, &size) == 0) {
+ /* see if we have an sdcard image. get its size if it exists */
+ if (size < 8*1024*1024ULL) {
+ fprintf(stderr, "### WARNING: SD Card files must be at least 8 MB, ignoring '%s'\n", opts->sdcard);
+ } else {
+ args[n++] = "-hda";
+ args[n++] = opts->sdcard;
+ use_sdcard_img = 1;
+ }
+ } else {
+ dprint("could not find or access sdcard image at '%s'", opts->sdcard);
+ }
+ }
+
+ if (!opts->logcat || opts->logcat[0] == 0) {
+ opts->logcat = getenv("ANDROID_LOG_TAGS");
+ if (opts->logcat && opts->logcat[0] == 0)
+ opts->logcat = NULL;
+ }
+
+#if 0
+ if (opts->console) {
+ derror( "option -console is obsolete. please use -shell instead" );
+ exit(1);
+ }
+#endif
+
+ /* we always send the kernel messages from ttyS0 to android_kmsg */
+ {
+ AndroidKmsgFlags flags = 0;
+
+ if (opts->show_kernel)
+ flags |= ANDROID_KMSG_PRINT_MESSAGES;
+
+ android_kmsg_init( flags );
+ args[n++] = "-serial";
+ args[n++] = "android-kmsg";
+ serial++;
+ }
+
+ /* XXXX: TODO: implement -shell and -logcat through qemud instead */
+ if (!opts->shell_serial)
+ opts->shell_serial = "stdio";
+ else
+ opts->shell = 1;
+
+ if (opts->shell || opts->logcat) {
+ args[n++] = "-serial";
+ args[n++] = opts->shell_serial;
+ shell_serial = serial++;
+ }
+
+ if (opts->old_system)
+ {
+ if (opts->radio) {
+ args[n++] = "-serial";
+ args[n++] = opts->radio;
+ radio_serial = serial++;
+ }
+ else {
+ args[n++] = "-serial";
+ args[n++] = "android-modem";
+ radio_serial = serial++;
+ }
+ if (opts->gps) {
+ args[n++] = "-serial";
+ args[n++] = opts->gps;
+ gps_serial = serial++;
+ }
+ }
+ else /* !opts->old_system */
+ {
+ args[n++] = "-serial";
+ args[n++] = "android-qemud";
+ qemud_serial = serial++;
+
+ if (opts->radio) {
+ CharDriverState* cs = qemu_chr_open(opts->radio);
+ if (cs == NULL) {
+ derror( "unsupported character device specification: %s\n"
+ "used -help-char-devices for list of available formats\n", opts->radio );
+ exit(1);
+ }
+ android_qemud_set_channel( ANDROID_QEMUD_GSM, cs);
+ }
+ else {
+ if ( android_qemud_get_channel( ANDROID_QEMUD_GSM, &android_modem_cs ) < 0 ) {
+ derror( "could not initialize qemud 'gsm' channel" );
+ exit(1);
+ }
+ }
+
+ if (opts->gps) {
+ CharDriverState* cs = qemu_chr_open(opts->gps);
+ if (cs == NULL) {
+ derror( "unsupported character device specification: %s\n"
+ "used -help-char-devices for list of available formats\n", opts->gps );
+ exit(1);
+ }
+ android_qemud_set_channel( ANDROID_QEMUD_GPS, cs);
+ }
+ else {
+ if ( android_qemud_get_channel( "gps", &android_gps_cs ) < 0 ) {
+ derror( "could not initialize qemud 'gps' channel" );
+ exit(1);
+ }
+ }
+ }
+
+ if (opts->noaudio) {
+ args[n++] = "-noaudio";
+ }
+
+#if 0
+ if (opts->mic) {
+ if (path_can_read(opts->mic)) {
+ args[n++] = "-mic";
+ args[n++] = opts->mic;
+ } else {
+ dprint("could not find or access audio input at '%s'", opts->mic);
+ }
+ }
+#endif
+
+ if (opts->trace) {
+ args[n++] = "-trace";
+ args[n++] = opts->trace;
+ args[n++] = "-tracing";
+ args[n++] = "off";
+ }
+
+ args[n++] = "-append";
+
+ {
+ static char params[1024];
+ char *p = params, *end = p + sizeof(params);
+
+ p = bufprint(p, end, "qemu=1 console=ttyS0" );
+
+ if (opts->shell || opts->logcat) {
+ p = bufprint(p, end, " androidboot.console=ttyS%d", shell_serial );
+ }
+
+ if (opts->trace) {
+ p = bufprint(p, end, " android.tracing=1");
+ }
+
+ if (!opts->nojni) {
+ p = bufprint(p, end, " android.checkjni=1");
+ }
+
+ if (opts->no_boot_anim) {
+ p = bufprint( p, end, " android.bootanim=0" );
+ }
+
+ if (opts->logcat) {
+ char* q = bufprint(p, end, " androidboot.logcat=%s", opts->logcat);
+
+ if (q < end) {
+ /* replace any space by a comma ! */
+ {
+ int nn;
+ for (nn = 1; p[nn] != 0; nn++)
+ if (p[nn] == ' ' || p[nn] == '\t')
+ p[nn] = ',';
+ p += nn;
+ }
+ }
+ p = q;
+ }
+
+ if (opts->old_system)
+ {
+ p = bufprint(p, end, " android.ril=ttyS%d", radio_serial);
+
+ if (opts->gps) {
+ p = bufprint(p, end, " android.gps=ttyS%d", gps_serial);
+ }
+ }
+ else
+ {
+ p = bufprint(p, end, " android.qemud=ttyS%d", qemud_serial);
+ }
+
+ if (dns_count > 0) {
+ p = bufprint(p, end, " android.ndns=%d", dns_count);
+ }
+
+ if (p >= end) {
+ fprintf(stderr, "### ERROR: kernel parameters too long\n");
+ exit(1);
+ }
+
+ args[n++] = strdup(params);
+ }
+
+ while(argc-- > 0) {
+ args[n++] = *argv++;
+ }
+ args[n] = 0;
+
+ if(VERBOSE_CHECK(init)) {
+ int i;
+ for(i = 0; i < n; i++) {
+ fprintf(stdout, "emulator: argv[%02d] = \"%s\"\n", i, args[i]);
+ }
+ }
+ return qemu_main(n, args);
+}
+
+/* this function is called from qemu_main() once all arguments have been parsed
+ * it should be used to setup any Android-specific items in the emulation before the
+ * main loop runs
+ */
+void android_emulation_setup( void )
+{
+ int tries = 16;
+ int base_port = 5554;
+ int success = 0;
+ int s;
+ struct in_addr guest_addr;
+ AndroidOptions* opts = qemulator->opts;
+
+ inet_aton("10.0.2.15", &guest_addr);
+
+#if 0
+ if (opts->adb_port) {
+ fprintf( stderr, "option -adb-port is obsolete, use -port instead\n" );
+ exit(1);
+ }
+#endif
+
+ if (opts->port) {
+ char* end;
+ int port = strtol( opts->port, &end, 0 );
+ if ( end == NULL || *end ||
+ (unsigned)((port - base_port) >> 1) >= (unsigned)tries )
+ {
+ derror( "option -port must be followed by an even integer number between %d and %d\n",
+ base_port, base_port + (tries-1)*2 );
+ exit(1);
+ }
+ if ( (port & 1) != 0 ) {
+ port &= ~1;
+ dwarning( "option -port must be followed by an even integer, using port number %d\n",
+ port );
+ }
+ base_port = port;
+ tries = 1;
+ }
+
+ for ( ; tries > 0; tries--, base_port += 2 ) {
+
+ /* setup first redirection for ADB, the Android Debug Bridge */
+ if ( slirp_redir( 0, base_port+1, guest_addr, 5555 ) < 0 )
+ continue;
+
+ /* setup second redirection for the emulator console */
+ if ( control_console_start( base_port ) < 0 ) {
+ slirp_unredir( 0, base_port+1 );
+ continue;
+ }
+
+ D( "control console listening on port %d, ADB on port %d", base_port, base_port+1 );
+ success = 1;
+ break;
+ }
+
+ if (!success) {
+ fprintf(stderr, "it seems too many emulator instances are running on this machine. Aborting\n" );
+ exit(1);
+ }
+
+ if (opts->report_console) {
+ report_console(opts->report_console, base_port);
+ }
+
+ android_modem_init( base_port );
+
+ android_base_port = base_port;
+ /* send a simple message to the ADB host server to tell it we just started.
+ * it should be listening on port 5037. if we can't reach it, don't bother
+ */
+ do
+ {
+ struct sockaddr_in addr;
+ char tmp[32];
+ int ret;
+
+ s = socket(PF_INET, SOCK_STREAM, 0);
+ if (s < 0) {
+ D("can't create socket to talk to the ADB server");
+ break;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(5037);
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ do {
+ ret = connect(s, (struct sockaddr*)&addr, sizeof(addr));
+ } while (ret < 0 && socket_errno == EINTR);
+
+ if (ret < 0) {
+ D("can't connect to ADB server: errno %d: %s", socket_errno, socket_errstr() );
+ break;
+ }
+
+ sprintf(tmp,"0012host:emulator:%d",base_port+1);
+
+ while ( send(s, tmp, 18+4, 0) < 0 && errno == EINTR ) {
+ };
+ D("sent '%s' to ADB server", tmp);
+ }
+ while (0);
+ if (s >= 0)
+ close(s);
+
+ /* setup the http proxy, if any */
+ if (VERBOSE_CHECK(proxy))
+ proxy_set_verbose(1);
+
+ if (!opts->http_proxy) {
+ opts->http_proxy = getenv("http_proxy");
+ }
+
+ do
+ {
+ const char* env = opts->http_proxy;
+ int envlen;
+ ProxyOption option_tab[4];
+ ProxyOption* option = option_tab;
+ char* p;
+ char* q;
+ const char* proxy_name;
+ int proxy_name_len;
+ int proxy_port;
+
+ if (!env)
+ break;
+
+ envlen = strlen(env);
+
+ /* skip the 'http://' header, if present */
+ if (envlen >= 7 && !memcmp(env, "http://", 7)) {
+ env += 7;
+ envlen -= 7;
+ }
+
+ /* do we have a username:password pair ? */
+ p = strchr(env, '@');
+ if (p != 0) {
+ q = strchr(env, ':');
+ if (q == NULL) {
+ BadHttpProxyFormat:
+ dprint("http_proxy format unsupported, try 'proxy:port' or 'username:password@proxy:port'");
+ break;
+ }
+
+ option->type = PROXY_OPTION_AUTH_USERNAME;
+ option->string = env;
+ option->string_len = q - env;
+ option++;
+
+ option->type = PROXY_OPTION_AUTH_PASSWORD;
+ option->string = q+1;
+ option->string_len = p - (q+1);
+ option++;
+
+ env = p+1;
+ }
+
+ p = strchr(env,':');
+ if (p == NULL)
+ goto BadHttpProxyFormat;
+
+ proxy_name = env;
+ proxy_name_len = p - env;
+ proxy_port = atoi(p+1);
+
+ D( "setting up http proxy: server=%.*s port=%d",
+ proxy_name_len, proxy_name, proxy_port );
+
+ if ( proxy_http_setup( proxy_name, proxy_name_len, proxy_port,
+ option - option_tab, option_tab ) < 0 )
+ {
+ dprint( "http proxy setup failed, check your $http_proxy variable");
+ }
+ }
+ while (0);
+
+ /* cool, now try to run the "ddms ping" command, which will take care of pinging usage
+ * if the user agreed for it. the emulator itself never sends anything to any outside
+ * machine
+ */
+ {
+#ifdef _WIN32
+# define _ANDROID_PING_PROGRAM "ddms.bat"
+#else
+# define _ANDROID_PING_PROGRAM "ddms"
+#endif
+
+ char tmp[PATH_MAX];
+ const char* appdir = get_app_dir();
+
+ if (snprintf( tmp, PATH_MAX, "%s%s%s", appdir, PATH_SEP,
+ _ANDROID_PING_PROGRAM ) >= PATH_MAX) {
+ dprint( "Application directory too long: %s", appdir);
+ return;
+ }
+
+ /* if the program isn't there, don't bother */
+ D( "ping program: %s", tmp);
+ if (path_exists(tmp)) {
+#ifdef _WIN32
+ STARTUPINFO startup;
+ PROCESS_INFORMATION pinfo;
+
+ ZeroMemory( &startup, sizeof(startup) );
+ startup.cb = sizeof(startup);
+ startup.dwFlags = STARTF_USESHOWWINDOW;
+ startup.wShowWindow = SW_SHOWMINIMIZED;
+
+ ZeroMemory( &pinfo, sizeof(pinfo) );
+
+ char* comspec = getenv("COMSPEC");
+ if (!comspec) comspec = "cmd.exe";
+
+ // Run
+ char args[PATH_MAX + 30];
+ if (snprintf( args, PATH_MAX, "/C \"%s\" ping emulator " VERSION_STRING,
+ tmp) >= PATH_MAX ) {
+ D( "DDMS path too long: %s", tmp);
+ return;
+ }
+
+ CreateProcess(
+ comspec, /* program path */
+ args, /* command line args */
+ NULL, /* process handle is not inheritable */
+ NULL, /* thread handle is not inheritable */
+ FALSE, /* no, don't inherit any handles */
+ DETACHED_PROCESS, /* the new process doesn't have a console */
+ NULL, /* use parent's environment block */
+ NULL, /* use parent's starting directory */
+ &startup, /* startup info, i.e. std handles */
+ &pinfo );
+
+ D( "ping command: %s %s", comspec, args );
+#else
+ int pid = fork();
+ if (pid == 0) {
+ int fd = open("/dev/null", O_WRONLY);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ execl( tmp, _ANDROID_PING_PROGRAM, "ping", "emulator", VERSION_STRING, NULL );
+ }
+ /* don't do anything in the parent or in case of error */
+ strncat( tmp, " ping emulator " VERSION_STRING, PATH_MAX - strlen(tmp) );
+ D( "ping command: %s", tmp );
+#endif
+ }
+ }
+}
+
+
+void android_emulation_teardown( void )
+{
+}
diff --git a/android_option.c b/android_option.c
new file mode 100644
index 0000000..1a8506e
--- /dev/null
+++ b/android_option.c
@@ -0,0 +1,240 @@
+#include "android_option.h"
+#include "android_debug.h"
+#include "android_utils.h"
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#define _VERBOSE_TAG(x,y) { #x, VERBOSE_##x, y },
+static const struct { const char* name; int flag; const char* text; }
+debug_tags[] = {
+ VERBOSE_TAG_LIST
+ { 0, 0, 0 }
+};
+
+static void parse_debug_tags( const char* tags );
+static void parse_env_debug_tags( void );
+
+
+typedef struct {
+ const char* name;
+ int var_offset;
+ int var_is_param;
+ int var_is_config;
+} OptionInfo;
+
+#define OPTION(_name,_type,_config) \
+ { #_name, offsetof(AndroidOptions,_name), _type, _config },
+
+
+static const OptionInfo option_keys[] = {
+#define OPT_PARAM(_name,_template,_descr) OPTION(_name,1,0)
+#define OPT_FLAG(_name,_descr) OPTION(_name,0,0)
+#define CFG_PARAM(_name,_template,_descr) OPTION(_name,1,1)
+#define CFG_FLAG(_name,_descr) OPTION(_name,0,1)
+#include "android_options.h"
+ { NULL, 0, 0, 0 }
+};
+
+int
+android_parse_options( int *pargc, char** *pargv, AndroidOptions* opt )
+{
+ int nargs = *pargc-1;
+ char** aread = *pargv+1;
+ char** awrite = aread;
+
+ memset( opt, 0, sizeof *opt );
+
+ while (nargs > 0 && aread[0][0] == '-') {
+ char* arg = aread[0]+1;
+ int nn;
+
+ /* an option cannot contain an underscore */
+ if (strchr(arg, '_') != NULL) {
+ break;
+ }
+
+ nargs--;
+ aread++;
+
+ /* for backwards compatibility with previous versions */
+ if (!strcmp(arg, "verbose")) {
+ arg = "debug-init";
+ }
+
+ /* special handing for -debug <tags> */
+ if (!strcmp(arg, "debug")) {
+ if (nargs == 0) {
+ derror( "-debug must be followed by tags (see -help-verbose)\n");
+ exit(1);
+ }
+ nargs--;
+ parse_debug_tags(*aread++);
+ continue;
+ }
+
+ /* special handling for -debug-<tag> and -debug-no-<tag> */
+ if (!strncmp(arg, "debug-", 6)) {
+ int remove = 0;
+ unsigned long mask = 0;
+ arg += 6;
+ if (!strncmp(arg, "no-", 3)) {
+ arg += 3;
+ remove = 1;
+ }
+ if (!strcmp(arg, "all")) {
+ mask = ~0;
+ }
+ for (nn = 0; debug_tags[nn].name; nn++) {
+ if (!strcmp(arg, debug_tags[nn].name)) {
+ mask = (1 << debug_tags[nn].flag);
+ break;
+ }
+ }
+ if (remove)
+ android_verbose &= ~mask;
+ else
+ android_verbose |= mask;
+ continue;
+ }
+
+ /* look into our table of options
+ *
+ * NOTE: the 'option_keys' table maps option names
+ * to field offsets into the AndroidOptions structure.
+ *
+ * however, the names stored in the table used underscores
+ * instead of dashes. this means that the command-line option
+ * '-foo-bar' will be associated to the name 'foo_bar' in
+ * this table, and will point to the field 'foo_bar' or
+ * AndroidOptions.
+ *
+ * as such, before comparing the current option to the
+ * content of the table, we're going to translate dashes
+ * into underscores.
+ */
+ {
+ const OptionInfo* oo = option_keys;
+ char arg2[64];
+ int len = strlen(arg);
+
+ /* copy into 'arg2' buffer, translating dashes
+ * to underscores. note that we truncate to 63
+ * characters, which should be enough in practice
+ */
+ if (len > sizeof(arg2)-1)
+ len = sizeof(arg2)-1;
+
+ memcpy(arg2, arg, len+1);
+ buffer_translate_char(arg2, len, '-', '_');
+
+ for ( ; oo->name; oo++ ) {
+ if ( !strcmp( oo->name, arg2 ) ) {
+ void* field = (char*)opt + oo->var_offset;
+
+ if (oo->var_is_param) {
+ /* parameter option */
+ if (nargs == 0) {
+ derror( "-%s must be followed by parameter (see -help-%s)",
+ arg, arg );
+ exit(1);
+ }
+ nargs--;
+ ((char**)field)[0] = *aread++;
+ } else {
+ /* flag option */
+ ((int*)field)[0] = 1;
+ }
+ break;
+ }
+ }
+
+ if (oo->name == NULL) { /* unknown option ? */
+ nargs++;
+ aread--;
+ break;
+ }
+ }
+ }
+
+ /* copy remaining parameters, if any, to command line */
+ *pargc = nargs + 1;
+
+ while (nargs > 0) {
+ awrite[0] = aread[0];
+ awrite ++;
+ aread ++;
+ nargs --;
+ }
+
+ awrite[0] = NULL;
+
+ return 0;
+}
+
+
+
+/* special handling of -debug option and tags */
+#define ENV_DEBUG "ANDROID_DEBUG"
+
+static void
+parse_debug_tags( const char* tags )
+{
+ char* x;
+ char* y;
+ char* x0;
+
+ if (tags == NULL)
+ return;
+
+ x = x0 = strdup(tags);
+ while (*x) {
+ y = strchr(x, ',');
+ if (y == NULL)
+ y = x + strlen(x);
+ else
+ *y++ = 0;
+
+ if (y > x+1) {
+ int nn, remove = 0;
+ unsigned mask = 0;
+
+ if (x[0] == '-') {
+ remove = 1;
+ x += 1;
+ }
+
+ if (!strcmp( "all", x ))
+ mask = ~0;
+ else {
+ for (nn = 0; debug_tags[nn].name != NULL; nn++) {
+ if ( !strcmp( debug_tags[nn].name, x ) ) {
+ mask |= (1 << debug_tags[nn].flag);
+ break;
+ }
+ }
+ }
+
+ if (mask == 0)
+ dprint( "ignoring unknown " ENV_DEBUG " item '%s'", x );
+ else {
+ if (remove)
+ android_verbose &= ~mask;
+ else
+ android_verbose |= mask;
+ }
+ }
+ x = y;
+ }
+
+ free(x0);
+}
+
+
+static void
+parse_env_debug_tags( void )
+{
+ const char* env = getenv( ENV_DEBUG );
+ parse_debug_tags( env );
+}
+
diff --git a/android_option.h b/android_option.h
new file mode 100644
index 0000000..e33a030
--- /dev/null
+++ b/android_option.h
@@ -0,0 +1,42 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_OPTION_H
+#define _ANDROID_OPTION_H
+
+/* define a structure that will hold all option variables
+ */
+typedef struct {
+#define OPT_PARAM(n,t,d) char* n;
+#define OPT_FLAG(n,d) int n;
+#include "android_options.h"
+} AndroidOptions;
+
+
+/* parse command-line arguments options and remove them from (argc,argv)
+ * 'opt' will be set to the content of parsed options
+ * returns 0 on success, -1 on error (unknown option)
+ */
+extern int
+android_parse_options( int *pargc, char** *pargv, AndroidOptions* opt );
+
+/* name of default keyset file */
+#define KEYSET_FILE "default.keyset"
+
+/* the default device DPI if none is specified by the skin
+ */
+#define DEFAULT_DEVICE_DPI 165
+
+/* default network settings for emulator */
+#define DEFAULT_NETSPEED "full"
+#define DEFAULT_NETDELAY "none"
+
+#endif /* _ANDROID_OPTION_H */
diff --git a/android_options.h b/android_options.h
new file mode 100644
index 0000000..695e17b
--- /dev/null
+++ b/android_options.h
@@ -0,0 +1,126 @@
+/* this header file can be included several times by the same source code.
+ * it contains the list of support command-line options for the Android
+ * emulator program
+ */
+#ifndef OPT_PARAM
+#error OPT_PARAM is not defined
+#endif
+#ifndef OPT_FLAG
+#error OPT_FLAG is not defined
+#endif
+#ifndef CFG_PARAM
+#define CFG_PARAM OPT_PARAM
+#endif
+#ifndef CFG_FLAG
+#define CFG_FLAG OPT_FLAG
+#endif
+
+/* required to ensure that the CONFIG_XXX macros are properly defined */
+#include "config.h"
+
+/* some options acts like flags, while others must be followed by a parameter
+ * string. nothing really new here.
+ *
+ * some options correspond to AVM (Android Virtual Machine) configuration
+ * and will be ignored if you start the emulator with the -avm <name> flag.
+ *
+ * however, if you use them with -avm-create <name>, these options will be
+ * recorded into the new AVM directory. once an AVM is created, there is no
+ * way to change these options.
+ *
+ * several macros are used to define options:
+ *
+ * OPT_FLAG( name, "description" )
+ * used to define a non-config flag option.
+ * * 'name' is the option suffix that must follow the dash (-)
+ * as well as the name of an integer variable whose value will
+ * be 1 if the flag is used, or 0 otherwise
+ * * "description" is a short description string that will be
+ * displayed by 'emulator -help'
+ *
+ * OPT_PARAM( name, "<param>", "description" )
+ * used to define a non-config parameter option
+ * * 'name' will point to a char* variable (NULL if option is unused)
+ * * "<param>" is a template for the parameter displayed by the help
+ * * 'varname' is the name of a char* variable that will point
+ * to the parameter string, if any, or will be NULL otherwise.
+ *
+ * CFG_FLAG( name, "description" )
+ * used to define a configuration-specific flag option
+ *
+ * CFG_PARAM( name, "<param>", "description" )
+ * used to define a configuration-specific parameter option
+ *
+ * NOTE: keep in mind that optio names are converted by translating
+ * dashes into underscore.
+ *
+ * this means that '-some-option' is equivalent to '-some_option'
+ * and will be backed by a variable name 'some_option'
+ *
+ */
+
+CFG_PARAM( system, "<dir>", "read system image from <dir>" )
+CFG_PARAM( datadir, "<dir>", "write user data into <dir>" )
+CFG_PARAM( kernel, "<file>", "use specific emulated kernel" )
+CFG_PARAM( ramdisk, "<file>", "ramdisk image (default <system>/ramdisk.img" )
+CFG_PARAM( image, "<file>", "system image (default <system>/system.img" )
+CFG_PARAM( initdata, "<file>", "initial data image (default <system>/userdata.img" )
+CFG_PARAM( data, "<file>", "data image (default <datadir>/userdata-qemu.img" )
+CFG_PARAM( cache, "<file>", "cache partition image (default is temporary file)" )
+CFG_FLAG ( nocache, "disable the cache partition" )
+OPT_PARAM( sdcard, "<file>", "SD card image (default <system>/sdcard.img")
+OPT_FLAG ( wipe_data, "reset the use data image (copy it from initdata)" )
+
+CFG_PARAM( skindir, "<dir>", "search skins in <dir> (default <system>/skins)" )
+CFG_PARAM( skin, "<file>", "select a given skin" )
+CFG_FLAG ( noskin, "don't use any emulator skin" )
+
+OPT_PARAM( netspeed, "<speed>", "maximum network download/upload speeds" )
+OPT_PARAM( netdelay, "<delay>", "network latency emulation" )
+OPT_FLAG ( netfast, "disable network shaping" )
+
+OPT_PARAM( trace, "<name>", "enable code profiling (F9 to start)" )
+OPT_FLAG ( show_kernel, "display kernel messages" )
+OPT_FLAG ( shell, "enable root shell on current terminal" )
+OPT_FLAG ( nojni, "disable JNI checks in the Dalvik runtime" )
+OPT_PARAM( logcat, "<tags>", "enable logcat output with given tags" )
+
+OPT_FLAG ( noaudio, "disable audio support" )
+OPT_PARAM( audio, "<backend>", "use specific audio backend" )
+OPT_PARAM( audio_in, "<backend>", "use specific audio input backend" )
+OPT_PARAM( audio_out,"<backend>", "use specific audio output backend" )
+
+OPT_FLAG ( raw_keys, "disable Unicode keyboard reverse-mapping" )
+OPT_PARAM( radio, "<device>", "redirect radio modem interface to character device" )
+OPT_PARAM( port, "<port>", "TCP port that will be used for the console" )
+OPT_PARAM( onion, "<image>", "use overlay PNG image over screen" )
+OPT_PARAM( onion_alpha, "<%age>", "specify onion-skin translucency" )
+OPT_PARAM( onion_rotation, "0|1|2|3", "specify onion-skin rotation" )
+
+OPT_PARAM( scale, "<scale>", "scale emulator window" )
+OPT_PARAM( dpi_device, "<dpi>", "specify device's resolution in dpi (default "
+ STRINGIFY(DEFAULT_DEVICE_DPI) ")" )
+
+OPT_PARAM( http_proxy, "<proxy>", "make TCP connections through a HTTP/HTTPS proxy" )
+OPT_PARAM( timezone, "<timezone>", "use this timezone instead of the host's default" )
+OPT_PARAM( dns_server, "<servers>", "use this DNS server(s) in the emulated system" )
+OPT_PARAM( cpu_delay, "<cpudelay>", "throttle CPU emulation" )
+OPT_FLAG ( no_boot_anim, "disable animation for faster boot" )
+
+OPT_FLAG( no_window, "disable graphical window display" )
+OPT_FLAG( version, "display emulator version number" )
+
+OPT_PARAM( report_console, "<socket>", "report console port to remote socket" )
+OPT_PARAM( gps, "<device>", "redirect NMEA GPS to character device" )
+OPT_PARAM( keyset, "<name>", "specify keyset file name" )
+OPT_PARAM( shell_serial, "<device>", "specific character device for root shell" )
+OPT_FLAG ( old_system, "support old (pre 1.4) system images" )
+
+#ifdef CONFIG_NAND_LIMITS
+OPT_PARAM( nand_limits, "<nlimits>", "enforce NAND/Flash read/write thresholds" )
+#endif
+
+#undef CFG_FLAG
+#undef CFG_PARAM
+#undef OPT_FLAG
+#undef OPT_PARAM
diff --git a/android_profile.c b/android_profile.c
new file mode 100644
index 0000000..f8b430d
--- /dev/null
+++ b/android_profile.c
@@ -0,0 +1,127 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_profile.h"
+#include <string.h>
+#include <unistd.h>
+
+/* this environment variable can be set to change the root profiles directory */
+#define ENV_PROFILE_DIR "ANDROID_PROFILE_DIR"
+
+/* otherwise, we're going to use <config>/EMULATOR_PROFILE_DIR */
+#ifdef _WIN32
+# define EMULATOR_PROFILE_DIR "EmulatorProfiles"
+#else
+# define EMULATOR_PROFILE_DIR "profiles"
+#endif
+
+static char* profile_dir;
+
+static char*
+profile_dir_find( void )
+{
+ const char* env = getenv( ENV_PROFILE_DIR );
+ if (env != NULL) {
+ int len = strlen(env);
+
+ if ( access( env, R_OK ) < 0 ) {
+ dprint( "%s variable does not point to a valid directory. ignored\n", ENV_PROFILE_DIR );
+ }
+ else {
+ dprint( "using '%s' as profile root directory", env );
+ if (len > 0 && env[len-1] == PATH_SEP[0]) {
+ len -= 1;
+ }
+ profile_dir = malloc( len+1 );
+ memcpy(profile_dir, env, len);
+ profile_dir[len] = 0;
+ return profile_dir;
+ }
+ }
+
+ {
+ char temp[512];
+ char* p = temp;
+ char* end = p + sizeof(temp);
+ p = bufprint_config_file( p, end, EMULATOR_PROFILE_DIR );
+ if (p >= end) {
+ fprintf( stderr, "emulator configuration directory path too long. aborting" );
+ exit(1);
+ }
+ if (p > temp && p[-1] == PATH_SEP[0])
+ p[-1] = 0;
+
+ dprint( "using '%s' as profile root directory", temp );
+ profile_dir = strdup( temp );
+ return profile_dir;
+ }
+}
+
+int
+android_profile_check_name( const char* profile_name )
+{
+ static const char* goodchars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-0123456789.";
+ int len = strlen(profile_name);
+ int slen = strspn(profile_name, goodchars);
+
+ return (len == slen);
+}
+
+char*
+android_profile_bufprint_path( char* p, char* end, const char* profile_name )
+{
+ return android_profile_bufprint_file_path( p, end, profile_name, NULL );
+}
+
+char*
+android_profile_strdup_path( const char* profile_name )
+{
+ return android_profile_strdup_file_path( profile_name, NULL );
+}
+
+char*
+android_profile_bufprint_file_path( char* p, char* end, const char* profile_name, const char* file_name )
+{
+ if (profile_dir == NULL)
+ profile_dir = profile_dir_find();
+
+ p = bufprint( p, end, "%s", profile_dir );
+ if (file_name != NULL) {
+ p = bufprint( p, end, PATH_SEP "%s", file_name );
+ }
+ return p;
+}
+
+char*
+android_profile_strdup_file_path( const char* profile_name, const char* file_name )
+{
+ int len1, len;
+ char* result;
+
+ if (profile_dir == NULL)
+ profile_dir = profile_dir_find();
+
+ len1 = strlen(profile_dir);
+ len = len1;
+ if (file_name) {
+ len += 1 + strlen(file_name);
+ }
+
+ result = malloc( len+1 );
+ memcpy( result, profile_dir, len1 );
+ if (file_name) {
+ result[len1] = PATH_SEP[0];
+ strcpy( result+len1+1, file_name );
+ }
+ result[len] = 0;
+ return result;
+}
+
diff --git a/android_profile.h b/android_profile.h
new file mode 100644
index 0000000..cc8b1d5
--- /dev/null
+++ b/android_profile.h
@@ -0,0 +1,34 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_PROFILE_H
+#define _ANDROID_PROFILE_H
+
+#include "android.h"
+#include "android_utils.h"
+
+/* verify that a profile name doesn't contain bad characters, returns 0 on success, or -1 in case of error */
+extern int android_profile_check_name( const char* profile_name );
+
+/* safely append the path of a given profile to a buffer */
+extern char* android_profile_bufprint_path( char* p, char* end, const char* profile_name );
+
+/* return a copy of a profile path */
+extern char* android_profile_strdup_path( const char* profile_name );
+
+/* safely append the path of a given profile file to a buffer */
+extern char* android_profile_bufprint_file_path( char* p, char* end, const char* profile_name, const char* file_name );
+
+/* return a copy of a profile file path */
+extern char* android_profile_strdup_file_path( const char* profile_name, const char* file_name );
+
+
+#endif /* ANDROID_PROFILE_H */
diff --git a/android_qemud.c b/android_qemud.c
new file mode 100644
index 0000000..cfbd540
--- /dev/null
+++ b/android_qemud.c
@@ -0,0 +1,497 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_qemud.h"
+#include "android_debug.h"
+#include "charpipe.h"
+#include "cbuffer.h"
+#include "android_utils.h"
+
+#define D(...) VERBOSE_PRINT(qemud,__VA_ARGS__)
+#define D_ACTIVE VERBOSE_CHECK(qemud)
+
+/* the T(...) macro is used to dump traffic */
+#define T_ACTIVE 0
+
+#if T_ACTIVE
+#define T(...) VERBOSE_PRINT(qemud,__VA_ARGS__)
+#else
+#define T(...) ((void)0)
+#endif
+
+#define MAX_PAYLOAD 4000
+#define MAX_CHANNELS 8
+
+#define CHANNEL_CONTROL_INDEX 0
+
+/** utilities
+ **/
+static int
+hexdigit( int c )
+{
+ unsigned d;
+
+ d = (unsigned)(c - '0');
+ if (d < 10) return d;
+
+ d = (unsigned)(c - 'a');
+ if (d < 6) return d+10;
+
+ d = (unsigned)(c - 'A');
+ if (d < 6) return d+10;
+
+ return -1;
+}
+
+static int
+hex2int( const uint8_t* hex, int len )
+{
+ int result = 0;
+ while (len > 0) {
+ int c = hexdigit(*hex++);
+ if (c < 0)
+ return -1;
+
+ result = (result << 4) | c;
+ len --;
+ }
+ return result;
+}
+
+static void
+int2hex( uint8_t* hex, int len, int val )
+{
+ static const uint8_t hexchars[16] = "0123456789abcdef";
+ while ( --len >= 0 )
+ *hex++ = hexchars[(val >> (len*4)) & 15];
+}
+
+/** packets
+ **/
+#define HEADER_SIZE 6
+
+typedef struct Packet {
+ struct Packet* next;
+ int len;
+ uint8_t header[HEADER_SIZE];
+ uint8_t data[MAX_PAYLOAD];
+} Packet;
+
+static Packet* _free_packets;
+
+static void
+packet_free( Packet* p )
+{
+ p->next = _free_packets;
+ _free_packets = p;
+}
+
+static Packet*
+packet_alloc( void )
+{
+ Packet* p = _free_packets;
+ if (p != NULL) {
+ _free_packets = p->next;
+ } else {
+ p = malloc(sizeof(*p));
+ if (p == NULL) {
+ derror("%s: not enough memory", __FUNCTION__);
+ exit(1);
+ }
+ }
+ p->next = NULL;
+ p->len = 0;
+ return p;
+}
+
+/** channels
+ **/
+typedef void (*EnqueueFunc)( void* user, Packet* p );
+
+typedef struct {
+ const char* name;
+ int index;
+ CharDriverState* cs;
+ EnqueueFunc enq_func;
+ void* enq_user;
+} Channel;
+
+
+static int
+channel_can_read( void* opaque )
+{
+ Channel* c = opaque;
+
+ return c->index < 0 ? 0 : MAX_PAYLOAD;
+}
+
+
+/* here, the data comes from the emulated device (e.g. GSM modem) through
+ * a charpipe, we simply need to send it through the multiplexer */
+static void
+channel_read( void* opaque, const uint8_t* from, int len )
+{
+ Channel* c = opaque;
+
+ if (c->enq_func != NULL) {
+ Packet* p = packet_alloc();
+
+ if (len > MAX_PAYLOAD)
+ len = MAX_PAYLOAD;
+
+ memcpy( p->data, from, len );
+ p->len = len + HEADER_SIZE;
+ int2hex( p->header+0, 4, len );
+ int2hex( p->header+4, 2, c->index );
+
+ c->enq_func( c->enq_user, p );
+ }
+ else
+ {
+ D("%s: discarding %d bytes for channel '%s'",
+ __FUNCTION__, len, c->name);
+ }
+}
+
+static void
+channel_init( Channel* c, const char* name, CharDriverState* peer_cs )
+{
+ c->name = name;
+ c->index = -1;
+ c->enq_func = NULL;
+ c->enq_user = NULL;
+ c->cs = peer_cs;
+}
+
+
+static void
+channel_set_peer( Channel* c, int index, EnqueueFunc enq_func, void* enq_user )
+{
+ c->index = index;
+ qemu_chr_add_read_handler( c->cs,
+ channel_can_read,
+ channel_read,
+ c );
+ c->enq_func = enq_func;
+ c->enq_user = enq_user;
+}
+
+
+static int
+channel_write( Channel*c , const uint8_t* buf, int len )
+{
+ return qemu_chr_write( c->cs, buf, len );
+}
+
+/** multiplexer
+ **/
+#define IN_BUFF_SIZE (2*MAX_PAYLOAD)
+
+typedef struct {
+ CharDriverState* cs;
+
+ CBuffer in_cbuffer[1];
+ int in_datalen;
+ int in_channel;
+
+ int count;
+ Channel channels[MAX_CHANNELS];
+ uint8_t in_buff[ IN_BUFF_SIZE + HEADER_SIZE ];
+} Multiplexer;
+
+
+/* called by channel_read when data comes from an emulated
+ * device, and needs to be multiplexed through the serial
+ * port
+ */
+static void
+multiplexer_enqueue( Multiplexer* m, Packet* p )
+{
+ T("%s: sending %d bytes: '%s'", __FUNCTION__,
+ p->len - HEADER_SIZE, quote_bytes( p->data, p->len - HEADER_SIZE ) );
+
+ qemu_chr_write( m->cs, p->header, HEADER_SIZE );
+ qemu_chr_write( m->cs, p->data, p->len - HEADER_SIZE );
+ packet_free(p);
+}
+
+/* called when we received a channel registration from the
+ * qemud daemon
+ */
+static void
+multiplexer_register_channel( Multiplexer* m,
+ const char* name,
+ int index )
+{
+ Channel* c = m->channels;
+ Channel* c_end = c + m->count;
+
+ for ( ; c < c_end; c++ ) {
+ if ( !strcmp(c->name, name) )
+ break;
+ }
+
+ if (c >= c_end) {
+ D( "%s: unknown channel name '%s'",
+ __FUNCTION__, name );
+ return;
+ }
+
+ if (c->index >= 0) {
+ D( "%s: channel '%s' re-assigned index %d",
+ __FUNCTION__, name, index );
+ c->index = index;
+ return;
+ }
+ channel_set_peer( c, index, (EnqueueFunc) multiplexer_enqueue, m );
+ D( "%s: channel '%s' registered as index %d",
+ __FUNCTION__, c->name, c->index );
+}
+
+
+/* handle answers from the control channel */
+static void
+multiplexer_handle_control( Multiplexer* m, Packet* p )
+{
+ int len = p->len - HEADER_SIZE;
+
+ /* for now, the only supported answer is 'ok:connect:<name>:<XX>' where
+ * <XX> is a hexdecimal channel numner */
+ D( "%s: received '%s'", __FUNCTION__, quote_bytes( (const void*)p->data, (unsigned)len ) );
+ if ( !memcmp( p->data, "ok:connect:", 11 ) ) do {
+ char* name = (char*)p->data + 11;
+ char* q = strchr( name, ':' );
+ int index;
+
+ if (q == NULL)
+ break;
+
+ q[0] = 0;
+ if (q + 3 > (char*)p->data + len)
+ break;
+
+ index = hex2int( (uint8_t*)q+1, 2 );
+ if (index < 0)
+ break;
+
+ multiplexer_register_channel( m, name, index );
+ goto Exit;
+ }
+ while(0);
+
+ D( "%s: unsupported message !!", __FUNCTION__ );
+Exit:
+ packet_free(p);
+}
+
+
+static int
+multiplexer_can_read( void* opaque )
+{
+ Multiplexer* m = opaque;
+
+ return cbuffer_write_avail( m->in_cbuffer );
+}
+
+/* the data comes from the serial port, we need to reconstruct packets then
+ * dispatch them to the appropriate channel */
+static void
+multiplexer_read( void* opaque, const uint8_t* from, int len )
+{
+ Multiplexer* m = opaque;
+ CBuffer* cb = m->in_cbuffer;
+ int ret = 0;
+
+ T("%s: received %d bytes from serial: '%s'",
+ __FUNCTION__, len, quote_bytes( from, len ));
+
+ ret = cbuffer_write( cb, from, len );
+ if (ret == 0)
+ return;
+
+ for (;;) {
+ int len = cbuffer_read_avail( cb );
+
+ if (m->in_datalen == 0) {
+ uint8_t header[HEADER_SIZE];
+
+ if (len < HEADER_SIZE)
+ break;
+
+ cbuffer_read( cb, header, HEADER_SIZE );
+ m->in_datalen = hex2int( header+0, 4 );
+ m->in_channel = hex2int( header+4, 2 );
+ }
+ else
+ {
+ Packet* p;
+
+ if (len < m->in_datalen)
+ break;
+
+ /* a full packet was received */
+ p = packet_alloc();
+ cbuffer_read( cb, p->data, m->in_datalen );
+ p->len = HEADER_SIZE + m->in_datalen;
+
+ /* find the channel for this packet */
+ if (m->in_channel == CHANNEL_CONTROL_INDEX)
+ multiplexer_handle_control( m, p );
+ else {
+ Channel* c = m->channels;
+ Channel* c_end = c + m->count;
+
+ for ( ; c < c_end; c++ ) {
+ if (c->index == m->in_channel) {
+ channel_write( c, p->data, m->in_datalen );
+ break;
+ }
+ }
+ packet_free(p);
+ }
+ m->in_datalen = 0;
+ }
+
+ }
+ return;
+}
+
+static void
+multiplexer_query_channel( Multiplexer* m, const char* name )
+{
+ Packet* p = packet_alloc();
+ int len;
+
+ len = snprintf( (char*)p->data, MAX_PAYLOAD, "connect:%s", name );
+
+ int2hex( p->header+0, 4, len );
+ int2hex( p->header+4, 2, CHANNEL_CONTROL_INDEX );
+ p->len = HEADER_SIZE + len;
+
+ multiplexer_enqueue( m, p );
+}
+
+
+static Channel*
+multiplexer_find_channel( Multiplexer* m, const char* name )
+{
+ int n;
+ for (n = 0; n < m->count; n++)
+ if ( !strcmp(m->channels[n].name, name) )
+ return m->channels + n;
+
+ return NULL;
+}
+
+
+static Multiplexer _multiplexer[1];
+static CharDriverState* android_qemud_cs;
+
+extern void
+android_qemud_init( void )
+{
+ Multiplexer* m = _multiplexer;
+
+ if (android_qemud_cs != NULL)
+ return;
+
+ m->count = 0;
+
+ cbuffer_reset( m->in_cbuffer, m->in_buff, sizeof(m->in_buff) );
+ m->in_datalen = 0;
+ m->in_channel = 0;
+
+ if (qemu_chr_open_charpipe( &android_qemud_cs, &m->cs ) < 0) {
+ derror( "%s: can't create charpipe to serial port",
+ __FUNCTION__ );
+ exit(1);
+ }
+
+ qemu_chr_add_read_handler( m->cs, multiplexer_can_read,
+ multiplexer_read, m );
+}
+
+
+CharDriverState* android_qemud_get_cs( void )
+{
+ if (android_qemud_cs == NULL)
+ android_qemud_init();
+
+ return android_qemud_cs;
+}
+
+
+extern int
+android_qemud_get_channel( const char* name, CharDriverState** pcs )
+{
+ Multiplexer* m = _multiplexer;
+ Channel* c;
+ CharDriverState* peer_cs;
+ int ret;
+
+ if (m->cs == NULL)
+ android_qemud_init();
+
+ c = multiplexer_find_channel( m, name );
+ if (c) {
+ derror( "%s: trying to get already-opened qemud channel '%s'",
+ __FUNCTION__, name );
+ return -1;
+ }
+
+ if (m->count >= MAX_CHANNELS) {
+ derror( "%s: too many registered channels (%d)",
+ __FUNCTION__, m->count );
+ return -1;
+ }
+
+ c = m->channels + m->count;
+
+ ret = qemu_chr_open_charpipe( &peer_cs, pcs );
+ if (ret == 0) {
+ channel_init(c, name, peer_cs);
+ m->count += 1;
+ multiplexer_query_channel( m, c->name );
+ }
+
+ return ret;
+}
+
+extern int
+android_qemud_set_channel( const char* name, CharDriverState* peer_cs )
+{
+ Multiplexer* m = _multiplexer;
+ Channel* c;
+ int ret;
+
+ if (m->cs == NULL)
+ android_qemud_init();
+
+ c = multiplexer_find_channel(m, name);
+ if (c != NULL) {
+ derror( "%s: trying to set opened qemud channel '%s'",
+ __FUNCTION__, name );
+ return -1;
+ }
+
+ if (m->count >= MAX_CHANNELS) {
+ derror( "%s: too many registered channels (%d)",
+ __FUNCTION__, m->count );
+ return -1;
+ }
+
+ c = m->channels + m->count;
+ channel_init(c, name, peer_cs);
+ m->count += 1;
+ multiplexer_query_channel( m, c->name );
+
+ return ret;
+}
diff --git a/android_qemud.h b/android_qemud.h
new file mode 100644
index 0000000..1e9fad5
--- /dev/null
+++ b/android_qemud.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _android_qemud_h
+#define _android_qemud_h
+
+#include "vl.h"
+
+/* recent versions of the emulated Android system contains a background
+ * daemon, named 'qemud', which runs as root and opens /dev/ttyS0
+ *
+ * its purpose is to multiplex several communication channels between
+ * the emulator and the system through a single serial port.
+ *
+ * each channel will be connected to a qemud-created unix socket on the
+ * system, and to either a emulated character device or other facility in
+ * the emulator.
+ *
+ * +--------> /dev/socket/qemud_gsm
+ * emulated GSM <-----+ ______|_
+ * | emulated | |
+ * +====> /dev/ttyS0 <===>| qemud |------> /dev/socket/qemud_gps
+ * | |________|
+ * emulated GPS <-----+ |
+ * | +---------> other
+ * |
+ * other <--------------+
+ *
+ *
+ * this is done to overcome specific permission problems, as well as to add various
+ * features that would require special kernel drivers otherwise even though they
+ * only need a simple character channel.
+ */
+
+/* initialize the qemud support code in the emulator
+ */
+
+extern void android_qemud_init( void );
+
+/* return the character driver state object that needs to be connected to the
+ * emulated serial port where all multiplexed channels go through.
+ */
+extern CharDriverState* android_qemud_get_cs( void );
+
+/* return the character driver state corresponding to a named qemud communication
+ * channel. this can be used to send/data the channel.
+ * returns 0 on success, or -1 in case of error
+ */
+extern int android_qemud_get_channel( const char* name, CharDriverState* *pcs );
+
+/* set the character driver state for a given qemud communication channel. this
+ * is used to attach the channel to an external char driver device directly.
+ * returns 0 on success, -1 on error
+ */
+extern int android_qemud_set_channel( const char* name, CharDriverState* peer_cs );
+
+/* list of known qemud channel names */
+#define ANDROID_QEMUD_GSM "gsm"
+#define ANDROID_QEMUD_GPS "gps"
+
+/* add new channel names here when you need them */
+
+#endif /* _android_qemud_h */
diff --git a/android_resource.c b/android_resource.c
new file mode 100644
index 0000000..083a000
--- /dev/null
+++ b/android_resource.c
@@ -0,0 +1,64 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_resource.h"
+#include "config-host.h"
+#include <string.h>
+
+typedef struct {
+ const char* name;
+ const unsigned char* base;
+ size_t size;
+} FileEntry;
+
+const unsigned char*
+_resource_find( const char* name,
+ const FileEntry* entries,
+ size_t *psize )
+{
+ const FileEntry* e = entries;
+
+ for ( ; e->name != NULL; e++ ) {
+ //dprint("SCAN %s\n", e->name);
+ if ( strcmp(e->name, name) == 0 ) {
+ *psize = e->size;
+ return e->base;
+ }
+ }
+ return NULL;
+}
+
+#undef _file_entries
+#define _file_entries _skin_entries
+const unsigned char*
+android_resource_find( const char* name,
+ size_t *psize )
+{
+# include "skin_default.h"
+ return _resource_find( name, _file_entries, psize );
+}
+
+#undef _file_entries
+#define _file_entries _icon_entries
+
+const unsigned char*
+android_icon_find( const char* name,
+ size_t *psize )
+{
+#ifdef _WIN32
+ return NULL;
+#else
+# include "android_icons.h"
+ return _resource_find( name, _file_entries, psize );
+#endif
+}
+
+
diff --git a/android_resource.h b/android_resource.h
new file mode 100644
index 0000000..00453af
--- /dev/null
+++ b/android_resource.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_RESOURCE_H
+#define _ANDROID_RESOURCE_H
+
+#include <stddef.h>
+
+extern const unsigned char*
+android_resource_find( const char* name,
+ size_t *psize );
+
+extern const unsigned char*
+android_icon_find( const char* name,
+ size_t *psize );
+
+#endif /* END */
+
diff --git a/android_timezone.c b/android_timezone.c
new file mode 100644
index 0000000..aac0696
--- /dev/null
+++ b/android_timezone.c
@@ -0,0 +1,720 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_timezone.h"
+#include "android_utils.h"
+#include "android.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "vl.h" /* for pstrcpy */
+
+#define DEBUG 1
+
+#if 1
+# define D_ACTIVE VERBOSE_CHECK(timezone)
+#else
+# define D_ACTIVE DEBUG
+#endif
+
+#if DEBUG
+# define D(...) do { if (D_ACTIVE) fprintf(stderr, __VA_ARGS__); } while (0)
+#else
+# define D(...) ((void)0)
+#endif
+
+
+
+static const char* get_zoneinfo_timezone( void ); /* forward */
+
+static char android_timezone0[256];
+static const char* android_timezone;
+static int android_timezone_init;
+
+static int
+check_timezone_is_zoneinfo(const char* tz)
+{
+ const char* slash1 = NULL, *slash2 = NULL;
+
+ if (tz == NULL)
+ return 0;
+
+ /* the name must be of the form Area/Location or Area/Location/SubLocation */
+ slash1 = strchr( tz, '/' );
+ if (slash1 == NULL || slash1[1] == 0)
+ return 0;
+
+ slash2 = strchr( slash1+1, '/');
+ if (slash2 != NULL) {
+ if (slash2[1] == 0 || strchr(slash2+1, '/') != NULL)
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+timezone_set( const char* tzname )
+{
+ int len;
+
+ if ( !check_timezone_is_zoneinfo(tzname) )
+ return -1;
+
+ len = strlen(tzname);
+ if (len > sizeof(android_timezone0)-1)
+ return -1;
+
+ strcpy( android_timezone0, tzname );
+ android_timezone = android_timezone0;
+ android_timezone_init = 1;
+
+ return 0;
+}
+
+
+char*
+bufprint_zoneinfo_timezone( char* p, char* end )
+{
+ const char* tz = get_zoneinfo_timezone();
+
+ if (tz == NULL || !check_timezone_is_zoneinfo(tz))
+ return bufprint(p, end, "Unknown/Unknown");
+ else
+ return bufprint(p, end, "%s", tz);
+}
+
+/* on OS X, the timezone directory is always /usr/share/zoneinfo
+ * this makes things easy.
+ */
+#ifdef __APPLE__
+
+#include <unistd.h>
+#include <limits.h>
+#define LOCALTIME_FILE "/etc/localtime"
+#define ZONEINFO_DIR "/usr/share/zoneinfo/"
+static const char*
+get_zoneinfo_timezone( void )
+{
+ if (!android_timezone_init) {
+ const char* tz = getenv("TZ");
+ char buff[PATH_MAX+1];
+
+ android_timezone_init = 1;
+ if (tz == NULL) {
+ int len = readlink(LOCALTIME_FILE, buff, sizeof(buff));
+ if (len < 0) {
+ dprint( "### WARNING: Could not read %s, something is very wrong on your system",
+ LOCALTIME_FILE);
+ return NULL;
+ }
+
+ buff[len] = 0;
+ D("%s: %s points to %s\n", __FUNCTION__, LOCALTIME_FILE, buff);
+ if ( memcmp(buff, ZONEINFO_DIR, sizeof(ZONEINFO_DIR)-1) ) {
+ dprint( "### WARNING: %s does not point to %s, can't determine zoneinfo timezone name",
+ LOCALTIME_FILE, ZONEINFO_DIR );
+ return NULL;
+ }
+ tz = buff + sizeof(ZONEINFO_DIR)-1;
+ if ( !check_timezone_is_zoneinfo(tz) ) {
+ dprint( "### WARNING: %s does not point to zoneinfo-compatible timezone name\n", LOCALTIME_FILE );
+ return NULL;
+ }
+ }
+ pstrcpy( android_timezone0, sizeof(android_timezone0), tz );
+ android_timezone = android_timezone0;
+ }
+ D( "found timezone %s", android_timezone );
+ return android_timezone;
+}
+
+#endif /* __APPLE__ */
+
+/* on Linux, with glibc2, the zoneinfo directory can be changed with TZDIR environment variable
+ * but should be /usr/share/zoneinfo by default. /etc/localtime is not guaranteed to exist on
+ * all platforms, so if it doesn't, try $TZDIR/localtime, then /usr/share/zoneinfo/locatime
+ * ugly, isn't it ?
+ *
+ * besides, modern Linux distribution don't make /etc/localtime a symlink but a straight copy of
+ * the original timezone file. the only way to know which zoneinfo name to retrieve is to compare
+ * it with all files in $TZDIR (at least those that match Area/Location or Area/Location/SubLocation
+ */
+#ifdef __linux__
+
+#include <unistd.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+
+#define ZONEINFO_DIR "/usr/share/zoneinfo/"
+#define LOCALTIME_FILE1 "/etc/localtime"
+
+typedef struct {
+ const char* localtime;
+ struct stat localtime_st;
+ char* path_end;
+ char* path_root;
+ char path[ PATH_MAX ];
+} ScanDataRec;
+
+static int
+compare_timezone_to_localtime( ScanDataRec* scan,
+ const char* path )
+{
+ struct stat st;
+ int fd1, fd2, result = 0;
+
+ D( "%s: comparing %s:", __FUNCTION__, path );
+
+ if ( stat( path, &st ) < 0 ) {
+ D( " can't stat: %s\n", strerror(errno) );
+ return 0;
+ }
+
+ if ( st.st_size != scan->localtime_st.st_size ) {
+ D( " size mistmatch (%lld != %lld)\n", st.st_size, scan->localtime_st.st_size );
+ return 0;
+ }
+
+ fd1 = open( scan->localtime, O_RDONLY );
+ if (fd1 < 0) {
+ D(" can't open %s: %s\n", scan->localtime, strerror(errno) );
+ return 0;
+ }
+ fd2 = open( path, O_RDONLY );
+ if (fd2 < 0) {
+ D(" can't open %s: %s\n", path, strerror(errno) );
+ close(fd1);
+ return 0;
+ }
+ do {
+ off_t nn;
+
+ for (nn = 0; nn < st.st_size; nn++) {
+ char temp[2];
+ int ret;
+
+ do { ret = read(fd1, &temp[0], 1); } while (ret < 0 && errno == EINTR);
+ if (ret < 0) break;
+
+ do { ret = read(fd2, &temp[1], 1); } while (ret < 0 && errno == EINTR);
+ if (ret < 0) break;
+
+ if (temp[0] != temp[1])
+ break;
+ }
+
+ result = (nn == st.st_size);
+
+ } while (0);
+
+ D( result ? " MATCH\n" : "no match\n" );
+
+ close(fd2);
+ close(fd1);
+
+ return result;
+}
+
+static const char*
+scan_timezone_dir( ScanDataRec* scan,
+ char* top,
+ int depth )
+{
+ DIR* d = opendir( scan->path );
+ const char* result = NULL;
+
+ D( "%s: entering '%s\n", __FUNCTION__, scan->path );
+ if (d != NULL) {
+ struct dirent* ent;
+ while ((ent = readdir(d)) != NULL) {
+ struct stat ent_st;
+ char* p = top;
+
+ if (ent->d_name[0] == '.') /* avoid hidden and special files */
+ continue;
+
+ p = bufprint( p, scan->path_end, "/%s", ent->d_name );
+ if (p >= scan->path_end)
+ continue;
+
+ //D( "%s: scanning '%s'\n", __FUNCTION__, scan->path );
+
+ if ( stat( scan->path, &ent_st ) < 0 )
+ continue;
+
+ if ( S_ISDIR(ent_st.st_mode) && depth < 2 )
+ {
+ //D( "%s: directory '%s'\n", __FUNCTION__, scan->path );
+ result = scan_timezone_dir( scan, p, depth + 1 );
+ if (result != NULL)
+ break;
+ }
+ else if ( S_ISREG(ent_st.st_mode) && (depth >= 1 && depth <= 2) )
+ {
+ char* name = scan->path_root + 1;
+
+ if ( check_timezone_is_zoneinfo( name ) )
+ {
+ if (compare_timezone_to_localtime( scan, scan->path ))
+ {
+ result = strdup( name );
+ D( "%s: found '%s'\n", __FUNCTION__, result );
+ break;
+ }
+ }
+ else
+ {
+ //D( "%s: ignoring '%s'\n", __FUNCTION__, scan->path );
+ }
+ }
+ }
+ closedir(d);
+ }
+ return result;
+}
+
+static const char*
+get_zoneinfo_timezone( void )
+{
+ if (!android_timezone_init)
+ {
+ const char* tz = getenv( "TZ" );
+
+ android_timezone_init = 1;
+
+ if ( tz != NULL && !check_timezone_is_zoneinfo(tz) ) {
+ D( "%s: ignoring non zoneinfo formatted TZ environment variable: '%s'\n",
+ __FUNCTION__, tz );
+ tz = NULL;
+ }
+
+ if (tz == NULL) {
+ char* tzdir = NULL;
+ int tzdirlen = 0;
+ char* localtime = NULL;
+ int len;
+ char temp[ PATH_MAX ];
+
+ /* determine the correct timezone directory */
+ {
+ const char* env = getenv("TZDIR");
+ const char* zoneinfo_dir = ZONEINFO_DIR;
+
+ if (env == NULL)
+ env = zoneinfo_dir;
+
+ if ( access( env, R_OK ) != 0 ) {
+ if ( env == zoneinfo_dir ) {
+ fprintf( stderr,
+ "### WARNING: could not find %s directory. unable to determine host timezone\n", env );
+ } else {
+ D( "%s: TZDIR does not point to valid directory, using %s instead\n",
+ __FUNCTION__, zoneinfo_dir );
+ env = zoneinfo_dir;
+ }
+ return NULL;
+ }
+ tzdir = strdup(env);
+ }
+
+ /* remove trailing slash, if any */
+ len = strlen(tzdir);
+ if (len > 0 && tzdir[len-1] == '/') {
+ tzdir[len-1] = 0;
+ len -= 1;
+ }
+ tzdirlen = len;
+ D( "%s: found timezone dir as %s\n", __FUNCTION__, tzdir );
+
+ /* try to find the localtime file */
+ localtime = LOCALTIME_FILE1;
+ if ( access( localtime, R_OK ) != 0 ) {
+ char *p = temp, *end = p + sizeof(temp);
+
+ p = bufprint( p, end, "%s/%s", tzdir, "localtime" );
+ if (p >= end || access( temp, R_OK ) != 0 ) {
+ fprintf( stderr, "### WARNING: could not find %s or %s. unable to determine host timezone\n",
+ LOCALTIME_FILE1, temp );
+ goto Exit;
+ }
+ localtime = temp;
+ }
+ localtime = strdup(localtime);
+ D( "%s: found localtime file as %s\n", __FUNCTION__, localtime );
+
+#if 1
+ /* if the localtime file is a link, make a quick check */
+ len = readlink( localtime, temp, sizeof(temp)-1 );
+ if (len >= 0 && len > tzdirlen + 2) {
+ temp[len] = 0;
+
+ /* verify that the link points to tzdir/<something> where <something> is a valid zoneinfo name */
+ if ( !memcmp( temp, tzdir, tzdirlen ) && temp[tzdirlen] == '/' ) {
+ if ( check_timezone_is_zoneinfo( temp + tzdirlen + 1 ) ) {
+ /* we have it ! */
+ tz = temp + tzdirlen + 1;
+ D( "%s: found zoneinfo timezone %s from %s symlink\n", __FUNCTION__, tz, localtime );
+ goto Exit;
+ }
+ D( "%s: %s link points to non-zoneinfo filename %s, comparing contents\n",
+ __FUNCTION__, localtime, temp );
+ }
+ }
+#endif
+
+ /* otherwise, parse all files under tzdir and see if we have something that looks like it */
+ {
+ ScanDataRec scan[1];
+
+ if ( stat( localtime, &scan->localtime_st ) < 0 ) {
+ fprintf( stderr, "### WARNING: can't access '%s', unable to determine host timezone\n",
+ localtime );
+ goto Exit;
+ }
+
+ scan->localtime = localtime;
+ scan->path_end = scan->path + sizeof(scan->path);
+ scan->path_root = bufprint( scan->path, scan->path_end, "%s", tzdir );
+
+ tz = scan_timezone_dir( scan, scan->path_root, 0 );
+ }
+
+ Exit:
+ if (tzdir)
+ free(tzdir);
+ if (localtime)
+ free(localtime);
+
+ if (tz == NULL)
+ return NULL;
+
+ pstrcpy( android_timezone0, sizeof(android_timezone0), tz );
+ android_timezone = android_timezone0;
+ }
+ D( "found timezone %s\n", android_timezone );
+ }
+ return android_timezone;
+}
+
+#endif /* __linux__ */
+
+
+/* on Windows, we need to translate the Windows timezone into a ZoneInfo one */
+#ifdef _WIN32
+#include <time.h>
+
+typedef struct {
+ const char* win_name;
+ const char* zoneinfo_name;
+} Win32Timezone;
+
+/* table generated from http://unicode.org/cldr/data/diff/supplemental/windows_tzid.html */
+static const Win32Timezone _win32_timezones[] = {
+ { "AUS Central Standard Time" , "Australia/Darwin" },
+ { "AUS Eastern Standard Time" , "Australia/Sydney" },
+ { "Acre Standard Time" , "America/Rio_Branco" },
+ { "Afghanistan Standard Time" , "Asia/Kabul" },
+ { "Africa_Central Standard Time" , "Africa/Kigali" },
+ { "Africa_Eastern Standard Time" , "Africa/Kampala" },
+ { "Africa_FarWestern Standard Time" , "Africa/El_Aaiun" },
+ { "Africa_Southern Standard Time" , "Africa/Johannesburg" },
+ { "Africa_Western Standard Time" , "Africa/Niamey" },
+ { "Aktyubinsk Standard Time" , "Asia/Aqtobe" },
+ { "Alaska Standard Time" , "America/Juneau" },
+ { "Alaska_Hawaii Standard Time" , "America/Anchorage" },
+ { "Alaskan Standard Time" , "America/Anchorage" },
+ { "Almaty Standard Time" , "Asia/Almaty" },
+ { "Amazon Standard Time" , "America/Manaus" },
+ { "America_Central Standard Time" , "America/Winnipeg" },
+ { "America_Eastern Standard Time" , "America/Panama" },
+ { "America_Mountain Standard Time" , "America/Edmonton" },
+ { "America_Pacific Standard Time" , "America/Vancouver" },
+ { "Anadyr Standard Time" , "Asia/Anadyr" },
+ { "Aqtau Standard Time" , "Asia/Aqtau" },
+ { "Aqtobe Standard Time" , "Asia/Aqtobe" },
+ { "Arab Standard Time" , "Asia/Riyadh" },
+ { "Arabian Standard Time" , "Asia/Bahrain" },
+ { "Arabic Standard Time" , "Asia/Baghdad" },
+ { "Argentina Standard Time" , "America/Buenos_Aires" },
+ { "Argentina_Western Standard Time" , "America/Mendoza" },
+ { "Armenia Standard Time" , "Asia/Yerevan" },
+ { "Ashkhabad Standard Time" , "Asia/Ashgabat" },
+ { "Atlantic Standard Time" , "America/Curacao" },
+ { "Australia_Central Standard Time" , "Australia/Adelaide" },
+ { "Australia_CentralWestern Standard Time", "Australia/Eucla" },
+ { "Australia_Eastern Standard Time" , "Australia/Sydney" },
+ { "Australia_Western Standard Time" , "Australia/Perth" },
+ { "Azerbaijan Standard Time" , "Asia/Baku" },
+ { "Azores Standard Time" , "Atlantic/Azores" },
+ { "Baku Standard Time" , "Asia/Baku" },
+ { "Bangladesh Standard Time" , "Asia/Dhaka" },
+ { "Bering Standard Time" , "America/Adak" },
+ { "Bhutan Standard Time" , "Asia/Thimphu" },
+ { "Bolivia Standard Time" , "America/La_Paz" },
+ { "Borneo Standard Time" , "Asia/Kuching" },
+ { "Brasilia Standard Time" , "America/Sao_Paulo" },
+ { "British Standard Time" , "Europe/London" },
+ { "Brunei Standard Time" , "Asia/Brunei" },
+ { "Canada Central Standard Time" , "America/Regina" },
+ { "Cape Verde Standard Time" , "Atlantic/Cape_Verde" },
+ { "Cape_Verde Standard Time" , "Atlantic/Cape_Verde" },
+ { "Caucasus Standard Time" , "Asia/Yerevan" },
+ { "Cen. Australia Standard Time" , "Australia/Adelaide" },
+ { "Central Standard Time" , "America/Chicago" },
+ { "Central America Standard Time" , "America/Guatemala" },
+ { "Central Asia Standard Time" , "Asia/Dhaka" },
+ { "Central Brazilian Standard Time" , "America/Manaus" },
+ { "Central Europe Standard Time" , "Europe/Prague" },
+ { "Central European Standard Time" , "Europe/Warsaw" },
+ { "Central Pacific Standard Time" , "Pacific/Guadalcanal" },
+ { "Central Standard Time (Mexico)" , "America/Mexico_City" },
+ { "Chamorro Standard Time" , "Pacific/Guam" },
+ { "Changbai Standard Time" , "Asia/Harbin" },
+ { "Chatham Standard Time" , "Pacific/Chatham" },
+ { "Chile Standard Time" , "America/Santiago" },
+ { "China Standard Time" , "Asia/Taipei" },
+ { "Choibalsan Standard Time" , "Asia/Choibalsan" },
+ { "Christmas Standard Time" , "Indian/Christmas" },
+ { "Cocos Standard Time" , "Indian/Cocos" },
+ { "Colombia Standard Time" , "America/Bogota" },
+ { "Cook Standard Time" , "Pacific/Rarotonga" },
+ { "Cuba Standard Time" , "America/Havana" },
+ { "Dacca Standard Time" , "Asia/Dhaka" },
+ { "Dateline Standard Time" , "Pacific/Kwajalein" },
+ { "Davis Standard Time" , "Antarctica/Davis" },
+ { "Dominican Standard Time" , "America/Santo_Domingo" },
+ { "DumontDUrville Standard Time" , "Antarctica/DumontDUrville" },
+ { "Dushanbe Standard Time" , "Asia/Dushanbe" },
+ { "Dutch_Guiana Standard Time" , "America/Paramaribo" },
+ { "E. Africa Standard Time" , "Africa/Nairobi" },
+ { "E. Australia Standard Time" , "Australia/Brisbane" },
+ { "E. Europe Standard Time" , "Europe/Minsk" },
+ { "E. South America Standard Time" , "America/Sao_Paulo" },
+ { "East_Timor Standard Time" , "Asia/Dili" },
+ { "Easter Standard Time" , "Pacific/Easter" },
+ { "Eastern Standard Time" , "America/New_York" },
+ { "Ecuador Standard Time" , "America/Guayaquil" },
+ { "Egypt Standard Time" , "Africa/Cairo" },
+ { "Ekaterinburg Standard Time" , "Asia/Yekaterinburg" },
+ { "Europe_Central Standard Time" , "Europe/Oslo" },
+ { "Europe_Eastern Standard Time" , "Europe/Vilnius" },
+ { "Europe_Western Standard Time" , "Atlantic/Canary" },
+ { "FLE Standard Time" , "Europe/Helsinki" },
+ { "Falkland Standard Time" , "Atlantic/Stanley" },
+ { "Fiji Standard Time" , "Pacific/Fiji" },
+ { "French_Guiana Standard Time" , "America/Cayenne" },
+ { "French_Southern Standard Time" , "Indian/Kerguelen" },
+ { "Frunze Standard Time" , "Asia/Bishkek" },
+ { "GMT Standard Time" , "Europe/Dublin" },
+ { "GTB Standard Time" , "Europe/Istanbul" },
+ { "Galapagos Standard Time" , "Pacific/Galapagos" },
+ { "Gambier Standard Time" , "Pacific/Gambier" },
+ { "Georgia Standard Time" , "Asia/Tbilisi" },
+ { "Georgian Standard Time" , "Asia/Tbilisi" },
+ { "Gilbert_Islands Standard Time" , "Pacific/Tarawa" },
+ { "Goose_Bay Standard Time" , "America/Goose_Bay" },
+ { "Greenland Standard Time" , "America/Godthab" },
+ { "Greenland_Central Standard Time" , "America/Scoresbysund" },
+ { "Greenland_Eastern Standard Time" , "America/Scoresbysund" },
+ { "Greenland_Western Standard Time" , "America/Godthab" },
+ { "Greenwich Standard Time" , "Africa/Casablanca" },
+ { "Guam Standard Time" , "Pacific/Guam" },
+ { "Gulf Standard Time" , "Asia/Muscat" },
+ { "Guyana Standard Time" , "America/Guyana" },
+ { "Hawaii_Aleutian Standard Time" , "Pacific/Honolulu" },
+ { "Hawaiian Standard Time" , "Pacific/Honolulu" },
+ { "Hong_Kong Standard Time" , "Asia/Hong_Kong" },
+ { "Hovd Standard Time" , "Asia/Hovd" },
+ { "India Standard Time" , "Asia/Calcutta" },
+ { "Indian_Ocean Standard Time" , "Indian/Chagos" },
+ { "Indochina Standard Time" , "Asia/Vientiane" },
+ { "Indonesia_Central Standard Time" , "Asia/Makassar" },
+ { "Indonesia_Eastern Standard Time" , "Asia/Jayapura" },
+ { "Indonesia_Western Standard Time" , "Asia/Jakarta" },
+ { "Iran Standard Time" , "Asia/Tehran" },
+ { "Irish Standard Time" , "Europe/Dublin" },
+ { "Irkutsk Standard Time" , "Asia/Irkutsk" },
+ { "Israel Standard Time" , "Asia/Jerusalem" },
+ { "Japan Standard Time" , "Asia/Tokyo" },
+ { "Jordan Standard Time" , "Asia/Amman" },
+ { "Kamchatka Standard Time" , "Asia/Kamchatka" },
+ { "Karachi Standard Time" , "Asia/Karachi" },
+ { "Kashgar Standard Time" , "Asia/Kashgar" },
+ { "Kazakhstan_Eastern Standard Time" , "Asia/Almaty" },
+ { "Kazakhstan_Western Standard Time" , "Asia/Aqtobe" },
+ { "Kizilorda Standard Time" , "Asia/Qyzylorda" },
+ { "Korea Standard Time" , "Asia/Seoul" },
+ { "Kosrae Standard Time" , "Pacific/Kosrae" },
+ { "Krasnoyarsk Standard Time" , "Asia/Krasnoyarsk" },
+ { "Kuybyshev Standard Time" , "Europe/Samara" },
+ { "Kwajalein Standard Time" , "Pacific/Kwajalein" },
+ { "Kyrgystan Standard Time" , "Asia/Bishkek" },
+ { "Lanka Standard Time" , "Asia/Colombo" },
+ { "Liberia Standard Time" , "Africa/Monrovia" },
+ { "Line_Islands Standard Time" , "Pacific/Kiritimati" },
+ { "Long_Shu Standard Time" , "Asia/Chongqing" },
+ { "Lord_Howe Standard Time" , "Australia/Lord_Howe" },
+ { "Macau Standard Time" , "Asia/Macau" },
+ { "Magadan Standard Time" , "Asia/Magadan" },
+ { "Malaya Standard Time" , "Asia/Kuala_Lumpur" },
+ { "Malaysia Standard Time" , "Asia/Kuching" },
+ { "Maldives Standard Time" , "Indian/Maldives" },
+ { "Marquesas Standard Time" , "Pacific/Marquesas" },
+ { "Marshall_Islands Standard Time" , "Pacific/Majuro" },
+ { "Mauritius Standard Time" , "Indian/Mauritius" },
+ { "Mawson Standard Time" , "Antarctica/Mawson" },
+ { "Mexico Standard Time" , "America/Mexico_City" },
+ { "Mexico Standard Time 2 Standard Time" , "America/Chihuahua" },
+ { "Mid-Atlantic Standard Time" , "America/Noronha" },
+ { "Middle East Standard Time" , "Asia/Beirut" },
+ { "Mongolia Standard Time" , "Asia/Ulaanbaatar" },
+ { "Montevideo Standard Time" , "America/Montevideo" },
+ { "Moscow Standard Time" , "Europe/Moscow" },
+ { "Mountain Standard Time" , "America/Denver" },
+ { "Mountain Standard Time (Mexico)" , "America/Chihuahua" },
+ { "Myanmar Standard Time" , "Asia/Rangoon" },
+ { "N. Central Asia Standard Time" , "Asia/Novosibirsk" },
+ { "Namibia Standard Time" , "Africa/Windhoek" },
+ { "Nauru Standard Time" , "Pacific/Nauru" },
+ { "Nepal Standard Time" , "Asia/Katmandu" },
+ { "New Zealand Standard Time" , "Pacific/Auckland" },
+ { "New_Caledonia Standard Time" , "Pacific/Noumea" },
+ { "New_Zealand Standard Time" , "Pacific/Auckland" },
+ { "Newfoundland Standard Time" , "America/St_Johns" },
+ { "Niue Standard Time" , "Pacific/Niue" },
+ { "Norfolk Standard Time" , "Pacific/Norfolk" },
+ { "Noronha Standard Time" , "America/Noronha" },
+ { "North Asia Standard Time" , "Asia/Krasnoyarsk" },
+ { "North Asia East Standard Time" , "Asia/Ulaanbaatar" },
+ { "North_Mariana Standard Time" , "Pacific/Saipan" },
+ { "Novosibirsk Standard Time" , "Asia/Novosibirsk" },
+ { "Omsk Standard Time" , "Asia/Omsk" },
+ { "Oral Standard Time" , "Asia/Oral" },
+ { "Pacific Standard Time" , "America/Los_Angeles" },
+ { "Pacific SA Standard Time" , "America/Santiago" },
+ { "Pacific Standard Time (Mexico)" , "America/Tijuana" },
+ { "Pakistan Standard Time" , "Asia/Karachi" },
+ { "Palau Standard Time" , "Pacific/Palau" },
+ { "Papua_New_Guinea Standard Time" , "Pacific/Port_Moresby" },
+ { "Paraguay Standard Time" , "America/Asuncion" },
+ { "Peru Standard Time" , "America/Lima" },
+ { "Philippines Standard Time" , "Asia/Manila" },
+ { "Phoenix_Islands Standard Time" , "Pacific/Enderbury" },
+ { "Pierre_Miquelon Standard Time" , "America/Miquelon" },
+ { "Pitcairn Standard Time" , "Pacific/Pitcairn" },
+ { "Ponape Standard Time" , "Pacific/Ponape" },
+ { "Qyzylorda Standard Time" , "Asia/Qyzylorda" },
+ { "Reunion Standard Time" , "Indian/Reunion" },
+ { "Romance Standard Time" , "Europe/Paris" },
+ { "Rothera Standard Time" , "Antarctica/Rothera" },
+ { "Russian Standard Time" , "Europe/Moscow" },
+ { "SA Eastern Standard Time" , "America/Buenos_Aires" },
+ { "SA Pacific Standard Time" , "America/Bogota" },
+ { "SA Western Standard Time" , "America/Caracas" },
+ { "SE Asia Standard Time" , "Asia/Bangkok" },
+ { "Sakhalin Standard Time" , "Asia/Sakhalin" },
+ { "Samara Standard Time" , "Europe/Samara" },
+ { "Samarkand Standard Time" , "Asia/Samarkand" },
+ { "Samoa Standard Time" , "Pacific/Apia" },
+ { "Seychelles Standard Time" , "Indian/Mahe" },
+ { "Shevchenko Standard Time" , "Asia/Aqtau" },
+ { "Singapore Standard Time" , "Asia/Singapore" },
+ { "Solomon Standard Time" , "Pacific/Guadalcanal" },
+ { "South Africa Standard Time" , "Africa/Johannesburg" },
+ { "South_Georgia Standard Time" , "Atlantic/South_Georgia" },
+ { "Sri Lanka Standard Time" , "Asia/Colombo" },
+ { "Suriname Standard Time" , "America/Paramaribo" },
+ { "Sverdlovsk Standard Time" , "Asia/Yekaterinburg" },
+ { "Syowa Standard Time" , "Antarctica/Syowa" },
+ { "Tahiti Standard Time" , "Pacific/Tahiti" },
+ { "Taipei Standard Time" , "Asia/Taipei" },
+ { "Tajikistan Standard Time" , "Asia/Dushanbe" },
+ { "Tashkent Standard Time" , "Asia/Tashkent" },
+ { "Tasmania Standard Time" , "Australia/Hobart" },
+ { "Tbilisi Standard Time" , "Asia/Tbilisi" },
+ { "Tokelau Standard Time" , "Pacific/Fakaofo" },
+ { "Tokyo Standard Time" , "Asia/Tokyo" },
+ { "Tonga Standard Time" , "Pacific/Tongatapu" },
+ { "Truk Standard Time" , "Pacific/Truk" },
+ { "Turkey Standard Time" , "Europe/Istanbul" },
+ { "Turkmenistan Standard Time" , "Asia/Ashgabat" },
+ { "Tuvalu Standard Time" , "Pacific/Funafuti" },
+ { "US Eastern Standard Time" , "America/Indianapolis" },
+ { "US Mountain Standard Time" , "America/Phoenix" },
+ { "Uralsk Standard Time" , "Asia/Oral" },
+ { "Uruguay Standard Time" , "America/Montevideo" },
+ { "Urumqi Standard Time" , "Asia/Urumqi" },
+ { "Uzbekistan Standard Time" , "Asia/Tashkent" },
+ { "Vanuatu Standard Time" , "Pacific/Efate" },
+ { "Venezuela Standard Time" , "America/Caracas" },
+ { "Vladivostok Standard Time" , "Asia/Vladivostok" },
+ { "Volgograd Standard Time" , "Europe/Volgograd" },
+ { "Vostok Standard Time" , "Antarctica/Vostok" },
+ { "W. Australia Standard Time" , "Australia/Perth" },
+ { "W. Central Africa Standard Time" , "Africa/Lagos" },
+ { "W. Europe Standard Time" , "Europe/Berlin" },
+ { "Wake Standard Time" , "Pacific/Wake" },
+ { "Wallis Standard Time" , "Pacific/Wallis" },
+ { "West Asia Standard Time" , "Asia/Karachi" },
+ { "West Pacific Standard Time" , "Pacific/Guam" },
+ { "Yakutsk Standard Time" , "Asia/Yakutsk" },
+ { "Yekaterinburg Standard Time" , "Asia/Yekaterinburg" },
+ { "Yerevan Standard Time" , "Asia/Yerevan" },
+ { "Yukon Standard Time" , "America/Yakutat" },
+ { NULL, NULL }
+};
+
+static const char*
+get_zoneinfo_timezone( void )
+{
+ if (!android_timezone_init)
+ {
+ char tzname[128];
+ time_t t = time(NULL);
+ struct tm* tm = localtime(&t);
+ const Win32Timezone* win32tz = _win32_timezones;
+
+ android_timezone_init = 1;
+
+ if (!tm) {
+ D("%s: could not determine current date/time\n", __FUNCTION__);
+ return NULL;
+ }
+
+ memset(tzname, 0, sizeof(tzname));
+ strftime(tzname, sizeof(tzname) - 1, "%Z", tm);
+
+ for (win32tz = _win32_timezones; win32tz->win_name != NULL; win32tz++)
+ if ( !strcmp(win32tz->win_name, tzname) ) {
+ android_timezone = win32tz->zoneinfo_name;
+ goto Exit;
+ }
+
+#if 0 /* TODO */
+ /* we didn't find it, this may come from localized versions of Windows. we're going to explore the registry,
+ * as the code in Postgresql does...
+ */
+#endif
+ D( "%s: could not determine current timezone\n", __FUNCTION__ );
+ return NULL;
+ }
+Exit:
+ D( "emulator: found timezone %s\n", android_timezone );
+ return android_timezone;
+}
+
+#endif /* _WIN32 */
+
diff --git a/android_timezone.h b/android_timezone.h
new file mode 100644
index 0000000..daaccf6
--- /dev/null
+++ b/android_timezone.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_TIMEZONE_H
+#define _ANDROID_TIMEZONE_H
+
+#include "android_utils.h"
+
+/* try to set the default host timezone, returns 0 on success, or -1 if
+ * 'tzname' is not in zoneinfo format (e.g. Area/Location)
+ */
+extern int timezone_set( const char* tzname );
+
+/* append the current host "zoneinfo" timezone name to a given buffer. note
+ * that this is something like "America/Los_Angeles", and not the human-friendly "PST"
+ * this is required by the Android emulated system...
+ *
+ * the implementation of this function is really tricky and is OS-dependent
+ * on Unix systems, it needs to cater to the TZ environment variable, uhhh
+ *
+ * if TZ is defined to something like "CET" or "PST", this will return the name "Unknown/Unknown"
+ */
+extern char* bufprint_zoneinfo_timezone( char* buffer, char* end );
+
+#endif /* _ANDROID_TIMEZONE_H */
diff --git a/android_utils.c b/android_utils.c
new file mode 100644
index 0000000..26518cd
--- /dev/null
+++ b/android_utils.c
@@ -0,0 +1,1764 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_utils.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#ifdef _WIN32
+#include <process.h>
+#include <shlobj.h>
+#include <tlhelp32.h>
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <limits.h>
+#include <winbase.h>
+#else
+#include <unistd.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <signal.h>
+#endif
+#include "android.h"
+#include "android_debug.h"
+
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+
+/** PATH HANDLING ROUTINES
+ **
+ ** path_parent() can be used to return the n-level parent of a given directory
+ ** this understands . and .. when encountered in the input path
+ **/
+
+static __inline__ int
+ispathsep(int c)
+{
+#ifdef _WIN32
+ return (c == '/' || c == '\\');
+#else
+ return (c == '/');
+#endif
+}
+
+char* path_parent( const char* path, int levels )
+{
+ const char* end = path + strlen(path);
+ char* result;
+
+ while (levels > 0) {
+ const char* base;
+
+ /* trim any trailing path separator */
+ while (end > path && ispathsep(end[-1]))
+ end--;
+
+ base = end;
+ while (base > path && !ispathsep(base[-1]))
+ base--;
+
+ if (base <= path) /* we can't go that far */
+ return NULL;
+
+ if (end == base+1 && base[0] == '.')
+ goto Next;
+
+ if (end == base+2 && base[0] == '.' && base[1] == '.') {
+ levels += 1;
+ goto Next;
+ }
+
+ levels -= 1;
+
+ Next:
+ end = base - 1;
+ }
+ result = malloc( end-path+1 );
+ if (result != NULL) {
+ memcpy( result, path, end-path );
+ result[end-path] = 0;
+ }
+ return result;
+}
+
+
+/** MISC FILE AND DIRECTORY HANDLING
+ **/
+
+int
+path_exists( const char* path )
+{
+ int ret;
+ CHECKED(ret, access(path, F_OK));
+ return (ret == 0) || (errno != ENOENT);
+}
+
+/* checks that a path points to a regular file */
+int
+path_is_regular( const char* path )
+{
+ int ret;
+ struct stat st;
+
+ CHECKED(ret, stat(path, &st));
+ if (ret < 0)
+ return 0;
+
+ return S_ISREG(st.st_mode);
+}
+
+
+/* checks that a path points to a directory */
+int
+path_is_dir( const char* path )
+{
+ int ret;
+ struct stat st;
+
+ CHECKED(ret, stat(path, &st));
+ if (ret < 0)
+ return 0;
+
+ return S_ISDIR(st.st_mode);
+}
+
+/* checks that one can read/write a given (regular) file */
+int
+path_can_read( const char* path )
+{
+ int ret;
+ CHECKED(ret, access(path, R_OK));
+ return (ret == 0);
+}
+
+int
+path_can_write( const char* path )
+{
+ int ret;
+ CHECKED(ret, access(path, R_OK));
+ return (ret == 0);
+}
+
+/* try to make a directory. returns 0 on success, -1 on failure
+ * (error code in errno) */
+int
+path_mkdir( const char* path, int mode )
+{
+#ifdef _WIN32
+ (void)mode;
+ return _mkdir(path);
+#else
+ int ret;
+ CHECKED(ret, mkdir(path, mode));
+ return ret;
+#endif
+}
+
+static int
+path_mkdir_recursive( char* path, unsigned len, int mode )
+{
+ char old_c;
+ int ret;
+ unsigned len2;
+
+ /* get rid of trailing separators */
+ while (len > 0 && ispathsep(path[len-1]))
+ len -= 1;
+
+ if (len == 0) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ /* check that the parent exists, 'len2' is the length of
+ * the parent part of the path */
+ len2 = len-1;
+ while (len2 > 0 && !ispathsep(path[len2-1]))
+ len2 -= 1;
+
+ if (len2 > 0) {
+ old_c = path[len2];
+ path[len2] = 0;
+ ret = 0;
+ if ( !path_exists(path) ) {
+ /* the parent doesn't exist, so try to create it */
+ ret = path_mkdir_recursive( path, len2, mode );
+ }
+ path[len2] = old_c;
+
+ if (ret < 0)
+ return ret;
+ }
+
+ /* at this point, we now the parent exists */
+ old_c = path[len];
+ path[len] = 0;
+ ret = path_mkdir( path, mode );
+ path[len] = old_c;
+
+ return ret;
+}
+
+/* ensure that a given directory exists, create it if not,
+ 0 on success, -1 on failure (error code in errno) */
+int
+path_mkdir_if_needed( const char* path, int mode )
+{
+ int ret = 0;
+
+ if (!path_exists(path)) {
+ ret = path_mkdir(path, mode);
+
+ if (ret < 0 && errno == ENOENT) {
+ char temp[MAX_PATH];
+ unsigned len = (unsigned)strlen(path);
+
+ if (len > sizeof(temp)-1) {
+ errno = EINVAL;
+ return -1;
+ }
+ memcpy( temp, path, len );
+ temp[len] = 0;
+
+ return path_mkdir_recursive(temp, len, mode);
+ }
+ }
+ return ret;
+}
+
+/* return the size of a given file in '*psize'. returns 0 on
+ * success, -1 on failure (error code in errno) */
+int
+path_get_size( const char* path, uint64_t *psize )
+{
+#ifdef _WIN32
+ /* avoid _stat64 which is only defined in MSVCRT.DLL, not CRTDLL.DLL */
+ /* do not use OpenFile() because it has strange search behaviour that could */
+ /* result in getting the size of a different file */
+ LARGE_INTEGER size;
+ HANDLE file = CreateFile( /* lpFilename */ path,
+ /* dwDesiredAccess */ GENERIC_READ,
+ /* dwSharedMode */ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ /* lpSecurityAttributes */ NULL,
+ /* dwCreationDisposition */ OPEN_EXISTING,
+ /* dwFlagsAndAttributes */ 0,
+ /* hTemplateFile */ NULL );
+ if (file == INVALID_HANDLE_VALUE) {
+ /* ok, just to play fair */
+ errno = ENOENT;
+ return -1;
+ }
+ if (!GetFileSizeEx(file, &size)) {
+ /* maybe we tried to get the size of a pipe or something like that ? */
+ *psize = 0;
+ }
+ else {
+ *psize = (uint64_t) size.QuadPart;
+ }
+ CloseHandle(file);
+ return 0;
+#else
+ int ret;
+ struct stat st;
+
+ CHECKED(ret, stat(path, &st));
+ if (ret == 0) {
+ *psize = (uint64_t) st.st_size;
+ }
+ return ret;
+#endif
+}
+
+
+/** USEFUL STRING BUFFER FUNCTIONS
+ **/
+
+char*
+vbufprint( char* buffer,
+ char* buffer_end,
+ const char* fmt,
+ va_list args )
+{
+ int len = vsnprintf( buffer, buffer_end - buffer, fmt, args );
+ if (len < 0 || buffer+len >= buffer_end) {
+ if (buffer < buffer_end)
+ buffer_end[-1] = 0;
+ return buffer_end;
+ }
+ return buffer + len;
+}
+
+char*
+bufprint(char* buffer, char* end, const char* fmt, ... )
+{
+ va_list args;
+ char* result;
+
+ va_start(args, fmt);
+ result = vbufprint(buffer, end, fmt, args);
+ va_end(args);
+ return result;
+}
+
+/** USEFUL DIRECTORY SUPPORT
+ **
+ ** bufprint_app_dir() returns the directory where the emulator binary is located
+ **
+ ** get_android_home() returns a user-specific directory where the emulator will
+ ** store its writable data (e.g. config files, profiles, etc...).
+ ** on Unix, this is $HOME/.android, on Windows, this is something like
+ ** "%USERPROFILE%/Local Settings/AppData/Android" on XP, and something different
+ ** on Vista.
+ **
+ ** both functions return a string that must be freed by the caller
+ **/
+
+#ifdef __linux__
+char*
+bufprint_app_dir(char* buff, char* end)
+{
+ char path[1024];
+ int len;
+ char* x;
+
+ len = readlink("/proc/self/exe", path, sizeof(path));
+ if (len <= 0 || len >= (int)sizeof(path)) goto Fail;
+ path[len] = 0;
+
+ x = strrchr(path, '/');
+ if (x == 0) goto Fail;
+ *x = 0;
+
+ return bufprint(buff, end, "%s", path);
+Fail:
+ fprintf(stderr,"cannot locate application directory\n");
+ exit(1);
+ return end;
+}
+
+#elif defined(__APPLE__)
+/* the following hack is needed in order to build with XCode 3.1
+ * don't ask me why, but it seems that there were changes in the
+ * GCC compiler that we don't have in our pre-compiled version
+ */
+#ifndef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
+#define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ MAC_OS_X_VERSION_10_4
+#endif
+#import <Carbon/Carbon.h>
+#include <unistd.h>
+
+char*
+bufprint_app_dir(char* buff, char* end)
+{
+ ProcessSerialNumber psn;
+ CFDictionaryRef dict;
+ CFStringRef value;
+ char s[PATH_MAX];
+ char* x;
+
+ GetCurrentProcess(&psn);
+ dict = ProcessInformationCopyDictionary(&psn, 0xffffffff);
+ value = (CFStringRef)CFDictionaryGetValue(dict,
+ CFSTR("CFBundleExecutable"));
+ CFStringGetCString(value, s, PATH_MAX - 1, kCFStringEncodingUTF8);
+ x = strrchr(s, '/');
+ if (x == 0) goto fail;
+ *x = 0;
+
+ return bufprint(buff, end, "%s", s);
+fail:
+ fprintf(stderr,"cannot locate application directory\n");
+ exit(1);
+ return end;
+}
+#elif defined _WIN32
+char*
+bufprint_app_dir(char* buff, char* end)
+{
+ char appDir[MAX_PATH];
+ char* sep;
+
+ GetModuleFileName( 0, appDir, sizeof(appDir)-1 );
+ sep = strrchr( appDir, '\\' );
+ if (sep)
+ *sep = 0;
+
+ return bufprint(buff, end, "%s", appDir);
+}
+#else
+char*
+bufprint_app_dir(char* buff, char* end)
+{
+ return bufprint(buff, end, ".");
+}
+#endif
+
+#ifdef _WIN32
+#define _ANDROID_PATH "Android"
+#else
+#define _ANDROID_PATH ".android"
+#endif
+
+char*
+bufprint_config_path(char* buff, char* end)
+{
+#ifdef _WIN32
+ char path[MAX_PATH];
+
+ SHGetFolderPath( NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE,
+ NULL, 0, path);
+
+ return bufprint(buff, end, "%s\\%s\\%s", path, _ANDROID_PATH, ANDROID_SDK_VERSION);
+#else
+ const char* home = getenv("HOME");
+ if (home == NULL)
+ home = "/tmp";
+ return bufprint(buff, end, "%s/%s/%s", home, _ANDROID_PATH, ANDROID_SDK_VERSION);
+#endif
+}
+
+char*
+bufprint_config_file(char* buff, char* end, const char* suffix)
+{
+ char* p;
+ p = bufprint_config_path(buff, end);
+ p = bufprint(p, end, PATH_SEP "%s", suffix);
+ return p;
+}
+
+char*
+bufprint_temp_dir(char* buff, char* end)
+{
+#ifdef _WIN32
+ char path[MAX_PATH];
+ DWORD retval;
+
+ retval = GetTempPath( sizeof(path), path );
+ if (retval > sizeof(path) || retval == 0) {
+ D( "can't locate TEMP directory" );
+ pstrcpy(path, sizeof(path), "C:\\Temp");
+ }
+ strncat( path, "\\AndroidEmulator", sizeof(path)-1 );
+ _mkdir(path);
+
+ return bufprint(buff, end, "%s", path);
+#else
+ const char* tmppath = "/tmp/android";
+ mkdir(tmppath, 0744);
+ return bufprint(buff, end, "%s", tmppath );
+#endif
+}
+
+char*
+bufprint_temp_file(char* buff, char* end, const char* suffix)
+{
+ char* p;
+ p = bufprint_temp_dir(buff, end);
+ p = bufprint(p, end, PATH_SEP "%s", suffix);
+ return p;
+}
+
+
+
+/** FILE LOCKS SUPPORT
+ **
+ ** a FileLock is useful to prevent several emulator instances from using the same
+ ** writable file (e.g. the userdata.img disk images).
+ **
+ ** create a FileLock object with filelock_create(), ithis function should return NULL
+ ** only if thee file doesn't exist, or if you don't have enough memory.
+ *
+ * then call filelock_lock() to try to acquire a lock for the corresponding file.
+ ** returns 0 on success, or -1 in case of error, which means that another program
+ ** is using the file or that the directory containing the file is read-only.
+ **
+ ** all file locks are automatically released and destroyed when the program exits.
+ ** the filelock_lock() function can also detect stale file locks that can linger
+ ** when the emulator crashes unexpectedly, and will happily clean them for you
+ **
+ ** here's how it works, three files are used:
+ ** file - the data file accessed by the emulator
+ ** lock - a lock file (file + '.lock')
+ ** temp - a temporary file make unique with mkstemp
+ **
+ ** when locking:
+ ** create 'temp' and store our pid in it
+ ** attemp to link 'lock' to 'temp'
+ ** if the link succeeds, we obtain the lock
+ ** unlink 'temp'
+ **
+ ** when unlocking:
+ ** unlink 'lock'
+ **
+ **
+ ** on Windows, 'lock' is a directory name. locking is equivalent to
+ ** creating it...
+ **
+ **/
+
+struct FileLock
+{
+ const char* file;
+ const char* lock;
+ char* temp;
+ int locked;
+ FileLock* next;
+};
+
+#define LOCK_NAME ".lock"
+#define TEMP_NAME ".tmp-XXXXXX"
+
+#ifdef _WIN32
+#define PIDFILE_NAME "pid"
+#endif
+
+/* returns 0 on success, -1 on failure */
+int
+filelock_lock( FileLock* lock )
+{
+ int ret;
+#ifdef _WIN32
+ int pidfile_fd = -1;
+
+ ret = _mkdir( lock->lock );
+ if (ret < 0) {
+ if (errno == ENOENT) {
+ D( "could not access directory '%s', check path elements", lock->lock );
+ return -1;
+ } else if (errno != EEXIST) {
+ D( "_mkdir(%s): %s", lock->lock, strerror(errno) );
+ return -1;
+ }
+
+ /* if we get here, it's because the .lock directory already exists */
+ /* check to see if there is a pid file in it */
+ D("directory '%s' already exist, waiting a bit to ensure that no other emulator instance is starting", lock->lock );
+ {
+ int _sleep = 200;
+ int tries;
+
+ for ( tries = 4; tries > 0; tries-- )
+ {
+ pidfile_fd = open( lock->temp, O_RDONLY );
+
+ if (pidfile_fd >= 0)
+ break;
+
+ Sleep( _sleep );
+ _sleep *= 2;
+ }
+ }
+
+ if (pidfile_fd < 0) {
+ D( "no pid file in '%s', assuming stale directory", lock->lock );
+ }
+ else
+ {
+ /* read the pidfile, and check wether the corresponding process is still running */
+ char buf[16];
+ int len, lockpid;
+ HANDLE processSnapshot;
+ PROCESSENTRY32 pe32;
+ int is_locked = 0;
+
+ len = read( pidfile_fd, buf, sizeof(buf)-1 );
+ if (len < 0) {
+ D( "could not read pid file '%s'", lock->temp );
+ close( pidfile_fd );
+ return -1;
+ }
+ buf[len] = 0;
+ lockpid = atoi(buf);
+
+ /* PID 0 is the IDLE process, and 0 is returned in case of invalid input */
+ if (lockpid == 0)
+ lockpid = -1;
+
+ close( pidfile_fd );
+
+ pe32.dwSize = sizeof( PROCESSENTRY32 );
+ processSnapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
+
+ if ( processSnapshot == INVALID_HANDLE_VALUE ) {
+ D( "could not retrieve the list of currently active processes\n" );
+ is_locked = 1;
+ }
+ else if ( !Process32First( processSnapshot, &pe32 ) )
+ {
+ D( "could not retrieve first process id\n" );
+ CloseHandle( processSnapshot );
+ is_locked = 1;
+ }
+ else
+ {
+ do {
+ if (pe32.th32ProcessID == lockpid) {
+ is_locked = 1;
+ break;
+ }
+ } while (Process32Next( processSnapshot, &pe32 ) );
+
+ CloseHandle( processSnapshot );
+ }
+
+ if (is_locked) {
+ D( "the file '%s' is locked by process ID %d\n", lock->file, lockpid );
+ return -1;
+ }
+ }
+ }
+
+ /* write our PID into the pid file */
+ pidfile_fd = open( lock->temp, O_WRONLY | O_CREAT | O_TRUNC );
+ if (pidfile_fd < 0) {
+ if (errno == EACCES) {
+ if ( unlink_file( lock->temp ) < 0 ) {
+ D( "could not remove '%s': %s\n", lock->temp, strerror(errno) );
+ return -1;
+ }
+ pidfile_fd = open( lock->temp, O_WRONLY | O_CREAT | O_TRUNC );
+ }
+ if (pidfile_fd < 0) {
+ D( "could not create '%s': %s\n", lock->temp, strerror(errno) );
+ return -1;
+ }
+ }
+
+ {
+ char buf[16];
+ sprintf( buf, "%ld", GetCurrentProcessId() );
+ ret = write( pidfile_fd, buf, strlen(buf) );
+ close(pidfile_fd);
+ if (ret < 0) {
+ D( "could not write PID to '%s'\n", lock->temp );
+ return -1;
+ }
+ }
+
+ lock->locked = 1;
+ return 0;
+#else
+ int temp_fd = -1;
+ int lock_fd = -1;
+ int rc, tries, _sleep;
+ FILE* f = NULL;
+ char pid[8];
+ struct stat st_temp;
+
+ strcpy( lock->temp, lock->file );
+ strcat( lock->temp, TEMP_NAME );
+ temp_fd = mkstemp( lock->temp );
+
+ if (temp_fd < 0) {
+ D("cannot create locking temp file '%s'", lock->temp );
+ goto Fail;
+ }
+
+ sprintf( pid, "%d", getpid() );
+ ret = write( temp_fd, pid, strlen(pid)+1 );
+ if (ret < 0) {
+ D( "cannot write to locking temp file '%s'", lock->temp);
+ goto Fail;
+ }
+ close( temp_fd );
+ temp_fd = -1;
+
+ CHECKED(rc, lstat( lock->temp, &st_temp ));
+ if (rc < 0) {
+ D( "can't properly stat our locking temp file '%s'", lock->temp );
+ goto Fail;
+ }
+
+ /* now attempt to link the temp file to the lock file */
+ _sleep = 0;
+ for ( tries = 4; tries > 0; tries-- )
+ {
+ struct stat st_lock;
+ int rc;
+
+ if (_sleep > 0) {
+ if (_sleep > 2000000) {
+ D( "cannot acquire lock file '%s'", lock->lock );
+ goto Fail;
+ }
+ usleep( _sleep );
+ }
+ _sleep += 200000;
+
+ /* the return value of link() is buggy on NFS */
+ CHECKED(rc, link( lock->temp, lock->lock ));
+
+ CHECKED(rc, lstat( lock->lock, &st_lock ));
+ if (rc == 0 &&
+ st_temp.st_rdev == st_lock.st_rdev &&
+ st_temp.st_ino == st_lock.st_ino )
+ {
+ /* SUCCESS */
+ lock->locked = 1;
+ CHECKED(rc, unlink( lock->temp ));
+ return 0;
+ }
+
+ /* if we get there, it means that the link() call failed */
+ /* check the lockfile to see if it is stale */
+ if (rc == 0) {
+ char buf[16];
+ time_t now;
+ int lockpid = 0;
+ int lockfd;
+ int stale = 2; /* means don't know */
+ struct stat st;
+
+ CHECKED(rc, time( &now));
+ st.st_mtime = now - 120;
+
+ CHECKED(lockfd, open( lock->lock,O_RDONLY ));
+ if ( lockfd >= 0 ) {
+ int len;
+
+ CHECKED(len, read( lockfd, buf, sizeof(buf)-1 ));
+ buf[len] = 0;
+ lockpid = atoi(buf);
+
+ CHECKED(rc, fstat( lockfd, &st ));
+ if (rc == 0)
+ now = st.st_atime;
+
+ CHECKED(rc, close(lockfd));
+ }
+ /* if there is a PID, check that it is still alive */
+ if (lockpid > 0) {
+ CHECKED(rc, kill( lockpid, 0 ));
+ if (rc == 0 || errno == EPERM) {
+ stale = 0;
+ } else if (rc < 0 && errno == ESRCH) {
+ stale = 1;
+ }
+ }
+ if (stale == 2) {
+ /* no pid, stale if the file is older than 1 minute */
+ stale = (now >= st.st_mtime + 60);
+ }
+
+ if (stale) {
+ D( "removing stale lockfile '%s'", lock->lock );
+ CHECKED(rc, unlink( lock->lock ));
+ _sleep = 0;
+ tries++;
+ }
+ }
+ }
+ D("file '%s' is already in use by another process", lock->file );
+
+Fail:
+ if (f)
+ fclose(f);
+
+ if (temp_fd >= 0) {
+ close(temp_fd);
+ }
+
+ if (lock_fd >= 0) {
+ close(lock_fd);
+ }
+
+ unlink( lock->lock );
+ unlink( lock->temp );
+ return -1;
+#endif
+}
+
+void
+filelock_unlock( FileLock* lock )
+{
+#ifdef _WIN32
+ unlink_file( (char*)lock->temp );
+ rmdir( (char*)lock->lock );
+ lock->locked = 0;
+#else
+ unlink( (char*)lock->lock );
+ lock->locked = 0;
+#endif
+}
+
+
+/* used to cleanup all locks at emulator exit */
+static FileLock* _all_filelocks;
+
+static void
+filelock_atexit( void )
+{
+ FileLock* lock;
+
+ for (lock = _all_filelocks; lock != NULL; lock = lock->next)
+ {
+ if (lock->locked)
+ filelock_unlock( lock );
+ }
+}
+
+/* create a file lock */
+FileLock*
+filelock_create( const char* file )
+{
+ int file_len = strlen(file);
+ int lock_len = file_len + sizeof(LOCK_NAME);
+#ifdef _WIN32
+ int temp_len = lock_len + 1 + sizeof(PIDFILE_NAME);
+#else
+ int temp_len = file_len + sizeof(TEMP_NAME);
+#endif
+ int total_len = sizeof(FileLock) + file_len + lock_len + temp_len + 3;
+
+ FileLock* lock = malloc(total_len);
+ if (lock == NULL)
+ goto Exit;
+
+ lock->file = (const char*)(lock + 1);
+ memcpy( (char*)lock->file, file, file_len+1 );
+
+ lock->lock = lock->file + file_len + 1;
+ memcpy( (char*)lock->lock, file, file_len+1 );
+ strcat( (char*)lock->lock, LOCK_NAME );
+
+ lock->temp = (char*)lock->lock + lock_len + 1;
+#ifdef _WIN32
+ sprintf( (char*)lock->temp, "%s\\" PIDFILE_NAME, lock->lock );
+#else
+ lock->temp[0] = 0;
+#endif
+ lock->locked = 0;
+
+ lock->next = _all_filelocks;
+ _all_filelocks = lock;
+
+ if (lock->next == NULL)
+ atexit( filelock_atexit );
+Exit:
+ return lock;
+}
+
+/** TEMP FILE SUPPORT
+ **
+ ** simple interface to create an empty temporary file on the system.
+ **
+ ** create the file with tempfile_create(), which returns a reference to a TempFile
+ ** object, or NULL if your system is so weird it doesn't have a temporary directory.
+ **
+ ** you can then call tempfile_path() to retrieve the TempFile's real path to open
+ ** it. the returned path is owned by the TempFile object and should not be freed.
+ **
+ ** all temporary files are destroyed when the program quits, unless you explicitely
+ ** close them before that with tempfile_close()
+ **/
+
+struct TempFile
+{
+ const char* name;
+ TempFile* next;
+};
+
+static void tempfile_atexit();
+static TempFile* _all_tempfiles;
+
+TempFile*
+tempfile_create( void )
+{
+ TempFile* tempfile;
+ const char* tempname = NULL;
+
+#ifdef _WIN32
+ char temp_namebuff[MAX_PATH];
+ char temp_dir[MAX_PATH];
+ char *p = temp_dir, *end = p + sizeof(temp_dir);
+ UINT retval;
+
+ p = bufprint_temp_dir( p, end );
+ if (p >= end) {
+ D( "TEMP directory path is too long" );
+ return NULL;
+ }
+
+ retval = GetTempFileName(temp_dir, "TMP", 0, temp_namebuff);
+ if (retval == 0) {
+ D( "can't create temporary file in '%s'", temp_dir );
+ return NULL;
+ }
+
+ tempname = temp_namebuff;
+#else
+#define TEMPLATE "/tmp/.android-emulator-XXXXXX"
+ int tempfd = -1;
+ char template[512];
+ char *p = template, *end = p + sizeof(template);
+
+ p = bufprint_temp_file( p, end, "emulator-XXXXXX" );
+ if (p >= end) {
+ D( "Xcannot create temporary file in /tmp/android !!" );
+ return NULL;
+ }
+
+ D( "template: %s", template );
+ tempfd = mkstemp( template );
+ if (tempfd < 0) {
+ D("cannot create temporary file in /tmp/android !!");
+ return NULL;
+ }
+ close(tempfd);
+ tempname = template;
+#endif
+ tempfile = malloc( sizeof(*tempfile) + strlen(tempname) + 1 );
+ tempfile->name = (char*)(tempfile + 1);
+ strcpy( (char*)tempfile->name, tempname );
+
+ tempfile->next = _all_tempfiles;
+ _all_tempfiles = tempfile;
+
+ if ( !tempfile->next ) {
+ atexit( tempfile_atexit );
+ }
+
+ return tempfile;
+}
+
+const char*
+tempfile_path(TempFile* temp)
+{
+ return temp ? temp->name : NULL;
+}
+
+void
+tempfile_close(TempFile* tempfile)
+{
+#ifdef _WIN32
+ DeleteFile(tempfile->name);
+#else
+ unlink(tempfile->name);
+#endif
+}
+
+/** TEMP FILE CLEANUP
+ **
+ **/
+
+/* we don't expect to use many temporary files */
+#define MAX_ATEXIT_FDS 16
+
+typedef struct {
+ int count;
+ int fds[ MAX_ATEXIT_FDS ];
+} AtExitFds;
+
+static void
+atexit_fds_add( AtExitFds* t, int fd )
+{
+ if (t->count < MAX_ATEXIT_FDS)
+ t->fds[t->count++] = fd;
+ else {
+ dwarning("%s: over %d calls. Program exit may not cleanup all temporary files",
+ __FUNCTION__, MAX_ATEXIT_FDS);
+ }
+}
+
+static void
+atexit_fds_del( AtExitFds* t, int fd )
+{
+ int nn;
+ for (nn = 0; nn < t->count; nn++)
+ if (t->fds[nn] == fd) {
+ /* move the last element to the current position */
+ t->count -= 1;
+ t->fds[nn] = t->fds[t->count];
+ break;
+ }
+}
+
+static void
+atexit_fds_close_all( AtExitFds* t )
+{
+ int nn;
+ for (nn = 0; nn < t->count; nn++)
+ close(t->fds[nn]);
+}
+
+static AtExitFds _atexit_fds[1];
+
+void
+atexit_close_fd(int fd)
+{
+ if (fd >= 0)
+ atexit_fds_add(_atexit_fds, fd);
+}
+
+void
+atexit_close_fd_remove(int fd)
+{
+ if (fd >= 0)
+ atexit_fds_del(_atexit_fds, fd);
+}
+
+static void
+tempfile_atexit( void )
+{
+ TempFile* tempfile;
+
+ atexit_fds_close_all( _atexit_fds );
+
+ for (tempfile = _all_tempfiles; tempfile; tempfile = tempfile->next)
+ tempfile_close(tempfile);
+}
+
+
+/** OTHER FILE UTILITIES
+ **
+ ** make_empty_file() creates an empty file at a given path location.
+ ** if the file already exists, it is truncated without warning
+ **
+ ** copy_file() copies one file into another.
+ **
+ ** both functions return 0 on success, and -1 on error
+ **/
+
+int
+make_empty_file( const char* path )
+{
+#ifdef _WIN32
+ int fd = _creat( path, S_IWRITE );
+#else
+ /* on Unix, only allow the owner to read/write, since the file *
+ * may contain some personal data we don't want to see exposed */
+ int fd = creat(path, S_IRUSR | S_IWUSR);
+#endif
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+ return -1;
+}
+
+int
+copy_file( const char* dest, const char* source )
+{
+ int fd, fs, result = -1;
+
+ if ( access(source, F_OK) < 0 ||
+ make_empty_file(dest) < 0) {
+ return -1;
+ }
+
+#ifdef _WIN32
+ fd = _open(dest, _O_RDWR | _O_BINARY);
+ fs = _open(source, _O_RDONLY | _O_BINARY);
+#else
+ fd = creat(dest, S_IRUSR | S_IWUSR);
+ fs = open(source, S_IREAD);
+#endif
+ if (fs >= 0 && fd >= 0) {
+ char buf[4096];
+ ssize_t total = 0;
+ ssize_t n;
+ result = 0; /* success */
+ while ((n = read(fs, buf, 4096)) > 0) {
+ if (write(fd, buf, n) != n) {
+ /* write failed. Make it return -1 so that an
+ * empty file be created. */
+ D("Failed to copy '%s' to '%s': %s (%d)",
+ source, dest, strerror(errno), errno);
+ result = -1;
+ break;
+ }
+ total += n;
+ }
+ }
+
+ if (fs >= 0) {
+ close(fs);
+ }
+ if (fd >= 0) {
+ close(fd);
+ }
+ return result;
+}
+
+int
+unlink_file( const char* path )
+{
+#ifdef _WIN32
+ int ret = _unlink( path );
+ if (ret == -1 && errno == EACCES) {
+ /* a first call to _unlink will fail if the file is set read-only */
+ /* we can however try to change its mode first and call unlink */
+ /* again... */
+ ret = _chmod( path, _S_IREAD | _S_IWRITE );
+ if (ret == 0)
+ ret = _unlink( path );
+ }
+ return ret;
+#else
+ return unlink(path);
+#endif
+}
+
+
+void*
+load_text_file(const char *fn)
+{
+ char *data;
+ int sz;
+ int fd;
+
+ data = NULL;
+ fd = open(fn, O_BINARY | O_RDONLY);
+ if(fd < 0) return NULL;
+
+ sz = lseek(fd, 0, SEEK_END);
+ if(sz < 0) goto oops;
+
+ if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
+
+ data = (char*) malloc(sz + 1);
+ if(data == 0) goto oops;
+
+ if(read(fd, data, sz) != sz) goto oops;
+ close(fd);
+ data[sz] = 0;
+
+ return data;
+
+oops:
+ close(fd);
+ if(data != 0)
+ free(data);
+ return NULL;
+}
+
+/** HOST RESOLUTION SETTINGS
+ **
+ ** return the main monitor's DPI resolution according to the host device
+ ** beware: this is not always reliable or even obtainable.
+ **
+ ** returns 0 on success, or -1 in case of error (e.g. the system returns funky values)
+ **/
+
+/** NOTE: the following code assumes that we exclusively use X11 on Linux, and Quartz on OS X
+ **/
+
+#ifdef _WIN32
+int
+get_monitor_resolution( int *px_dpi, int *py_dpi )
+{
+ HDC displayDC = CreateDC( "DISPLAY", NULL, NULL, NULL );
+ int xdpi, ydpi;
+
+ if (displayDC == NULL) {
+ D( "%s: could not get display DC\n", __FUNCTION__ );
+ return -1;
+ }
+ xdpi = GetDeviceCaps( displayDC, LOGPIXELSX );
+ ydpi = GetDeviceCaps( displayDC, LOGPIXELSY );
+
+ /* sanity checks */
+ if (xdpi < 20 || xdpi > 400 || ydpi < 20 || ydpi > 400) {
+ D( "%s: bad resolution: xpi=%d ydpi=%d", __FUNCTION__,
+ xdpi, ydpi );
+ return -1;
+ }
+
+ *px_dpi = xdpi;
+ *py_dpi = ydpi;
+ return 0;
+}
+#elif defined __APPLE__
+int
+get_monitor_resolution( int *px_dpi, int *py_dpi )
+{
+ fprintf(stderr, "emulator: FIXME: implement get_monitor_resolution on OS X\n" );
+ return -1;
+}
+#else /* Linux and others */
+#include <SDL.h>
+#include <SDL_syswm.h>
+#include <X11/Xlib.h>
+#define MM_PER_INCH 25.4
+
+int
+get_monitor_resolution( int *px_dpi, int *py_dpi )
+{
+ SDL_SysWMinfo info;
+ Display* display;
+ int screen;
+ int width, width_mm, height, height_mm, xdpi, ydpi;
+
+ SDL_VERSION(&info.version);
+
+ if ( !SDL_GetWMInfo(&info) ) {
+ D( "%s: SDL_GetWMInfo() failed: %s", __FUNCTION__, SDL_GetError());
+ return -1;
+ }
+
+ display = info.info.x11.display;
+ screen = XDefaultScreen(display);
+
+ width = XDisplayWidth(display, screen);
+ width_mm = XDisplayWidthMM(display, screen);
+ height = XDisplayHeight(display, screen);
+ height_mm = XDisplayHeightMM(display, screen);
+
+ if (width_mm <= 0 || height_mm <= 0) {
+ D( "%s: bad screen dimensions: width_mm = %d, height_mm = %d",
+ __FUNCTION__, width_mm, height_mm);
+ return -1;
+ }
+
+ D( "%s: found screen width=%d height=%d width_mm=%d height_mm=%d",
+ __FUNCTION__, width, height, width_mm, height_mm );
+
+ xdpi = width * MM_PER_INCH / width_mm;
+ ydpi = height * MM_PER_INCH / height_mm;
+
+ if (xdpi < 20 || xdpi > 400 || ydpi < 20 || ydpi > 400) {
+ D( "%s: bad resolution: xpi=%d ydpi=%d", __FUNCTION__,
+ xdpi, ydpi );
+ return -1;
+ }
+
+ *px_dpi = xdpi;
+ *py_dpi = ydpi;
+
+ return 0;
+}
+#endif
+
+
+
+void
+disable_sigalrm( signal_state_t *state )
+{
+#ifdef _WIN32
+ (void)state;
+#else
+ sigset_t set;
+
+ sigemptyset(&set);
+ sigaddset(&set, SIGALRM);
+ pthread_sigmask (SIG_BLOCK, &set, &state->old);
+#endif
+}
+
+void
+restore_sigalrm( signal_state_t *state )
+{
+#ifdef _WIN32
+ (void)state;
+#else
+ pthread_sigmask (SIG_SETMASK, &state->old, NULL);
+#endif
+}
+
+void
+sleep_ms( int timeout_ms )
+{
+#ifdef _WIN32
+ if (timeout_ms <= 0)
+ return;
+
+ Sleep( timeout_ms );
+#else
+ if (timeout_ms <= 0)
+ return;
+
+ BEGIN_NOSIGALRM
+ usleep( timeout_ms*1000 );
+ END_NOSIGALRM
+#endif
+}
+
+
+extern void
+print_tabular( const char** strings, int count,
+ const char* prefix, int width )
+{
+ int nrows, ncols, r, c, n, maxw = 0;
+
+ for (n = 0; n < count; n++) {
+ int len = strlen(strings[n]);
+ if (len > maxw)
+ maxw = len;
+ }
+ maxw += 2;
+ ncols = width/maxw;
+ nrows = (count + ncols-1)/ncols;
+
+ for (r = 0; r < nrows; r++) {
+ printf( "%s", prefix );
+ for (c = 0; c < ncols; c++) {
+ int index = c*nrows + r;
+ if (index >= count) {
+ break;
+ }
+ printf( "%-*s", maxw, strings[index] );
+ }
+ printf( "\n" );
+ }
+}
+
+extern void
+stralloc_tabular( stralloc_t* out,
+ const char** strings, int count,
+ const char* prefix, int width )
+{
+ int nrows, ncols, r, c, n, maxw = 0;
+
+ for (n = 0; n < count; n++) {
+ int len = strlen(strings[n]);
+ if (len > maxw)
+ maxw = len;
+ }
+ maxw += 2;
+ ncols = width/maxw;
+ nrows = (count + ncols-1)/ncols;
+
+ for (r = 0; r < nrows; r++) {
+ stralloc_add_str( out, prefix );
+ for (c = 0; c < ncols; c++) {
+ int index = c*nrows + r;
+ if (index >= count) {
+ break;
+ }
+ stralloc_add_format( out, "%-*s", maxw, strings[index] );
+ }
+ stralloc_add_str( out, "\n" );
+ }
+}
+
+extern void
+buffer_translate_char( char* buff, unsigned len,
+ char from, char to )
+{
+ char* p = buff;
+ char* end = p + len;
+
+ while (p != NULL && (p = memchr(p, from, (size_t)(end - p))) != NULL)
+ *p++ = to;
+}
+
+extern void
+string_translate_char( char* str, char from, char to )
+{
+ char* p = str;
+ while (p != NULL && (p = strchr(p, from)) != NULL)
+ *p++ = to;
+}
+
+/** DYNAMIC STRINGS
+ **/
+
+extern void
+stralloc_reset( stralloc_t* s )
+{
+ free(s->s);
+ s->s = NULL;
+ s->n = 0;
+ s->a = 0;
+}
+
+extern void
+stralloc_ready( stralloc_t* s, unsigned int len )
+{
+ unsigned old_max = s->a;
+ unsigned new_max = old_max;
+
+ while (new_max < len) {
+ unsigned new_max2 = new_max + (new_max >> 1) + 16;
+ if (new_max2 < new_max)
+ new_max2 = UINT_MAX;
+ new_max = new_max2;
+ }
+
+ s->s = realloc( s->s, new_max );
+ if (s->s == NULL) {
+ derror( "%s: not enough memory to reallocate %ld bytes",
+ __FUNCTION__, new_max );
+ exit(1);
+ }
+ s->a = new_max;
+}
+
+extern void
+stralloc_readyplus( stralloc_t* s, unsigned int len )
+{
+ unsigned len2 = s->n + len;
+
+ if (len2 < s->n) { /* overflow ? */
+ derror("%s: trying to grow by too many bytes: %ld",
+ __FUNCTION__, len);
+ exit(1);
+ }
+ stralloc_ready( s, len2 );
+}
+
+extern void
+stralloc_copy( stralloc_t* s, stralloc_t* from )
+{
+ stralloc_ready(s, from->n);
+ memcpy( s->s, from->s, from->n );
+ s->n = from->n;
+}
+
+extern void
+stralloc_append( stralloc_t* s, stralloc_t* from )
+{
+ stralloc_readyplus( s, from->n );
+ memcpy( s->s + s->n, from->s, from->n );
+ s->n += from->n;
+}
+
+extern void
+stralloc_add_c( stralloc_t* s, int c )
+{
+ stralloc_add_bytes( s, (char*)&c, 1 );
+}
+
+extern void
+stralloc_add_str( stralloc_t* s, const char* str )
+{
+ stralloc_add_bytes( s, str, strlen(str) );
+}
+
+extern void
+stralloc_add_bytes( stralloc_t* s, const void* from, unsigned len )
+{
+ stralloc_readyplus( s, len );
+ memcpy( s->s + s->n, from, len );
+ s->n += len;
+}
+
+extern char*
+stralloc_cstr( stralloc_t* s )
+{
+ stralloc_readyplus( s, 1 );
+ s->s[s->n] = 0;
+ return s->s;
+}
+
+extern void
+stralloc_format( stralloc_t* s, const char* fmt, ... )
+{
+ stralloc_reset(s);
+ stralloc_ready(s, 10);
+
+ while (1) {
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vsnprintf( s->s, s->a, fmt, args );
+ va_end(args);
+
+ /* funky old C libraries returns -1 when truncation occurs */
+ if (n > -1 && n < s->a) {
+ s->n = n;
+ break;
+ }
+ if (n > -1) { /* we now precisely what we need */
+ stralloc_ready( s, n+1 );
+ } else {
+ stralloc_ready( s, s->a*2 );
+ }
+ }
+}
+
+extern void
+stralloc_add_format( stralloc_t* s, const char* fmt, ... )
+{
+ STRALLOC_DEFINE(s2);
+
+ stralloc_ready(s, 10);
+ while (1) {
+ int n;
+ va_list args;
+
+ va_start(args, fmt);
+ n = vsnprintf( s2->s, s2->a, fmt, args );
+ va_end(args);
+
+ /* some C libraries return -1 when truncation occurs */
+ if (n > -1 && n < s2->a) {
+ s2->n = n;
+ break;
+ }
+ if (n > -1) { /* we now precisely what we need */
+ stralloc_ready( s2, n+1 );
+ } else {
+ stralloc_ready( s2, s2->a*2 );
+ }
+ }
+
+ stralloc_append( s, s2 );
+ stralloc_reset( s2 );
+}
+
+
+extern void
+stralloc_add_quote_c( stralloc_t* s, int c )
+{
+ stralloc_add_quote_bytes( s, (char*)&c, 1 );
+}
+
+extern void
+stralloc_add_quote_str( stralloc_t* s, const char* str )
+{
+ stralloc_add_quote_bytes( s, str, strlen(str) );
+}
+
+extern void
+stralloc_add_quote_bytes( stralloc_t* s, const void* from, unsigned len )
+{
+ uint8_t* p = (uint8_t*) from;
+ uint8_t* end = p + len;
+
+ for ( ; p < end; p++ ) {
+ int c = p[0];
+
+ if (c == '\\') {
+ stralloc_add_str( s, "\\\\" );
+ } else if (c >= ' ' && c < 128) {
+ stralloc_add_c( s, c );
+ } else if (c == '\n') {
+ stralloc_add_str( s, "\\n" );
+ } else if (c == '\t') {
+ stralloc_add_str( s, "\\t" );
+ } else if (c == '\r') {
+ stralloc_add_str( s, "\\r" );
+ } else {
+ stralloc_add_format( s, "\\x%02x", c );
+ }
+ }
+}
+
+/** TEMP CHAR STRINGS
+ **
+ ** implement a circular ring of temporary string buffers
+ **/
+
+typedef struct Temptring {
+ struct TempString* next;
+ char* buffer;
+ int size;
+} TempString;
+
+#define MAX_TEMP_STRINGS 16
+
+static TempString _temp_strings[ MAX_TEMP_STRINGS ];
+static int _temp_string_n;
+
+extern char*
+tempstr_get( int size )
+{
+ TempString* t = &_temp_strings[_temp_string_n];
+
+ if ( ++_temp_string_n >= MAX_TEMP_STRINGS )
+ _temp_string_n = 0;
+
+ size += 1; /* reserve 1 char for terminating zero */
+
+ if (t->size < size) {
+ t->buffer = realloc( t->buffer, size );
+ if (t->buffer == NULL) {
+ derror( "%s: could not allocate %d bytes",
+ __FUNCTION__, size );
+ exit(1);
+ }
+ t->size = size;
+ }
+ return t->buffer;
+}
+
+extern char*
+tempstr_from_stralloc( stralloc_t* s )
+{
+ char* q = tempstr_get( s->n );
+
+ memcpy( q, s->s, s->n );
+ q[s->n] = 0;
+ return q;
+}
+
+/** QUOTING
+ **
+ ** dumps a human-readable version of a string. this replaces
+ ** newlines with \n, etc...
+ **/
+
+extern const char*
+quote_bytes( const char* str, int len )
+{
+ STRALLOC_DEFINE(s);
+ char* q;
+
+ stralloc_add_quote_bytes( s, str, len );
+ q = tempstr_from_stralloc( s );
+ stralloc_reset(s);
+ return q;
+}
+
+extern const char*
+quote_str( const char* str )
+{
+ int len = strlen(str);
+ return quote_bytes( str, len );
+}
+
+/** DYNAMIC ARRAYS OF POINTERS
+ **/
+
+void
+qvector_init( qvector_t* v )
+{
+ v->i = NULL;
+ v->n = v->a = 0;
+}
+
+void
+qvector_reset( qvector_t* v )
+{
+ free(v->i);
+ v->i = NULL;
+ v->n = v->a = 0;
+}
+
+void
+qvector_ready( qvector_t* v, unsigned len )
+{
+ unsigned old_a = v->a;
+ unsigned new_a = old_a;
+ unsigned max_a = UINT_MAX/sizeof(v->i[0]);
+
+ if (len <= old_a)
+ return;
+
+ if (len > max_a) {
+ derror("panic: %s: length too long (%d)", __FUNCTION__, len);
+ exit(1);
+ }
+
+ while (new_a < len) {
+ unsigned new_a2 = new_a + (new_a >> 1) + 8;
+ if (new_a2 < new_a || new_a2 > max_a)
+ new_a2 = max_a;
+ new_a = max_a;
+ }
+ v->i = realloc( v->i, new_a*sizeof(v->i[0]) );
+ v->a = new_a;
+}
+
+void
+qvector_readyplus( qvector_t* v, unsigned len )
+{
+ unsigned len2 = len + v->n;
+
+ if (len2 < len) {
+ derror("panic: %s: length too long (%d)", __FUNCTION__, len);
+ exit(1);
+ }
+ qvector_ready(v, len2);
+}
+
+void
+qvector_add( qvector_t* v, void* item )
+{
+ qvector_readyplus(v, 1);
+ v->i[v->n] = item;
+ v->n += 1;
+}
+
+int
+qvector_del( qvector_t* v, void* item )
+{
+ int index = qvector_index(v, item);
+ if (index < 0) return 0;
+ qvector_remove(v, index);
+ return 1;
+}
+
+extern void*
+qvector_get( qvector_t* v, int index )
+{
+ if ((unsigned)index >= (unsigned)v->n)
+ return NULL;
+
+ return v->i[index];
+}
+
+extern void
+qvector_set( qvector_t* v, int index, void* item )
+{
+ if ((unsigned)index < (unsigned)v->n)
+ v->i[index] = item;
+ }
+
+int
+qvector_len( qvector_t* v )
+{
+ return v->n;
+}
+
+int
+qvector_index( qvector_t* v, void* item )
+{
+ int nn;
+ for (nn = 0; nn < v->n; nn++)
+ if (v->i[nn] == item)
+ return nn;
+ return -1;
+}
+
+void
+qvector_insert( qvector_t* v, int index, void* item )
+{
+ if (index < 0) index = 0;
+ if (index > v->n) index = v->n;
+
+ memmove( v->i + index, v->i + index + 1, sizeof(v->i[0]) );
+ v->i[index] = item;
+ v->n += 1;
+}
+
+void
+qvector_remove( qvector_t* v, int index )
+{
+ if (index < 0 || index >= v->n )
+ return;
+
+ memmove( v->i + index + 1, v->i + index, v->n - index - 1 );
+ v->n -= 1;
+}
+
+void
+qvector_remove_n( qvector_t* v, int index, int count )
+{
+ int end = index + count;
+
+ if (index < 0 || index >= v->n || end <= index)
+ return;
+
+ if (end > v->n) {
+ end = v->n;
+ count = end - index;
+ }
+
+ memmove( v->i + index + count, v->i + index, v->n - index - count );
+ v->n -= count;
+}
+
diff --git a/android_utils.h b/android_utils.h
new file mode 100644
index 0000000..56dbc9a
--- /dev/null
+++ b/android_utils.h
@@ -0,0 +1,404 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_UTILS_H
+#define _ANDROID_UTILS_H
+
+#include "android_debug.h"
+#include <stdint.h> /* for uint64_t */
+
+#ifndef STRINGIFY
+#define _STRINGIFY(x) #x
+#define STRINGIFY(x) _STRINGIFY(x)
+#endif
+
+#ifndef GLUE
+#define _GLUE(x,y) x##y
+#define GLUE(x,y) _GLUE(x,y)
+
+#define _GLUE3(x,y,z) x##y##z
+#define GLUE3(x,y,z) _GLUE3(x,y,z)
+#endif
+
+/* O_BINARY is required in the MS C library to avoid opening file
+ * in text mode (the default, ahhhhh)
+ */
+#if !defined(_WIN32) && !defined(O_BINARY)
+# define O_BINARY 0
+#endif
+
+/* define PATH_SEP as a string containing the directory separateor */
+#ifdef _WIN32
+# define PATH_SEP "\\"
+#else
+# define PATH_SEP "/"
+#endif
+
+/* get MAX_PATH, note that MAX_PATH is set to 260 on Windows for
+ * stupid backwards-compatibility reason, though any 32-bit version
+ * of the OS handles much much longer paths
+ */
+#ifdef _WIN32
+# undef MAX_PATH
+# define MAX_PATH 1024
+#else
+# include <limits.h>
+# define MAX_PATH PATH_MAX
+#endif
+
+/** NON-GRAPHIC USAGE
+ **
+ ** this variable is TRUE if the -no-window argument was used.
+ ** the emulator will still simulate a framebuffer according to the selected skin
+ ** but no window will be displayed on the host computer.
+ **/
+extern int arg_no_window;
+
+/** EINTR HANDLING
+ **
+ ** since QEMU uses SIGALRM pretty extensively, having a system call returning
+ ** EINTR on Unix happens very frequently. provide a simple macro to guard against
+ ** this.
+ **/
+
+#ifdef _WIN32
+# define CHECKED(ret, call) (ret) = (call)
+#else
+# define CHECKED(ret, call) do { (ret) = (call); } while ((ret) < 0 && errno == EINTR)
+#endif
+
+/** MISC FILE AND DIRECTORY HANDLING
+ **/
+
+/* checks that a given file exists */
+extern int path_exists( const char* path );
+
+/* checks that a path points to a regular file */
+extern int path_is_regular( const char* path );
+
+/* checks that a path points to a directory */
+extern int path_is_dir( const char* path );
+
+/* checks that one can read/write a given (regular) file */
+extern int path_can_read( const char* path );
+extern int path_can_write( const char* path );
+
+/* try to make a directory. returns 0 on success, -1 on error */
+extern int path_mkdir( const char* path, int mode );
+
+/* ensure that a given directory exists, create it if not,
+ 0 on success, -1 on error */
+extern int path_mkdir_if_needed( const char* path, int mode );
+
+/* return the size of a given file in '*psize'. returns 0 on
+ * success, -1 on failure (error code in errno) */
+extern int path_get_size( const char* path, uint64_t *psize );
+
+/** PATH HANDLING ROUTINES
+ **
+ ** path_parent() can be used to return the n-level parent of a given directory
+ ** this understands . and .. when encountered in the input path
+ **/
+
+extern char* path_parent( const char* path, int levels );
+
+/** FORMATTED BUFFER PRINTING
+ **
+ ** bufprint() allows your to easily and safely append formatted string
+ ** content to a given bounded character buffer, in a way that is easier
+ ** to use than raw snprintf()
+ **
+ ** 'buffer' is the start position in the buffer,
+ ** 'buffend' is the end of the buffer, the function assumes (buffer <= buffend)
+ ** 'format' is a standard printf-style format string, followed by any number
+ ** of formatting arguments
+ **
+ ** the function returns the next position in the buffer if everything fits
+ ** in it. in case of overflow or formatting error, it will always return "buffend"
+ **
+ ** this allows you to chain several calls to bufprint() and only check for
+ ** overflow at the end, for exemple:
+ **
+ ** char buffer[1024];
+ ** char* p = buffer;
+ ** char* end = p + sizeof(buffer);
+ **
+ ** p = bufprint(p, end, "%s/%s", first, second);
+ ** p = bufprint(p, end, "/%s", third);
+ ** if (p >= end) ---> overflow
+ **
+ ** as a convenience, the appended string is zero-terminated if there is no overflow.
+ ** (this means that even if p >= end, the content of "buffer" is zero-terminated)
+ **
+ ** vbufprint() is a variant that accepts a va_list argument
+ **/
+
+extern char* vbufprint(char* buffer, char* buffend, const char* fmt, va_list args );
+extern char* bufprint (char* buffer, char* buffend, const char* fmt, ... );
+
+/** USEFUL DIRECTORY SUPPORT
+ **
+ ** bufprint_add_dir() appends the application's directory to a given bounded buffer
+ **
+ ** bufprint_config_path() appends the applications' user-specific configuration directory
+ ** to a bounded buffer. on Unix this is usually ~/.android, and something a bit more
+ ** complex on Windows
+ **
+ ** bufprint_config_file() appends the name of a file or directory relative to the
+ ** user-specific configuration directory to a bounded buffer. this really is equivalent
+ ** to concat-ing the config path + path separator + 'suffix'
+ **
+ ** bufprint_temp_dir() appends the temporary directory's path to a given bounded buffer
+ **
+ ** bufprint_temp_file() appens the name of a file or directory relative to the
+ ** temporary directory. equivalent to concat-ing the temp path + path separator + 'suffix'
+ **/
+
+extern char* bufprint_app_dir (char* buffer, char* buffend);
+extern char* bufprint_config_path(char* buffer, char* buffend);
+extern char* bufprint_config_file(char* buffer, char* buffend, const char* suffix);
+extern char* bufprint_temp_dir (char* buffer, char* buffend);
+extern char* bufprint_temp_file (char* buffer, char* buffend, const char* suffix);
+
+/** FILE LOCKS SUPPORT
+ **
+ ** a FileLock is useful to prevent several emulator instances from using the same
+ ** writable file (e.g. the userdata.img disk images).
+ **
+ ** create a FileLock object with filelock_create(), note that the function will *not*
+ ** return NULL if the file doesn't exist.
+ *
+ * then call filelock_lock() to try to acquire a lock for the corresponding file.
+ ** returns 0 on success, or -1 in case of error, which means that another program
+ ** is using the file or that the directory containing the file is read-only.
+ **
+ ** all file locks are automatically released and destroyed when the program exits.
+ ** the filelock_lock() function can also detect stale file locks that can linger
+ ** when the emulator crashes unexpectedly, and will happily clean them for you
+ **/
+
+typedef struct FileLock FileLock;
+
+extern FileLock* filelock_create( const char* path );
+extern int filelock_lock( FileLock* lock );
+extern void filelock_unlock( FileLock* lock );
+
+/** TEMP FILE SUPPORT
+ **
+ ** simple interface to create an empty temporary file on the system.
+ **
+ ** create the file with tempfile_create(), which returns a reference to a TempFile
+ ** object, or NULL if your system is so weird it doesn't have a temporary directory.
+ **
+ ** you can then call tempfile_path() to retrieve the TempFile's real path to open
+ ** it. the returned path is owned by the TempFile object and should not be freed.
+ **
+ ** all temporary files are destroyed when the program quits, unless you explicitely
+ ** close them before that with tempfile_close()
+ **/
+
+typedef struct TempFile TempFile;
+
+extern TempFile* tempfile_create( void );
+extern const char* tempfile_path( TempFile* temp );
+extern void tempfile_close( TempFile* temp );
+
+/** TEMP FILE CLEANUP
+ **
+ ** We delete all temporary files in atexit()-registered callbacks.
+ ** however, the Win32 DeleteFile is unable to remove a file unless
+ ** all HANDLEs to it are closed in the terminating process.
+ **
+ ** Call 'atexit_close_fd' on a newly open-ed file descriptor to indicate
+ ** that you want it closed in atexit() time. You should always call
+ ** this function unless you're certain that the corresponding file
+ ** cannot be temporary.
+ **
+ ** Call 'atexit_close_fd_remove' before explicitely closing a 'fd'
+ **/
+extern void atexit_close_fd(int fd);
+extern void atexit_close_fd_remove(int fd);
+
+/** OTHER FILE UTILITIES
+ **
+ ** make_empty_file() creates an empty file at a given path location.
+ ** if the file already exists, it is truncated without warning
+ **
+ ** copy_file() copies one file into another.
+ **
+ ** unlink_file() is equivalent to unlink() on Unix, on Windows,
+ ** it will handle the case where _unlink() fails because the file is
+ ** read-only by trying to change its access rights then calling _unlink()
+ ** again.
+ **
+ ** these functions return 0 on success, and -1 on error
+ **
+ ** load_text_file() reads a file into a heap-allocated memory block,
+ ** and appends a 0 to it. the caller must free it
+ **/
+
+extern int make_empty_file( const char* path );
+extern int copy_file( const char* dest, const char* source );
+extern int unkink_file( const char* path );
+extern void* load_text_file( const char* path );
+
+/** HOST RESOLUTION SETTINGS
+ **
+ ** return the main monitor's DPI resolution according to the host device
+ ** beware: this is not always reliable or even obtainable.
+ **
+ ** returns 0 on success, or -1 in case of error (e.g. the system returns funky values)
+ **/
+extern int get_monitor_resolution( int *px_dpi, int *py_dpi );
+
+/** SIGNAL HANDLING
+ **
+ ** the following can be used to block SIGALRM for a given period of time.
+ ** use with caution, the QEMU execution loop uses SIGALRM extensively
+ **
+ **/
+#ifdef _WIN32
+typedef struct { int dumy; } signal_state_t;
+#else
+#include <signal.h>
+typedef struct { sigset_t old; } signal_state_t;
+#endif
+
+extern void disable_sigalrm( signal_state_t *state );
+extern void restore_sigalrm( signal_state_t *state );
+
+#ifdef _WIN32
+
+#define BEGIN_NOSIGALRM \
+ {
+
+#define END_NOSIGALRM \
+ }
+
+#else /* !WIN32 */
+
+#define BEGIN_NOSIGALRM \
+ { signal_state_t __sigalrm_state; \
+ disable_sigalrm( &__sigalrm_state );
+
+#define END_NOSIGALRM \
+ restore_sigalrm( &__sigalrm_state ); \
+ }
+
+#endif /* !WIN32 */
+
+/** TIME HANDLING
+ **
+ ** sleep for a given time in milliseconds. note: this uses
+ ** disable_sigalrm()/restore_sigalrm()
+ **/
+
+extern void sleep_ms( int timeout );
+
+/** TABULAR OUTPUT
+ **
+ ** prints a list of strings in row/column format
+ **
+ **/
+
+extern void print_tabular( const char** strings, int count,
+ const char* prefix, int width );
+
+/** CHARACTER TRANSLATION
+ **
+ ** converts one character into another in strings
+ **/
+
+extern void buffer_translate_char( char* buff, unsigned len,
+ char from, char to );
+
+extern void string_translate_char( char* str, char from, char to );
+
+/** DYNAMIC STRINGS
+ **/
+
+typedef struct {
+ char* s;
+ unsigned n;
+ unsigned a;
+} stralloc_t;
+
+#define STRALLOC_INIT { NULL, 0, 0 }
+#define STRALLOC_DEFINE(s) stralloc_t s[1] = { STRALLOC_INIT }
+
+extern void stralloc_reset( stralloc_t* s );
+extern void stralloc_ready( stralloc_t* s, unsigned len );
+extern void stralloc_readyplus( stralloc_t* s, unsigned len );
+
+extern void stralloc_copy( stralloc_t* s, stralloc_t* from );
+extern void stralloc_append( stralloc_t* s, stralloc_t* from );
+
+extern void stralloc_add_c( stralloc_t* s, int c );
+extern void stralloc_add_str( stralloc_t* s, const char* str );
+extern void stralloc_add_bytes( stralloc_t* s, const void* from, unsigned len );
+
+extern char* stralloc_cstr( stralloc_t* s );
+
+extern void stralloc_format( stralloc_t* s, const char* fmt, ... );
+extern void stralloc_add_format( stralloc_t* s, const char* fmt, ... );
+
+extern void stralloc_add_quote_c( stralloc_t* s, int c );
+extern void stralloc_add_quote_str( stralloc_t* s, const char* str );
+extern void stralloc_add_quote_bytes( stralloc_t* s, const void* from, unsigned len );
+
+extern void stralloc_tabular( stralloc_t* s, const char** strings, int count,
+ const char* prefix, int width );
+
+
+/** TEMP CHAR STRINGS
+ **
+ ** implement a circular ring of temporary string buffers
+ **/
+
+extern char* tempstr_get( int size );
+extern char* tempstr_format( const char* fmt, ... );
+extern char* tempstr_from_stralloc( stralloc_t* s );
+
+/** QUOTING
+ **
+ ** dumps a human-readable version of a string. this replaces
+ ** newlines with \n, etc...
+ **/
+
+extern const char* quote_bytes( const char* str, int len );
+extern const char* quote_str( const char* str );
+
+/** DYNAMIC ARRAYS OF POINTERS
+ **/
+
+typedef struct {
+ void** i;
+ unsigned n;
+ unsigned a;
+} qvector_t;
+
+#define QVECTOR_INIT { NULL, 0, 0 }
+#define QVECTOR_DEFINE(v) qvector_t v[1] = QVECTOR_INIT
+
+extern void qvector_init( qvector_t* v );
+extern void qvector_reset( qvector_t* v );
+extern void qvector_ready( qvector_t* v, unsigned len );
+extern void qvector_readyplus( qvector_t* v, unsigned len );
+extern void qvector_add( qvector_t* v, void* item );
+extern int qvector_del( qvector_t* v, void* item ); /* returns 1 if deleted, 0 otherwise */
+extern void* qvector_get( qvector_t* v, int index );
+extern int qvector_len( qvector_t* v );
+extern int qvector_index( qvector_t* v, void* item ); /* returns -1 is not found */
+extern void qvector_insert( qvector_t* v, int index, void* item );
+extern void qvector_remove( qvector_t* v, int index );
+extern void qvector_remove_n( qvector_t* v, int index, int count );
+
+#endif /* _ANDROID_UTILS_H */
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index 71e5235..d18705b 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -1,6 +1,7 @@
/*
* QEMU ALSA audio driver
*
+ * Copyright (c) 2008 The Android Open Source Project
* Copyright (c) 2005 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -26,6 +27,77 @@
#define AUDIO_CAP "alsa"
#include "audio_int.h"
+#include <dlfcn.h>
+#include <pthread.h>
+#include "android_debug.h"
+
+#define DEBUG 1
+
+#if DEBUG
+# include <stdio.h>
+# define D(...) VERBOSE_PRINT(audio,__VA_ARGS__)
+# define D_ACTIVE VERBOSE_CHECK(audio)
+# define O(...) VERBOSE_PRINT(audioout,__VA_ARGS__)
+# define I(...) VERBOSE_PRINT(audioin,__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+# define D_ACTIVE 0
+# define O(...) ((void)0)
+# define I(...) ((void)0)
+#endif
+
+
+#define STRINGIFY_(x) #x
+#define STRINGIFY(x) STRINGIFY_(x)
+
+#define DYN_SYMBOLS \
+ DYN_FUNCTION(size_t,snd_pcm_sw_params_sizeof,(void)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_current,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params_set_start_threshold,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_sw_params_current,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \
+ DYN_FUNCTION(size_t,snd_pcm_hw_params_sizeof,(void)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_any,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_access,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_format,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_rate_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_channels_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_buffer_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_buffer_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
+ DYN_FUNCTION(int,snd_pcm_prepare,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_period_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_period_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_period_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_get_buffer_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_buffer_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)) \
+ DYN_FUNCTION(int,snd_pcm_hw_params_set_period_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_avail_update,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(int,snd_pcm_drop,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_writei,(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)) \
+ DYN_FUNCTION(snd_pcm_sframes_t,snd_pcm_readi,(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)) \
+ DYN_FUNCTION(snd_pcm_state_t,snd_pcm_state,(snd_pcm_t *pcm)) \
+ DYN_FUNCTION(const char*,snd_strerror,(int errnum)) \
+ DYN_FUNCTION(int,snd_pcm_open,(snd_pcm_t **pcm, const char *name,snd_pcm_stream_t stream, int mode)) \
+ DYN_FUNCTION(int,snd_pcm_close,(snd_pcm_t *pcm)) \
+
+
+
+/* define pointers to library functions we're going to use */
+#define DYN_FUNCTION(ret,name,sig) \
+ static ret (*func_ ## name)sig;
+
+DYN_SYMBOLS
+
+#undef DYN_FUNCTION
+
+#define func_snd_pcm_hw_params_alloca(ptr) \
+ do { assert(ptr); *ptr = (snd_pcm_hw_params_t *) alloca(func_snd_pcm_hw_params_sizeof()); memset(*ptr, 0, func_snd_pcm_hw_params_sizeof()); } while (0)
+
+#define func_snd_pcm_sw_params_alloca(ptr) \
+ do { assert(ptr); *ptr = (snd_pcm_sw_params_t *) alloca(func_snd_pcm_sw_params_sizeof()); memset(*ptr, 0, func_snd_pcm_sw_params_sizeof()); } while (0)
+
+static void* alsa_lib;
typedef struct ALSAVoiceOut {
HWVoiceOut hw;
@@ -107,7 +179,7 @@ static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
- AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
+ AUD_log (AUDIO_CAP, "Reason: %s\n", func_snd_strerror (err));
}
static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
@@ -125,12 +197,12 @@ static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
AUD_vlog (AUDIO_CAP, fmt, ap);
va_end (ap);
- AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err));
+ AUD_log (AUDIO_CAP, "Reason: %s\n", func_snd_strerror (err));
}
static void alsa_anal_close (snd_pcm_t **handlep)
{
- int err = snd_pcm_close (*handlep);
+ int err = func_snd_pcm_close (*handlep);
if (err) {
alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep);
}
@@ -228,16 +300,16 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
int err;
snd_pcm_sw_params_t *sw_params;
- snd_pcm_sw_params_alloca (&sw_params);
+ func_snd_pcm_sw_params_alloca (&sw_params);
- err = snd_pcm_sw_params_current (handle, sw_params);
+ err = func_snd_pcm_sw_params_current (handle, sw_params);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to get current software parameters\n");
return;
}
- err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
+ err = func_snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to set software threshold to %ld\n",
@@ -245,7 +317,7 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
return;
}
- err = snd_pcm_sw_params (handle, sw_params);
+ err = func_snd_pcm_sw_params (handle, sw_params);
if (err < 0) {
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to set software parameters\n");
@@ -269,9 +341,9 @@ static int alsa_open (int in, struct alsa_params_req *req,
buffer_size = req->buffer_size;
nchannels = req->nchannels;
- snd_pcm_hw_params_alloca (&hw_params);
+ func_snd_pcm_hw_params_alloca (&hw_params);
- err = snd_pcm_open (
+ err = func_snd_pcm_open (
&handle,
pcm_name,
in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,
@@ -282,13 +354,13 @@ static int alsa_open (int in, struct alsa_params_req *req,
return -1;
}
- err = snd_pcm_hw_params_any (handle, hw_params);
+ err = func_snd_pcm_hw_params_any (handle, hw_params);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n");
goto err;
}
- err = snd_pcm_hw_params_set_access (
+ err = func_snd_pcm_hw_params_set_access (
handle,
hw_params,
SND_PCM_ACCESS_RW_INTERLEAVED
@@ -298,22 +370,22 @@ static int alsa_open (int in, struct alsa_params_req *req,
goto err;
}
- err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
+ err = func_snd_pcm_hw_params_set_format (handle, hw_params, req->fmt);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt);
goto err;
}
- err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0);
+ err = func_snd_pcm_hw_params_set_rate_near (handle, hw_params, (unsigned*)&freq, 0);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq);
goto err;
}
- err = snd_pcm_hw_params_set_channels_near (
+ err = func_snd_pcm_hw_params_set_channels_near (
handle,
hw_params,
- &nchannels
+ (unsigned*)&nchannels
);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to set number of channels %d\n",
@@ -338,7 +410,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
if (buffer_size) {
if ((in && conf.size_in_usec_in) || (!in && conf.size_in_usec_out)) {
if (period_size) {
- err = snd_pcm_hw_params_set_period_time_near (
+ err = func_snd_pcm_hw_params_set_period_time_near (
handle,
hw_params,
&period_size,
@@ -352,7 +424,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
}
}
- err = snd_pcm_hw_params_set_buffer_time_near (
+ err = func_snd_pcm_hw_params_set_buffer_time_near (
handle,
hw_params,
&buffer_size,
@@ -374,7 +446,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
minval = period_size;
dir = 0;
- err = snd_pcm_hw_params_get_period_size_min (
+ err = func_snd_pcm_hw_params_get_period_size_min (
hw_params,
&minval,
&dir
@@ -400,7 +472,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
}
}
- err = snd_pcm_hw_params_set_period_size (
+ err = func_snd_pcm_hw_params_set_period_size (
handle,
hw_params,
period_size,
@@ -414,7 +486,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
}
minval = buffer_size;
- err = snd_pcm_hw_params_get_buffer_size_min (
+ err = func_snd_pcm_hw_params_get_buffer_size_min (
hw_params,
&minval
);
@@ -438,7 +510,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
}
}
- err = snd_pcm_hw_params_set_buffer_size (
+ err = func_snd_pcm_hw_params_set_buffer_size (
handle,
hw_params,
buffer_size
@@ -454,19 +526,19 @@ static int alsa_open (int in, struct alsa_params_req *req,
dolog ("warning: Buffer size is not set\n");
}
- err = snd_pcm_hw_params (handle, hw_params);
+ err = func_snd_pcm_hw_params (handle, hw_params);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to apply audio parameters\n");
goto err;
}
- err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
+ err = func_snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size);
if (err < 0) {
alsa_logerr2 (err, typ, "Failed to get buffer size\n");
goto err;
}
- err = snd_pcm_prepare (handle);
+ err = func_snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
goto err;
@@ -511,7 +583,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
static int alsa_recover (snd_pcm_t *handle)
{
- int err = snd_pcm_prepare (handle);
+ int err = func_snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr (err, "Failed to prepare handle %p\n", handle);
return -1;
@@ -523,11 +595,11 @@ static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)
{
snd_pcm_sframes_t avail;
- avail = snd_pcm_avail_update (handle);
+ avail = func_snd_pcm_avail_update (handle);
if (avail < 0) {
if (avail == -EPIPE) {
if (!alsa_recover (handle)) {
- avail = snd_pcm_avail_update (handle);
+ avail = func_snd_pcm_avail_update (handle);
}
}
@@ -575,7 +647,7 @@ static int alsa_run_out (HWVoiceOut *hw)
hw->clip (dst, src, len);
while (len) {
- written = snd_pcm_writei (alsa->handle, dst, len);
+ written = func_snd_pcm_writei (alsa->handle, dst, len);
if (written <= 0) {
switch (written) {
@@ -639,10 +711,14 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
struct alsa_params_obt obt;
audfmt_e effective_fmt;
int endianness;
- int err;
+ int err, result = -1;
snd_pcm_t *handle;
audsettings_t obt_as;
+ /* shut alsa debug spew */
+ if (!D_ACTIVE)
+ stdio_disable();
+
req.fmt = aud_to_alsafmt (as->fmt);
req.freq = as->freq;
req.nchannels = as->nchannels;
@@ -650,13 +726,13 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
req.buffer_size = conf.buffer_size_out;
if (alsa_open (0, &req, &obt, &handle)) {
- return -1;
+ goto Exit;
}
err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
if (err) {
alsa_anal_close (&handle);
- return -1;
+ goto Exit;
}
obt_as.freq = obt.freq;
@@ -672,11 +748,17 @@ static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
alsa_anal_close (&handle);
- return -1;
+ goto Exit;
}
alsa->handle = handle;
- return 0;
+ result = 0; /* success */
+
+Exit:
+ if (!D_ACTIVE)
+ stdio_enable();
+
+ return result;
}
static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
@@ -684,14 +766,14 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause)
int err;
if (pause) {
- err = snd_pcm_drop (handle);
+ err = func_snd_pcm_drop (handle);
if (err < 0) {
alsa_logerr (err, "Could not stop %s\n", typ);
return -1;
}
}
else {
- err = snd_pcm_prepare (handle);
+ err = func_snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr (err, "Could not prepare handle for %s\n", typ);
return -1;
@@ -724,11 +806,15 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
struct alsa_params_req req;
struct alsa_params_obt obt;
int endianness;
- int err;
+ int err, result = -1;
audfmt_e effective_fmt;
snd_pcm_t *handle;
audsettings_t obt_as;
+ /* shut alsa debug spew */
+ if (!D_ACTIVE)
+ stdio_disable();
+
req.fmt = aud_to_alsafmt (as->fmt);
req.freq = as->freq;
req.nchannels = as->nchannels;
@@ -736,13 +822,13 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
req.buffer_size = conf.buffer_size_in;
if (alsa_open (1, &req, &obt, &handle)) {
- return -1;
+ goto Exit;
}
err = alsa_to_audfmt (obt.fmt, &effective_fmt, &endianness);
if (err) {
alsa_anal_close (&handle);
- return -1;
+ goto Exit;
}
obt_as.freq = obt.freq;
@@ -758,11 +844,17 @@ static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n",
hw->samples, 1 << hw->info.shift);
alsa_anal_close (&handle);
- return -1;
+ goto Exit;
}
alsa->handle = handle;
- return 0;
+ result = 0; /* success */
+
+Exit:
+ if (!D_ACTIVE)
+ stdio_enable();
+
+ return result;
}
static void alsa_fini_in (HWVoiceIn *hw)
@@ -805,7 +897,7 @@ static int alsa_run_in (HWVoiceIn *hw)
return 0;
}
- if (!avail && (snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
+ if (!avail && (func_snd_pcm_state (alsa->handle) == SND_PCM_STATE_PREPARED)) {
avail = hw->samples;
}
@@ -834,7 +926,7 @@ static int alsa_run_in (HWVoiceIn *hw)
dst = hw->conv_buf + bufs[i].add;
while (len) {
- nread = snd_pcm_readi (alsa->handle, src, len);
+ nread = func_snd_pcm_readi (alsa->handle, src, len);
if (nread <= 0) {
switch (nread) {
@@ -907,11 +999,46 @@ static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...)
static void *alsa_audio_init (void)
{
- return &conf;
+ void* result = NULL;
+
+ alsa_lib = dlopen( "libasound.so", RTLD_NOW );
+ if (alsa_lib == NULL)
+ alsa_lib = dlopen( "libasound.so.2", RTLD_NOW );
+
+ if (alsa_lib == NULL) {
+ ldebug("could not find libasound on this system\n");
+ goto Exit;
+ }
+
+#undef DYN_FUNCTION
+#define DYN_FUNCTION(ret,name,sig) \
+ do { \
+ (func_ ##name) = dlsym( alsa_lib, STRINGIFY(name) ); \
+ if ((func_##name) == NULL) { \
+ ldebug("could not find %s in libasound\n", STRINGIFY(name)); \
+ goto Fail; \
+ } \
+ } while (0);
+
+ DYN_SYMBOLS
+
+ result = &conf;
+ goto Exit;
+
+Fail:
+ ldebug("%s: failed to open library\n", __FUNCTION__);
+ dlclose(alsa_lib);
+
+Exit:
+ return result;
}
static void alsa_audio_fini (void *opaque)
{
+ if (alsa_lib != NULL) {
+ dlclose(alsa_lib);
+ alsa_lib = NULL;
+ }
(void) opaque;
}
@@ -961,7 +1088,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
struct audio_driver alsa_audio_driver = {
INIT_FIELD (name = ) "alsa",
- INIT_FIELD (descr = ) "ALSA http://www.alsa-project.org",
+ INIT_FIELD (descr = ) "ALSA audio (www.alsa-project.org)",
INIT_FIELD (options = ) alsa_options,
INIT_FIELD (init = ) alsa_audio_init,
INIT_FIELD (fini = ) alsa_audio_fini,
diff --git a/audio/audio.c b/audio/audio.c
index 8e7af1a..4ba1f7d 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -1,6 +1,7 @@
/*
* QEMU Audio subsystem
*
+ * Copyright (c) 2007-2008 The Android Open Source Project
* Copyright (c) 2003-2005 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -25,6 +26,8 @@
#define AUDIO_CAP "audio"
#include "audio_int.h"
+#include "android_utils.h"
+#include "android.h"
/* #define DEBUG_PLIVE */
/* #define DEBUG_LIVE */
@@ -34,8 +37,8 @@
#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown"
static struct audio_driver *drvtab[] = {
-#ifdef CONFIG_OSS
- &oss_audio_driver,
+#ifdef CONFIG_ESD
+ &esd_audio_driver,
#endif
#ifdef CONFIG_ALSA
&alsa_audio_driver,
@@ -49,13 +52,91 @@ static struct audio_driver *drvtab[] = {
#ifdef CONFIG_FMOD
&fmod_audio_driver,
#endif
+#ifdef CONFIG_WINAUDIO
+ &win_audio_driver,
+#endif
#ifdef CONFIG_SDL
&sdl_audio_driver,
#endif
+#ifdef CONFIG_OSS
+ &oss_audio_driver,
+#endif
&no_audio_driver,
+#if 0 /* disabled WAV audio for now - until we find a user-friendly way to use it */
&wav_audio_driver
+#endif
};
+
+int
+audio_get_backend_count( int is_input )
+{
+ int nn, count = 0;
+
+ for (nn = 0; nn < sizeof(drvtab)/sizeof(drvtab[0]); nn++)
+ {
+ if (is_input) {
+ if ( drvtab[nn]->max_voices_in > 0 )
+ count += 1;
+ } else {
+ if ( drvtab[nn]->max_voices_out > 0 )
+ count += 1;
+ }
+ }
+ return count;
+}
+
+const char*
+audio_get_backend_name( int is_input, int index, const char* *pinfo )
+{
+ int nn;
+
+ index += 1;
+ for (nn = 0; nn < sizeof(drvtab)/sizeof(drvtab[0]); nn++)
+ {
+ if (is_input) {
+ if ( drvtab[nn]->max_voices_in > 0 ) {
+ if ( --index == 0 ) {
+ *pinfo = drvtab[nn]->descr;
+ return drvtab[nn]->name;
+ }
+ }
+ } else {
+ if ( drvtab[nn]->max_voices_out > 0 ) {
+ if ( --index == 0 ) {
+ *pinfo = drvtab[nn]->descr;
+ return drvtab[nn]->name;
+ }
+ }
+ }
+ }
+ *pinfo = NULL;
+ return NULL;
+}
+
+
+int
+audio_check_backend_name( int is_input, const char* name )
+{
+ int nn;
+
+ for (nn = 0; nn < sizeof(drvtab)/sizeof(drvtab[0]); nn++)
+ {
+ if ( !strcmp(drvtab[nn]->name, name) ) {
+ if (is_input) {
+ if (drvtab[nn]->max_voices_in > 0)
+ return 1;
+ } else {
+ if (drvtab[nn]->max_voices_out > 0)
+ return 1;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+
struct fixed_settings {
int enabled;
int nb_voices;
@@ -100,7 +181,7 @@ static struct {
0 /* log_to_monitor */
};
-static AudioState glob_audio_state;
+AudioState glob_audio_state;
volume_t nominal_volume = {
0,
@@ -303,6 +384,10 @@ static const char *audio_get_conf_str (const char *key,
}
}
+/* defined in android_sdl.c */
+extern void dprintn(const char* fmt, ...);
+extern void dprintnv(const char* fmt, va_list args);
+
void AUD_vlog (const char *cap, const char *fmt, va_list ap)
{
if (conf.log_to_monitor) {
@@ -313,11 +398,14 @@ void AUD_vlog (const char *cap, const char *fmt, va_list ap)
term_vprintf (fmt, ap);
}
else {
+ if (!VERBOSE_CHECK(audio))
+ return;
+
if (cap) {
- fprintf (stderr, "%s: ", cap);
+ dprintn("%s: ", cap);
}
- vfprintf (stderr, fmt, ap);
+ dprintnv(fmt, ap);
}
}
@@ -605,11 +693,11 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
}
if (info->sign) {
- memset (buf, len << info->shift, 0x00);
+ memset (buf, 0x80, len << info->shift);
}
else {
if (info->bits == 8) {
- memset (buf, len << info->shift, 0x80);
+ memset (buf, 0x80, len << info->shift);
}
else {
int i;
@@ -1024,7 +1112,9 @@ int AUD_write (SWVoiceOut *sw, void *buf, int size)
return 0;
}
- bytes = sw->hw->pcm_ops->write (sw, buf, size);
+ BEGIN_NOSIGALRM
+ bytes = sw->hw->pcm_ops->write (sw, buf, size);
+ END_NOSIGALRM
return bytes;
}
@@ -1042,7 +1132,9 @@ int AUD_read (SWVoiceIn *sw, void *buf, int size)
return 0;
}
- bytes = sw->hw->pcm_ops->read (sw, buf, size);
+ BEGIN_NOSIGALRM
+ bytes = sw->hw->pcm_ops->read (sw, buf, size);
+ END_NOSIGALRM
return bytes;
}
@@ -1068,7 +1160,9 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
hw->pending_disable = 0;
if (!hw->enabled) {
hw->enabled = 1;
- hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
+ BEGIN_NOSIGALRM
+ hw->pcm_ops->ctl_out (hw, VOICE_ENABLE);
+ END_NOSIGALRM
}
}
else {
@@ -1109,7 +1203,9 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
if (on) {
if (!hw->enabled) {
hw->enabled = 1;
- hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
+ BEGIN_NOSIGALRM
+ hw->pcm_ops->ctl_in (hw, VOICE_ENABLE);
+ END_NOSIGALRM
}
sw->total_hw_samples_acquired = hw->total_samples_captured;
}
@@ -1124,7 +1220,9 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
if (nb_active == 1) {
hw->enabled = 0;
- hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
+ BEGIN_NOSIGALRM
+ hw->pcm_ops->ctl_in (hw, VOICE_DISABLE);
+ END_NOSIGALRM
}
}
}
@@ -1244,7 +1342,9 @@ static void audio_run_out (AudioState *s)
#endif
hw->enabled = 0;
hw->pending_disable = 0;
- hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
+ BEGIN_NOSIGALRM
+ hw->pcm_ops->ctl_out (hw, VOICE_DISABLE);
+ END_NOSIGALRM
for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) {
sc->sw.active = 0;
audio_recalc_and_notify_capture (sc->cap);
@@ -1265,7 +1365,9 @@ static void audio_run_out (AudioState *s)
}
prev_rpos = hw->rpos;
- played = hw->pcm_ops->run_out (hw);
+ BEGIN_NOSIGALRM
+ played = hw->pcm_ops->run_out (hw);
+ END_NOSIGALRM
if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) {
dolog ("hw->rpos=%d hw->samples=%d played=%d\n",
hw->rpos, hw->samples, played);
@@ -1334,7 +1436,9 @@ static void audio_run_in (AudioState *s)
SWVoiceIn *sw;
int captured, min;
- captured = hw->pcm_ops->run_in (hw);
+ BEGIN_NOSIGALRM
+ captured = hw->pcm_ops->run_in (hw);
+ END_NOSIGALRM
min = audio_pcm_hw_find_min_in (hw);
hw->total_samples_captured += captured - min;
@@ -1404,8 +1508,36 @@ static void audio_run_capture (AudioState *s)
static void audio_timer (void *opaque)
{
- AudioState *s = opaque;
-
+ AudioState* s = opaque;
+#if 0
+#define MAX_DIFFS 1000
+ int64_t now = qemu_get_clock(vm_clock);
+ static int64_t last = 0;
+ static float diffs[MAX_DIFFS];
+ static int num_diffs;
+
+ if (last == 0)
+ last = now;
+ else {
+ diffs[num_diffs] = (float)((now-last)/1e6); /* last diff in ms */
+ if (++num_diffs == MAX_DIFFS) {
+ double min_diff = 1e6, max_diff = -1e6;
+ double all_diff = 0.;
+ int nn;
+
+ for (nn = 0; nn < num_diffs; nn++) {
+ if (diffs[nn] < min_diff) min_diff = diffs[nn];
+ if (diffs[nn] > max_diff) max_diff = diffs[nn];
+ all_diff += diffs[nn];
+ }
+ all_diff *= 1.0/num_diffs;
+ printf("audio timer: min_diff=%6.2g max_diff=%6.2g avg_diff=%6.2g samples=%d\n",
+ min_diff, max_diff, all_diff, num_diffs);
+ num_diffs = 0;
+ }
+ }
+ last = now;
+#endif
audio_run_out (s);
audio_run_in (s);
audio_run_capture (s);
@@ -1530,17 +1662,43 @@ void AUD_help (void)
);
}
-static int audio_driver_init (AudioState *s, struct audio_driver *drv)
+static int audio_driver_init (AudioState *s, struct audio_driver *drv, int out)
{
+ void* opaque;
+
if (drv->options) {
audio_process_options (drv->name, drv->options);
}
- s->drv_opaque = drv->init ();
- if (s->drv_opaque) {
+ /* is the driver already initialized ? */
+ if (out) {
+ if (drv == s->drv_in) {
+ s->drv_out = drv;
+ s->drv_out_opaque = s->drv_in_opaque;
+ return 0;
+ }
+ } else {
+ if (drv == s->drv_out) {
+ s->drv_in = drv;
+ s->drv_in_opaque = s->drv_out_opaque;
+ return 0;
+ }
+ }
+
+ BEGIN_NOSIGALRM
+ opaque = drv->init();
+ END_NOSIGALRM
+
+ if (opaque != NULL) {
audio_init_nb_voices_out (s, drv);
audio_init_nb_voices_in (s, drv);
- s->drv = drv;
+ if (out) {
+ s->drv_out = drv;
+ s->drv_out_opaque = opaque;
+ } else {
+ s->drv_in = drv;
+ s->drv_in_opaque = opaque;
+ }
return 0;
}
else {
@@ -1556,21 +1714,30 @@ static void audio_vm_change_state_handler (void *opaque, int running)
HWVoiceIn *hwi = NULL;
int op = running ? VOICE_ENABLE : VOICE_DISABLE;
- while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
- hwo->pcm_ops->ctl_out (hwo, op);
- }
+ BEGIN_NOSIGALRM
+ while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
+ hwo->pcm_ops->ctl_out (hwo, op);
+ }
- while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
- hwi->pcm_ops->ctl_in (hwi, op);
- }
+ while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) {
+ hwi->pcm_ops->ctl_in (hwi, op);
+ }
+ END_NOSIGALRM
}
+// to make sure audio_atexit() is only called once
+static int initialized = 0;
+
static void audio_atexit (void)
{
AudioState *s = &glob_audio_state;
HWVoiceOut *hwo = NULL;
HWVoiceIn *hwi = NULL;
+ if (!initialized) return;
+ initialized = 0;
+
+ BEGIN_NOSIGALRM
while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) {
SWVoiceCap *sc;
@@ -1592,9 +1759,13 @@ static void audio_atexit (void)
hwi->pcm_ops->fini_in (hwi);
}
- if (s->drv) {
- s->drv->fini (s->drv_opaque);
+ if (s->drv_in) {
+ s->drv_in->fini (s->drv_in_opaque);
}
+ if (s->drv_out) {
+ s->drv_out->fini (s->drv_out_opaque);
+ }
+ END_NOSIGALRM
}
static void audio_save (QEMUFile *f, void *opaque)
@@ -1630,11 +1801,70 @@ void AUD_remove_card (QEMUSoundCard *card)
qemu_free (card->name);
}
+static int
+find_audio_driver( AudioState* s, int out )
+{
+ int i, done = 0, def;
+ const char* envname;
+ const char* drvname;
+ struct audio_driver* drv = NULL;
+ const char* drvtype = out ? "output" : "input";
+
+ envname = out ? "QEMU_AUDIO_OUT_DRV" : "QEMU_AUDIO_IN_DRV";
+ drvname = audio_get_conf_str(envname, NULL, &def);
+ if (drvname == NULL) {
+ drvname = audio_get_conf_str("QEMU_AUDIO_DRV", NULL, &def);
+ }
+
+ if (drvname != NULL) { /* look for a specific driver */
+ for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+ if (!strcmp (drvname, drvtab[i]->name)) {
+ drv = drvtab[i];
+ break;
+ }
+ }
+ }
+
+ if (drv != NULL) {
+ done = !audio_driver_init (s, drv, out);
+ if (!done) {
+ dolog ("Could not initialize '%s' %s audio backend, trying default one.\n",
+ drvname, drvtype);
+ dolog ("Run with -qemu -audio-help to list available backends\n");
+ drv = NULL;
+ }
+ }
+
+ if (!drv) {
+ for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
+ if (drvtab[i]->can_be_default) {
+ drv = drvtab[i];
+ done = !audio_driver_init (s, drv, out);
+ if (done)
+ break;
+ }
+ }
+ }
+
+ if (!done) {
+ drv = &no_audio_driver;
+ done = !audio_driver_init (s, drv, out);
+ if (!done) {
+ /* this should never happen */
+ dolog ("Could not initialize audio subsystem\n");
+ return -1;
+ }
+ dolog ("warning: Could not find suitable audio %s backend\n", drvtype);
+ }
+
+ if (VERBOSE_CHECK(init))
+ dprint("using '%s' audio %s backend", drv->name, drvtype );
+ return 0;
+}
+
+
AudioState *AUD_init (void)
{
- size_t i;
- int done = 0;
- const char *drvname;
AudioState *s = &glob_audio_state;
LIST_INIT (&s->hw_head_out);
@@ -1665,47 +1895,9 @@ AudioState *AUD_init (void)
s->nb_hw_voices_in = 0;
}
+ if ( find_audio_driver (s, 0) == 0 &&
+ find_audio_driver (s, 1) == 0 )
{
- int def;
- drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def);
- }
-
- if (drvname) {
- int found = 0;
-
- for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
- if (!strcmp (drvname, drvtab[i]->name)) {
- done = !audio_driver_init (s, drvtab[i]);
- found = 1;
- break;
- }
- }
-
- if (!found) {
- dolog ("Unknown audio driver `%s'\n", drvname);
- dolog ("Run with -audio-help to list available drivers\n");
- }
- }
-
- if (!done) {
- for (i = 0; !done && i < sizeof (drvtab) / sizeof (drvtab[0]); i++) {
- if (drvtab[i]->can_be_default) {
- done = !audio_driver_init (s, drvtab[i]);
- }
- }
- }
-
- if (!done) {
- done = !audio_driver_init (s, &no_audio_driver);
- if (!done) {
- dolog ("Could not initialize audio subsystem\n");
- }
- else {
- dolog ("warning: Using timer based audio emulation\n");
- }
- }
-
- if (done) {
VMChangeStateEntry *e;
if (conf.period.hz <= 0) {
@@ -1731,12 +1923,20 @@ AudioState *AUD_init (void)
return NULL;
}
+ initialized = 1;
+
LIST_INIT (&s->card_head);
register_savevm ("audio", 0, 1, audio_save, audio_load, s);
qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks);
return s;
}
+// this was added to work around a deadlock in SDL when quitting
+void AUD_cleanup()
+{
+ audio_atexit();
+}
+
CaptureVoiceOut *AUD_add_capture (
AudioState *s,
audsettings_t *as,
@@ -1845,21 +2045,16 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
if (!cap->cb_head.lh_first) {
SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1;
-
while (sw) {
- SWVoiceCap *sc = (SWVoiceCap *) sw;
#ifdef DEBUG_CAPTURE
dolog ("freeing %s\n", sw->name);
#endif
-
sw1 = sw->entries.le_next;
if (sw->rate) {
st_rate_stop (sw->rate);
sw->rate = NULL;
}
LIST_REMOVE (sw, entries);
- LIST_REMOVE (sc, entries);
- qemu_free (sc);
sw = sw1;
}
LIST_REMOVE (cap, entries);
diff --git a/audio/audio.h b/audio/audio.h
index c097f39..cc7aa04 100644
--- a/audio/audio.h
+++ b/audio/audio.h
@@ -93,6 +93,8 @@ void AUD_log (const char *cap, const char *fmt, ...)
#endif
;
+extern AudioState glob_audio_state;
+
AudioState *AUD_init (void);
void AUD_help (void);
void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card);
@@ -166,4 +168,13 @@ uint32_t lsbindex (uint32_t u);
#define audio_MAX(a, b) ((a)<(b)?(b):(a))
#endif
+extern int
+audio_get_backend_count( int is_input );
+
+extern const char*
+audio_get_backend_name( int is_input, int index, const char* *pinfo );
+
+extern int
+audio_check_backend_name( int is_input, const char* name );
+
#endif /* audio.h */
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 1a15d4c..099bcbd 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -182,8 +182,10 @@ struct SWVoiceCap {
};
struct AudioState {
- struct audio_driver *drv;
- void *drv_opaque;
+ struct audio_driver* drv_in;
+ void* drv_in_opaque;
+ struct audio_driver* drv_out;
+ void* drv_out_opaque;
QEMUTimer *ts;
LIST_HEAD (card_listhead, QEMUSoundCard) card_head;
@@ -197,8 +199,10 @@ struct AudioState {
extern struct audio_driver no_audio_driver;
extern struct audio_driver oss_audio_driver;
extern struct audio_driver sdl_audio_driver;
+extern struct audio_driver win_audio_driver;
extern struct audio_driver wav_audio_driver;
extern struct audio_driver fmod_audio_driver;
+extern struct audio_driver esd_audio_driver;
extern struct audio_driver alsa_audio_driver;
extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
diff --git a/audio/audio_pt_int.c b/audio/audio_pt_int.c
new file mode 100644
index 0000000..3f01762
--- /dev/null
+++ b/audio/audio_pt_int.c
@@ -0,0 +1,149 @@
+#include "vl.h"
+#include "audio.h"
+
+#define AUDIO_CAP "audio-pt"
+
+#include "audio_int.h"
+#include "audio_pt_int.h"
+
+static void logerr (struct audio_pt *pt, int err, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ AUD_vlog (pt->drv, fmt, ap);
+ va_end (ap);
+
+ AUD_log (NULL, "\n");
+ AUD_log (pt->drv, "Reason: %s\n", strerror (err));
+}
+
+int audio_pt_init (struct audio_pt *p, void *(*func) (void *),
+ void *opaque, const char *drv, const char *cap)
+{
+ int err, err2;
+ const char *efunc;
+
+ p->drv = drv;
+
+ err = pthread_mutex_init (&p->mutex, NULL);
+ if (err) {
+ efunc = "pthread_mutex_init";
+ goto err0;
+ }
+
+ err = pthread_cond_init (&p->cond, NULL);
+ if (err) {
+ efunc = "pthread_cond_init";
+ goto err1;
+ }
+
+ err = pthread_create (&p->thread, NULL, func, opaque);
+ if (err) {
+ efunc = "pthread_create";
+ goto err2;
+ }
+
+ return 0;
+
+ err2:
+ err2 = pthread_cond_destroy (&p->cond);
+ if (err2) {
+ logerr (p, err2, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
+ }
+
+ err1:
+ err2 = pthread_mutex_destroy (&p->mutex);
+ if (err2) {
+ logerr (p, err2, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
+ }
+
+ err0:
+ logerr (p, err, "%s(%s): %s failed", cap, AUDIO_FUNC, efunc);
+ return -1;
+}
+
+int audio_pt_fini (struct audio_pt *p, const char *cap)
+{
+ int err, ret = 0;
+
+ err = pthread_cond_destroy (&p->cond);
+ if (err) {
+ logerr (p, err, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC);
+ ret = -1;
+ }
+
+ err = pthread_mutex_destroy (&p->mutex);
+ if (err) {
+ logerr (p, err, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC);
+ ret = -1;
+ }
+ return ret;
+}
+
+int audio_pt_lock (struct audio_pt *p, const char *cap)
+{
+ int err;
+
+ err = pthread_mutex_lock (&p->mutex);
+ if (err) {
+ logerr (p, err, "%s(%s): pthread_mutex_lock failed", cap, AUDIO_FUNC);
+ return -1;
+ }
+ return 0;
+}
+
+int audio_pt_unlock (struct audio_pt *p, const char *cap)
+{
+ int err;
+
+ err = pthread_mutex_unlock (&p->mutex);
+ if (err) {
+ logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
+ return -1;
+ }
+ return 0;
+}
+
+int audio_pt_wait (struct audio_pt *p, const char *cap)
+{
+ int err;
+
+ err = pthread_cond_wait (&p->cond, &p->mutex);
+ if (err) {
+ logerr (p, err, "%s(%s): pthread_cond_wait failed", cap, AUDIO_FUNC);
+ return -1;
+ }
+ return 0;
+}
+
+int audio_pt_unlock_and_signal (struct audio_pt *p, const char *cap)
+{
+ int err;
+
+ err = pthread_mutex_unlock (&p->mutex);
+ if (err) {
+ logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC);
+ return -1;
+ }
+ err = pthread_cond_signal (&p->cond);
+ if (err) {
+ logerr (p, err, "%s(%s): pthread_cond_signal failed", cap, AUDIO_FUNC);
+ return -1;
+ }
+ return 0;
+}
+
+int audio_pt_join (struct audio_pt *p, void **arg, const char *cap)
+{
+ int err;
+ void *ret;
+
+ err = pthread_join (p->thread, &ret);
+ if (err) {
+ logerr (p, err, "%s(%s): pthread_join failed", cap, AUDIO_FUNC);
+ return -1;
+ }
+ *arg = ret;
+ return 0;
+}
diff --git a/audio/audio_pt_int.h b/audio/audio_pt_int.h
new file mode 100644
index 0000000..0dfff76
--- /dev/null
+++ b/audio/audio_pt_int.h
@@ -0,0 +1,22 @@
+#ifndef QEMU_AUDIO_PT_INT_H
+#define QEMU_AUDIO_PT_INT_H
+
+#include <pthread.h>
+
+struct audio_pt {
+ const char *drv;
+ pthread_t thread;
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+};
+
+int audio_pt_init (struct audio_pt *, void *(*) (void *), void *,
+ const char *, const char *);
+int audio_pt_fini (struct audio_pt *, const char *);
+int audio_pt_lock (struct audio_pt *, const char *);
+int audio_pt_unlock (struct audio_pt *, const char *);
+int audio_pt_wait (struct audio_pt *, const char *);
+int audio_pt_unlock_and_signal (struct audio_pt *, const char *);
+int audio_pt_join (struct audio_pt *, void **, const char *);
+
+#endif /* audio_pt_int.h */
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 13e1c3e..4575a56 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -205,7 +205,9 @@ static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp)
LIST_REMOVE (hw, entries);
glue (s->nb_hw_voices_, TYPE) += 1;
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
+ BEGIN_NOSIGALRM
glue (hw->pcm_ops->fini_, TYPE) (hw);
+ END_NOSIGALRM
qemu_free (hw);
*hwp = NULL;
}
@@ -243,7 +245,8 @@ static HW *glue (audio_pcm_hw_find_specific_, TYPE) (
static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
{
HW *hw;
- struct audio_driver *drv = s->drv;
+ struct audio_driver *drv = glue(s->drv_, TYPE);
+ int err;
if (!glue (s->nb_hw_voices_, TYPE)) {
return NULL;
@@ -271,9 +274,11 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
#ifdef DAC
LIST_INIT (&hw->cap_head);
#endif
- if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
+ BEGIN_NOSIGALRM
+ err = glue (hw->pcm_ops->init_, TYPE) (hw, as);
+ END_NOSIGALRM
+ if (err)
goto err0;
- }
if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) {
dolog ("hw->samples=%d\n", hw->samples);
@@ -302,7 +307,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
return hw;
err1:
+ BEGIN_NOSIGALRM
glue (hw->pcm_ops->fini_, TYPE) (hw);
+ END_NOSIGALRM
err0:
qemu_free (hw);
return NULL;
@@ -431,7 +438,7 @@ SW *glue (AUD_open_, TYPE) (
goto fail;
}
- if (audio_bug (AUDIO_FUNC, !s->drv)) {
+ if (audio_bug (AUDIO_FUNC, !glue (s->drv_, TYPE))) {
dolog ("Can not open `%s' (no host audio driver)\n", name);
goto fail;
}
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 8512f12..cf3eaf9 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -1,6 +1,7 @@
/*
* QEMU OS X CoreAudio audio driver
*
+ * Copyright (c) 2008 The Android Open Source Project
* Copyright (c) 2005 Mike Kronenberg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -31,27 +32,35 @@
#define AUDIO_CAP "coreaudio"
#include "audio_int.h"
+#define ENABLE_IN 1
+
+#if 0
+# define D(...) fprintf(stderr, __VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
struct {
- int buffer_frames;
- int nbuffers;
+ int out_buffer_frames;
+ int out_nbuffers;
+ int in_buffer_frames;
+ int in_nbuffers;
int isAtexit;
} conf = {
- .buffer_frames = 512,
- .nbuffers = 4,
+ .out_buffer_frames = 512,
+ .out_nbuffers = 4,
+ .in_buffer_frames = 512,
+ .in_nbuffers = 4,
.isAtexit = 0
};
-typedef struct coreaudioVoiceOut {
- HWVoiceOut hw;
- pthread_mutex_t mutex;
- int isAtexit;
- AudioDeviceID outputDeviceID;
- UInt32 audioDevicePropertyBufferFrameSize;
- AudioStreamBasicDescription outputStreamBasicDescription;
- int live;
- int decr;
- int rpos;
-} coreaudioVoiceOut;
+/***************************************************************************************/
+/***************************************************************************************/
+/*** ***/
+/*** U T I L I T Y R O U T I N E S ***/
+/*** ***/
+/***************************************************************************************/
+/***************************************************************************************/
static void coreaudio_logstatus (OSStatus status)
{
@@ -143,13 +152,40 @@ static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 (
coreaudio_logstatus (status);
}
-static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
+static void coreaudio_atexit (void)
+{
+ conf.isAtexit = 1;
+}
+
+/***************************************************************************************/
+/***************************************************************************************/
+/*** ***/
+/*** S H A R E D I N / O U T V O I C E ***/
+/*** ***/
+/***************************************************************************************/
+/***************************************************************************************/
+
+typedef struct coreAudioVoice {
+ pthread_mutex_t mutex;
+ AudioDeviceID deviceID;
+ Boolean isInput;
+ UInt32 bufferFrameSize;
+ AudioStreamBasicDescription streamBasicDescription;
+ AudioDeviceIOProc ioproc;
+ int live;
+ int decr;
+ int pos;
+} coreaudioVoice;
+
+
+static inline UInt32
+coreaudio_voice_isPlaying (coreaudioVoice* core)
{
OSStatus status;
UInt32 result = 0;
- UInt32 propertySize = sizeof(outputDeviceID);
+ UInt32 propertySize = sizeof(core->deviceID);
status = AudioDeviceGetProperty(
- outputDeviceID, 0, 0,
+ core->deviceID, 0, core->isInput,
kAudioDevicePropertyDeviceIsRunning, &propertySize, &result);
if (status != kAudioHardwareNoError) {
coreaudio_logerr(status,
@@ -158,12 +194,8 @@ static inline UInt32 isPlaying (AudioDeviceID outputDeviceID)
return result;
}
-static void coreaudio_atexit (void)
-{
- conf.isAtexit = 1;
-}
-
-static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
+static int
+coreaudio_voice_lock (coreaudioVoice* core, const char *fn_name)
{
int err;
@@ -176,7 +208,8 @@ static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name)
return 0;
}
-static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
+static int
+coreaudio_voice_unlock (coreaudioVoice* core, const char *fn_name)
{
int err;
@@ -189,114 +222,81 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
return 0;
}
-static int coreaudio_run_out (HWVoiceOut *hw)
+static int
+coreaudio_voice_ctl (coreaudioVoice* core, int cmd)
{
- int live, decr;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
-
- if (coreaudio_lock (core, "coreaudio_run_out")) {
- return 0;
- }
+ OSStatus status;
- live = audio_pcm_hw_get_live_out (hw);
+ switch (cmd) {
+ case VOICE_ENABLE:
+ /* start playback */
+ D("%s: %s started\n", __FUNCTION__, core->isInput ? "input" : "output");
+ if (!coreaudio_voice_isPlaying(core)) {
+ status = AudioDeviceStart(core->deviceID, core->ioproc);
+ if (status != kAudioHardwareNoError) {
+ coreaudio_logerr (status, "Could not resume playback\n");
+ }
+ }
+ break;
- if (core->decr > live) {
- ldebug ("core->decr %d live %d core->live %d\n",
- core->decr,
- live,
- core->live);
+ case VOICE_DISABLE:
+ /* stop playback */
+ D("%s: %s stopped\n", __FUNCTION__, core->isInput ? "input" : "output");
+ if (!conf.isAtexit) {
+ if (coreaudio_voice_isPlaying(core)) {
+ status = AudioDeviceStop(core->deviceID, core->ioproc);
+ if (status != kAudioHardwareNoError) {
+ coreaudio_logerr (status, "Could not pause playback\n");
+ }
+ }
+ }
+ break;
}
-
- decr = audio_MIN (core->decr, live);
- core->decr -= decr;
-
- core->live = live - decr;
- hw->rpos = core->rpos;
-
- coreaudio_unlock (core, "coreaudio_run_out");
- return decr;
+ return 0;
}
-/* callback to feed audiooutput buffer */
-static OSStatus audioDeviceIOProc(
- AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* hwptr)
+static void
+coreaudio_voice_fini (coreaudioVoice* core)
{
- UInt32 frame, frameCount;
- float *out = outOutputData->mBuffers[0].mData;
- HWVoiceOut *hw = hwptr;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr;
- int rpos, live;
- st_sample_t *src;
-#ifndef FLOAT_MIXENG
-#ifdef RECIPROCAL
- const float scale = 1.f / UINT_MAX;
-#else
- const float scale = UINT_MAX;
-#endif
-#endif
-
- if (coreaudio_lock (core, "audioDeviceIOProc")) {
- inInputTime = 0;
- return 0;
- }
+ OSStatus status;
+ int err;
- frameCount = core->audioDevicePropertyBufferFrameSize;
- live = core->live;
+ if (!conf.isAtexit) {
+ /* stop playback */
+ coreaudio_voice_ctl(core, VOICE_DISABLE);
- /* if there are not enough samples, set signal and return */
- if (live < frameCount) {
- inInputTime = 0;
- coreaudio_unlock (core, "audioDeviceIOProc(empty)");
- return 0;
+ /* remove callback */
+ status = AudioDeviceRemoveIOProc(core->deviceID, core->ioproc);
+ if (status != kAudioHardwareNoError) {
+ coreaudio_logerr (status, "Could not remove IOProc\n");
+ }
}
+ core->deviceID = kAudioDeviceUnknown;
- rpos = core->rpos;
- src = hw->mix_buf + rpos;
-
- /* fill buffer */
- for (frame = 0; frame < frameCount; frame++) {
-#ifdef FLOAT_MIXENG
- *out++ = src[frame].l; /* left channel */
- *out++ = src[frame].r; /* right channel */
-#else
-#ifdef RECIPROCAL
- *out++ = src[frame].l * scale; /* left channel */
- *out++ = src[frame].r * scale; /* right channel */
-#else
- *out++ = src[frame].l / scale; /* left channel */
- *out++ = src[frame].r / scale; /* right channel */
-#endif
-#endif
+ /* destroy mutex */
+ err = pthread_mutex_destroy(&core->mutex);
+ if (err) {
+ dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
}
-
- rpos = (rpos + frameCount) % hw->samples;
- core->decr += frameCount;
- core->rpos = rpos;
-
- coreaudio_unlock (core, "audioDeviceIOProc");
- return 0;
}
-static int coreaudio_write (SWVoiceOut *sw, void *buf, int len)
-{
- return audio_pcm_sw_write (sw, buf, len);
-}
-static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
+static int
+coreaudio_voice_init (coreaudioVoice* core,
+ audsettings_t* as,
+ int frameSize,
+ AudioDeviceIOProc ioproc,
+ void* hw,
+ int input)
{
- OSStatus status;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
- UInt32 propertySize;
- int err;
- int bits = 8;
- const char *typ = "playback";
+ OSStatus status;
+ UInt32 propertySize;
+ int err;
+ int bits = 8;
AudioValueRange frameRange;
+ const char* typ = input ? "input" : "playback";
+
+ core->isInput = input ? true : false;
/* create mutex */
err = pthread_mutex_init(&core->mutex, NULL);
@@ -309,20 +309,24 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
bits = 16;
}
- audio_pcm_init_info (&hw->info, as);
-
+ // TODO: audio_pcm_init_info (&hw->info, as);
/* open default output device */
- propertySize = sizeof(core->outputDeviceID);
+ /* note: we use DefaultSystemOutputDevice because DefaultOutputDevice seems to
+ * always link to the internal speakers, and not the ones selected through system properties
+ * go figure...
+ */
+ propertySize = sizeof(core->deviceID);
status = AudioHardwareGetProperty(
- kAudioHardwarePropertyDefaultOutputDevice,
+ input ? kAudioHardwarePropertyDefaultInputDevice :
+ kAudioHardwarePropertyDefaultSystemOutputDevice,
&propertySize,
- &core->outputDeviceID);
+ &core->deviceID);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
- "Could not get default output Device\n");
+ "Could not get default %s device\n", typ);
return -1;
}
- if (core->outputDeviceID == kAudioDeviceUnknown) {
+ if (core->deviceID == kAudioDeviceUnknown) {
dolog ("Could not initialize %s - Unknown Audiodevice\n", typ);
return -1;
}
@@ -330,9 +334,9 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
/* get minimum and maximum buffer frame sizes */
propertySize = sizeof(frameRange);
status = AudioDeviceGetProperty(
- core->outputDeviceID,
- 0,
+ core->deviceID,
0,
+ core->isInput,
kAudioDevicePropertyBufferFrameSizeRange,
&propertySize,
&frameRange);
@@ -342,100 +346,101 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
return -1;
}
- if (frameRange.mMinimum > conf.buffer_frames) {
- core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum;
- dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum);
+ if (frameRange.mMinimum > frameSize) {
+ core->bufferFrameSize = (UInt32) frameRange.mMinimum;
+ dolog ("warning: Upsizing Output Buffer Frames to %f\n", frameRange.mMinimum);
}
- else if (frameRange.mMaximum < conf.buffer_frames) {
- core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
- dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
+ else if (frameRange.mMaximum < frameSize) {
+ core->bufferFrameSize = (UInt32) frameRange.mMaximum;
+ dolog ("warning: Downsizing Output Buffer Frames to %f\n", frameRange.mMaximum);
}
else {
- core->audioDevicePropertyBufferFrameSize = conf.buffer_frames;
+ core->bufferFrameSize = frameSize;
}
/* set Buffer Frame Size */
- propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
+ propertySize = sizeof(core->bufferFrameSize);
status = AudioDeviceSetProperty(
- core->outputDeviceID,
+ core->deviceID,
NULL,
0,
- false,
+ core->isInput,
kAudioDevicePropertyBufferFrameSize,
propertySize,
- &core->audioDevicePropertyBufferFrameSize);
+ &core->bufferFrameSize);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not set device buffer frame size %ld\n",
- core->audioDevicePropertyBufferFrameSize);
+ core->bufferFrameSize);
return -1;
}
/* get Buffer Frame Size */
- propertySize = sizeof(core->audioDevicePropertyBufferFrameSize);
+ propertySize = sizeof(core->bufferFrameSize);
status = AudioDeviceGetProperty(
- core->outputDeviceID,
+ core->deviceID,
0,
- false,
+ core->isInput,
kAudioDevicePropertyBufferFrameSize,
&propertySize,
- &core->audioDevicePropertyBufferFrameSize);
+ &core->bufferFrameSize);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get device buffer frame size\n");
return -1;
}
- hw->samples = conf.nbuffers * core->audioDevicePropertyBufferFrameSize;
+ // TODO: hw->samples = *pNBuffers * core->bufferFrameSize;
/* get StreamFormat */
- propertySize = sizeof(core->outputStreamBasicDescription);
+ propertySize = sizeof(core->streamBasicDescription);
status = AudioDeviceGetProperty(
- core->outputDeviceID,
+ core->deviceID,
0,
- false,
+ core->isInput,
kAudioDevicePropertyStreamFormat,
&propertySize,
- &core->outputStreamBasicDescription);
+ &core->streamBasicDescription);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ,
"Could not get Device Stream properties\n");
- core->outputDeviceID = kAudioDeviceUnknown;
+ core->deviceID = kAudioDeviceUnknown;
return -1;
}
/* set Samplerate */
- core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
- propertySize = sizeof(core->outputStreamBasicDescription);
+ core->streamBasicDescription.mSampleRate = (Float64) as->freq;
+ propertySize = sizeof(core->streamBasicDescription);
status = AudioDeviceSetProperty(
- core->outputDeviceID,
- 0,
+ core->deviceID,
0,
0,
+ core->isInput,
kAudioDevicePropertyStreamFormat,
propertySize,
- &core->outputStreamBasicDescription);
+ &core->streamBasicDescription);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n",
as->freq);
- core->outputDeviceID = kAudioDeviceUnknown;
+ core->deviceID = kAudioDeviceUnknown;
return -1;
}
/* set Callback */
- status = AudioDeviceAddIOProc(core->outputDeviceID, audioDeviceIOProc, hw);
+ core->ioproc = ioproc;
+ status = AudioDeviceAddIOProc(core->deviceID, ioproc, hw);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not set IOProc\n");
- core->outputDeviceID = kAudioDeviceUnknown;
+ core->deviceID = kAudioDeviceUnknown;
return -1;
}
/* start Playback */
- if (!isPlaying(core->outputDeviceID)) {
- status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
+ if (!input && !coreaudio_voice_isPlaying(core)) {
+ status = AudioDeviceStart(core->deviceID, core->ioproc);
if (status != kAudioHardwareNoError) {
coreaudio_logerr2 (status, typ, "Could not start playback\n");
- AudioDeviceRemoveIOProc(core->outputDeviceID, audioDeviceIOProc);
- core->outputDeviceID = kAudioDeviceUnknown;
+ AudioDeviceRemoveIOProc(core->deviceID, core->ioproc);
+ core->deviceID = kAudioDeviceUnknown;
return -1;
}
}
@@ -443,84 +448,332 @@ static int coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
return 0;
}
-static void coreaudio_fini_out (HWVoiceOut *hw)
+
+/***************************************************************************************/
+/***************************************************************************************/
+/*** ***/
+/*** O U T P U T V O I C E ***/
+/*** ***/
+/***************************************************************************************/
+/***************************************************************************************/
+
+typedef struct coreaudioVoiceOut {
+ HWVoiceOut hw;
+ coreaudioVoice core[1];
+} coreaudioVoiceOut;
+
+#define CORE_OUT(hw) ((coreaudioVoiceOut*)(hw))->core
+
+
+static int
+coreaudio_run_out (HWVoiceOut *hw)
{
- OSStatus status;
- int err;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+ int live, decr;
+ coreaudioVoice *core = CORE_OUT(hw);
- if (!conf.isAtexit) {
- /* stop playback */
- if (isPlaying(core->outputDeviceID)) {
- status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
- if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Could not stop playback\n");
- }
- }
+ if (coreaudio_voice_lock (core, "coreaudio_run_out")) {
+ return 0;
+ }
- /* remove callback */
- status = AudioDeviceRemoveIOProc(core->outputDeviceID,
- audioDeviceIOProc);
- if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Could not remove IOProc\n");
- }
+ live = audio_pcm_hw_get_live_out (hw);
+
+ if (core->decr > live) {
+ ldebug ("core->decr %d live %d core->live %d\n",
+ core->decr,
+ live,
+ core->live);
}
- core->outputDeviceID = kAudioDeviceUnknown;
- /* destroy mutex */
- err = pthread_mutex_destroy(&core->mutex);
- if (err) {
- dolog("Could not destroy mutex\nReason: %s\n", strerror (err));
+ decr = audio_MIN (core->decr, live);
+ core->decr -= decr;
+ core->live = live - decr;
+ hw->rpos = core->pos;
+
+ coreaudio_voice_unlock (core, "coreaudio_run_out");
+ return decr;
+}
+
+
+/* callback to feed audiooutput buffer */
+static OSStatus
+audioOutDeviceIOProc(
+ AudioDeviceID inDevice,
+ const AudioTimeStamp* inNow,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* inInputTime,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* inOutputTime,
+ void* hwptr)
+{
+ UInt32 frame, frameCount;
+ float *out = outOutputData->mBuffers[0].mData;
+ HWVoiceOut *hw = hwptr;
+ coreaudioVoice *core = CORE_OUT(hw);
+ int rpos, live;
+ st_sample_t *src;
+#ifndef FLOAT_MIXENG
+#ifdef RECIPROCAL
+ const float scale = 1.f / UINT_MAX;
+#else
+ const float scale = UINT_MAX;
+#endif
+#endif
+
+ if (coreaudio_voice_lock (core, "audioDeviceIOProc")) {
+ inInputTime = 0;
+ return 0;
}
+
+ frameCount = core->bufferFrameSize;
+ live = core->live;
+
+ /* if there are not enough samples, set signal and return */
+ if (live < frameCount) {
+ inInputTime = 0;
+ coreaudio_voice_unlock (core, "audioDeviceIOProc(empty)");
+ return 0;
+ }
+
+ rpos = core->pos;
+ src = hw->mix_buf + rpos;
+
+ /* fill buffer */
+ for (frame = 0; frame < frameCount; frame++) {
+#ifdef FLOAT_MIXENG
+ *out++ = src[frame].l; /* left channel */
+ *out++ = src[frame].r; /* right channel */
+#else
+#ifdef RECIPROCAL
+ *out++ = src[frame].l * scale; /* left channel */
+ *out++ = src[frame].r * scale; /* right channel */
+#else
+ *out++ = src[frame].l / scale; /* left channel */
+ *out++ = src[frame].r / scale; /* right channel */
+#endif
+#endif
+ }
+
+ rpos = (rpos + frameCount) % hw->samples;
+ core->decr += frameCount;
+ core->pos = rpos;
+
+ coreaudio_voice_unlock (core, "audioDeviceIOProc");
+ return 0;
}
-static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static int
+coreaudio_write (SWVoiceOut *sw, void *buf, int len)
{
- OSStatus status;
- coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
+ return audio_pcm_sw_write (sw, buf, len);
+}
- switch (cmd) {
- case VOICE_ENABLE:
- /* start playback */
- if (!isPlaying(core->outputDeviceID)) {
- status = AudioDeviceStart(core->outputDeviceID, audioDeviceIOProc);
- if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Could not resume playback\n");
- }
- }
- break;
+static int
+coreaudio_init_out (HWVoiceOut *hw, audsettings_t *as)
+{
+ coreaudioVoice* core = CORE_OUT(hw);
+ int err;
- case VOICE_DISABLE:
- /* stop playback */
- if (!conf.isAtexit) {
- if (isPlaying(core->outputDeviceID)) {
- status = AudioDeviceStop(core->outputDeviceID, audioDeviceIOProc);
- if (status != kAudioHardwareNoError) {
- coreaudio_logerr (status, "Could not pause playback\n");
- }
- }
- }
- break;
+ audio_pcm_init_info (&hw->info, as);
+
+ err = coreaudio_voice_init( core, as, conf.out_buffer_frames, audioOutDeviceIOProc, hw, 0 );
+ if (err < 0)
+ return err;
+
+ hw->samples = core->bufferFrameSize * conf.out_nbuffers;
+ return 0;
+}
+
+static void
+coreaudio_fini_out (HWVoiceOut *hw)
+{
+
+ coreaudioVoice* core = CORE_OUT(hw);
+
+ coreaudio_voice_fini(core);
+}
+
+static int
+coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+ coreaudioVoice* core = CORE_OUT(hw);
+
+ return coreaudio_voice_ctl(core, cmd);
+}
+
+/***************************************************************************************/
+/***************************************************************************************/
+/*** ***/
+/*** I N P U T V O I C E ***/
+/*** ***/
+/***************************************************************************************/
+/***************************************************************************************/
+
+
+
+typedef struct coreaudioVoiceIn {
+ HWVoiceIn hw;
+ coreaudioVoice core[1];
+} coreaudioVoiceIn;
+
+#define CORE_IN(hw) ((coreaudioVoiceIn*)(hw))->core
+
+
+static int
+coreaudio_run_in (HWVoiceIn *hw)
+{
+ int decr;
+
+ coreaudioVoice *core = CORE_IN(hw);
+
+ if (coreaudio_voice_lock (core, "coreaudio_run_in")) {
+ return 0;
+ }
+
+ D("%s: core.decr=%d core.pos=%d\n", __FUNCTION__, core->decr, core->pos);
+ decr = core->decr;
+ core->decr -= decr;
+ hw->wpos = core->pos;
+
+ coreaudio_voice_unlock (core, "coreaudio_run_in");
+ return decr;
+}
+
+
+/* callback to feed audiooutput buffer */
+static OSStatus
+audioInDeviceIOProc(
+ AudioDeviceID inDevice,
+ const AudioTimeStamp* inNow,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* inInputTime,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* inOutputTime,
+ void* hwptr)
+{
+ UInt32 frame, frameCount;
+ float *in = inInputData->mBuffers[0].mData;
+ HWVoiceIn *hw = hwptr;
+ coreaudioVoice *core = CORE_IN(hw);
+ int wpos, avail;
+ st_sample_t *dst;
+#ifndef FLOAT_MIXENG
+#ifdef RECIPROCAL
+ const float scale = 1.f / UINT_MAX;
+#else
+ const float scale = UINT_MAX;
+#endif
+#endif
+
+ if (coreaudio_voice_lock (core, "audioDeviceIOProc")) {
+ inInputTime = 0;
+ return 0;
+ }
+
+ frameCount = core->bufferFrameSize;
+ avail = hw->samples - hw->total_samples_captured - core->decr;
+
+ D("%s: enter avail=%d core.decr=%d core.pos=%d hw.samples=%d hw.total_samples_captured=%d frameCount=%d\n",
+ __FUNCTION__, avail, core->decr, core->pos, hw->samples, hw->total_samples_captured, (int)frameCount);
+
+ /* if there are not enough samples, set signal and return */
+ if (avail < frameCount) {
+ inInputTime = 0;
+ coreaudio_voice_unlock (core, "audioDeviceIOProc(empty)");
+ return 0;
}
+
+ wpos = core->pos;
+ dst = hw->conv_buf + wpos;
+
+ /* fill buffer */
+ for (frame = 0; frame < frameCount; frame++) {
+#ifdef FLOAT_MIXENG
+ dst[frame].l = *in++; /* left channel */
+ dst[frame].r = *in++; /* right channel */
+#else
+#ifdef RECIPROCAL
+ dst[frame].l = *in++ * scale; /* left channel */
+ dst[frame].r = *in++ * scale; /* right channel */
+#else
+ dst[frame].l = *in++ / scale; /* left channel */
+ dst[frame].r = *in++ / scale; /* right channel */
+#endif
+#endif
+ }
+
+ wpos = (wpos + frameCount) % hw->samples;
+ core->decr += frameCount;
+ core->pos = wpos;
+
+ D("exit: core.decr=%d core.pos=%d\n", core->decr, core->pos);
+ coreaudio_voice_unlock (core, "audioDeviceIOProc");
+ return 0;
+}
+
+static int
+coreaudio_read (SWVoiceIn *sw, void *buf, int len)
+{
+ int result = audio_pcm_sw_read(sw, buf, len);
+ D("%s: audio_pcm_sw_read(%d) returned %d\n", __FUNCTION__, len, result);
+ return result;
+}
+
+static int
+coreaudio_init_in (HWVoiceIn *hw, audsettings_t *as)
+{
+ coreaudioVoice* core = CORE_IN(hw);
+ int err;
+
+ audio_pcm_init_info (&hw->info, as);
+
+ err = coreaudio_voice_init( core, as, conf.in_buffer_frames, audioInDeviceIOProc, hw, 1 );
+ if (err < 0) {
+ return err;
+ }
+
+ hw->samples = core->bufferFrameSize * conf.in_nbuffers;
return 0;
}
-static void *coreaudio_audio_init (void)
+static void
+coreaudio_fini_in (HWVoiceIn *hw)
+{
+
+ coreaudioVoice* core = CORE_IN(hw);
+
+ coreaudio_voice_fini(core);
+}
+
+static int
+coreaudio_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+ coreaudioVoice* core = CORE_IN(hw);
+
+ return coreaudio_voice_ctl(core, cmd);
+}
+
+static void*
+coreaudio_audio_init (void)
{
atexit(coreaudio_atexit);
return &coreaudio_audio_init;
}
-static void coreaudio_audio_fini (void *opaque)
+static void
+coreaudio_audio_fini (void *opaque)
{
(void) opaque;
}
static struct audio_option coreaudio_options[] = {
- {"BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_frames,
- "Size of the buffer in frames", NULL, 0},
- {"BUFFER_COUNT", AUD_OPT_INT, &conf.nbuffers,
- "Number of buffers", NULL, 0},
+ {"OUT_BUFFER_SIZE", AUD_OPT_INT, &conf.out_buffer_frames,
+ "Size of the output buffer in frames", NULL, 0},
+ {"OUT_BUFFER_COUNT", AUD_OPT_INT, &conf.out_nbuffers,
+ "Number of output buffers", NULL, 0},
+ {"IN_BUFFER_SIZE", AUD_OPT_INT, &conf.in_buffer_frames,
+ "Size of the input buffer in frames", NULL, 0},
+ {"IN_BUFFER_COUNT", AUD_OPT_INT, &conf.in_nbuffers,
+ "Number of input buffers", NULL, 0},
{NULL, 0, NULL, NULL, NULL, 0}
};
@@ -531,24 +784,39 @@ static struct audio_pcm_ops coreaudio_pcm_ops = {
coreaudio_write,
coreaudio_ctl_out,
+#if ENABLE_IN
+ coreaudio_init_in,
+ coreaudio_fini_in,
+ coreaudio_run_in,
+ coreaudio_read,
+ coreaudio_ctl_in
+#else
NULL,
NULL,
NULL,
NULL,
NULL
+#endif
};
struct audio_driver coreaudio_audio_driver = {
INIT_FIELD (name = ) "coreaudio",
INIT_FIELD (descr = )
- "CoreAudio http://developer.apple.com/audio/coreaudio.html",
+ "CoreAudio (developer.apple.com/audio/coreaudio.html)",
INIT_FIELD (options = ) coreaudio_options,
INIT_FIELD (init = ) coreaudio_audio_init,
INIT_FIELD (fini = ) coreaudio_audio_fini,
INIT_FIELD (pcm_ops = ) &coreaudio_pcm_ops,
INIT_FIELD (can_be_default = ) 1,
+#if ENABLE_IN
+ INIT_FIELD (max_voices_out = ) 1,
+ INIT_FIELD (max_voices_in = ) 1,
+ INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
+ INIT_FIELD (voice_size_in = ) sizeof (coreaudioVoiceIn),
+#else
INIT_FIELD (max_voices_out = ) 1,
INIT_FIELD (max_voices_in = ) 0,
INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut),
- INIT_FIELD (voice_size_in = ) 0
+ INIT_FIELD (voice_size_in = ) 0,
+#endif
};
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index 90a0333..6104acb 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -1067,7 +1067,7 @@ static struct audio_pcm_ops dsound_pcm_ops = {
struct audio_driver dsound_audio_driver = {
INIT_FIELD (name = ) "dsound",
INIT_FIELD (descr = )
- "DirectSound http://wikipedia.org/wiki/DirectSound",
+ "DirectSound audio (www.wikipedia.org/wiki/DirectSound)",
INIT_FIELD (options = ) dsound_options,
INIT_FIELD (init = ) dsound_audio_init,
INIT_FIELD (fini = ) dsound_audio_fini,
diff --git a/audio/esdaudio.c b/audio/esdaudio.c
new file mode 100644
index 0000000..9aeb8a5
--- /dev/null
+++ b/audio/esdaudio.c
@@ -0,0 +1,692 @@
+/*
+ * QEMU ESD audio driver
+ *
+ * Copyright (c) 2008 The Android Open Source Project
+ * Copyright (c) 2006 Frederick Reeve (brushed up by malc)
+ *
+ * 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 <esd.h>
+#include "vl.h"
+#include "audio.h"
+#include <signal.h>
+
+#define AUDIO_CAP "esd"
+#include "audio_int.h"
+#include "audio_pt_int.h"
+#include <dlfcn.h>
+
+#include "android_debug.h"
+
+#define DEBUG 1
+
+#if DEBUG
+# include <stdio.h>
+# define D(...) VERBOSE_PRINT(audio,__VA_ARGS__)
+# define D_ACTIVE VERBOSE_CHECK(audio)
+# define O(...) VERBOSE_PRINT(audioout,__VA_ARGS__)
+# define I(...) VERBOSE_PRINT(audioin,__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+# define D_ACTIVE 0
+# define O(...) ((void)0)
+# define I(...) ((void)0)
+#endif
+
+#define STRINGIFY_(x) #x
+#define STRINGIFY(x) STRINGIFY_(x)
+
+typedef struct {
+ HWVoiceOut hw;
+ int done;
+ int live;
+ int decr;
+ int rpos;
+ void *pcm_buf;
+ int fd;
+ struct audio_pt pt;
+} ESDVoiceOut;
+
+typedef struct {
+ HWVoiceIn hw;
+ int done;
+ int dead;
+ int incr;
+ int wpos;
+ void *pcm_buf;
+ int fd;
+ struct audio_pt pt;
+} ESDVoiceIn;
+
+static struct {
+ int samples;
+ int divisor;
+ char *dac_host;
+ char *adc_host;
+} conf = {
+ 1024,
+ 2,
+ NULL,
+ NULL
+};
+
+/* link dynamically to the libesd.so */
+
+#define ESD_SYMBOLS \
+ ESD_FUNCTION(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \
+ ESD_FUNCTION(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \
+ ESD_FUNCTION(int,esd_open_sound,( const char *host )) \
+ ESD_FUNCTION(int,esd_close,(int)) \
+
+/* define pointers to library functions we're going to use */
+#define ESD_FUNCTION(ret,name,sig) \
+ static ret (*func_ ## name)sig;
+
+ESD_SYMBOLS
+
+#undef ESD_FUNCTION
+
+static void* esd_lib;
+
+static void GCC_FMT_ATTR (2, 3) qesd_logerr (int err, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ AUD_vlog (AUDIO_CAP, fmt, ap);
+ va_end (ap);
+
+ AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err));
+}
+
+/* playback */
+static void *qesd_thread_out (void *arg)
+{
+ ESDVoiceOut* esd = arg;
+ HWVoiceOut* hw = &esd->hw;
+ int threshold;
+ sigset_t set;
+
+ threshold = conf.divisor ? hw->samples / conf.divisor : 0;
+
+ /* ignore SIGALRM in this thread */
+ sigemptyset(&set);
+ sigaddset(&set, SIGALRM);
+
+ pthread_sigmask( SIG_BLOCK, &set, NULL);
+
+ O("EsounD output thread starting, threshold is %d samples", threshold);
+ for (;;) {
+ int decr, to_mix, rpos;
+
+ for (;;) {
+ if (esd->done) {
+ goto exit;
+ }
+
+ if (esd->live > threshold) {
+ break;
+ }
+
+ if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
+ O("EsounD output thread aborting on wait error");
+ goto exit;
+ }
+ }
+
+ decr = to_mix = esd->live;
+ rpos = hw->rpos;
+
+ if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
+ O("EsounD output thread aborting on unlock error");
+ return NULL;
+ }
+
+ while (to_mix) {
+ ssize_t written;
+ int chunk = audio_MIN (to_mix, hw->samples - rpos);
+ st_sample_t *src = hw->mix_buf + rpos;
+
+ hw->clip (esd->pcm_buf, src, chunk);
+
+ again:
+ written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift);
+ if (written == -1) {
+ if (errno == EINTR || errno == EAGAIN) {
+ goto again;
+ }
+ qesd_logerr (errno, "write failed\n");
+ O("EsounD output thread aborting on write error: %s", strerror(errno));
+ return NULL;
+ }
+
+ if (written != chunk << hw->info.shift) {
+ int wsamples = written >> hw->info.shift;
+ int wbytes = wsamples << hw->info.shift;
+ if (wbytes != written) {
+ dolog ("warning: Misaligned write %d (requested %d), "
+ "alignment %d\n",
+ wbytes, written, hw->info.align + 1);
+ }
+ to_mix -= wsamples;
+ rpos = (rpos + wsamples) % hw->samples;
+ break;
+ }
+
+ rpos = (rpos + chunk) % hw->samples;
+ to_mix -= chunk;
+ }
+
+ if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+ O("EsounD output thread aborting on lock error\n");
+ return NULL;
+ }
+
+ esd->rpos = rpos;
+ esd->live -= decr;
+ esd->decr += decr;
+ }
+ O("EsounD output thread exiting");
+
+ exit:
+ audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+ return NULL;
+}
+
+static int qesd_run_out (HWVoiceOut *hw)
+{
+ int live, decr;
+ ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+
+ if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+ O("%s: exiting on lock error", __FUNCTION__);
+ return 0;
+ }
+
+ live = audio_pcm_hw_get_live_out (hw);
+ decr = audio_MIN (live, esd->decr);
+ esd->decr -= decr;
+ esd->live = live - decr;
+ hw->rpos = esd->rpos;
+ if (esd->live > 0) {
+ O("%s: signaling %d samples\n", esd->live);
+ audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+ }
+ else {
+ O(".");
+ audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+ }
+ return decr;
+}
+
+static int qesd_write (SWVoiceOut *sw, void *buf, int len)
+{
+ return audio_pcm_sw_write (sw, buf, len);
+}
+
+static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as)
+{
+ ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+ audsettings_t obt_as = *as;
+ int esdfmt = ESD_STREAM | ESD_PLAY;
+ int result = -1;
+
+ /* shut down verbose debug spew */
+ if (!D_ACTIVE)
+ stdio_disable();
+
+ O("initializing EsoundD audio output");
+ esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
+ switch (as->fmt) {
+ case AUD_FMT_S8:
+ case AUD_FMT_U8:
+ esdfmt |= ESD_BITS8;
+ obt_as.fmt = AUD_FMT_U8;
+ break;
+#if 0
+ case AUD_FMT_S32:
+ case AUD_FMT_U32:
+ dolog ("Will use 16 instead of 32 bit samples\n");
+#endif
+ case AUD_FMT_S16:
+ case AUD_FMT_U16:
+ deffmt:
+ esdfmt |= ESD_BITS16;
+ obt_as.fmt = AUD_FMT_S16;
+ break;
+
+ default:
+ dolog ("Internal logic error: Bad audio format %d\n", as->fmt);
+#ifdef DEBUG_FMOD
+ abort ();
+#endif
+ goto deffmt;
+
+ }
+ obt_as.endianness = 0;
+
+ audio_pcm_init_info (&hw->info, &obt_as);
+
+ hw->samples = conf.samples;
+ esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ if (!esd->pcm_buf) {
+ dolog ("Could not allocate buffer (%d bytes)\n",
+ hw->samples << hw->info.shift);
+ goto exit;
+ }
+
+ esd->fd = func_esd_play_stream (esdfmt, as->freq, conf.dac_host, NULL);
+ if (esd->fd < 0) {
+ if (conf.dac_host == NULL) {
+ esd->fd = func_esd_play_stream (esdfmt, as->freq, "localhost", NULL);
+ }
+ if (esd->fd < 0) {
+ qesd_logerr (errno, "esd_play_stream failed\n");
+ goto fail2;
+ }
+ }
+
+ if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) {
+ goto fail3;
+ }
+
+ result = 0; /* success */
+ goto exit;
+
+ fail3:
+ if (close (esd->fd)) {
+ qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
+ AUDIO_FUNC, esd->fd);
+ }
+ esd->fd = -1;
+
+ fail2:
+ qemu_free (esd->pcm_buf);
+ esd->pcm_buf = NULL;
+
+ exit:
+ if (!D_ACTIVE)
+ stdio_enable();
+
+ return result;
+}
+
+static void qesd_fini_out (HWVoiceOut *hw)
+{
+ void *ret;
+ ESDVoiceOut *esd = (ESDVoiceOut *) hw;
+
+ audio_pt_lock (&esd->pt, AUDIO_FUNC);
+ esd->done = 1;
+ audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+ audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
+
+ if (esd->fd >= 0) {
+ if (close (esd->fd)) {
+ qesd_logerr (errno, "failed to close esd socket\n");
+ }
+ esd->fd = -1;
+ }
+
+ audio_pt_fini (&esd->pt, AUDIO_FUNC);
+
+ qemu_free (esd->pcm_buf);
+ esd->pcm_buf = NULL;
+}
+
+static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...)
+{
+ (void) hw;
+ (void) cmd;
+ return 0;
+}
+
+/* capture */
+static void *qesd_thread_in (void *arg)
+{
+ ESDVoiceIn *esd = arg;
+ HWVoiceIn *hw = &esd->hw;
+ int threshold;
+
+ threshold = conf.divisor ? hw->samples / conf.divisor : 0;
+
+ for (;;) {
+ int incr, to_grab, wpos;
+
+ for (;;) {
+ if (esd->done) {
+ goto exit;
+ }
+
+ if (esd->dead > threshold) {
+ break;
+ }
+
+ if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) {
+ goto exit;
+ }
+ }
+
+ incr = to_grab = esd->dead;
+ wpos = hw->wpos;
+
+ if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) {
+ return NULL;
+ }
+
+ while (to_grab) {
+ ssize_t nread;
+ int chunk = audio_MIN (to_grab, hw->samples - wpos);
+ void *buf = advance (esd->pcm_buf, wpos);
+
+ again:
+ nread = read (esd->fd, buf, chunk << hw->info.shift);
+ if (nread == -1) {
+ if (errno == EINTR || errno == EAGAIN) {
+ goto again;
+ }
+ qesd_logerr (errno, "read failed\n");
+ return NULL;
+ }
+
+ if (nread != chunk << hw->info.shift) {
+ int rsamples = nread >> hw->info.shift;
+ int rbytes = rsamples << hw->info.shift;
+ if (rbytes != nread) {
+ dolog ("warning: Misaligned write %d (requested %d), "
+ "alignment %d\n",
+ rbytes, nread, hw->info.align + 1);
+ }
+ to_grab -= rsamples;
+ wpos = (wpos + rsamples) % hw->samples;
+ break;
+ }
+
+ hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift,
+ &nominal_volume);
+ wpos = (wpos + chunk) % hw->samples;
+ to_grab -= chunk;
+ }
+
+ if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+ return NULL;
+ }
+
+ esd->wpos = wpos;
+ esd->dead -= incr;
+ esd->incr += incr;
+ }
+
+ exit:
+ audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+ return NULL;
+}
+
+static int qesd_run_in (HWVoiceIn *hw)
+{
+ int live, incr, dead;
+ ESDVoiceIn *esd = (ESDVoiceIn *) hw;
+
+ if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) {
+ return 0;
+ }
+
+ live = audio_pcm_hw_get_live_in (hw);
+ dead = hw->samples - live;
+ incr = audio_MIN (dead, esd->incr);
+ esd->incr -= incr;
+ esd->dead = dead - incr;
+ hw->wpos = esd->wpos;
+ if (esd->dead > 0) {
+ audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+ }
+ else {
+ audio_pt_unlock (&esd->pt, AUDIO_FUNC);
+ }
+ return incr;
+}
+
+static int qesd_read (SWVoiceIn *sw, void *buf, int len)
+{
+ return audio_pcm_sw_read (sw, buf, len);
+}
+
+static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as)
+{
+ ESDVoiceIn *esd = (ESDVoiceIn *) hw;
+ audsettings_t obt_as = *as;
+ int esdfmt = ESD_STREAM | ESD_RECORD;
+ int result = -1;
+
+ /* shut down verbose debug spew */
+ if (!D_ACTIVE)
+ stdio_disable();
+
+ esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO;
+ switch (as->fmt) {
+ case AUD_FMT_S8:
+ case AUD_FMT_U8:
+ esdfmt |= ESD_BITS8;
+ obt_as.fmt = AUD_FMT_U8;
+ break;
+
+ case AUD_FMT_S16:
+ case AUD_FMT_U16:
+ esdfmt |= ESD_BITS16;
+ obt_as.fmt = AUD_FMT_S16;
+ break;
+#if 0
+ case AUD_FMT_S32:
+ case AUD_FMT_U32:
+ dolog ("Will use 16 instead of 32 bit samples\n");
+ esdfmt |= ESD_BITS16;
+ obt_as.fmt = AUD_FMT_S16;
+ break;
+#endif
+ }
+ obt_as.endianness = 0;
+
+ audio_pcm_init_info (&hw->info, &obt_as);
+
+ hw->samples = conf.samples;
+ esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ if (!esd->pcm_buf) {
+ dolog ("Could not allocate buffer (%d bytes)\n",
+ hw->samples << hw->info.shift);
+ goto exit;
+ }
+
+ esd->fd = func_esd_record_stream (esdfmt, as->freq, conf.adc_host, NULL);
+ if (esd->fd < 0) {
+ if (conf.adc_host == NULL) {
+ esd->fd = func_esd_record_stream (esdfmt, as->freq, "localhost", NULL);
+ }
+ if (esd->fd < 0) {
+ qesd_logerr (errno, "esd_record_stream failed\n");
+ goto fail2;
+ }
+ }
+
+ if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) {
+ goto fail3;
+ }
+
+ result = 0; /* success */
+ goto exit;
+
+ fail3:
+ if (close (esd->fd)) {
+ qesd_logerr (errno, "%s: close on esd socket(%d) failed\n",
+ AUDIO_FUNC, esd->fd);
+ }
+ esd->fd = -1;
+
+ fail2:
+ qemu_free (esd->pcm_buf);
+ esd->pcm_buf = NULL;
+
+ exit:
+ if (!D_ACTIVE)
+ stdio_enable();
+
+ return result;
+}
+
+static void qesd_fini_in (HWVoiceIn *hw)
+{
+ void *ret;
+ ESDVoiceIn *esd = (ESDVoiceIn *) hw;
+
+ audio_pt_lock (&esd->pt, AUDIO_FUNC);
+ esd->done = 1;
+ audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC);
+ audio_pt_join (&esd->pt, &ret, AUDIO_FUNC);
+
+ if (esd->fd >= 0) {
+ if (close (esd->fd)) {
+ qesd_logerr (errno, "failed to close esd socket\n");
+ }
+ esd->fd = -1;
+ }
+
+ audio_pt_fini (&esd->pt, AUDIO_FUNC);
+
+ qemu_free (esd->pcm_buf);
+ esd->pcm_buf = NULL;
+}
+
+static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...)
+{
+ (void) hw;
+ (void) cmd;
+ return 0;
+}
+
+/* common */
+static void *qesd_audio_init (void)
+{
+ void* result = NULL;
+
+ D("%s: entering", __FUNCTION__);
+
+ if (esd_lib == NULL) {
+ int fd;
+
+ esd_lib = dlopen( "libesd.so", RTLD_NOW );
+ if (esd_lib == NULL)
+ esd_lib = dlopen( "libesd.so.0", RTLD_NOW );
+
+ if (esd_lib == NULL) {
+ D("could not find libesd on this system");
+ goto Exit;
+ }
+
+ #undef ESD_FUNCTION
+ #define ESD_FUNCTION(ret,name,sig) \
+ do { \
+ (func_ ##name) = dlsym( esd_lib, STRINGIFY(name) ); \
+ if ((func_##name) == NULL) { \
+ D("could not find %s in libesd\n", STRINGIFY(name)); \
+ goto Fail; \
+ } \
+ } while (0);
+
+ ESD_SYMBOLS
+
+ fd = func_esd_open_sound(conf.dac_host);
+ if (fd < 0) {
+ D("%s: could not open direct sound server connection, trying localhost",
+ __FUNCTION__);
+ fd = func_esd_open_sound("localhost");
+ if (fd < 0) {
+ D("%s: could not open localhost sound server connection", __FUNCTION__);
+ goto Fail;
+ }
+ }
+
+ D("%s: EsounD server connection succeeded", __FUNCTION__);
+ /* func_esd_close(fd); */
+ }
+ result = &conf;
+ goto Exit;
+
+Fail:
+ D("%s: failed to open library", __FUNCTION__);
+ dlclose(esd_lib);
+ esd_lib = NULL;
+
+Exit:
+ return result;
+}
+
+static void qesd_audio_fini (void *opaque)
+{
+ (void) opaque;
+ if (esd_lib != NULL) {
+ dlclose(esd_lib);
+ esd_lib = NULL;
+ }
+ ldebug ("esd_fini");
+}
+
+struct audio_option qesd_options[] = {
+ {"SAMPLES", AUD_OPT_INT, &conf.samples,
+ "buffer size in samples", NULL, 0},
+
+ {"DIVISOR", AUD_OPT_INT, &conf.divisor,
+ "threshold divisor", NULL, 0},
+
+ {"DAC_HOST", AUD_OPT_STR, &conf.dac_host,
+ "playback host", NULL, 0},
+
+ {"ADC_HOST", AUD_OPT_STR, &conf.adc_host,
+ "capture host", NULL, 0},
+
+ {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+struct audio_pcm_ops qesd_pcm_ops = {
+ qesd_init_out,
+ qesd_fini_out,
+ qesd_run_out,
+ qesd_write,
+ qesd_ctl_out,
+
+ qesd_init_in,
+ qesd_fini_in,
+ qesd_run_in,
+ qesd_read,
+ qesd_ctl_in,
+};
+
+struct audio_driver esd_audio_driver = {
+ INIT_FIELD (name = ) "esd",
+ INIT_FIELD (descr = )
+ "EsounD audio (en.wikipedia.org/wiki/Esound)",
+ INIT_FIELD (options = ) qesd_options,
+ INIT_FIELD (init = ) qesd_audio_init,
+ INIT_FIELD (fini = ) qesd_audio_fini,
+ INIT_FIELD (pcm_ops = ) &qesd_pcm_ops,
+ INIT_FIELD (can_be_default = ) 1,
+ INIT_FIELD (max_voices_out = ) INT_MAX,
+ INIT_FIELD (max_voices_in = ) 1,
+ INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut),
+ INIT_FIELD (voice_size_in = ) sizeof (ESDVoiceIn)
+};
diff --git a/audio/noaudio.c b/audio/noaudio.c
index a3423e5..3567e9c 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -159,7 +159,7 @@ static struct audio_pcm_ops no_pcm_ops = {
struct audio_driver no_audio_driver = {
INIT_FIELD (name = ) "none",
- INIT_FIELD (descr = ) "Timer based audio emulation",
+ INIT_FIELD (descr = ) "disabled audio",
INIT_FIELD (options = ) NULL,
INIT_FIELD (init = ) no_audio_init,
INIT_FIELD (fini = ) no_audio_fini,
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index 125e4c8..4d36e45 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -755,7 +755,7 @@ static struct audio_pcm_ops oss_pcm_ops = {
struct audio_driver oss_audio_driver = {
INIT_FIELD (name = ) "oss",
- INIT_FIELD (descr = ) "OSS http://www.opensound.com",
+ INIT_FIELD (descr = ) "OSS audio (www.opensound.com)",
INIT_FIELD (options = ) oss_options,
INIT_FIELD (init = ) oss_audio_init,
INIT_FIELD (fini = ) oss_audio_fini,
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index f2a6896..83469ac 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -28,12 +28,17 @@
#define AUDIO_CAP "sdl"
#include "audio_int.h"
-typedef struct SDLVoiceOut {
- HWVoiceOut hw;
- int live;
- int rpos;
- int decr;
-} SDLVoiceOut;
+/* define DEBUG to 1 to dump audio debugging info at runtime to stderr */
+#define DEBUG 0
+
+/* define NEW_AUDIO to 1 to activate the new audio thread callback */
+#define NEW_AUDIO 1
+
+#if DEBUG
+# define D(...) fprintf(stderr, __VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
static struct {
int nb_samples;
@@ -41,12 +46,41 @@ static struct {
1024
};
+#if DEBUG
+int64_t start_time;
+#endif
+
+#if NEW_AUDIO
+
+#define AUDIO_BUFFER_SIZE (8192)
+
+typedef HWVoiceOut SDLVoiceOut;
+
+struct SDLAudioState {
+ int exit;
+ SDL_mutex* mutex;
+ int initialized;
+ uint8_t data[ AUDIO_BUFFER_SIZE ];
+ int pos, count;
+} glob_sdl;
+#else /* !NEW_AUDIO */
+
+typedef struct SDLVoiceOut {
+ HWVoiceOut hw;
+ int live;
+ int rpos;
+ int decr;
+} SDLVoiceOut;
+
struct SDLAudioState {
int exit;
SDL_mutex *mutex;
SDL_sem *sem;
int initialized;
} glob_sdl;
+
+#endif /* !NEW_AUDIO */
+
typedef struct SDLAudioState SDLAudioState;
static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
@@ -78,6 +112,7 @@ static int sdl_unlock (SDLAudioState *s, const char *forfn)
return 0;
}
+#if !NEW_AUDIO
static int sdl_post (SDLAudioState *s, const char *forfn)
{
if (SDL_SemPost (s->sem)) {
@@ -104,6 +139,7 @@ static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)
return sdl_post (s, forfn);
}
+#endif
static int aud_to_sdlfmt (audfmt_e fmt, int *shift)
{
@@ -190,13 +226,62 @@ static void sdl_close (SDLAudioState *s)
if (s->initialized) {
sdl_lock (s, "sdl_close");
s->exit = 1;
+#if NEW_AUDIO
+ sdl_unlock (s, "sdl_close");
+#else
sdl_unlock_and_post (s, "sdl_close");
+#endif
SDL_PauseAudio (1);
SDL_CloseAudio ();
s->initialized = 0;
}
}
+#if NEW_AUDIO
+
+static void sdl_callback (void *opaque, Uint8 *buf, int len)
+{
+#if DEBUG
+ int64_t now;
+#endif
+ SDLAudioState *s = &glob_sdl;
+
+ if (s->exit) {
+ return;
+ }
+
+ sdl_lock (s, "sdl_callback");
+#if DEBUG
+ if (s->count > 0) {
+ now = qemu_get_clock(vm_clock);
+ if (start_time == 0)
+ start_time = now;
+ now = now - start_time;
+ D( "R %6.3f: pos:%5d count:%5d len:%5d\n", now/1e9, s->pos, s->count, len );
+ }
+#endif
+ while (len > 0) {
+ int avail = audio_MIN( AUDIO_BUFFER_SIZE - s->pos, s->count );
+
+ if (avail == 0)
+ break;
+
+ if (avail > len)
+ avail = len;
+
+ memcpy( buf, s->data + s->pos, avail );
+ buf += avail;
+ len -= avail;
+
+ s->count -= avail;
+ s->pos += avail;
+ if (s->pos == AUDIO_BUFFER_SIZE)
+ s->pos = 0;
+ }
+ sdl_unlock (s, "sdl_callback");
+}
+
+#else /* !NEW_AUDIO */
static void sdl_callback (void *opaque, Uint8 *buf, int len)
{
SDLVoiceOut *sdl = opaque;
@@ -255,12 +340,69 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
}
/* dolog ("done len=%d\n", len); */
}
+#endif /* !NEW_AUDIO */
static int sdl_write_out (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
+#if NEW_AUDIO
+
+static int sdl_run_out (HWVoiceOut *hw)
+{
+ SDLAudioState *s = &glob_sdl;
+ int live, avail, end, total;
+
+ if (sdl_lock (s, "sdl_run_out")) {
+ return 0;
+ }
+ avail = AUDIO_BUFFER_SIZE - s->count;
+ end = s->pos + s->count;
+ if (end >= AUDIO_BUFFER_SIZE)
+ end -= AUDIO_BUFFER_SIZE;
+ sdl_unlock (s, "sdl_run_out");
+
+ live = audio_pcm_hw_get_live_out (hw);
+
+ total = 0;
+ while (live > 0) {
+ int bytes = audio_MIN(AUDIO_BUFFER_SIZE - end, avail);
+ int samples = bytes >> hw->info.shift;
+ int hwsamples = audio_MIN(hw->samples - hw->rpos, live);
+ uint8_t* dst = s->data + end;
+ st_sample_t* src = hw->mix_buf + hw->rpos;
+
+ if (samples == 0)
+ break;
+
+ if (samples > hwsamples) {
+ samples = hwsamples;
+ bytes = hwsamples << hw->info.shift;
+ }
+
+ hw->clip (dst, src, samples);
+ hw->rpos += samples;
+ if (hw->rpos == hw->samples)
+ hw->rpos = 0;
+
+ live -= samples;
+ avail -= bytes;
+ end += bytes;
+ if (end == AUDIO_BUFFER_SIZE)
+ end = 0;
+
+ total += bytes;
+ }
+
+ sdl_lock (s, "sdl_run_out");
+ s->count += total;
+ sdl_unlock (s, "sdl_run_out");
+
+ return total >> hw->info.shift;
+}
+
+#else /* !NEW_AUDIO */
static int sdl_run_out (HWVoiceOut *hw)
{
int decr, live;
@@ -294,6 +436,7 @@ static int sdl_run_out (HWVoiceOut *hw)
}
return decr;
}
+#endif /* !NEW_AUDIO */
static void sdl_fini_out (HWVoiceOut *hw)
{
@@ -302,6 +445,54 @@ static void sdl_fini_out (HWVoiceOut *hw)
sdl_close (&glob_sdl);
}
+#if DEBUG
+
+typedef struct { int value; const char* name; } MatchRec;
+typedef const MatchRec* Match;
+
+static const char*
+match_find( Match matches, int value, char* temp )
+{
+ int nn;
+ for ( nn = 0; matches[nn].name != NULL; nn++ ) {
+ if ( matches[nn].value == value )
+ return matches[nn].name;
+ }
+ sprintf( temp, "(%d?)", value );
+ return temp;
+}
+
+static const MatchRec sdl_audio_format_matches[] = {
+ { AUDIO_U8, "AUDIO_U8" },
+ { AUDIO_S8, "AUDIO_S8" },
+ { AUDIO_U16, "AUDIO_U16LE" },
+ { AUDIO_S16, "AUDIO_S16LE" },
+ { AUDIO_U16MSB, "AUDIO_U16BE" },
+ { AUDIO_S16MSB, "AUDIO_S16BE" },
+ { 0, NULL }
+};
+
+static void
+print_sdl_audiospec( SDL_AudioSpec* spec, const char* prefix )
+{
+ char temp[64];
+ const char* fmt;
+
+ if (!prefix)
+ prefix = "";
+
+ printf( "%s audiospec [freq:%d format:%s channels:%d samples:%d bytes:%d",
+ prefix,
+ spec->freq,
+ match_find( sdl_audio_format_matches, spec->format, temp ),
+ spec->channels,
+ spec->samples,
+ spec->size
+ );
+ printf( "]\n" );
+}
+#endif
+
static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
{
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
@@ -322,26 +513,38 @@ static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as)
req.callback = sdl_callback;
req.userdata = sdl;
+#if DEBUG
+ print_sdl_audiospec( &req, "wanted" );
+#endif
+
if (sdl_open (&req, &obt)) {
return -1;
}
+#if DEBUG
+ print_sdl_audiospec( &req, "obtained" );
+#endif
+
err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess);
if (err) {
sdl_close (s);
return -1;
}
- obt_as.freq = obt.freq;
- obt_as.nchannels = obt.channels;
- obt_as.fmt = effective_fmt;
+ obt_as.freq = obt.freq;
+ obt_as.nchannels = obt.channels;
+ obt_as.fmt = effective_fmt;
obt_as.endianness = endianess;
audio_pcm_init_info (&hw->info, &obt_as);
hw->samples = obt.samples;
+#if DEBUG
+ start_time = qemu_get_clock(vm_clock);
+#endif
+
s->initialized = 1;
- s->exit = 0;
+ s->exit = 0;
SDL_PauseAudio (0);
return 0;
}
@@ -377,7 +580,7 @@ static void *sdl_audio_init (void)
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
-
+#if !NEW_AUDIO
s->sem = SDL_CreateSemaphore (0);
if (!s->sem) {
sdl_logerr ("Failed to create SDL semaphore\n");
@@ -385,7 +588,7 @@ static void *sdl_audio_init (void)
SDL_QuitSubSystem (SDL_INIT_AUDIO);
return NULL;
}
-
+#endif
return s;
}
@@ -393,8 +596,16 @@ static void sdl_audio_fini (void *opaque)
{
SDLAudioState *s = opaque;
sdl_close (s);
- SDL_DestroySemaphore (s->sem);
- SDL_DestroyMutex (s->mutex);
+#if !NEW_AUDIO
+ if (s->sem) {
+ SDL_DestroySemaphore (s->sem);
+ s->sem = NULL;
+ }
+#endif
+ if (s->mutex) {
+ SDL_DestroyMutex (s->mutex);
+ s->mutex = NULL;
+ }
SDL_QuitSubSystem (SDL_INIT_AUDIO);
}
@@ -420,7 +631,7 @@ static struct audio_pcm_ops sdl_pcm_ops = {
struct audio_driver sdl_audio_driver = {
INIT_FIELD (name = ) "sdl",
- INIT_FIELD (descr = ) "SDL http://www.libsdl.org",
+ INIT_FIELD (descr = ) "SDL audio (www.libsdl.org)",
INIT_FIELD (options = ) sdl_options,
INIT_FIELD (init = ) sdl_audio_init,
INIT_FIELD (fini = ) sdl_audio_fini,
diff --git a/audio/wavaudio.c b/audio/wavaudio.c
index c359fc4..7d4fed1 100644
--- a/audio/wavaudio.c
+++ b/audio/wavaudio.c
@@ -1,6 +1,7 @@
/*
* QEMU WAV audio driver
*
+ * Copyright (c) 2007 The Android Open Source Project
* Copyright (c) 2004-2005 Vassili Karpov (malc)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -26,6 +27,10 @@
#define AUDIO_CAP "wav"
#include "audio_int.h"
+#define WAV_AUDIO_IN 1
+
+/** VOICE OUT (Saving to a .WAV file)
+ **/
typedef struct WAVVoiceOut {
HWVoiceOut hw;
QEMUFile *f;
@@ -37,7 +42,7 @@ typedef struct WAVVoiceOut {
static struct {
audsettings_t settings;
const char *wav_path;
-} conf = {
+} conf_out = {
{
44100,
2,
@@ -46,7 +51,7 @@ static struct {
"qemu.wav"
};
-static int wav_run_out (HWVoiceOut *hw)
+static int wav_out_run (HWVoiceOut *hw)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
int rpos, live, decr, samples;
@@ -91,7 +96,7 @@ static int wav_run_out (HWVoiceOut *hw)
return decr;
}
-static int wav_write_out (SWVoiceOut *sw, void *buf, int len)
+static int wav_out_write (SWVoiceOut *sw, void *buf, int len)
{
return audio_pcm_sw_write (sw, buf, len);
}
@@ -106,7 +111,7 @@ static void le_store (uint8_t *buf, uint32_t val, int len)
}
}
-static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
+static int wav_out_init (HWVoiceOut *hw, audsettings_t *as)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
int bits16 = 0, stereo = 0;
@@ -116,7 +121,7 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04,
0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00
};
- audsettings_t wav_as = conf.settings;
+ audsettings_t wav_as = conf_out.settings;
(void) as;
@@ -151,10 +156,10 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4);
le_store (hdr + 32, 1 << (bits16 + stereo), 2);
- wav->f = fopen (conf.wav_path, "wb");
+ wav->f = fopen (conf_out.wav_path, "wb");
if (!wav->f) {
dolog ("Failed to open wave file `%s'\nReason: %s\n",
- conf.wav_path, strerror (errno));
+ conf_out.wav_path, strerror (errno));
qemu_free (wav->pcm_buf);
wav->pcm_buf = NULL;
return -1;
@@ -164,7 +169,7 @@ static int wav_init_out (HWVoiceOut *hw, audsettings_t *as)
return 0;
}
-static void wav_fini_out (HWVoiceOut *hw)
+static void wav_out_fini (HWVoiceOut *hw)
{
WAVVoiceOut *wav = (WAVVoiceOut *) hw;
uint8_t rlen[4];
@@ -192,16 +197,212 @@ static void wav_fini_out (HWVoiceOut *hw)
wav->pcm_buf = NULL;
}
-static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)
+static int wav_out_ctl (HWVoiceOut *hw, int cmd, ...)
+{
+ (void) hw;
+ (void) cmd;
+ return 0;
+}
+
+
+#if WAV_AUDIO_IN
+
+/** WAV IN (Reading from a .WAV file)
+ **/
+
+ static struct {
+ const char *wav_path;
+} conf_in = {
+ "qemu.wav"
+};
+
+typedef struct WAVVoiceIn {
+ HWVoiceIn hw;
+ QEMUFile* f;
+ int64_t old_ticks;
+ void* pcm_buf;
+ int total_samples;
+ int total_size;
+} WAVVoiceIn;
+
+
+static int
+le_read( const uint8_t* p, int size ) {
+ int shift = 0;
+ int result = 0;
+ for ( ; size > 0; size-- ) {
+ result = result | (p[0] << shift);
+ p += 1;
+ shift += 8;
+ }
+ return result;
+}
+
+static int
+wav_in_init (HWVoiceIn *hw, audsettings_t *as)
+{
+ WAVVoiceIn* wav = (WAVVoiceIn *) hw;
+ const char* path = conf_in.wav_path;
+ uint8_t hdr[44];
+ audsettings_t wav_as = *as;
+ int nchannels, freq, format, bits;
+
+ wav->f = fopen (path, "rb");
+ if (wav->f == NULL) {
+ dolog("Failed to open wave file '%s'\nReason: %s\n", path,
+ strerror(errno));
+ return -1;
+ }
+
+ if (qemu_get_buffer (wav->f, hdr, sizeof(hdr)) != (int)sizeof(hdr)) {
+ dolog("File '%s' to be a .wav file\n", path);
+ goto Fail;
+ }
+
+ /* check that this is a wave file */
+ if ( hdr[0] != 'R' || hdr[1] != 'I' || hdr[2] != 'F' || hdr[3] != 'F' ||
+ hdr[8] != 'W' || hdr[9] != 'A' || hdr[10]!= 'V' || hdr[11]!= 'E' ||
+ hdr[12]!= 'f' || hdr[13]!= 'm' || hdr[14]!= 't' || hdr[15]!= ' ' ||
+ hdr[40]!= 'd' || hdr[41]!= 'a' || hdr[42]!= 't' || hdr[43]!= 'a') {
+ dolog("File '%s' is not a valid .wav file\n", path);
+ goto Fail;
+ }
+
+ nchannels = le_read( hdr+22, 2 );
+ freq = le_read( hdr+24, 4 );
+ format = le_read( hdr+32, 2 );
+ bits = le_read( hdr+34, 2 );
+
+ wav->total_size = le_read( hdr+40, 4 );
+
+ /* perform some sainty checks */
+ switch (nchannels) {
+ case 1:
+ case 2: break;
+ default:
+ dolog("unsupported number of channels (%d) in '%s'\n",
+ nchannels, path);
+ goto Fail;
+ }
+
+ switch (format) {
+ case 1:
+ case 2:
+ case 4: break;
+ default:
+ dolog("unsupported bytes per sample (%d) in '%s'\n",
+ format, path);
+ goto Fail;
+ }
+
+ if (format*8/nchannels != bits) {
+ dolog("invalid bits per sample (%d, expected %d) in '%s'\n",
+ bits, format*8/nchannels, path);
+ goto Fail;
+ }
+
+ wav_as.nchannels = nchannels;
+ wav_as.fmt = (bits == 8) ? AUD_FMT_U8 : AUD_FMT_S16;
+ wav_as.freq = freq;
+ wav_as.endianness = 0; /* always little endian */
+
+ audio_pcm_init_info (&hw->info, &wav_as);
+
+ hw->samples = 1024;
+ wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift);
+ if (!wav->pcm_buf) {
+ goto Fail;
+ }
+ return 0;
+
+Fail:
+ fclose (wav->f);
+ wav->f = NULL;
+ return -1;
+}
+
+
+static void wav_in_fini (HWVoiceIn *hw)
+{
+ WAVVoiceIn *wav = (WAVVoiceIn *) hw;
+
+ if (!wav->f) {
+ return;
+ }
+
+ fclose (wav->f);
+ wav->f = NULL;
+
+ qemu_free (wav->pcm_buf);
+ wav->pcm_buf = NULL;
+}
+
+static int wav_in_run (HWVoiceIn *hw)
+{
+ WAVVoiceIn* wav = (WAVVoiceIn *) hw;
+ int wpos, live, decr, samples;
+ uint8_t* src;
+ st_sample_t* dst;
+
+ int64_t now = qemu_get_clock (vm_clock);
+ int64_t ticks = now - wav->old_ticks;
+ int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec;
+
+ if (bytes > INT_MAX) {
+ samples = INT_MAX >> hw->info.shift;
+ }
+ else {
+ samples = bytes >> hw->info.shift;
+ }
+
+ live = audio_pcm_hw_get_live_in (hw);
+ if (!live) {
+ return 0;
+ }
+
+ wav->old_ticks = now;
+
+ decr = audio_MIN (live, samples);
+ samples = decr;
+ wpos = hw->wpos;
+ while (samples) {
+ int left_till_end_samples = hw->samples - wpos;
+ int convert_samples = audio_MIN (samples, left_till_end_samples);
+
+ dst = hw->conv_buf + wpos;
+ src = advance (wav->pcm_buf, wpos << hw->info.shift);
+
+ qemu_get_buffer (wav->f, src, convert_samples << hw->info.shift);
+ memcpy (dst, src, convert_samples << hw->info.shift);
+
+ wpos = (wpos + convert_samples) % hw->samples;
+ samples -= convert_samples;
+ wav->total_samples += convert_samples;
+ }
+
+ hw->wpos = wpos;
+ return decr;
+}
+
+static int wav_in_read (SWVoiceIn *sw, void *buf, int len)
+{
+ return audio_pcm_sw_read (sw, buf, len);
+}
+
+static int wav_in_ctl (HWVoiceIn *hw, int cmd, ...)
{
(void) hw;
(void) cmd;
return 0;
}
+#endif /* WAV_AUDIO_IN */
+
+/** COMMON CODE
+ **/
static void *wav_audio_init (void)
{
- return &conf;
+ return &conf_out;
}
static void wav_audio_fini (void *opaque)
@@ -211,45 +412,65 @@ static void wav_audio_fini (void *opaque)
}
struct audio_option wav_options[] = {
- {"FREQUENCY", AUD_OPT_INT, &conf.settings.freq,
+ {"FREQUENCY", AUD_OPT_INT, &conf_out.settings.freq,
"Frequency", NULL, 0},
- {"FORMAT", AUD_OPT_FMT, &conf.settings.fmt,
+ {"FORMAT", AUD_OPT_FMT, &conf_out.settings.fmt,
"Format", NULL, 0},
- {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels,
+ {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf_out.settings.nchannels,
"Number of channels (1 - mono, 2 - stereo)", NULL, 0},
- {"PATH", AUD_OPT_STR, &conf.wav_path,
- "Path to wave file", NULL, 0},
+ {"PATH", AUD_OPT_STR, &conf_out.wav_path,
+ "Path to output .wav file", NULL, 0},
+
+#if WAV_AUDIO_IN
+ {"IN_PATH", AUD_OPT_STR, &conf_in.wav_path,
+ "Path to input .wav file", NULL, 0},
+#endif
{NULL, 0, NULL, NULL, NULL, 0}
};
struct audio_pcm_ops wav_pcm_ops = {
- wav_init_out,
- wav_fini_out,
- wav_run_out,
- wav_write_out,
- wav_ctl_out,
-
+ wav_out_init,
+ wav_out_fini,
+ wav_out_run,
+ wav_out_write,
+ wav_out_ctl,
+
+#if WAV_AUDIO_IN
+ wav_in_init,
+ wav_in_fini,
+ wav_in_run,
+ wav_in_read,
+ wav_in_ctl
+#else
NULL,
NULL,
NULL,
NULL,
NULL
+#endif
};
struct audio_driver wav_audio_driver = {
INIT_FIELD (name = ) "wav",
INIT_FIELD (descr = )
- "WAV renderer http://wikipedia.org/wiki/WAV",
+ "WAV file read/write (www.wikipedia.org/wiki/WAV)",
INIT_FIELD (options = ) wav_options,
INIT_FIELD (init = ) wav_audio_init,
INIT_FIELD (fini = ) wav_audio_fini,
INIT_FIELD (pcm_ops = ) &wav_pcm_ops,
INIT_FIELD (can_be_default = ) 0,
+#if WAV_AUDIO_IN
+ INIT_FIELD (max_voices_in = ) 1,
+ INIT_FIELD (max_voices_out = ) 1,
+ INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut),
+ INIT_FIELD (voice_size_in = ) sizeof (WAVVoiceIn)
+#else
INIT_FIELD (max_voices_out = ) 1,
INIT_FIELD (max_voices_in = ) 0,
INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut),
INIT_FIELD (voice_size_in = ) 0
+#endif
};
diff --git a/audio/wavcapture.c b/audio/wavcapture.c
index 0f6f7bf..748b580 100644
--- a/audio/wavcapture.c
+++ b/audio/wavcapture.c
@@ -103,8 +103,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
}
if (nchannels != 1 && nchannels != 2) {
- term_printf ("incorrect channel count %d, must be 1 or 2\n",
- nchannels);
+ term_printf ("incorrect channel count %d, must be 1 or 2\n", bits);
return -1;
}
@@ -122,8 +121,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq,
wav = qemu_mallocz (sizeof (*wav));
if (!wav) {
- term_printf ("Could not allocate memory for wav capture (%zu bytes)",
- sizeof (*wav));
+ AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav));
return -1;
}
diff --git a/audio/winaudio.c b/audio/winaudio.c
new file mode 100644
index 0000000..63cd351
--- /dev/null
+++ b/audio/winaudio.c
@@ -0,0 +1,668 @@
+/*
+ * QEMU "simple" Windows audio driver
+ *
+ * Copyright (c) 2007 The Android Open Source Project
+ *
+ * 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 WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmsystem.h>
+
+#define AUDIO_CAP "winaudio"
+#include "audio_int.h"
+
+/* define DEBUG to 1 to dump audio debugging info at runtime to stderr */
+#define DEBUG 0
+
+#if 1
+# define D_ACTIVE 1
+#else
+# define D_ACTIVE DEBUG
+#endif
+
+#if DEBUG
+# define D(...) do{ if (D_ACTIVE) printf(__VA_ARGS__); } while(0)
+#else
+# define D(...) ((void)0)
+#endif
+
+static struct {
+ int nb_samples;
+} conf = {
+ 1024
+};
+
+#if DEBUG
+int64_t start_time;
+int64_t last_time;
+#endif
+
+#define NUM_OUT_BUFFERS 8 /* must be at least 2 */
+
+/** COMMON UTILITIES
+ **/
+
+#if DEBUG
+static void
+dump_mmerror( const char* func, MMRESULT error )
+{
+ const char* reason = NULL;
+
+ fprintf(stderr, "%s returned error: ", func);
+ switch (error) {
+ case MMSYSERR_ALLOCATED: reason="specified resource is already allocated"; break;
+ case MMSYSERR_BADDEVICEID: reason="bad device id"; break;
+ case MMSYSERR_NODRIVER: reason="no driver is present"; break;
+ case MMSYSERR_NOMEM: reason="unable to allocate or lock memory"; break;
+ case WAVERR_BADFORMAT: reason="unsupported waveform-audio format"; break;
+ case WAVERR_SYNC: reason="device is synchronous"; break;
+ default:
+ fprintf(stderr, "unknown(%d)\n", error);
+ }
+ if (reason)
+ fprintf(stderr, "%s\n", reason);
+}
+#else
+# define dump_mmerror(func,error) ((void)0)
+#endif
+
+
+/** AUDIO OUT
+ **/
+
+typedef struct WinAudioOut {
+ HWVoiceOut hw;
+ HWAVEOUT waveout;
+ int silence;
+ CRITICAL_SECTION lock;
+ unsigned char* buffer_bytes;
+ WAVEHDR buffers[ NUM_OUT_BUFFERS ];
+ int write_index; /* starting first writable buffer */
+ int write_count; /* available writable buffers count */
+ int write_pos; /* position in current writable buffer */
+ int write_size; /* size in bytes of each buffer */
+} WinAudioOut;
+
+/* The Win32 callback that is called when a buffer has finished playing */
+static void CALLBACK
+winaudio_out_buffer_done (HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
+ DWORD dwParam1, DWORD dwParam2)
+{
+ WinAudioOut* s = (WinAudioOut*) dwInstance;
+
+ /* Only service "buffer done playing" messages */
+ if ( uMsg != WOM_DONE )
+ return;
+
+ /* Signal that we are done playing a buffer */
+ EnterCriticalSection( &s->lock );
+ if (s->write_count < NUM_OUT_BUFFERS)
+ s->write_count += 1;
+ LeaveCriticalSection( &s->lock );
+}
+
+static int
+winaudio_out_write (SWVoiceOut *sw, void *buf, int len)
+{
+ return audio_pcm_sw_write (sw, buf, len);
+}
+
+static void
+winaudio_out_fini (HWVoiceOut *hw)
+{
+ WinAudioOut* s = (WinAudioOut*) hw;
+ int i;
+
+ if (s->waveout) {
+ waveOutReset(s->waveout);
+ s->waveout = 0;
+ }
+
+ for ( i=0; i<NUM_OUT_BUFFERS; ++i ) {
+ if ( s->buffers[i].dwUser != 0xFFFF ) {
+ waveOutUnprepareHeader(
+ s->waveout, &s->buffers[i], sizeof(s->buffers[i]) );
+ s->buffers[i].dwUser = 0xFFFF;
+ }
+ }
+
+ if (s->buffer_bytes != NULL) {
+ qemu_free(s->buffer_bytes);
+ s->buffer_bytes = NULL;
+ }
+
+ if (s->waveout) {
+ waveOutClose(s->waveout);
+ s->waveout = NULL;
+ }
+}
+
+
+static int
+winaudio_out_init (HWVoiceOut *hw, audsettings_t *as)
+{
+ WinAudioOut* s = (WinAudioOut*) hw;
+ MMRESULT result;
+ WAVEFORMATEX format;
+ int shift, i, samples_size;
+
+ s->waveout = NULL;
+ InitializeCriticalSection( &s->lock );
+ for (i = 0; i < NUM_OUT_BUFFERS; i++) {
+ s->buffers[i].dwUser = 0xFFFF;
+ }
+ s->buffer_bytes = NULL;
+
+ /* compute desired wave output format */
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ format.nChannels = as->nchannels;
+ format.nSamplesPerSec = as->freq;
+ format.nAvgBytesPerSec = as->freq*as->nchannels;
+
+ s->silence = 0;
+
+ switch (as->fmt) {
+ case AUD_FMT_S8: shift = 0; break;
+ case AUD_FMT_U8: shift = 0; s->silence = 0x80; break;
+ case AUD_FMT_S16: shift = 1; break;
+ case AUD_FMT_U16: shift = 1; s->silence = 0x8000; break;
+ default:
+ fprintf(stderr, "qemu: winaudio: Bad output audio format: %d\n",
+ as->fmt);
+ return -1;
+ }
+
+ format.nAvgBytesPerSec = (format.nSamplesPerSec & format.nChannels) << shift;
+ format.nBlockAlign = format.nChannels << shift;
+ format.wBitsPerSample = 8 << shift;
+ format.cbSize = 0;
+
+ /* open the wave out device */
+ result = waveOutOpen( &s->waveout, WAVE_MAPPER, &format,
+ (DWORD_PTR)winaudio_out_buffer_done, (DWORD_PTR) hw,
+ CALLBACK_FUNCTION);
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror( "qemu: winaudio: waveOutOpen()", result);
+ return -1;
+ }
+
+ samples_size = format.nBlockAlign * conf.nb_samples;
+ s->buffer_bytes = qemu_malloc( NUM_OUT_BUFFERS * samples_size );
+ if (s->buffer_bytes == NULL) {
+ waveOutClose( s->waveout );
+ s->waveout = NULL;
+ fprintf(stderr, "not enough memory for Windows audio buffers\n");
+ return -1;
+ }
+
+ for (i = 0; i < NUM_OUT_BUFFERS; i++) {
+ memset( &s->buffers[i], 0, sizeof(s->buffers[i]) );
+ s->buffers[i].lpData = (LPSTR)(s->buffer_bytes + i*samples_size);
+ s->buffers[i].dwBufferLength = samples_size;
+ s->buffers[i].dwFlags = WHDR_DONE;
+
+ result = waveOutPrepareHeader( s->waveout, &s->buffers[i],
+ sizeof(s->buffers[i]) );
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror("waveOutPrepareHeader()", result);
+ return -1;
+ }
+ }
+
+#if DEBUG
+ /* Check the sound device we retrieved */
+ {
+ WAVEOUTCAPS caps;
+
+ result = waveOutGetDevCaps((UINT) s->waveout, &caps, sizeof(caps));
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror("waveOutGetDevCaps()", result);
+ } else
+ printf("Audio out device: %s\n", caps.szPname);
+ }
+#endif
+
+ audio_pcm_init_info (&hw->info, as);
+ hw->samples = conf.nb_samples*2;
+
+ s->write_index = 0;
+ s->write_count = NUM_OUT_BUFFERS;
+ s->write_pos = 0;
+ s->write_size = samples_size;
+ return 0;
+}
+
+
+static int
+winaudio_out_run (HWVoiceOut *hw)
+{
+ WinAudioOut* s = (WinAudioOut*) hw;
+ int played = 0;
+ int has_buffer;
+ int live = audio_pcm_hw_get_live_out (hw);
+
+ if (!live) {
+ return 0;
+ }
+
+ EnterCriticalSection( &s->lock );
+ has_buffer = (s->write_count > 0);
+ LeaveCriticalSection( &s->lock );
+
+ if (has_buffer) {
+ while (live > 0) {
+ WAVEHDR* wav_buffer = s->buffers + s->write_index;
+ int wav_bytes = (s->write_size - s->write_pos);
+ int wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live);
+ int hw_samples = audio_MIN(hw->samples - hw->rpos, live);
+ st_sample_t* src = hw->mix_buf + hw->rpos;
+ uint8_t* dst = (uint8_t*)wav_buffer->lpData + s->write_pos;
+
+ if (wav_samples > hw_samples) {
+ wav_samples = hw_samples;
+ }
+
+ wav_bytes = wav_samples << hw->info.shift;
+
+ //D("run_out: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d rpos:%d hwsamples:%d\n", s->write_index,
+ // s->write_pos, s->write_size, wav_samples, wav_bytes, live, hw->rpos, hw->samples);
+ hw->clip (dst, src, wav_samples);
+ hw->rpos += wav_samples;
+ if (hw->rpos >= hw->samples)
+ hw->rpos -= hw->samples;
+
+ live -= wav_samples;
+ played += wav_samples;
+ s->write_pos += wav_bytes;
+ if (s->write_pos == s->write_size) {
+#if xxDEBUG
+ int64_t now = qemu_get_clock(vm_clock) - start_time;
+ int64_t diff = now - last_time;
+
+ D("run_out: (%7.3f:%7d):waveOutWrite buffer:%d\n",
+ now/1e9, (now-last_time)/1e9, s->write_index);
+ last_time = now;
+#endif
+ waveOutWrite( s->waveout, wav_buffer, sizeof(*wav_buffer) );
+ s->write_pos = 0;
+ s->write_index += 1;
+ if (s->write_index == NUM_OUT_BUFFERS)
+ s->write_index = 0;
+
+ EnterCriticalSection( &s->lock );
+ if (--s->write_count == 0) {
+ live = 0;
+ }
+ LeaveCriticalSection( &s->lock );
+ }
+ }
+
+ }
+ return played;
+}
+
+static int
+winaudio_out_ctl (HWVoiceOut *hw, int cmd, ...)
+{
+ WinAudioOut* s = (WinAudioOut*) hw;
+
+ switch (cmd) {
+ case VOICE_ENABLE:
+ waveOutRestart( s->waveout );
+ break;
+
+ case VOICE_DISABLE:
+ waveOutPause( s->waveout );
+ break;
+ }
+ return 0;
+}
+
+/** AUDIO IN
+ **/
+
+#define NUM_IN_BUFFERS 2
+
+typedef struct WinAudioIn {
+ HWVoiceIn hw;
+ HWAVEIN wavein;
+ CRITICAL_SECTION lock;
+ unsigned char* buffer_bytes;
+ WAVEHDR buffers[ NUM_IN_BUFFERS ];
+ int read_index;
+ int read_count;
+ int read_pos;
+ int read_size;
+} WinAudioIn;
+
+/* The Win32 callback that is called when a buffer has finished playing */
+static void CALLBACK
+winaudio_in_buffer_done (HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
+ DWORD dwParam1, DWORD dwParam2)
+{
+ WinAudioIn* s = (WinAudioIn*) dwInstance;
+
+ /* Only service "buffer done playing" messages */
+ if ( uMsg != WIM_DATA )
+ return;
+
+ /* Signal that we are done playing a buffer */
+ EnterCriticalSection( &s->lock );
+ if (s->read_count < NUM_IN_BUFFERS)
+ s->read_count += 1;
+ //D(".%c",s->read_count + '0'); fflush(stdout);
+ LeaveCriticalSection( &s->lock );
+}
+
+static void
+winaudio_in_fini (HWVoiceIn *hw)
+{
+ WinAudioIn* s = (WinAudioIn*) hw;
+ int i;
+
+ if (s->wavein) {
+ waveInReset(s->wavein);
+ s->wavein = 0;
+ }
+
+ for ( i=0; i<NUM_OUT_BUFFERS; ++i ) {
+ if ( s->buffers[i].dwUser != 0xFFFF ) {
+ waveInUnprepareHeader(
+ s->wavein, &s->buffers[i], sizeof(s->buffers[i]) );
+ s->buffers[i].dwUser = 0xFFFF;
+ }
+ }
+
+ if (s->buffer_bytes != NULL) {
+ qemu_free(s->buffer_bytes);
+ s->buffer_bytes = NULL;
+ }
+
+ if (s->wavein) {
+ waveInClose(s->wavein);
+ s->wavein = NULL;
+ }
+}
+
+
+static int
+winaudio_in_init (HWVoiceIn *hw, audsettings_t *as)
+{
+ WinAudioIn* s = (WinAudioIn*) hw;
+ MMRESULT result;
+ WAVEFORMATEX format;
+ int shift, i, samples_size;
+
+ s->wavein = NULL;
+ InitializeCriticalSection( &s->lock );
+ for (i = 0; i < NUM_OUT_BUFFERS; i++) {
+ s->buffers[i].dwUser = 0xFFFF;
+ }
+ s->buffer_bytes = NULL;
+
+ /* compute desired wave input format */
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ format.nChannels = as->nchannels;
+ format.nSamplesPerSec = as->freq;
+ format.nAvgBytesPerSec = as->freq*as->nchannels;
+
+ switch (as->fmt) {
+ case AUD_FMT_S8: shift = 0; break;
+ case AUD_FMT_U8: shift = 0; break;
+ case AUD_FMT_S16: shift = 1; break;
+ case AUD_FMT_U16: shift = 1; break;
+ default:
+ fprintf(stderr, "qemu: winaudio: Bad input audio format: %d\n",
+ as->fmt);
+ return -1;
+ }
+
+ format.nAvgBytesPerSec = (format.nSamplesPerSec * format.nChannels) << shift;
+ format.nBlockAlign = format.nChannels << shift;
+ format.wBitsPerSample = 8 << shift;
+ format.cbSize = 0;
+
+ /* open the wave in device */
+ result = waveInOpen( &s->wavein, WAVE_MAPPER, &format,
+ (DWORD_PTR)winaudio_in_buffer_done, (DWORD_PTR) hw,
+ CALLBACK_FUNCTION);
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror( "qemu: winaudio: waveInOpen()", result);
+ return -1;
+ }
+
+ samples_size = format.nBlockAlign * conf.nb_samples;
+ s->buffer_bytes = qemu_malloc( NUM_IN_BUFFERS * samples_size );
+ if (s->buffer_bytes == NULL) {
+ waveInClose( s->wavein );
+ s->wavein = NULL;
+ fprintf(stderr, "not enough memory for Windows audio buffers\n");
+ return -1;
+ }
+
+ for (i = 0; i < NUM_IN_BUFFERS; i++) {
+ memset( &s->buffers[i], 0, sizeof(s->buffers[i]) );
+ s->buffers[i].lpData = (LPSTR)(s->buffer_bytes + i*samples_size);
+ s->buffers[i].dwBufferLength = samples_size;
+ s->buffers[i].dwFlags = WHDR_DONE;
+
+ result = waveInPrepareHeader( s->wavein, &s->buffers[i],
+ sizeof(s->buffers[i]) );
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror("waveInPrepareHeader()", result);
+ return -1;
+ }
+
+ result = waveInAddBuffer( s->wavein, &s->buffers[i],
+ sizeof(s->buffers[i]) );
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror("waveInAddBuffer()", result);
+ return -1;
+ }
+ }
+
+#if DEBUG
+ /* Check the sound device we retrieved */
+ {
+ WAVEINCAPS caps;
+
+ result = waveInGetDevCaps((UINT) s->wavein, &caps, sizeof(caps));
+ if ( result != MMSYSERR_NOERROR ) {
+ dump_mmerror("waveInGetDevCaps()", result);
+ } else
+ printf("Audio in device: %s\n", caps.szPname);
+ }
+#endif
+
+ audio_pcm_init_info (&hw->info, as);
+ hw->samples = conf.nb_samples*2;
+
+ s->read_index = 0;
+ s->read_count = 0;
+ s->read_pos = 0;
+ s->read_size = samples_size;
+ return 0;
+}
+
+
+/* report the number of captured samples to the audio subsystem */
+static int
+winaudio_in_run (HWVoiceIn *hw)
+{
+ WinAudioIn* s = (WinAudioIn*) hw;
+ int captured = 0;
+ int has_buffer;
+ int live = hw->samples - hw->total_samples_captured;
+
+ if (!live) {
+#if 0
+ static int counter;
+ if (++counter == 100) {
+ D("0"); fflush(stdout);
+ counter = 0;
+ }
+#endif
+ return 0;
+ }
+
+ EnterCriticalSection( &s->lock );
+ has_buffer = (s->read_count > 0);
+ LeaveCriticalSection( &s->lock );
+
+ if (has_buffer > 0) {
+ while (live > 0) {
+ WAVEHDR* wav_buffer = s->buffers + s->read_index;
+ int wav_bytes = (s->read_size - s->read_pos);
+ int wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live);
+ int hw_samples = audio_MIN(hw->samples - hw->wpos, live);
+ st_sample_t* dst = hw->conv_buf + hw->wpos;
+ uint8_t* src = (uint8_t*)wav_buffer->lpData + s->read_pos;
+
+ if (wav_samples > hw_samples) {
+ wav_samples = hw_samples;
+ }
+
+ wav_bytes = wav_samples << hw->info.shift;
+
+ D("%s: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d wpos:%d hwsamples:%d\n",
+ __FUNCTION__, s->read_index, s->read_pos, s->read_size, wav_samples, wav_bytes, live,
+ hw->wpos, hw->samples);
+
+ hw->conv(dst, src, wav_samples, &nominal_volume);
+
+ hw->wpos += wav_samples;
+ if (hw->wpos >= hw->samples)
+ hw->wpos -= hw->samples;
+
+ live -= wav_samples;
+ captured += wav_samples;
+ s->read_pos += wav_bytes;
+ if (s->read_pos == s->read_size) {
+ s->read_pos = 0;
+ s->read_index += 1;
+ if (s->read_index == NUM_IN_BUFFERS)
+ s->read_index = 0;
+
+ waveInAddBuffer( s->wavein, wav_buffer, sizeof(*wav_buffer) );
+
+ EnterCriticalSection( &s->lock );
+ if (--s->read_count == 0) {
+ live = 0;
+ }
+ LeaveCriticalSection( &s->lock );
+ }
+ }
+ }
+ return captured;
+}
+
+
+static int
+winaudio_in_read (SWVoiceIn *sw, void *buf, int len)
+{
+ int ret = audio_pcm_sw_read (sw, buf, len);
+ if (ret > 0)
+ D("%s: (%d) returned %d\n", __FUNCTION__, len, ret);
+ return ret;
+}
+
+
+static int
+winaudio_in_ctl (HWVoiceIn *hw, int cmd, ...)
+{
+ WinAudioIn* s = (WinAudioIn*) hw;
+
+ switch (cmd) {
+ case VOICE_ENABLE:
+ D("%s: enable audio in\n", __FUNCTION__);
+ waveInStart( s->wavein );
+ break;
+
+ case VOICE_DISABLE:
+ D("%s: disable audio in\n", __FUNCTION__);
+ waveInStop( s->wavein );
+ break;
+ }
+ return 0;
+}
+
+/** AUDIO STATE
+ **/
+
+typedef struct WinAudioState {
+ int dummy;
+} WinAudioState;
+
+static WinAudioState g_winaudio;
+
+static void*
+winaudio_init(void)
+{
+ WinAudioState* s = &g_winaudio;
+
+#if DEBUG
+ start_time = qemu_get_clock(vm_clock);
+ last_time = 0;
+#endif
+
+ return s;
+}
+
+
+static void
+winaudio_fini (void *opaque)
+{
+}
+
+static struct audio_option winaudio_options[] = {
+ {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
+ "Size of Windows audio buffer in samples", NULL, 0},
+ {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+static struct audio_pcm_ops winaudio_pcm_ops = {
+ winaudio_out_init,
+ winaudio_out_fini,
+ winaudio_out_run,
+ winaudio_out_write,
+ winaudio_out_ctl,
+
+ winaudio_in_init,
+ winaudio_in_fini,
+ winaudio_in_run,
+ winaudio_in_read,
+ winaudio_in_ctl
+};
+
+struct audio_driver win_audio_driver = {
+ INIT_FIELD (name = ) "winaudio",
+ INIT_FIELD (descr = ) "Windows wave audio",
+ INIT_FIELD (options = ) winaudio_options,
+ INIT_FIELD (init = ) winaudio_init,
+ INIT_FIELD (fini = ) winaudio_fini,
+ INIT_FIELD (pcm_ops = ) &winaudio_pcm_ops,
+ INIT_FIELD (can_be_default = ) 1,
+ INIT_FIELD (max_voices_out = ) 1,
+ INIT_FIELD (max_voices_in = ) 1,
+ INIT_FIELD (voice_size_out = ) sizeof (WinAudioOut),
+ INIT_FIELD (voice_size_in = ) sizeof (WinAudioIn)
+};
diff --git a/block-bochs.c b/block-bochs.c
deleted file mode 100644
index 62317af..0000000
--- a/block-bochs.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Block driver for the various disk image formats used by Bochs
- * Currently only for "growing" type in read-only mode
- *
- * Copyright (c) 2005 Alex Beregszaszi
- *
- * 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 "block_int.h"
-
-/**************************************************************/
-
-#define HEADER_MAGIC "Bochs Virtual HD Image"
-#define HEADER_VERSION 0x00010000
-#define HEADER_SIZE 512
-
-#define REDOLOG_TYPE "Redolog"
-#define GROWING_TYPE "Growing"
-
-// not allocated: 0xffffffff
-
-// always little-endian
-struct bochs_header {
- char magic[32]; // "Bochs Virtual HD Image"
- char type[16]; // "Redolog"
- char subtype[16]; // "Undoable" / "Volatile" / "Growing"
- uint32_t version;
- uint32_t header; // size of header
-
- union {
- struct {
- uint32_t catalog; // num of entries
- uint32_t bitmap; // bitmap size
- uint32_t extent; // extent size
- uint64_t disk; // disk size
- char padding[HEADER_SIZE - 64 - 8 - 20];
- } redolog;
- char padding[HEADER_SIZE - 64 - 8];
- } extra;
-};
-
-typedef struct BDRVBochsState {
- int fd;
-
- uint32_t *catalog_bitmap;
- int catalog_size;
-
- int data_offset;
-
- int bitmap_blocks;
- int extent_blocks;
- int extent_size;
-} BDRVBochsState;
-
-static int bochs_probe(const uint8_t *buf, int buf_size, const char *filename)
-{
- const struct bochs_header *bochs = (const void *)buf;
-
- if (buf_size < HEADER_SIZE)
- return 0;
-
- if (!strcmp(bochs->magic, HEADER_MAGIC) &&
- !strcmp(bochs->type, REDOLOG_TYPE) &&
- !strcmp(bochs->subtype, GROWING_TYPE) &&
- (le32_to_cpu(bochs->version) == HEADER_VERSION))
- return 100;
-
- return 0;
-}
-
-static int bochs_open(BlockDriverState *bs, const char *filename)
-{
- BDRVBochsState *s = bs->opaque;
- int fd, i;
- struct bochs_header bochs;
-
- 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; // no write support yet
-
- s->fd = fd;
-
- if (read(fd, &bochs, sizeof(bochs)) != sizeof(bochs)) {
- goto fail;
- }
-
- if (strcmp(bochs.magic, HEADER_MAGIC) ||
- strcmp(bochs.type, REDOLOG_TYPE) ||
- strcmp(bochs.subtype, GROWING_TYPE) ||
- (le32_to_cpu(bochs.version) != HEADER_VERSION)) {
- goto fail;
- }
-
- bs->total_sectors = le64_to_cpu(bochs.extra.redolog.disk) / 512;
-
- lseek(s->fd, le32_to_cpu(bochs.header), SEEK_SET);
-
- s->catalog_size = le32_to_cpu(bochs.extra.redolog.catalog);
- s->catalog_bitmap = qemu_malloc(s->catalog_size * 4);
- if (!s->catalog_bitmap)
- goto fail;
- if (read(s->fd, s->catalog_bitmap, s->catalog_size * 4) !=
- s->catalog_size * 4)
- goto fail;
- for (i = 0; i < s->catalog_size; i++)
- le32_to_cpus(&s->catalog_bitmap[i]);
-
- s->data_offset = le32_to_cpu(bochs.header) + (s->catalog_size * 4);
-
- s->bitmap_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.bitmap) - 1) / 512;
- s->extent_blocks = 1 + (le32_to_cpu(bochs.extra.redolog.extent) - 1) / 512;
-
- s->extent_size = le32_to_cpu(bochs.extra.redolog.extent);
-
- return 0;
- fail:
- close(fd);
- return -1;
-}
-
-static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
-{
- BDRVBochsState *s = bs->opaque;
- int64_t offset = sector_num * 512;
- int64_t extent_index, extent_offset, bitmap_offset, block_offset;
- char bitmap_entry;
-
- // seek to sector
- extent_index = offset / s->extent_size;
- extent_offset = (offset % s->extent_size) / 512;
-
- if (s->catalog_bitmap[extent_index] == 0xffffffff)
- {
-// fprintf(stderr, "page not allocated [%x - %x:%x]\n",
-// sector_num, extent_index, extent_offset);
- return -1; // not allocated
- }
-
- bitmap_offset = s->data_offset + (512 * s->catalog_bitmap[extent_index] *
- (s->extent_blocks + s->bitmap_blocks));
- block_offset = bitmap_offset + (512 * (s->bitmap_blocks + extent_offset));
-
-// fprintf(stderr, "sect: %x [ext i: %x o: %x] -> %x bitmap: %x block: %x\n",
-// sector_num, extent_index, extent_offset,
-// le32_to_cpu(s->catalog_bitmap[extent_index]),
-// bitmap_offset, block_offset);
-
- // read in bitmap for current extent
- lseek(s->fd, bitmap_offset + (extent_offset / 8), SEEK_SET);
-
- read(s->fd, &bitmap_entry, 1);
-
- if (!((bitmap_entry >> (extent_offset % 8)) & 1))
- {
-// fprintf(stderr, "sector (%x) in bitmap not allocated\n",
-// sector_num);
- return -1; // not allocated
- }
-
- lseek(s->fd, block_offset, SEEK_SET);
-
- return 0;
-}
-
-static int bochs_read(BlockDriverState *bs, int64_t sector_num,
- uint8_t *buf, int nb_sectors)
-{
- BDRVBochsState *s = bs->opaque;
- int ret;
-
- while (nb_sectors > 0) {
- if (!seek_to_sector(bs, sector_num))
- {
- ret = read(s->fd, buf, 512);
- if (ret != 512)
- return -1;
- }
- else
- memset(buf, 0, 512);
- nb_sectors--;
- sector_num++;
- buf += 512;
- }
- return 0;
-}
-
-static void bochs_close(BlockDriverState *bs)
-{
- BDRVBochsState *s = bs->opaque;
- qemu_free(s->catalog_bitmap);
- close(s->fd);
-}
-
-BlockDriver bdrv_bochs = {
- "bochs",
- sizeof(BDRVBochsState),
- bochs_probe,
- bochs_open,
- bochs_read,
- NULL,
- bochs_close,
-};
diff --git a/block-cow.c b/block-cow.c
deleted file mode 100644
index 6af8b74..0000000
--- a/block-cow.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Block driver for the COW format
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#ifndef _WIN32
-#include "vl.h"
-#include "block_int.h"
-#include <sys/mman.h>
-
-/**************************************************************/
-/* COW block driver using file system holes */
-
-/* user mode linux compatible COW file */
-#define COW_MAGIC 0x4f4f4f4d /* MOOO */
-#define COW_VERSION 2
-
-struct cow_header_v2 {
- uint32_t magic;
- uint32_t version;
- char backing_file[1024];
- int32_t mtime;
- uint64_t size;
- uint32_t sectorsize;
-};
-
-typedef struct BDRVCowState {
- int fd;
- uint8_t *cow_bitmap; /* if non NULL, COW mappings are used first */
- uint8_t *cow_bitmap_addr; /* mmap address of cow_bitmap */
- int cow_bitmap_size;
- int64_t cow_sectors_offset;
-} BDRVCowState;
-
-static int cow_probe(const uint8_t *buf, int buf_size, const char *filename)
-{
- const struct cow_header_v2 *cow_header = (const void *)buf;
-
- if (buf_size >= sizeof(struct cow_header_v2) &&
- be32_to_cpu(cow_header->magic) == COW_MAGIC &&
- be32_to_cpu(cow_header->version) == COW_VERSION)
- return 100;
- else
- return 0;
-}
-
-static int cow_open(BlockDriverState *bs, const char *filename)
-{
- BDRVCowState *s = bs->opaque;
- int fd;
- struct cow_header_v2 cow_header;
- int64_t size;
-
- 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;
- }
- s->fd = fd;
- /* see if it is a cow image */
- if (read(fd, &cow_header, sizeof(cow_header)) != sizeof(cow_header)) {
- goto fail;
- }
-
- if (be32_to_cpu(cow_header.magic) != COW_MAGIC ||
- be32_to_cpu(cow_header.version) != COW_VERSION) {
- goto fail;
- }
-
- /* cow image found */
- size = be64_to_cpu(cow_header.size);
- bs->total_sectors = size / 512;
-
- pstrcpy(bs->backing_file, sizeof(bs->backing_file),
- cow_header.backing_file);
-
-#if 0
- if (cow_header.backing_file[0] != '\0') {
- if (stat(cow_header.backing_file, &st) != 0) {
- fprintf(stderr, "%s: could not find original disk image '%s'\n", filename, cow_header.backing_file);
- goto fail;
- }
- if (st.st_mtime != be32_to_cpu(cow_header.mtime)) {
- fprintf(stderr, "%s: original raw disk image '%s' does not match saved timestamp\n", filename, cow_header.backing_file);
- goto fail;
- }
- fd = open(cow_header.backing_file, O_RDONLY | O_LARGEFILE);
- if (fd < 0)
- goto fail;
- bs->fd = fd;
- }
-#endif
- /* mmap the bitmap */
- s->cow_bitmap_size = ((bs->total_sectors + 7) >> 3) + sizeof(cow_header);
- s->cow_bitmap_addr = mmap(get_mmap_addr(s->cow_bitmap_size),
- s->cow_bitmap_size,
- PROT_READ | PROT_WRITE,
- MAP_SHARED, s->fd, 0);
- if (s->cow_bitmap_addr == MAP_FAILED)
- goto fail;
- s->cow_bitmap = s->cow_bitmap_addr + sizeof(cow_header);
- s->cow_sectors_offset = (s->cow_bitmap_size + 511) & ~511;
- return 0;
- fail:
- close(fd);
- return -1;
-}
-
-static inline void cow_set_bit(uint8_t *bitmap, int64_t bitnum)
-{
- bitmap[bitnum / 8] |= (1 << (bitnum%8));
-}
-
-static inline int is_bit_set(const uint8_t *bitmap, int64_t bitnum)
-{
- return !!(bitmap[bitnum / 8] & (1 << (bitnum%8)));
-}
-
-
-/* Return true if first block has been changed (ie. current version is
- * in COW file). Set the number of continuous blocks for which that
- * is true. */
-static inline int is_changed(uint8_t *bitmap,
- int64_t sector_num, int nb_sectors,
- int *num_same)
-{
- int changed;
-
- if (!bitmap || nb_sectors == 0) {
- *num_same = nb_sectors;
- return 0;
- }
-
- changed = is_bit_set(bitmap, sector_num);
- for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) {
- if (is_bit_set(bitmap, sector_num + *num_same) != changed)
- break;
- }
-
- return changed;
-}
-
-static int cow_is_allocated(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, int *pnum)
-{
- BDRVCowState *s = bs->opaque;
- return is_changed(s->cow_bitmap, sector_num, nb_sectors, pnum);
-}
-
-static int cow_read(BlockDriverState *bs, int64_t sector_num,
- uint8_t *buf, int nb_sectors)
-{
- BDRVCowState *s = bs->opaque;
- int ret, n;
-
- while (nb_sectors > 0) {
- if (is_changed(s->cow_bitmap, sector_num, nb_sectors, &n)) {
- lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
- ret = read(s->fd, buf, n * 512);
- if (ret != n * 512)
- return -1;
- } else {
- memset(buf, 0, n * 512);
- }
- nb_sectors -= n;
- sector_num += n;
- buf += n * 512;
- }
- return 0;
-}
-
-static int cow_write(BlockDriverState *bs, int64_t sector_num,
- const uint8_t *buf, int nb_sectors)
-{
- BDRVCowState *s = bs->opaque;
- int ret, i;
-
- lseek(s->fd, s->cow_sectors_offset + sector_num * 512, SEEK_SET);
- ret = write(s->fd, buf, nb_sectors * 512);
- if (ret != nb_sectors * 512)
- return -1;
- for (i = 0; i < nb_sectors; i++)
- cow_set_bit(s->cow_bitmap, sector_num + i);
- return 0;
-}
-
-static void cow_close(BlockDriverState *bs)
-{
- BDRVCowState *s = bs->opaque;
- munmap(s->cow_bitmap_addr, s->cow_bitmap_size);
- close(s->fd);
-}
-
-static int cow_create(const char *filename, int64_t image_sectors,
- const char *image_filename, int flags)
-{
- int fd, cow_fd;
- struct cow_header_v2 cow_header;
- struct stat st;
-
- if (flags)
- return -ENOTSUP;
-
- cow_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
- 0644);
- if (cow_fd < 0)
- return -1;
- memset(&cow_header, 0, sizeof(cow_header));
- cow_header.magic = cpu_to_be32(COW_MAGIC);
- cow_header.version = cpu_to_be32(COW_VERSION);
- if (image_filename) {
- fd = open(image_filename, O_RDONLY | O_BINARY);
- if (fd < 0) {
- close(cow_fd);
- return -1;
- }
- if (fstat(fd, &st) != 0) {
- close(fd);
- return -1;
- }
- close(fd);
- cow_header.mtime = cpu_to_be32(st.st_mtime);
- realpath(image_filename, cow_header.backing_file);
- }
- cow_header.sectorsize = cpu_to_be32(512);
- cow_header.size = cpu_to_be64(image_sectors * 512);
- write(cow_fd, &cow_header, sizeof(cow_header));
- /* resize to include at least all the bitmap */
- ftruncate(cow_fd, sizeof(cow_header) + ((image_sectors + 7) >> 3));
- close(cow_fd);
- return 0;
-}
-
-static void cow_flush(BlockDriverState *bs)
-{
- BDRVCowState *s = bs->opaque;
- fsync(s->fd);
-}
-
-BlockDriver bdrv_cow = {
- "cow",
- sizeof(BDRVCowState),
- cow_probe,
- cow_open,
- cow_read,
- cow_write,
- cow_close,
- cow_create,
- cow_flush,
- cow_is_allocated,
-};
-#endif
diff --git a/block-vmdk.c b/block-vmdk.c
deleted file mode 100644
index 4cc3db8..0000000
--- a/block-vmdk.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Block driver for the VMDK format
- *
- * Copyright (c) 2004 Fabrice Bellard
- * Copyright (c) 2005 Filip Navara
- *
- * 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 "block_int.h"
-
-#define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D')
-#define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V')
-
-typedef struct {
- uint32_t version;
- uint32_t flags;
- uint32_t disk_sectors;
- uint32_t granularity;
- uint32_t l1dir_offset;
- uint32_t l1dir_size;
- uint32_t file_sectors;
- uint32_t cylinders;
- uint32_t heads;
- uint32_t sectors_per_track;
-} VMDK3Header;
-
-typedef struct {
- uint32_t version;
- uint32_t flags;
- int64_t capacity;
- int64_t granularity;
- int64_t desc_offset;
- int64_t desc_size;
- int32_t num_gtes_per_gte;
- int64_t rgd_offset;
- int64_t gd_offset;
- int64_t grain_offset;
- char filler[1];
- char check_bytes[4];
-} __attribute__((packed)) VMDK4Header;
-
-#define L2_CACHE_SIZE 16
-
-typedef struct BDRVVmdkState {
- int fd;
- int64_t l1_table_offset;
- int64_t l1_backup_table_offset;
- uint32_t *l1_table;
- uint32_t *l1_backup_table;
- unsigned int l1_size;
- uint32_t l1_entry_sectors;
-
- unsigned int l2_size;
- uint32_t *l2_cache;
- uint32_t l2_cache_offsets[L2_CACHE_SIZE];
- uint32_t l2_cache_counts[L2_CACHE_SIZE];
-
- unsigned int cluster_sectors;
-} BDRVVmdkState;
-
-static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
-{
- uint32_t magic;
-
- if (buf_size < 4)
- return 0;
- magic = be32_to_cpu(*(uint32_t *)buf);
- if (magic == VMDK3_MAGIC ||
- magic == VMDK4_MAGIC)
- return 100;
- else
- return 0;
-}
-
-static int vmdk_open(BlockDriverState *bs, const char *filename)
-{
- BDRVVmdkState *s = bs->opaque;
- int fd, i;
- uint32_t magic;
- int l1_size;
-
- 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))
- goto fail;
- magic = be32_to_cpu(magic);
- if (magic == VMDK3_MAGIC) {
- VMDK3Header header;
- if (read(fd, &header, sizeof(header)) !=
- sizeof(header))
- goto fail;
- s->cluster_sectors = le32_to_cpu(header.granularity);
- s->l2_size = 1 << 9;
- s->l1_size = 1 << 6;
- bs->total_sectors = le32_to_cpu(header.disk_sectors);
- s->l1_table_offset = le32_to_cpu(header.l1dir_offset) << 9;
- s->l1_backup_table_offset = 0;
- 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))
- goto fail;
- bs->total_sectors = le64_to_cpu(header.capacity);
- s->cluster_sectors = le64_to_cpu(header.granularity);
- s->l2_size = le32_to_cpu(header.num_gtes_per_gte);
- s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
- if (s->l1_entry_sectors <= 0)
- goto fail;
- s->l1_size = (bs->total_sectors + s->l1_entry_sectors - 1)
- / 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;
- } 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)
- 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]);
- }
-
- if (s->l1_backup_table_offset) {
- 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)
- 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]);
- }
- }
-
- 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);
- return -1;
-}
-
-static uint64_t get_cluster_offset(BlockDriverState *bs,
- uint64_t offset, int allocate)
-{
- BDRVVmdkState *s = bs->opaque;
- unsigned int l1_index, l2_offset, l2_index;
- int min_index, i, j;
- uint32_t min_count, *l2_table, tmp;
- uint64_t cluster_offset;
-
- l1_index = (offset >> 9) / s->l1_entry_sectors;
- if (l1_index >= s->l1_size)
- return 0;
- l2_offset = s->l1_table[l1_index];
- if (!l2_offset)
- return 0;
- for(i = 0; i < L2_CACHE_SIZE; i++) {
- if (l2_offset == s->l2_cache_offsets[i]) {
- /* increment the hit count */
- if (++s->l2_cache_counts[i] == 0xffffffff) {
- for(j = 0; j < L2_CACHE_SIZE; j++) {
- s->l2_cache_counts[j] >>= 1;
- }
- }
- l2_table = s->l2_cache + (i * s->l2_size);
- goto found;
- }
- }
- /* not found: load a new entry in the least used one */
- min_index = 0;
- min_count = 0xffffffff;
- for(i = 0; i < L2_CACHE_SIZE; i++) {
- if (s->l2_cache_counts[i] < min_count) {
- min_count = s->l2_cache_counts[i];
- min_index = i;
- }
- }
- l2_table = s->l2_cache + (min_index * s->l2_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))
- 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) {
- if (!allocate)
- return 0;
- cluster_offset = lseek(s->fd, 0, SEEK_END);
- ftruncate(s->fd, 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))
- 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))
- return 0;
- }
- }
- cluster_offset <<= 9;
- return cluster_offset;
-}
-
-static int vmdk_is_allocated(BlockDriverState *bs, int64_t sector_num,
- int nb_sectors, int *pnum)
-{
- BDRVVmdkState *s = bs->opaque;
- int index_in_cluster, n;
- uint64_t cluster_offset;
-
- cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
- index_in_cluster = sector_num % s->cluster_sectors;
- n = s->cluster_sectors - index_in_cluster;
- if (n > nb_sectors)
- n = nb_sectors;
- *pnum = n;
- return (cluster_offset != 0);
-}
-
-static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
- uint8_t *buf, int nb_sectors)
-{
- BDRVVmdkState *s = bs->opaque;
- int ret, index_in_cluster, n;
- uint64_t cluster_offset;
-
- while (nb_sectors > 0) {
- cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
- index_in_cluster = sector_num % s->cluster_sectors;
- n = s->cluster_sectors - index_in_cluster;
- if (n > nb_sectors)
- n = nb_sectors;
- if (!cluster_offset) {
- 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)
- return -1;
- }
- nb_sectors -= n;
- sector_num += n;
- buf += n * 512;
- }
- return 0;
-}
-
-static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
- const uint8_t *buf, int nb_sectors)
-{
- BDRVVmdkState *s = bs->opaque;
- int ret, index_in_cluster, n;
- uint64_t cluster_offset;
-
- while (nb_sectors > 0) {
- index_in_cluster = sector_num & (s->cluster_sectors - 1);
- n = s->cluster_sectors - index_in_cluster;
- if (n > nb_sectors)
- n = nb_sectors;
- cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
- 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)
- return -1;
- nb_sectors -= n;
- sector_num += n;
- buf += n * 512;
- }
- return 0;
-}
-
-static int vmdk_create(const char *filename, int64_t total_size,
- const char *backing_file, int flags)
-{
- int fd, i;
- VMDK4Header header;
- uint32_t tmp, magic, grains, gd_size, gt_size, gt_count;
- char *desc_template =
- "# Disk DescriptorFile\n"
- "version=1\n"
- "CID=%x\n"
- "parentCID=ffffffff\n"
- "createType=\"monolithicSparse\"\n"
- "\n"
- "# Extent description\n"
- "RW %lu SPARSE \"%s\"\n"
- "\n"
- "# The Disk Data Base \n"
- "#DDB\n"
- "\n"
- "ddb.virtualHWVersion = \"3\"\n"
- "ddb.geometry.cylinders = \"%lu\"\n"
- "ddb.geometry.heads = \"16\"\n"
- "ddb.geometry.sectors = \"63\"\n"
- "ddb.adapterType = \"ide\"\n";
- char desc[1024];
- const char *real_filename, *temp_str;
-
- /* XXX: add support for backing file */
-
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
- 0644);
- if (fd < 0)
- return -1;
- magic = cpu_to_be32(VMDK4_MAGIC);
- memset(&header, 0, sizeof(header));
- header.version = cpu_to_le32(1);
- header.flags = cpu_to_le32(3); /* ?? */
- header.capacity = cpu_to_le64(total_size);
- header.granularity = cpu_to_le64(128);
- header.num_gtes_per_gte = cpu_to_le32(512);
-
- grains = (total_size + header.granularity - 1) / header.granularity;
- gt_size = ((header.num_gtes_per_gte * sizeof(uint32_t)) + 511) >> 9;
- gt_count = (grains + header.num_gtes_per_gte - 1) / header.num_gtes_per_gte;
- gd_size = (gt_count * sizeof(uint32_t) + 511) >> 9;
-
- header.desc_offset = 1;
- header.desc_size = 20;
- header.rgd_offset = header.desc_offset + header.desc_size;
- header.gd_offset = header.rgd_offset + gd_size + (gt_size * gt_count);
- header.grain_offset =
- ((header.gd_offset + gd_size + (gt_size * gt_count) +
- header.granularity - 1) / header.granularity) *
- header.granularity;
-
- header.desc_offset = cpu_to_le64(header.desc_offset);
- header.desc_size = cpu_to_le64(header.desc_size);
- header.rgd_offset = cpu_to_le64(header.rgd_offset);
- header.gd_offset = cpu_to_le64(header.gd_offset);
- header.grain_offset = cpu_to_le64(header.grain_offset);
-
- header.check_bytes[0] = 0xa;
- header.check_bytes[1] = 0x20;
- header.check_bytes[2] = 0xd;
- header.check_bytes[3] = 0xa;
-
- /* write all the data */
- write(fd, &magic, sizeof(magic));
- write(fd, &header, sizeof(header));
-
- ftruncate(fd, header.grain_offset << 9);
-
- /* write grain directory */
- lseek(fd, le64_to_cpu(header.rgd_offset) << 9, SEEK_SET);
- for (i = 0, tmp = header.rgd_offset + gd_size;
- i < gt_count; i++, tmp += gt_size)
- write(fd, &tmp, sizeof(tmp));
-
- /* write backup grain directory */
- lseek(fd, le64_to_cpu(header.gd_offset) << 9, SEEK_SET);
- for (i = 0, tmp = header.gd_offset + gd_size;
- i < gt_count; i++, tmp += gt_size)
- write(fd, &tmp, sizeof(tmp));
-
- /* compose the descriptor */
- 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(desc, desc_template, time(NULL), (unsigned long)total_size,
- real_filename, total_size / (63 * 16));
-
- /* write the descriptor */
- lseek(fd, le64_to_cpu(header.desc_offset) << 9, SEEK_SET);
- write(fd, desc, strlen(desc));
-
- close(fd);
- return 0;
-}
-
-static void vmdk_close(BlockDriverState *bs)
-{
- BDRVVmdkState *s = bs->opaque;
- qemu_free(s->l1_table);
- qemu_free(s->l2_cache);
- close(s->fd);
-}
-
-static void vmdk_flush(BlockDriverState *bs)
-{
- BDRVVmdkState *s = bs->opaque;
- fsync(s->fd);
-}
-
-BlockDriver bdrv_vmdk = {
- "vmdk",
- sizeof(BDRVVmdkState),
- vmdk_probe,
- vmdk_open,
- vmdk_read,
- vmdk_write,
- vmdk_close,
- vmdk_create,
- vmdk_flush,
- vmdk_is_allocated,
-};
diff --git a/block-vpc.c b/block-vpc.c
deleted file mode 100644
index bdc3b88..0000000
--- a/block-vpc.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Block driver for Conectix/Microsoft Virtual PC images
- *
- * Copyright (c) 2005 Alex Beregszaszi
- *
- * 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 "block_int.h"
-
-/**************************************************************/
-
-#define HEADER_SIZE 512
-
-//#define CACHE
-
-// always big-endian
-struct vpc_subheader {
- char magic[8]; // "conectix" / "cxsparse"
- union {
- struct {
- uint32_t unk1[2];
- uint32_t unk2; // always zero?
- uint32_t subheader_offset;
- uint32_t unk3; // some size?
- char creator[4]; // "vpc "
- uint16_t major;
- uint16_t minor;
- char guest[4]; // "Wi2k"
- uint32_t unk4[7];
- uint8_t vnet_id[16]; // virtual network id, purpose unknown
- // next 16 longs are used, but dunno the purpose
- // next 6 longs unknown, following 7 long maybe a serial
- char padding[HEADER_SIZE - 84];
- } main;
- struct {
- uint32_t unk1[2]; // all bits set
- uint32_t unk2; // always zero?
- uint32_t pagetable_offset;
- uint32_t unk3;
- uint32_t pagetable_entries; // 32bit/entry
- uint32_t pageentry_size; // 512*8*512
- uint32_t nb_sectors;
- char padding[HEADER_SIZE - 40];
- } sparse;
- char padding[HEADER_SIZE - 8];
- } type;
-};
-
-typedef struct BDRVVPCState {
- int fd;
-
- int pagetable_entries;
- uint32_t *pagetable;
-
- uint32_t pageentry_size;
-#ifdef CACHE
- uint8_t *pageentry_u8;
- uint32_t *pageentry_u32;
- uint16_t *pageentry_u16;
-
- uint64_t last_bitmap;
-#endif
-} BDRVVPCState;
-
-static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
-{
- if (buf_size >= 8 && !strncmp(buf, "conectix", 8))
- return 100;
- return 0;
-}
-
-static int vpc_open(BlockDriverState *bs, const char *filename)
-{
- BDRVVPCState *s = bs->opaque;
- int fd, i;
- struct vpc_subheader header;
-
- 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; // no write support yet
-
- s->fd = fd;
-
- if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
- goto fail;
-
- if (strncmp(header.magic, "conectix", 8))
- goto fail;
- lseek(s->fd, be32_to_cpu(header.type.main.subheader_offset), SEEK_SET);
-
- if (read(fd, &header, HEADER_SIZE) != HEADER_SIZE)
- goto fail;
-
- if (strncmp(header.magic, "cxsparse", 8))
- goto fail;
-
- bs->total_sectors = ((uint64_t)be32_to_cpu(header.type.sparse.pagetable_entries) *
- be32_to_cpu(header.type.sparse.pageentry_size)) / 512;
-
- lseek(s->fd, be32_to_cpu(header.type.sparse.pagetable_offset), SEEK_SET);
-
- s->pagetable_entries = be32_to_cpu(header.type.sparse.pagetable_entries);
- s->pagetable = qemu_malloc(s->pagetable_entries * 4);
- if (!s->pagetable)
- goto fail;
- if (read(s->fd, s->pagetable, s->pagetable_entries * 4) !=
- s->pagetable_entries * 4)
- goto fail;
- for (i = 0; i < s->pagetable_entries; i++)
- be32_to_cpus(&s->pagetable[i]);
-
- s->pageentry_size = be32_to_cpu(header.type.sparse.pageentry_size);
-#ifdef CACHE
- s->pageentry_u8 = qemu_malloc(512);
- if (!s->pageentry_u8)
- goto fail;
- s->pageentry_u32 = s->pageentry_u8;
- s->pageentry_u16 = s->pageentry_u8;
- s->last_pagetable = -1;
-#endif
-
- return 0;
- fail:
- close(fd);
- return -1;
-}
-
-static inline int seek_to_sector(BlockDriverState *bs, int64_t sector_num)
-{
- BDRVVPCState *s = bs->opaque;
- uint64_t offset = sector_num * 512;
- uint64_t bitmap_offset, block_offset;
- uint32_t pagetable_index, pageentry_index;
-
- pagetable_index = offset / s->pageentry_size;
- pageentry_index = (offset % s->pageentry_size) / 512;
-
- if (pagetable_index > s->pagetable_entries || s->pagetable[pagetable_index] == 0xffffffff)
- return -1; // not allocated
-
- bitmap_offset = 512 * s->pagetable[pagetable_index];
- block_offset = bitmap_offset + 512 + (512 * pageentry_index);
-
-// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
-// sector_num, pagetable_index, pageentry_index,
-// bitmap_offset, block_offset);
-
-// disabled by reason
-#if 0
-#ifdef CACHE
- if (bitmap_offset != s->last_bitmap)
- {
- lseek(s->fd, bitmap_offset, SEEK_SET);
-
- s->last_bitmap = bitmap_offset;
-
- // Scary! Bitmap is stored as big endian 32bit entries,
- // while we used to look it up byte by byte
- read(s->fd, s->pageentry_u8, 512);
- for (i = 0; i < 128; i++)
- be32_to_cpus(&s->pageentry_u32[i]);
- }
-
- if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
- return -1;
-#else
- lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
-
- read(s->fd, &bitmap_entry, 1);
-
- if ((bitmap_entry >> (pageentry_index % 8)) & 1)
- return -1; // not allocated
-#endif
-#endif
- lseek(s->fd, block_offset, SEEK_SET);
-
- return 0;
-}
-
-static int vpc_read(BlockDriverState *bs, int64_t sector_num,
- uint8_t *buf, int nb_sectors)
-{
- BDRVVPCState *s = bs->opaque;
- int ret;
-
- while (nb_sectors > 0) {
- if (!seek_to_sector(bs, sector_num))
- {
- ret = read(s->fd, buf, 512);
- if (ret != 512)
- return -1;
- }
- else
- memset(buf, 0, 512);
- nb_sectors--;
- sector_num++;
- buf += 512;
- }
- return 0;
-}
-
-static void vpc_close(BlockDriverState *bs)
-{
- BDRVVPCState *s = bs->opaque;
- qemu_free(s->pagetable);
-#ifdef CACHE
- qemu_free(s->pageentry_u8);
-#endif
- close(s->fd);
-}
-
-BlockDriver bdrv_vpc = {
- "vpc",
- sizeof(BDRVVPCState),
- vpc_probe,
- vpc_open,
- vpc_read,
- NULL,
- vpc_close,
-};
diff --git a/block-vvfat.c b/block-vvfat.c
index 9dedf91..c365b9c 100644
--- a/block-vvfat.c
+++ b/block-vvfat.c
@@ -1,9 +1,9 @@
/* vim:set shiftwidth=4 ts=8: */
/*
* QEMU Block driver for virtual VFAT (shadows a local directory)
- *
+ *
* Copyright (c) 2004,2005 Johannes E. Schindelin
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@@ -38,7 +38,7 @@
/* TODO: add ":bootsector=blabla.img:" */
/* LATER TODO: add automatic boot sector generation from
BOOTEASY.ASM and Ranish Partition Manager
- Note that DOS assumes the system files to be the first files in the
+ Note that DOS assumes the system files to be the first files in the
file system (test if the boot sector still relies on that fact)! */
/* MAYBE TODO: write block-visofs.c */
/* TODO: call try_commit() only after a timeout */
@@ -153,7 +153,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
index_to<0 || index_to>=array->next ||
index_from<0 || index_from>=array->next)
return -1;
-
+
if(index_to==index_from)
return 0;
@@ -167,7 +167,7 @@ static inline int array_roll(array_t* array,int index_to,int index_from,int coun
memmove(to+is*count,to,from-to);
else
memmove(from,from+is*count,to-from);
-
+
memcpy(to,buf,is*count);
free(buf);
@@ -319,10 +319,10 @@ typedef struct BDRVVVFATState {
BlockDriverState* bs; /* pointer to parent */
unsigned int first_sectors_number; /* 1 for a single partition, 0x40 for a disk with partition table */
unsigned char first_sectors[0x40*0x200];
-
+
int fat_type; /* 16 or 32 */
array_t fat,directory,mapping;
-
+
unsigned int cluster_size;
unsigned int sectors_per_cluster;
unsigned int sectors_per_fat;
@@ -332,7 +332,7 @@ typedef struct BDRVVVFATState {
uint32_t sector_count; /* total number of sectors of the partition */
uint32_t cluster_count; /* total number of clusters of this partition */
uint32_t max_fat_value;
-
+
int current_fd;
mapping_t* current_mapping;
unsigned char* cluster; /* points to current cluster */
@@ -365,7 +365,7 @@ static void init_mbr(BDRVVVFATState* s)
partition_t* partition=&(real_mbr->partition[0]);
memset(s->first_sectors,0,512);
-
+
partition->attributes=0x80; /* bootable */
partition->start_head=1;
partition->start_sector=1;
@@ -485,7 +485,7 @@ static inline uint8_t fat_chksum(const direntry_t* entry)
for(i=0;i<11;i++)
chksum=(((chksum&0xfe)>>1)|((chksum&0x01)?0x80:0))
+(unsigned char)entry->name[i];
-
+
return chksum;
}
@@ -561,7 +561,7 @@ static inline void init_fat(BDRVVVFATState* s)
s->sectors_per_fat * 0x200 / s->fat.item_size - 1);
}
memset(s->fat.pointer,0,s->fat.size);
-
+
switch(s->fat_type) {
case 12: s->max_fat_value=0xfff; break;
case 16: s->max_fat_value=0xffff; break;
@@ -586,10 +586,10 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
memcpy(entry->name,filename,strlen(filename));
return entry;
}
-
+
entry_long=create_long_filename(s,filename);
-
- i = strlen(filename);
+
+ i = strlen(filename);
for(j = i - 1; j>0 && filename[j]!='.';j--);
if (j > 0)
i = (j > 8 ? 8 : j);
@@ -599,7 +599,7 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
entry=array_get_next(&(s->directory));
memset(entry->name,0x20,11);
strncpy(entry->name,filename,i);
-
+
if(j > 0)
for (i = 0; i < 3 && filename[j+1+i]; i++)
entry->extension[i] = filename[j+1+i];
@@ -625,7 +625,7 @@ static inline direntry_t* create_short_and_long_name(BDRVVVFATState* s,
if(entry1==entry) /* no dupe found */
break;
- /* use all 8 characters of name */
+ /* use all 8 characters of name */
if(entry->name[7]==' ') {
int j;
for(j=6;j>0 && entry->name[j]==' ';j--)
@@ -682,11 +682,11 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
mapping->end = mapping->begin;
return -1;
}
-
+
i = mapping->info.dir.first_dir_index =
first_cluster == 0 ? 0 : s->directory.next;
- /* actually read the directory, and allocate the mappings */
+ /* actually read the directory, and allocate the mappings */
while((entry=readdir(dir))) {
unsigned int length=strlen(dirname)+2+strlen(entry->d_name);
char* buffer;
@@ -697,7 +697,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
if(first_cluster == 0 && (is_dotdot || is_dot))
continue;
-
+
buffer=(char*)malloc(length);
assert(buffer);
snprintf(buffer,length,"%s/%s",dirname,entry->d_name);
@@ -772,7 +772,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
memset(array_get(&(s->directory), cur), 0,
(ROOT_ENTRIES - cur) * sizeof(direntry_t));
}
-
+
/* reget the mapping, since s->mapping was possibly realloc()ed */
mapping = (mapping_t*)array_get(&(s->mapping), mapping_index);
first_cluster += (s->directory.next - mapping->info.dir.first_dir_index)
@@ -781,7 +781,7 @@ static int read_directory(BDRVVVFATState* s, int mapping_index)
direntry = (direntry_t*)array_get(&(s->directory), mapping->dir_index);
set_begin_of_direntry(direntry, mapping->begin);
-
+
return 0;
}
@@ -832,7 +832,7 @@ static int init_directories(BDRVVVFATState* s,
*/
i = 1+s->sectors_per_cluster*0x200*8/s->fat_type;
s->sectors_per_fat=(s->sector_count+i)/i; /* round up */
-
+
array_init(&(s->mapping),sizeof(mapping_t));
array_init(&(s->directory),sizeof(direntry_t));
@@ -864,7 +864,7 @@ static int init_directories(BDRVVVFATState* s,
for (i = 0, cluster = 0; i < s->mapping.next; i++) {
int j;
- /* MS-DOS expects the FAT to be 0 for the root directory
+ /* MS-DOS expects the FAT to be 0 for the root directory
* (except for the media byte). */
/* LATER TODO: still true for FAT32? */
int fix_fat = (i != 0);
@@ -990,7 +990,7 @@ DLOG(if (stderr == NULL) {
s->qcow_filename = NULL;
s->fat2 = NULL;
s->downcase_short_names = 1;
-
+
if (!strstart(dirname, "fat:", NULL))
return -1;
@@ -1080,7 +1080,7 @@ static inline int find_mapping_for_cluster_aux(BDRVVVFATState* s,int cluster_num
assert(index1<=index2);
DLOG(mapping=array_get(&(s->mapping),index1);
assert(mapping->begin<=cluster_num);
- assert(index2 >= s->mapping.next ||
+ assert(index2 >= s->mapping.next ||
((mapping = array_get(&(s->mapping),index2)) &&
mapping->end>cluster_num)));
}
@@ -1243,7 +1243,7 @@ static void print_mapping(const mapping_t* mapping)
}
#endif
-static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
+static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVVVFATState *s = bs->opaque;
@@ -1678,7 +1678,7 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
}
/*
- * This function looks at the modified data (qcow).
+ * This function looks at the modified data (qcow).
* It returns 0 upon inconsistency or error, and the number of clusters
* used by the directory, its subdirectories and their files.
*/
@@ -1713,7 +1713,7 @@ static int check_directory_consistency(BDRVVVFATState *s,
} else
/* new directory */
schedule_mkdir(s, cluster_num, strdup(path));
-
+
lfn_init(&lfn);
do {
int i;
@@ -2053,7 +2053,7 @@ static int commit_mappings(BDRVVVFATState* s,
}
next_mapping->dir_index = mapping->dir_index;
- next_mapping->first_mapping_index =
+ next_mapping->first_mapping_index =
mapping->first_mapping_index < 0 ?
array_index(&(s->mapping), mapping) :
mapping->first_mapping_index;
@@ -2073,7 +2073,7 @@ static int commit_mappings(BDRVVVFATState* s,
mapping = next_mapping;
}
-
+
cluster = c1;
}
@@ -2178,7 +2178,7 @@ static int commit_one_file(BDRVVVFATState* s,
for (i = s->cluster_size; i < offset; i += s->cluster_size)
c = modified_fat_get(s, c);
- fd = open(mapping->path, O_RDWR | O_CREAT, 0666);
+ fd = open(mapping->path, O_BINARY | O_RDWR | O_CREAT, 0666);
if (fd < 0) {
fprintf(stderr, "Could not open %s... (%s, %d)\n", mapping->path,
strerror(errno), errno);
@@ -2559,7 +2559,7 @@ static int do_commit(BDRVVVFATState* s)
return ret;
}
- /* copy FAT (with bdrv_read) */
+ /* copy FAT (with bdrv_read) */
memcpy(s->fat.pointer, s->fat2, 0x200 * s->sectors_per_fat);
/* recurse direntries from root (using bs->bdrv_read) */
@@ -2601,10 +2601,10 @@ DLOG(checkpoint());
return do_commit(s);
}
-static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
+static int vvfat_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
- BDRVVVFATState *s = bs->opaque;
+ BDRVVVFATState *s = bs->opaque;
int i, ret;
DLOG(checkpoint());
@@ -2643,7 +2643,7 @@ DLOG(checkpoint());
begin = sector_num;
if (end > sector_num + nb_sectors)
end = sector_num + nb_sectors;
- dir_index = mapping->dir_index +
+ dir_index = mapping->dir_index +
0x10 * (begin - mapping->begin * s->sectors_per_cluster);
direntries = (direntry_t*)(buf + 0x200 * (begin - sector_num));
@@ -2702,7 +2702,7 @@ static int vvfat_is_allocated(BlockDriverState *bs,
*n = nb_sectors;
else if (*n < 0)
return 0;
- return 1;
+ return 1;
}
static int write_target_commit(BlockDriverState *bs, int64_t sector_num,
diff --git a/block.c b/block.c
index ceb0532..3afd3d7 100644
--- a/block.c
+++ b/block.c
@@ -1,8 +1,8 @@
/*
* QEMU System Emulator block driver
- *
+ *
* Copyright (c) 2003 Fabrice Bellard
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@@ -57,7 +57,7 @@ static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFI
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
{
- kern_return_t kernResult;
+ kern_return_t kernResult;
mach_port_t masterPort;
CFMutableDictionaryRef classesToMatch;
@@ -65,8 +65,8 @@ kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
if ( KERN_SUCCESS != kernResult ) {
printf( "IOMasterPort returned %d\n", kernResult );
}
-
- classesToMatch = IOServiceMatching( kIOCDMediaClass );
+
+ classesToMatch = IOServiceMatching( kIOCDMediaClass );
if ( classesToMatch == NULL ) {
printf( "IOServiceMatching returned a NULL dictionary.\n" );
} else {
@@ -77,7 +77,7 @@ kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
{
printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
}
-
+
return kernResult;
}
@@ -103,7 +103,7 @@ kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex ma
}
IOObjectRelease( nextMedia );
}
-
+
return kernResult;
}
@@ -144,7 +144,7 @@ BlockDriver *bdrv_find_format(const char *format_name)
return NULL;
}
-int bdrv_create(BlockDriver *drv,
+int bdrv_create(BlockDriver *drv,
const char *filename, int64_t size_in_sectors,
const char *backing_file, int flags)
{
@@ -215,7 +215,7 @@ static BlockDriver *find_image_format(const char *filename)
}
close(fd);
}
-
+
drv = NULL;
score_max = 0;
for(drv1 = first_drv; drv1 != NULL; drv1 = drv1->next) {
@@ -237,10 +237,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
io_iterator_t mediaIterator;
char bsdPath[ MAXPATHLEN ];
int fd;
-
+
kernResult = FindEjectableCDMedia( &mediaIterator );
kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
-
+
if ( bsdPath[ 0 ] != '\0' ) {
strcat(bsdPath,"s0");
/* some CDs don't have a partition 0 */
@@ -252,7 +252,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot)
}
filename = bsdPath;
}
-
+
if ( mediaIterator )
IOObjectRelease( mediaIterator );
}
@@ -265,7 +265,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
{
int ret;
char tmp_filename[1024];
-
+
bs->read_only = 0;
bs->is_temporary = 0;
bs->encrypted = 0;
@@ -273,7 +273,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
if (snapshot) {
BlockDriverState *bs1;
int64_t total_size;
-
+
/* if snapshot, we create a temporary backing file and open it
instead of opening 'filename' directly */
@@ -288,10 +288,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
}
total_size = bs1->total_sectors;
bdrv_delete(bs1);
-
+
get_tmp_filename(tmp_filename, sizeof(tmp_filename));
/* XXX: use cow for linux as it is more efficient ? */
- if (bdrv_create(&bdrv_qcow, tmp_filename,
+ if (bdrv_create(&bdrv_qcow, tmp_filename,
total_size, filename, 0) < 0) {
return -1;
}
@@ -309,7 +309,7 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
bs->opaque = qemu_mallocz(drv->instance_size);
if (bs->opaque == NULL && drv->instance_size > 0)
return -1;
-
+
ret = drv->bdrv_open(bs, filename);
if (ret < 0) {
qemu_free(bs->opaque);
@@ -412,7 +412,7 @@ int bdrv_commit(BlockDriverState *bs)
}
/* return -1 if error */
-int bdrv_read(BlockDriverState *bs, int64_t sector_num,
+int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
int ret, n;
@@ -451,7 +451,7 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
}
/* return -1 if error */
-int bdrv_write(BlockDriverState *bs, int64_t sector_num,
+int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
if (!bs->inserted)
@@ -459,7 +459,7 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num,
if (bs->read_only)
return -1;
if (sector_num == 0 && bs->boot_sector_enabled && nb_sectors > 0) {
- memcpy(bs->boot_sector_data, buf, 512);
+ memcpy(bs->boot_sector_data, buf, 512);
}
return bs->drv->bdrv_write(bs, sector_num, buf, nb_sectors);
}
@@ -479,7 +479,7 @@ void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size)
memset(bs->boot_sector_data + size, 0, 512 - size);
}
-void bdrv_set_geometry_hint(BlockDriverState *bs,
+void bdrv_set_geometry_hint(BlockDriverState *bs,
int cyls, int heads, int secs)
{
bs->cyls = cyls;
@@ -499,7 +499,7 @@ void bdrv_set_translation_hint(BlockDriverState *bs, int translation)
bs->translation = translation;
}
-void bdrv_get_geometry_hint(BlockDriverState *bs,
+void bdrv_get_geometry_hint(BlockDriverState *bs,
int *pcyls, int *pheads, int *psecs)
{
*pcyls = bs->cyls;
@@ -542,7 +542,7 @@ void bdrv_set_locked(BlockDriverState *bs, int locked)
bs->locked = locked;
}
-void bdrv_set_change_cb(BlockDriverState *bs,
+void bdrv_set_change_cb(BlockDriverState *bs,
void (*change_cb)(void *opaque), void *opaque)
{
bs->change_cb = change_cb;
@@ -580,7 +580,7 @@ void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size)
}
}
-void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
+void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
void *opaque)
{
BlockDriver *drv;
@@ -729,28 +729,28 @@ static int raw_open(BlockDriverState *bs, const char *filename)
return 0;
}
-static int raw_read(BlockDriverState *bs, int64_t sector_num,
+static int raw_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
int ret;
-
+
lseek(s->fd, sector_num * 512, SEEK_SET);
ret = read(s->fd, buf, nb_sectors * 512);
- if (ret != nb_sectors * 512)
+ if (ret != nb_sectors * 512)
return -1;
return 0;
}
-static int raw_write(BlockDriverState *bs, int64_t sector_num,
+static int raw_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVRawState *s = bs->opaque;
int ret;
-
+
lseek(s->fd, sector_num * 512, SEEK_SET);
ret = write(s->fd, buf, nb_sectors * 512);
- if (ret != nb_sectors * 512)
+ if (ret != nb_sectors * 512)
return -1;
return 0;
}
@@ -814,7 +814,7 @@ static int raw_create(const char *filename, int64_t total_size,
if (flags || backing_file)
return -ENOTSUP;
- fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
+ fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
if (fd < 0)
return -EIO;
@@ -845,14 +845,7 @@ BlockDriver bdrv_raw = {
void bdrv_init(void)
{
bdrv_register(&bdrv_raw);
-#ifndef _WIN32
- bdrv_register(&bdrv_cow);
-#endif
- bdrv_register(&bdrv_qcow);
- bdrv_register(&bdrv_vmdk);
bdrv_register(&bdrv_cloop);
+ bdrv_register(&bdrv_qcow);
bdrv_register(&bdrv_dmg);
- bdrv_register(&bdrv_bochs);
- bdrv_register(&bdrv_vpc);
- bdrv_register(&bdrv_vvfat);
}
diff --git a/cbuffer.c b/cbuffer.c
new file mode 100644
index 0000000..082b0dd
--- /dev/null
+++ b/cbuffer.c
@@ -0,0 +1,231 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "cbuffer.h"
+#include "android_utils.h"
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <stdio.h>
+
+#define DEBUG 0
+
+#if DEBUG
+# define ASSERT(cond,fmt,...) ({ if (!(cond)) { fprintf(stderr, fmt, __VA_ARGS__); assert(cond); } })
+#else
+# define ASSERT(cond,fmt,...) ((void)0)
+#endif
+
+#if DEBUG
+void
+cbuffer_assert( CBuffer* cb, const char* file, long lineno )
+{
+ const char* reason = NULL;
+
+ if (cb->rpos < 0 || cb->rpos >= cb->size) {
+ reason = "rpos is out of bounds";
+ }
+ else if (cb->count < 0 || cb->count > cb->size) {
+ reason = "count is incorrect";
+ }
+ if (!reason)
+ return;
+
+ fprintf(stderr, "assert:%s:%ld: assertion failed: %s (pos=%d count=%d size=%d)\n",
+ file, lineno, reason, cb->rpos, cb->count, cb->size);
+ assert(0);
+}
+# define CBUFFER_ASSERT(cb) cbuffer_assert(cb,__FUNCTION__,__LINE__)
+#else
+# define CBUFFER_ASSERT(cb) ((void)0)
+#endif
+
+int
+cbuffer_write_peek( CBuffer* cb, uint8_t* *pbase )
+{
+ int wpos = cb->rpos + cb->count;
+ int avail = cb->size - cb->count;
+
+ CBUFFER_ASSERT(cb);
+
+ if (wpos >= cb->size)
+ wpos -= cb->size;
+
+ if (wpos + avail > cb->size)
+ avail = cb->size - wpos;
+
+ *pbase = cb->buff + wpos;
+ return avail;
+}
+
+void
+cbuffer_write_step( CBuffer* cb, int len )
+{
+ CBUFFER_ASSERT(cb);
+
+ cb->count += len;
+ if (cb->count > cb->size)
+ cb->count = cb->size;
+}
+
+
+int
+cbuffer_write( CBuffer* cb, const void* from, int len )
+{
+ int len2 = len;
+
+ CBUFFER_ASSERT(cb);
+
+ while (len2 > 0) {
+ int avail = cb->size - cb->count;
+ int wpos = cb->rpos + cb->count;
+
+ ASSERT(avail >= 0, "avail is negative: %d", avail);
+
+ if (avail == 0)
+ break;
+
+ if (wpos >= cb->size)
+ wpos -= cb->size;
+
+ ASSERT( wpos >= 0 && wpos < cb->size, "wpos is out-of-bounds: %d (rpos=%d)", wpos, cb->rpos);
+
+ if (wpos + avail > cb->size)
+ avail = cb->size - wpos;
+
+ if (avail > len2)
+ avail = len2;
+
+ memcpy( cb->buff + wpos, (const char*)from, avail );
+
+ from = (char*)from + avail;
+ len2 -= avail;
+ cb->count += avail;
+ }
+ return len - len2;
+}
+
+int
+cbuffer_read( CBuffer* cb, void* to, int len )
+{
+ int len2 = len;
+
+ CBUFFER_ASSERT(cb);
+
+ while (len2 > 0) {
+ int avail = cb->count;
+ int rpos = cb->rpos;
+
+ ASSERT(avail >= 0, "avail is negative: %d", avail);
+
+ if (avail == 0)
+ break;
+
+ ASSERT((rpos >= 0 && rpos < cb->size), "rpos is out-of-bounds: %d", rpos);
+
+ if (rpos+avail > cb->size)
+ avail = cb->size - rpos;
+
+ if (avail > len2)
+ avail = len2;
+
+ memcpy( (char*)to, (const char*)cb->buff + rpos, avail );
+ to = (char*)to + avail;
+ len2 -= avail;
+ cb->count -= avail;
+ cb->rpos += avail;
+ if (cb->rpos >= cb->size)
+ cb->rpos -= cb->size;
+ }
+ return len - len2;
+}
+
+int
+cbuffer_read_peek( CBuffer* cb, uint8_t* *pbase )
+{
+ int rpos = cb->rpos;
+ int avail = cb->count;
+
+ CBUFFER_ASSERT(cb);
+
+ if (rpos + avail > cb->size)
+ avail = cb->size - rpos;
+
+ *pbase = cb->buff + rpos;
+ return avail;
+}
+
+
+void
+cbuffer_read_step( CBuffer* cb, int len )
+{
+ CBUFFER_ASSERT(cb);
+
+ if (len > cb->count)
+ len = cb->count;
+
+ cb->rpos += len;
+ if (cb->rpos >= cb->size)
+ cb->rpos -= cb->size;
+
+ cb->count -= len;
+}
+
+const char*
+cbuffer_quote( CBuffer* cb )
+{
+ STRALLOC_DEFINE(s);
+ char* q;
+
+ stralloc_format( s, "cbuffer %p (pos=%d count=%d size=%d)",
+ cb, cb->rpos, cb->count, cb->size );
+
+ q = tempstr_from_stralloc( s );
+ stralloc_reset(s);
+
+ return q;
+}
+
+const char*
+cbuffer_quote_data( CBuffer* cb )
+{
+ STRALLOC_DEFINE(s);
+ int len = cb->count;
+ int rpos = cb->rpos;
+ char* result;
+
+ while (len > 0) {
+ int avail = len;
+
+ if (rpos >= cb->size)
+ rpos -= cb->size;
+
+ if (rpos + avail > cb->size)
+ avail = cb->size - rpos;
+
+ stralloc_add_quote_bytes( s, cb->buff + rpos, avail );
+ rpos += avail;
+ len -= avail;
+ }
+
+ result = tempstr_from_stralloc(s);
+ stralloc_reset(s);
+
+ return result;
+}
+
+void
+cbuffer_print( CBuffer* cb )
+{
+ /* print the content of a cbuffer */
+ printf( "%s: %s", cbuffer_quote(cb), cbuffer_quote_data(cb) );
+}
+
diff --git a/cbuffer.h b/cbuffer.h
new file mode 100644
index 0000000..d25d765
--- /dev/null
+++ b/cbuffer.h
@@ -0,0 +1,61 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _qemu_cbuffer_h
+#define _qemu_cbuffer_h
+
+#include <stdint.h>
+
+/* Basic circular buffer type and methods */
+
+typedef struct {
+ uint8_t* buff;
+ int size;
+ int rpos;
+ int count;
+} CBuffer;
+
+static __inline__ void
+cbuffer_reset( CBuffer* cb, void* buff, int size )
+{
+ cb->buff = buff;
+ cb->size = size;
+ cb->rpos = 0;
+ cb->count = 0;
+}
+
+static __inline__ int
+cbuffer_write_avail( CBuffer* cb )
+{
+ return cb->size - cb->count;
+}
+
+extern int cbuffer_write( CBuffer* cb, const void* from, int len );
+extern int cbuffer_write_peek( CBuffer* cb, uint8_t* *pbase );
+extern void cbuffer_write_step( CBuffer* cb, int len );
+
+static __inline__ int
+cbuffer_read_avail( CBuffer* cb )
+{
+ return cb->count;
+}
+
+extern int cbuffer_read( CBuffer* cb, void* to, int len );
+extern int cbuffer_read_peek( CBuffer* cb, uint8_t* *pbase );
+extern void cbuffer_read_step( CBuffer* cb, int len );
+
+extern const char* cbuffer_quote( CBuffer* cb );
+extern const char* cbuffer_quote_data( CBuffer* cb );
+extern void cbuffer_print( CBuffer* cb );
+
+#endif /* qemu_cbuffer_h */
+
+
diff --git a/charpipe.c b/charpipe.c
new file mode 100644
index 0000000..cb4698f
--- /dev/null
+++ b/charpipe.c
@@ -0,0 +1,298 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "cbuffer.h"
+#include "android_debug.h"
+
+#define xxDEBUG
+
+#ifdef DEBUG
+# include <stdio.h>
+# define D(...) ( fprintf( stderr, __VA_ARGS__ ), fprintf(stderr, "\n") )
+#else
+# define D(...) ((void)0)
+#endif
+
+/* we want to implement a bi-directionnal communication channel
+ * between two QEMU character drivers that merge well into the
+ * QEMU event loop.
+ *
+ * each half of the channel has its own object and buffer, and
+ * we implement communication through charpipe_poll() which
+ * must be called by the main event loop after its call to select()
+ *
+ */
+
+#define BIP_BUFFER_SIZE 512
+
+typedef struct BipBuffer {
+ struct BipBuffer* next;
+ CBuffer cb[1];
+ char buff[ BIP_BUFFER_SIZE ];
+} BipBuffer;
+
+static BipBuffer* _free_bip_buffers;
+
+static BipBuffer*
+bip_buffer_alloc( void )
+{
+ BipBuffer* bip = _free_bip_buffers;
+ if (bip != NULL) {
+ _free_bip_buffers = bip->next;
+ } else {
+ bip = malloc( sizeof(*bip) );
+ if (bip == NULL) {
+ derror( "%s: not enough memory", __FUNCTION__ );
+ exit(1);
+ }
+ }
+ bip->next = NULL;
+ cbuffer_reset( bip->cb, bip->buff, sizeof(bip->buff) );
+ return bip;
+}
+
+static void
+bip_buffer_free( BipBuffer* bip )
+{
+ bip->next = _free_bip_buffers;
+ _free_bip_buffers = bip;
+}
+
+/* this models each half of the charpipe */
+typedef struct CharPipeHalf {
+ CharDriverState cs[1];
+ BipBuffer* bip_first;
+ BipBuffer* bip_last;
+ struct CharPipeHalf* peer; /* NULL if closed */
+ IOCanRWHandler* fd_can_read;
+ IOReadHandler* fd_read;
+ void* fd_opaque;
+} CharPipeHalf;
+
+
+
+static void
+charpipehalf_close( CharDriverState* cs )
+{
+ CharPipeHalf* ph = cs->opaque;
+
+ while (ph->bip_first) {
+ BipBuffer* bip = ph->bip_first;
+ ph->bip_first = bip->next;
+ bip_buffer_free(bip);
+ }
+ ph->bip_last = NULL;
+
+ ph->peer = NULL;
+ ph->fd_can_read = NULL;
+ ph->fd_read = NULL;
+ ph->fd_opaque = NULL;
+}
+
+
+static void
+charpipehalf_add_read_handler( CharDriverState* cs,
+ IOCanRWHandler* fd_can_read,
+ IOReadHandler* fd_read,
+ void* fd_opaque )
+{
+ CharPipeHalf* ph = cs->opaque;
+
+ ph->fd_can_read = fd_can_read;
+ ph->fd_read = fd_read;
+ ph->fd_opaque = fd_opaque;
+}
+
+
+static int
+charpipehalf_write( CharDriverState* cs, const uint8_t* buf, int len )
+{
+ CharPipeHalf* ph = cs->opaque;
+ CharPipeHalf* peer = ph->peer;
+ BipBuffer* bip = ph->bip_last;
+ int ret = 0;
+
+ D("%s: writing %d bytes to %p: '%s'", __FUNCTION__,
+ len, ph, quote_bytes( buf, len ));
+
+ if (bip == NULL && peer != NULL && peer->fd_read != NULL) {
+ /* no buffered data, try to write directly to the peer */
+ while (len > 0) {
+ int size;
+
+ if (peer->fd_can_read) {
+ size = peer->fd_can_read( peer->fd_opaque );
+ if (size == 0)
+ break;
+
+ if (size > len)
+ size = len;
+ } else
+ size = len;
+
+ peer->fd_read( peer->fd_opaque, buf, size );
+ buf += size;
+ len -= size;
+ ret += size;
+ }
+ }
+
+ if (len == 0)
+ return ret;
+
+ /* buffer the remaining data */
+ if (bip == NULL) {
+ bip = bip_buffer_alloc();
+ ph->bip_first = ph->bip_last = bip;
+ }
+
+ while (len > 0) {
+ int len2 = cbuffer_write( bip->cb, buf, len );
+
+ buf += len2;
+ ret += len2;
+ len -= len2;
+ if (len == 0)
+ break;
+
+ /* ok, we need another buffer */
+ ph->bip_last = bip_buffer_alloc();
+ bip->next = ph->bip_last;
+ bip = ph->bip_last;
+ }
+ return ret;
+}
+
+
+static void
+charpipehalf_poll( CharPipeHalf* ph )
+{
+ CharPipeHalf* peer = ph->peer;
+ int size;
+
+ if (peer == NULL || peer->fd_read == NULL)
+ return;
+
+ while (1) {
+ BipBuffer* bip = ph->bip_first;
+ uint8_t* base;
+ int avail;
+
+ if (bip == NULL)
+ break;
+
+ size = cbuffer_read_avail(bip->cb);
+ if (size == 0) {
+ ph->bip_first = bip->next;
+ if (ph->bip_first == NULL)
+ ph->bip_last = NULL;
+ bip_buffer_free(bip);
+ continue;
+ }
+
+ if (ph->fd_can_read) {
+ int size2 = peer->fd_can_read( peer->fd_opaque );
+
+ if (size2 == 0)
+ break;
+
+ if (size > size2)
+ size = size2;
+ }
+
+ avail = cbuffer_read_peek( bip->cb, &base );
+ if (avail > size)
+ avail = size;
+ D("%s: sending %d bytes from %p: '%s'", __FUNCTION__,
+ avail, ph, quote_bytes( base, avail ));
+
+ peer->fd_read( peer->fd_opaque, base, avail );
+ cbuffer_read_step( bip->cb, avail );
+ }
+}
+
+
+static void
+charpipehalf_init( CharPipeHalf* ph, CharPipeHalf* peer )
+{
+ CharDriverState* cs = ph->cs;
+
+ ph->bip_first = NULL;
+ ph->bip_last = NULL;
+ ph->peer = peer;
+ ph->fd_can_read = NULL;
+ ph->fd_read = NULL;
+ ph->fd_opaque = NULL;
+
+ cs->chr_write = charpipehalf_write;
+ cs->chr_add_read_handler = charpipehalf_add_read_handler;
+ cs->chr_ioctl = NULL;
+ cs->chr_send_event = NULL;
+ cs->chr_close = charpipehalf_close;
+ cs->opaque = ph;
+}
+
+
+typedef struct CharPipeState {
+ CharPipeHalf a[1];
+ CharPipeHalf b[1];
+} CharPipeState;
+
+
+
+#define MAX_CHAR_PIPES 8
+
+static CharPipeState _s_charpipes[ MAX_CHAR_PIPES ];
+
+int
+qemu_chr_open_charpipe( CharDriverState* *pfirst, CharDriverState* *psecond )
+{
+ CharPipeState* cp = _s_charpipes;
+ CharPipeState* cp_end = cp + MAX_CHAR_PIPES;
+
+ for ( ; cp < cp_end; cp++ ) {
+ if ( cp->a->peer == NULL && cp->b->peer == NULL )
+ break;
+ }
+
+ if (cp == cp_end) { /* can't allocate one */
+ *pfirst = NULL;
+ *psecond = NULL;
+ return -1;
+ }
+
+ charpipehalf_init( cp->a, cp->b );
+ charpipehalf_init( cp->b, cp->a );
+
+ *pfirst = cp->a->cs;
+ *psecond = cp->b->cs;
+ return 0;
+}
+
+void
+charpipe_poll( void )
+{
+ CharPipeState* cp = _s_charpipes;
+ CharPipeState* cp_end = cp + MAX_CHAR_PIPES;
+
+ for ( ; cp < cp_end; cp++ ) {
+ CharPipeHalf* half;
+
+ half = cp->a;
+ if (half->peer != NULL)
+ charpipehalf_poll(half);
+
+ half = cp->b;
+ if (half->peer != NULL)
+ charpipehalf_poll(half);
+ }
+}
diff --git a/charpipe.h b/charpipe.h
new file mode 100644
index 0000000..77f5fb2
--- /dev/null
+++ b/charpipe.h
@@ -0,0 +1,26 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _CHARPIPE_H
+#define _CHARPIPE_H
+
+#include "vl.h"
+
+/* open two connected character drivers that can be used to communicate by internal
+ * QEMU components. For Android, this is used to connect an emulated serial port
+ * with the android modem
+ */
+extern int qemu_chr_open_charpipe( CharDriverState* *pfirst, CharDriverState* *psecond );
+
+/* must be called from the main event loop to poll all charpipes */
+extern void charpipe_poll( void );
+
+#endif /* _CHARPIPE_H */
diff --git a/configure b/configure
index e6c74e4..6a420b4 100755
--- a/configure
+++ b/configure
@@ -15,6 +15,7 @@ TMPC="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.c"
TMPO="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.o"
TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}"
TMPS="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.S"
+TMPL="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.log"
# default parameters
prefix=""
@@ -23,6 +24,12 @@ static="no"
cross_prefix=""
cc="gcc"
host_cc="gcc"
+if [ -n "$CC" ] ; then
+ cc="$CC"
+fi
+if [ -n "$HOSTCC" ] ; then
+ host_cc="$HOSTCC"
+fi
ar="ar"
make="make"
install="install"
@@ -65,6 +72,18 @@ case "$cpu" in
;;
x86_64|amd64)
cpu="x86_64"
+ # if the kernel release contains mixed64, we have a 64-bit kernel with
+ # a 32-bit environment. We should generate i386 binaries then or things
+ # will go very wrong
+ kernel_mixed=`uname -r | grep mixed64`
+ if test ! -z "$kernel_mixed" ; then
+ cpu="i386"
+ fi
+ # another specific case
+ kernel_uXen=`uname -r | grep "gg.*-xenU"`
+ if test ! -z "$kernel_uXen" ; then
+ cpu="i386"
+ fi
;;
*)
cpu="unknown"
@@ -80,7 +99,9 @@ adlib="no"
oss="no"
dsound="no"
coreaudio="no"
+winaudio="no"
alsa="no"
+esd="no"
fmod="no"
fmod_lib=""
fmod_inc=""
@@ -91,12 +112,15 @@ profiler="no"
kernel_path=""
cocoa="no"
check_gfx="yes"
-check_gcc="yes"
+check_gcc="no" # 2006-10-10; digit: no check required anymore
softmmu="yes"
user="no"
build_docs="no"
build_acpi_tables="no"
uname_release=""
+shaper="no"
+debug="no"
+android_nand_limits="no"
# OS specific
targetos=`uname -s`
@@ -104,6 +128,7 @@ case $targetos in
CYGWIN*)
mingw32="yes"
CFLAGS="-O2 -mno-cygwin"
+LDFLAGS="-mno-cygwin -mwindows"
;;
MINGW32*)
mingw32="yes"
@@ -131,7 +156,6 @@ SunOS)
solaris="yes"
;;
*)
-oss="yes"
linux="yes"
user="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
@@ -181,6 +205,8 @@ for opt do
;;
--cc=*) cc="$optarg"
;;
+ --debug) debug="yes"
+ ;;
--host-cc=*) host_cc="$optarg"
;;
--make=*) make="$optarg"
@@ -201,10 +227,18 @@ for opt do
;;
--disable-sdl) sdl="no"
;;
+ --static-sdl) force_static_sdl="yes"
+ ;;
--enable-coreaudio) coreaudio="yes"
;;
+ --enable-winaudio) winaudio="yes"
+ ;;
--enable-alsa) alsa="yes"
;;
+ --enable-esd) esd="yes"
+ ;;
+ --enable-oss) oss="yes"
+ ;;
--enable-dsound) dsound="yes"
;;
--enable-fmod) fmod="yes"
@@ -243,6 +277,22 @@ for opt do
;;
--enable-iasl) build_acpi_tables="yes"
;;
+## Added functions for Android ##
+ --enable-qfb) qfb="yes"
+ ;;
+ --enable-trace) trace="yes"
+ ;;
+ --enable-skins) skins="yes"
+ ;;
+ --enable-nand) nand="yes"
+ ;;
+ --enable-shaper) shaper="yes"
+ ;;
+ --use-sdl-config=*) sdl_config="$optarg"
+ ;;
+ --enable-nand-limits) android_nand_limits="yes"
+ ;;
+#################################
esac
done
@@ -281,7 +331,10 @@ echo " --enable-cocoa enable COCOA (Mac OS X only)"
echo " --enable-mingw32 enable Win32 cross compilation with mingw32"
echo " --enable-adlib enable Adlib emulation"
echo " --enable-coreaudio enable Coreaudio audio driver"
+echo " --enable-winaudio enable Windows Wave audio driver"
echo " --enable-alsa enable ALSA audio driver"
+echo " --enable-esd enable ESD audio driver"
+echo " --enable-oss enable OSS audio driver"
echo " --enable-fmod enable FMOD audio driver"
echo " --enabled-dsound enable DirectSound audio driver"
echo " --enable-system enable all system emulation targets"
@@ -292,6 +345,16 @@ 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 " --enable-iasl compilation of ACPI tables with the IASL compiler"
+## Added functions for Android ##
+echo " --static-sdl force static linking of libSDL"
+echo " --enable-qfb enable QEMU FUSE Bridge support"
+echo " --enable-trace enable ARM trace support"
+echo " --enable-skins enable device skin feature (requires SDL)"
+echo " --enable-nand enable NAND image support"
+echo " --enable-shaper enable network shaping support"
+echo " --use-sdl-config=FILE use a specific sdl-config script"
+echo " --enable-nand-limits enable NAND read/write thresholding support"
+#################################
echo ""
echo "NOTE: The object files are build at the place where configure is launched"
exit 1
@@ -317,6 +380,7 @@ if test "$mingw32" = "yes" ; then
linux="no"
EXESUF=".exe"
oss="no"
+ TMPE="$TMPE$EXESUF"
if [ "$cpu" = "i386" ] ; then
kqemu="yes"
fi
@@ -329,7 +393,7 @@ if test "$solaris" = "yes" ; then
#
# gcc for solaris 10/fcs in /usr/sfw/bin doesn't compile qemu correctly
# override the check with --disable-gcc-check
- #
+ #
if test "$solarisrev" -eq 10 -a "$check_gcc" = "yes" ; then
solgcc=`which $cc`
if test "$solgcc" = "/usr/sfw/bin/gcc" ; then
@@ -360,13 +424,15 @@ if test "$solaris" = "yes" ; then
fi
exit 1
fi
-fi
+fi
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"
+ # x86_64-softmmu has been removed from the default list because it doesn't build on Intel MAC
+ # 2006-10-10; digit
+ target_list="i386-softmmu ppc-softmmu sparc-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
fi
# the following are Linux specific
if [ "$user" = "yes" ] ; then
@@ -424,7 +490,7 @@ if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/nu
have_gcc3_options="yes"
fi
-# Check for gcc4, error if pre-gcc4
+# Check for gcc4, error if pre-gcc4
if test "$check_gcc" = "yes" ; then
cat > $TMPC <<EOF
#if __GNUC__ < 4
@@ -441,56 +507,132 @@ EOF
fi
fi
+# use our own static build of libpng + libz, since their respective configure script
+# make it hard to build these libraries statically on Cygwin/MSYS
+#
+png=no
+png_static=yes
+png_static_libs="\$(SRC_PATH)/libpng.a \$(SRC_PATH)/libz.a"
+png_cflags="\$(ZLIB_CFLAGS) \$(LIBPNG_CFLAGS)"
+
##########################################
# SDL probe
sdl_too_old=no
if test -z "$sdl" ; then
-
-sdl_config="sdl-config"
-sdl=no
-sdl_static=no
-
-if test "$mingw32" = "yes" -a ! -z "$cross_prefix" ; then
-# win32 cross compilation case
- sdl_config="i386-mingw32msvc-sdl-config"
- sdl=yes
-else
-# normal SDL probe
-cat > $TMPC << EOF
+ if test -z "$sdl_config" ; then
+ sdl_config="sdl-config"
+ fi
+ sdl=no
+ sdl_static=no
+ if test "$mingw32" = "yes" -a ! -z "$cross_prefix" ; then
+ # win32 cross compilation case
+ sdl_config="i386-mingw32msvc-sdl-config"
+ sdl=yes
+ else
+ # normal SDL probe
+ cat > $TMPC << EOF
#include <SDL.h>
#undef main /* We don't want SDL to override our main() */
int main( void ) { return SDL_Init (SDL_INIT_VIDEO); }
EOF
+ sdl_cflags=`$sdl_config --cflags 2> /dev/null`
+ sdl_libs=`$sdl_config --libs 2> /dev/null`
+
+ if $cc -o $TMPE $sdl_cflags $TMPC $sdl_libs 2> /dev/null ; then
+ _sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'`
+ if test "$_sdlversion" -lt 121 ; then
+ sdl_too_old=yes
+ else
+ sdl=yes
+ fi
+ fi # sdl compile and link test
+
+ # static link with sdl ? only test if needed
+ aa="no"
+ if test "$force_static_sdl" = "yes" -o "$sdl" = "no"; then
+ sdl_static_libs=`$sdl_config --static-libs`
+ if test -n "$sdl_static_libs"; then
+ if $cc -o $TMPE $sdl_cflags $TMPC $sdl_static_libs 2> $TMPL; then
+ sdl_static=yes
+ else
+ echo "Warning: static libSDL link doesn't work."
+ if [ "x$linux" == "xyes" ]; then
+ echo "Are you missing the libaudio-dev and the libxt-dev libraries?"
+ fi
+ echo "Correct the errors below and try again"
+ cat $TMPL
+ fi
+ fi
+ fi
+ fi # cross compilation
+fi # -w "$sdl"
-if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC `$sdl_config --libs 2> /dev/null` 2> /dev/null ; then
-_sdlversion=`$sdl_config --version | sed 's/[^0-9]//g'`
-if test "$_sdlversion" -lt 121 ; then
-sdl_too_old=yes
+if test "$force_static_sdl" = "yes" ; then
+ if test "$sdl_static" = "no"; then
+ echo "could not find a usable static version of SDL"
+ exit 3
+ else
+ sdl="no"
+ fi
else
-sdl=yes
+ # favor dynamic linking in the normal case
+ if test "$sdl" = "yes"; then
+ sdl_static="no"
+ 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`
-if [ "$aa" = "yes" ] ; then
- sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`"
-fi
+########################################################
+# ALSA probe
+#
+if test "$alsa" = "yes"; then
+ alsa_cflags=`pkg-config --cflags alsa 2> /dev/null`
+ alsa_libs=`pkg-config --libs alsa 2> /dev/null`
+
+ cat > $TMPC << EOF
+#include <alsa/asoundlib.h>
+int main( void ) { snd_pcm_t* handle; return snd_pcm_open( &handle,NULL,0,0); }
+EOF
-if $cc -o $TMPE `$sdl_config --cflags 2> /dev/null` $TMPC $sdl_static_libs 2> /dev/null; then
- sdl_static=yes
+ if $cc -o $TMPE $alsa_cflags $TMPC $alsa_libs 2> $TMPL ; then
+ echo "ALSA seems to be usable on this system"
+ else
+ echo "the ALSA development files do not seem to be installed on this system"
+ if [ "x$linux" = "xyes" ] ; then
+ echo "Are you missing the libasound-dev package ?"
+ fi
+ echo "Correct the erros below and try again"
+ cat $TMPL
+ exit 1
+ fi
fi
-fi # static link
+########################################################
+# ESD probe
+#
+if test "$esd" = "yes"; then
+ esd_cflags=`pkg-config --cflags esound 2> /dev/null`
+ esd_libs=`pkg-config --libs esound 2> /dev/null`
-fi # sdl compile test
+ cat > $TMPC << EOF
+#include <esd.h>
+int main( void ) { return esd_open_sound(0); }
+EOF
-fi # cross compilation
-fi # -z $sdl
+ if $cc -o $TMPE $esd_cflags $TMPC $esd_libs 2> $TMPL ; then
+ echo "ESD seems to be usable on this system"
+ else
+ echo "the EsounD development files do not seem to be installed on this system"
+ if [ "x$linux" = "xyes" ] ; then
+ echo "Are you missing the libesd-dev package ?"
+ fi
+ echo "Correct the errors below and try again:"
+ cat $TMPL
+ rm -f $TMPC $TMPO $TMPE $TMPL
+ exit 1
+ fi
+fi
# Check if tools are available to build documentation.
if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then
@@ -531,19 +673,30 @@ echo "host CPU $cpu"
echo "host big endian $bigendian"
echo "target list $target_list"
echo "gprof enabled $gprof"
+echo "gdb stub $gdbstub"
echo "profiler $profiler"
+echo "debug build $debug"
echo "static build $static"
if test "$darwin" = "yes" ; then
echo "Cocoa support $cocoa"
fi
-echo "SDL support $sdl"
-if test "$sdl" != "no" ; then
- echo "SDL static link $sdl_static"
+png_support="$png"
+if test "$png" = "no" -a "$png_static" = "yes" ; then
+ png_support="static"
+fi
+echo "PNG support $png_support"
+sdl_support="$sdl"
+if test "$sdl" = "no" -a "$sdl_static" = "yes"; then
+ sdl_support="static"
fi
+echo "SDL support $sdl_support"
echo "mingw32 support $mingw32"
echo "Adlib support $adlib"
echo "CoreAudio support $coreaudio"
+echo "WinAudio support $winaudio"
echo "ALSA support $alsa"
+echo "ESD support $esd"
+echo "OSS support $oss"
echo "DSound support $dsound"
if test "$fmod" = "yes"; then
if test -z $fmod_lib || test -z $fmod_inc; then
@@ -591,6 +744,13 @@ if test "$have_gcc3_options" = "yes" ; then
echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak
fi
echo "HOST_CC=$host_cc" >> $config_mak
+
+if test "$debug" = "yes"; then
+ echo "OPTIM=-O0 -g -fno-strict-aliasing" >> $config_mak
+else
+ echo "OPTIM=-O2 -fomit-frame-pointer -fno-strict-aliasing" >> $config_mak
+fi
+
echo "AR=$ar" >> $config_mak
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
echo "CFLAGS=$CFLAGS" >> $config_mak
@@ -686,10 +846,22 @@ if test "$coreaudio" = "yes" ; then
echo "CONFIG_COREAUDIO=yes" >> $config_mak
echo "#define CONFIG_COREAUDIO 1" >> $config_h
fi
+if test "$winaudio" = "yes" ; then
+ echo "CONFIG_WINAUDIO=yes" >> $config_mak
+ echo "#define CONFIG_WINAUDIO 1" >> $config_h
+fi
if test "$alsa" = "yes" ; then
echo "CONFIG_ALSA=yes" >> $config_mak
+ echo "CONFIG_ALSA_INC=$alsa_cflags" >> $config_mak
+ echo "CONFIG_ALSA_LIB=$alsa_libs" >> $config_mak
echo "#define CONFIG_ALSA 1" >> $config_h
fi
+if test "$esd" = "yes" ; then
+ echo "CONFIG_ESD=yes" >> $config_mak
+ echo "CONFIG_ESD_INC=$esd_cflags" >> $config_mak
+ echo "CONFIG_ESD_LIB=$esd_libs" >> $config_mak
+ echo "#define CONFIG_ESD 1" >> $config_h
+fi
if test "$dsound" = "yes" ; then
echo "CONFIG_DSOUND=yes" >> $config_mak
echo "#define CONFIG_DSOUND 1" >> $config_h
@@ -723,6 +895,11 @@ if [ "$bsd" = "yes" ] ; then
echo "#define _BSD 1" >> $config_h
fi
+if test "$skins" = "yes" ; then
+ echo "CONFIG_SKINS=yes" >> $config_mak
+ echo "#define CONFIG_SKINS 1" >> $config_h
+fi
+
echo "#define CONFIG_UNAME_RELEASE \"$uname_release\"" >> $config_h
for target in $target_list; do
@@ -748,7 +925,7 @@ if expr $target : '.*-user' > /dev/null ; then
fi
if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
- -a "$sdl" = "no" -a "$cocoa" = "no" ; then
+ -a "$sdl" = "no" -a "$sdl_static" = "no" -a "$cocoa" = "no" ; then
echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
echo "To build QEMU without graphical output configure with --disable-gfx-check"
echo "Note that this will disable all output from the virtual graphics card."
@@ -796,6 +973,24 @@ elif test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" ; then
echo "#define TARGET_ARCH \"arm\"" >> $config_h
echo "#define TARGET_ARM 1" >> $config_h
bflt="yes"
+## Added functions for Android ##
+ if test "$qfb" = "yes" ; then
+ echo "CONFIG_QFB=yes" >> $config_mak
+ echo "#define CONFIG_QFB 1" >> $config_h
+ fi
+ if test "$trace" = "yes" ; then
+ echo "CONFIG_TRACE=yes" >> $config_mak
+ echo "#define CONFIG_TRACE 1" >> $config_h
+ fi
+ if test "$nand" = "yes" ; then
+ echo "CONFIG_NAND=yes" >> $config_mak
+ echo "#define CONFIG_NAND 1" >> $config_h
+ fi
+ if test "$shaper" = "yes"; then
+ echo "CONFIG_SHAPER=yes" >> $config_mak
+ echo "#define CONFIG_SHAPER 1" >> $config_h
+ fi
+#################################
elif test "$target_cpu" = "sparc" ; then
echo "TARGET_ARCH=sparc" >> $config_mak
echo "#define TARGET_ARCH \"sparc\"" >> $config_h
@@ -861,23 +1056,30 @@ fi
# sdl defines
if test "$target_user_only" = "no"; then
- if test "$target_softmmu" = "no" -o "$static" = "yes"; then
- sdl1=$sdl_static
- else
- sdl1=$sdl
- fi
- if test "$sdl1" = "yes" ; then
+ if test "$sdl" = "yes" -o "$sdl_static" = "yes" ; then
echo "#define CONFIG_SDL 1" >> $config_h
echo "CONFIG_SDL=yes" >> $config_mak
- if test "$target_softmmu" = "no" -o "$static" = "yes"; then
+ if test "$sdl_static" = "yes"; then
echo "SDL_LIBS=$sdl_static_libs" >> $config_mak
else
- echo "SDL_LIBS=`$sdl_config --libs`" >> $config_mak
+ echo "SDL_LIBS=$sdl_libs" >> $config_mak
fi
if [ "${aa}" = "yes" ] ; then
- echo "SDL_CFLAGS=`$sdl_config --cflags` `aalib-config --cflags`" >> $config_mak
+ echo "SDL_CFLAGS=$sdl_cflags `aalib-config --cflags`" >> $config_mak
+ else
+ echo "SDL_CFLAGS=$sdl_cflags" >> $config_mak
+ fi
+ fi
+fi
+
+# png defines
+if test "$png" = "yes" -o "$png_static" = "yes" ; then
+ if test "$target_softmmu" = "yes" -o "$static" = "yes"; then
+ echo "PNG_CFLAGS=$png_cflags" >> $config_mak
+ if test "$png_static" = "yes"; then
+ echo "PNG_LIBS=$png_static_libs" >> $config_mak
else
- echo "SDL_CFLAGS=`$sdl_config --cflags`" >> $config_mak
+ echo "PNG_LIBS=$png_libs" >> $config_mak
fi
fi
fi
@@ -903,4 +1105,8 @@ if test "$source_path_used" = "yes" ; then
done
fi
+if test "$android_nand_limits" = "yes"; then
+ echo "#define CONFIG_NAND_LIMITS 1" >> $config_h
+fi
+
rm -f $TMPO $TMPC $TMPE $TMPS
diff --git a/console.c b/console.c
index f039dfc..e9e2fe6 100644
--- a/console.c
+++ b/console.c
@@ -1,8 +1,8 @@
/*
* QEMU graphical console
- *
+ *
* Copyright (c) 2004 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
@@ -132,7 +132,7 @@ struct TextConsole {
int nb_esc_params;
/* kbd read handler */
- IOCanRWHandler *fd_can_read;
+ IOCanRWHandler *fd_can_read;
IOReadHandler *fd_read;
void *fd_opaque;
/* fifo for key pressed */
@@ -176,8 +176,8 @@ static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
r = (rgba >> 16) & 0xff;
g = (rgba >> 8) & 0xff;
b = (rgba) & 0xff;
- color = (rgb_to_index[r] * 6 * 6) +
- (rgb_to_index[g] * 6) +
+ color = (rgb_to_index[r] * 6 * 6) +
+ (rgb_to_index[g] * 6) +
(rgb_to_index[b]);
break;
#endif
@@ -201,14 +201,14 @@ static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
return color;
}
-static void vga_fill_rect (DisplayState *ds,
+static void vga_fill_rect (DisplayState *ds,
int posx, int posy, int width, int height, uint32_t color)
{
uint8_t *d, *d1;
int x, y, bpp;
-
+
bpp = (ds->depth + 7) >> 3;
- d1 = ds->data +
+ d1 = ds->data +
ds->linesize * posy + bpp * posx;
for (y = 0; y < height; y++) {
d = d1;
@@ -246,9 +246,9 @@ static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w,
bpp = (ds->depth + 7) >> 3;
wb = w * bpp;
if (yd <= ys) {
- s = ds->data +
+ s = ds->data +
ds->linesize * ys + bpp * xs;
- d = ds->data +
+ d = ds->data +
ds->linesize * yd + bpp * xd;
for (y = 0; y < h; y++) {
memmove(d, s, wb);
@@ -256,9 +256,9 @@ static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w,
s += ds->linesize;
}
} else {
- s = ds->data +
+ s = ds->data +
ds->linesize * (ys + h - 1) + bpp * xs;
- d = ds->data +
+ d = ds->data +
ds->linesize * (yd + h - 1) + bpp * xd;
for (y = 0; y < h; y++) {
memmove(d, s, wb);
@@ -401,7 +401,7 @@ static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
}
#endif
-static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
+static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
TextAttributes *t_attrib)
{
uint8_t *d;
@@ -424,7 +424,7 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
}
bpp = (ds->depth + 7) >> 3;
- d = ds->data +
+ d = ds->data +
ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
linesize = ds->linesize;
font_ptr = vgafont16 + FONT_HEIGHT * ch;
@@ -521,9 +521,9 @@ static void update_xy(TextConsole *s, int x, int y)
y2 += s->total_height;
if (y2 < s->height) {
c = &s->cells[y1 * s->width + x];
- vga_putcharxy(s->ds, x, y2, c->ch,
+ vga_putcharxy(s->ds, x, y2, c->ch,
&(c->t_attrib));
- dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
+ dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
}
@@ -546,10 +546,10 @@ static void console_show_cursor(TextConsole *s, int show)
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
} else {
- vga_putcharxy(s->ds, s->x, y, c->ch,
+ vga_putcharxy(s->ds, s->x, y, c->ch,
&(c->t_attrib));
}
- dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
+ dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
}
@@ -560,7 +560,7 @@ static void console_refresh(TextConsole *s)
TextCell *c;
int x, y, y1;
- if (s != active_console)
+ if (s != active_console)
return;
vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
@@ -569,7 +569,7 @@ static void console_refresh(TextConsole *s)
for(y = 0; y < s->height; y++) {
c = s->cells + y1 * s->width;
for(x = 0; x < s->width; x++) {
- vga_putcharxy(s->ds, x, y, c->ch,
+ vga_putcharxy(s->ds, x, y, c->ch,
&(c->t_attrib));
c++;
}
@@ -584,7 +584,7 @@ static void console_scroll(int ydelta)
{
TextConsole *s;
int i, y1;
-
+
s = active_console;
if (!s || !s->text_console)
return;
@@ -639,13 +639,13 @@ static void console_put_lf(TextConsole *s)
c++;
}
if (s == active_console && s->y_displayed == s->y_base) {
- vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
- s->width * FONT_WIDTH,
+ vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
+ s->width * FONT_WIDTH,
(s->height - 1) * FONT_HEIGHT);
vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
- s->width * FONT_WIDTH, FONT_HEIGHT,
+ s->width * FONT_WIDTH, FONT_HEIGHT,
color_table[0][s->t_attrib_default.bgcol]);
- dpy_update(s->ds, 0, 0,
+ dpy_update(s->ds, 0, 0,
s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
}
}
@@ -767,7 +767,7 @@ static void console_putchar(TextConsole *s, int ch)
console_put_lf(s);
break;
case '\b': /* backspace */
- if (s->x > 0)
+ if (s->x > 0)
s->x--;
break;
case '\t': /* tabspace */
@@ -786,9 +786,11 @@ static void console_putchar(TextConsole *s, int ch)
break;
default:
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;
+ if (s->x < s->width) {
+ 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) {
@@ -811,7 +813,7 @@ static void console_putchar(TextConsole *s, int ch)
case TTY_STATE_CSI: /* handle escape sequence parameters */
if (ch >= '0' && ch <= '9') {
if (s->nb_esc_params < MAX_ESC_PARAMS) {
- s->esc_params[s->nb_esc_params] =
+ s->esc_params[s->nb_esc_params] =
s->esc_params[s->nb_esc_params] * 10 + ch - '0';
}
} else {
@@ -884,8 +886,8 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
return len;
}
-static void console_chr_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *fd_can_read,
+static void console_chr_add_read_handler(CharDriverState *chr,
+ IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque)
{
TextConsole *s = chr->opaque;
@@ -914,7 +916,7 @@ static void kbd_send_chars(void *opaque)
TextConsole *s = opaque;
int len;
uint8_t buf[16];
-
+
len = s->fd_can_read(s->fd_opaque);
if (len > s->out_fifo.count)
len = s->out_fifo.count;
@@ -1055,12 +1057,12 @@ CharDriverState *text_console_init(DisplayState *ds)
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);
-
+
if (!color_inited) {
color_inited = 1;
for(j = 0; j < 2; j++) {
for(i = 0; i < 8; i++) {
- color_table[j][i] = col_expand(s->ds,
+ color_table[j][i] = col_expand(s->ds,
vga_get_color(s->ds, color_table_rgb[j][i]));
}
}
diff --git a/cpu-all.h b/cpu-all.h
index 145d84b..d4fd2a7 100644
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -339,7 +339,13 @@ static inline void stl_le_p(void *ptr, int v)
static inline void stq_le_p(void *ptr, uint64_t v)
{
+#if defined(__i386__) && __GNUC__ >= 4
+ const union { uint64_t v; uint32_t p[2]; } x = { .v = v };
+ ((uint32_t *)ptr)[0] = x.p[0];
+ ((uint32_t *)ptr)[1] = x.p[1];
+#else
*(uint64_t *)ptr = v;
+#endif
}
/* float access */
@@ -971,7 +977,7 @@ static inline int64_t cpu_get_real_ticks(void)
return val;
}
-#elif defined(__sparc_v9__)
+#elif defined(__sparc__) && defined(HOST_SOLARIS)
static inline int64_t cpu_get_real_ticks (void)
{
diff --git a/cpu-exec.c b/cpu-exec.c
index 60239d4..8d733bd 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -1,6 +1,6 @@
/*
* i386 emulator main execution loop
- *
+ *
* Copyright (c) 2003-2005 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
@@ -21,6 +21,22 @@
#include "exec.h"
#include "disas.h"
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+extern int qemu_milli_needed;
+extern int qemu_milli_check(void);
+extern void qemu_check_interrupts(void);
+
+extern int qemu_cpu_delay;
+extern int qemu_cpu_delay_count;
+
#if !defined(CONFIG_SOFTMMU)
#undef EAX
#undef ECX
@@ -54,7 +70,7 @@ void cpu_loop_exit(void)
/* exit the current TB from a signal handler. The host registers are
restored in a state compatible with the CPU emulator
*/
-void cpu_resume_from_signal(CPUState *env1, void *puc)
+void cpu_resume_from_signal(CPUState *env1, void *puc)
{
#if !defined(CONFIG_SOFTMMU)
struct ucontext *uc = puc;
@@ -83,13 +99,13 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
unsigned int h;
target_ulong phys_pc, phys_page1, phys_page2, virt_page2;
uint8_t *tc_ptr;
-
+
spin_lock(&tb_lock);
tb_invalidated_flag = 0;
-
+
regs_to_env(); /* XXX: do it just before cpu_gen_code() */
-
+
/* find translated block using physical mappings */
phys_pc = get_phys_addr_code(env, pc);
phys_page1 = phys_pc & TARGET_PAGE_MASK;
@@ -100,13 +116,13 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
tb = *ptb1;
if (!tb)
goto not_found;
- if (tb->pc == pc &&
+ if (tb->pc == pc &&
tb->page_addr[0] == phys_page1 &&
- tb->cs_base == cs_base &&
+ tb->cs_base == cs_base &&
tb->flags == flags) {
/* check next page if needed */
if (tb->page_addr[1] != -1) {
- virt_page2 = (pc & TARGET_PAGE_MASK) +
+ virt_page2 = (pc & TARGET_PAGE_MASK) +
TARGET_PAGE_SIZE;
phys_page2 = get_phys_addr_code(env, virt_page2);
if (tb->page_addr[1] == phys_page2)
@@ -132,9 +148,13 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
tb->tc_ptr = tc_ptr;
tb->cs_base = cs_base;
tb->flags = flags;
+#ifdef CONFIG_TRACE
+ tb->bb_rec = NULL;
+ tb->prev_time = 0;
+#endif
cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
-
+
/* check next page if needed */
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
phys_page2 = -1;
@@ -142,7 +162,7 @@ static TranslationBlock *tb_find_slow(target_ulong pc,
phys_page2 = get_phys_addr_code(env, virt_page2);
}
tb_link_phys(tb, phys_pc, phys_page2);
-
+
found:
/* we add the TB in the virtual pc hash table */
env->tb_jmp_cache[tb_jmp_cache_hash_func(pc)] = tb;
@@ -278,8 +298,8 @@ int cpu_exec(CPUState *env1)
}
#elif defined(TARGET_PPC)
if (env1->halted) {
- if (env1->msr[MSR_EE] &&
- (env1->interrupt_request &
+ if (env1->msr[MSR_EE] &&
+ (env1->interrupt_request &
(CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) {
env1->halted = 0;
} else {
@@ -317,7 +337,7 @@ int cpu_exec(CPUState *env1)
}
#endif
- cpu_single_env = env1;
+ cpu_single_env = env1;
/* first we save global registers */
saved_env = env;
@@ -393,9 +413,9 @@ int cpu_exec(CPUState *env1)
which will be hanlded outside the cpu execution
loop */
#if defined(TARGET_I386)
- do_interrupt_user(env->exception_index,
- env->exception_is_int,
- env->error_code,
+ do_interrupt_user(env->exception_index,
+ env->exception_is_int,
+ env->error_code,
env->exception_next_eip);
#endif
ret = env->exception_index;
@@ -405,9 +425,9 @@ int cpu_exec(CPUState *env1)
/* simulate a real cpu exception. On i386, it can
trigger new exceptions, but we do not handle
double or triple faults yet. */
- do_interrupt(env->exception_index,
- env->exception_is_int,
- env->error_code,
+ do_interrupt(env->exception_index,
+ env->exception_is_int,
+ env->error_code,
env->exception_next_eip, 0);
#elif defined(TARGET_PPC)
do_interrupt(env);
@@ -422,7 +442,7 @@ int cpu_exec(CPUState *env1)
#endif
}
env->exception_index = -1;
- }
+ }
#ifdef USE_KQEMU
if (kqemu_is_ok(env) && env->interrupt_request == 0) {
int ret;
@@ -452,15 +472,15 @@ int cpu_exec(CPUState *env1)
T0 = 0; /* force lookup of first TB */
for(;;) {
#if defined(__sparc__) && !defined(HOST_SOLARIS)
- /* g1 can be modified by some libc? functions */
+ /* g1 can be modified by some libc? functions */
tmp_T0 = T0;
-#endif
+#endif
interrupt_request = env->interrupt_request;
if (__builtin_expect(interrupt_request, 0)) {
#if defined(TARGET_I386)
/* if hardware interrupt pending, we execute it */
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
- (env->eflags & IF_MASK) &&
+ (env->eflags & IF_MASK) &&
!(env->hflags & HF_INHIBIT_IRQ_MASK)) {
int intno;
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
@@ -627,7 +647,7 @@ int cpu_exec(CPUState *env1)
#elif defined(TARGET_SH4)
cpu_dump_state(env, logfile, fprintf, 0);
#else
-#error unsupported target CPU
+#error unsupported target CPU
#endif
}
#endif
@@ -641,7 +661,7 @@ int cpu_exec(CPUState *env1)
#endif
#if defined(__sparc__) && !defined(HOST_SOLARIS)
T0 = tmp_T0;
-#endif
+#endif
/* see if we can patch the calling TB. When the TB
spans two pages, we cannot safely do a direct
jump. */
@@ -652,7 +672,7 @@ int cpu_exec(CPUState *env1)
#endif
tb->page_addr[1] == -1
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
- && (tb->cflags & CF_CODE_COPY) ==
+ && (tb->cflags & CF_CODE_COPY) ==
(((TranslationBlock *)(T0 & ~3))->cflags & CF_CODE_COPY)
#endif
) {
@@ -660,7 +680,7 @@ int cpu_exec(CPUState *env1)
tb_add_jump((TranslationBlock *)(long)(T0 & ~3), T0 & 3, tb);
#if defined(USE_CODE_COPY)
/* propagates the FP use info */
- ((TranslationBlock *)(T0 & ~3))->cflags |=
+ ((TranslationBlock *)(T0 & ~3))->cflags |=
(tb->cflags & CF_FP_USED);
#endif
spin_unlock(&tb_lock);
@@ -674,7 +694,7 @@ int cpu_exec(CPUState *env1)
__asm__ __volatile__("call %0\n\t"
"mov %%o7,%%i0"
: /* no outputs */
- : "r" (gen_func)
+ : "r" (gen_func)
: "i0", "i1", "i2", "i3", "i4", "i5",
"l0", "l1", "l2", "l3", "l4", "l5",
"l6", "l7");
@@ -685,6 +705,15 @@ int cpu_exec(CPUState *env1)
: /* no outputs */
: "r" (gen_func)
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
+#elif defined(TARGET_X86_64) && defined(__i386__)
+ asm volatile ("push %%ebx\n"
+ "push %%esi\n"
+ "push %%edi\n"
+ "call *%0\n"
+ "pop %%edi\n"
+ "pop %%esi\n"
+ "pop %%ebx\n"
+ : : "r" (gen_func) : "ebx", "esi", "edi");
#elif defined(TARGET_I386) && defined(USE_CODE_COPY)
{
if (!(tb->cflags & CF_CODE_COPY)) {
@@ -788,6 +817,30 @@ int cpu_exec(CPUState *env1)
cpu_loop_exit();
}
#endif
+
+#if 0 /* digit: implement high-resolution polling */
+ if (qemu_milli_needed) {
+ static int counter;
+
+ if (++counter == 50) {
+ counter = 0;
+ if (qemu_milli_check())
+ qemu_check_interrupts();
+ }
+ }
+#endif
+/* ANDROID-BEGIN */
+ if (qemu_cpu_delay) {
+ if (++qemu_cpu_delay_count >= qemu_cpu_delay) {
+ qemu_cpu_delay_count = 0;
+#ifdef _WIN32
+ Sleep(1);
+#else
+ usleep(1000);
+#endif
+ }
+ }
+/* ANDROID-END */
}
} else {
env_to_regs();
@@ -852,7 +905,7 @@ int cpu_exec(CPUState *env1)
#endif
env = saved_env;
/* fail safe : never use cpu_single_env outside cpu_exec() */
- cpu_single_env = NULL;
+ cpu_single_env = NULL;
return ret;
}
@@ -879,7 +932,7 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
env = s;
if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
selector &= 0xffff;
- cpu_x86_load_seg_cache(env, seg_reg, selector,
+ cpu_x86_load_seg_cache(env, seg_reg, selector,
(selector << 4), 0xffff, 0);
} else {
load_seg(seg_reg, selector);
@@ -893,7 +946,7 @@ void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
saved_env = env;
env = s;
-
+
helper_fsave((target_ulong)ptr, data32);
env = saved_env;
@@ -905,7 +958,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
saved_env = env;
env = s;
-
+
helper_frstor((target_ulong)ptr, data32);
env = saved_env;
@@ -922,7 +975,7 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
write caused the exception and otherwise 0'. 'old_set' is the
signal set which should be restored */
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
- int is_write, sigset_t *old_set,
+ int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
@@ -931,7 +984,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
- qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
+ qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
@@ -940,7 +993,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
}
/* see if it is an MMU fault */
- ret = cpu_x86_handle_mmu_fault(env, address, is_write,
+ ret = cpu_x86_handle_mmu_fault(env, address, is_write,
((env->hflags & HF_CPL_MASK) == 3), 0);
if (ret < 0)
return 0; /* not an MMU fault */
@@ -955,7 +1008,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
}
if (ret == 1) {
#if 0
- printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
+ printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
env->eip, env->cr[2], env->error_code);
#endif
/* we restore the process signal mask as the sigreturn should
@@ -982,7 +1035,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
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",
+ 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 */
@@ -1018,7 +1071,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
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",
+ 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 */
@@ -1050,11 +1103,11 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
{
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",
+ 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 */
@@ -1078,7 +1131,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
}
if (ret == 1) {
#if 0
- printf("PF exception: NIP=0x%08x error=0x%x %p\n",
+ 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
@@ -1100,11 +1153,11 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
{
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",
+ 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 */
@@ -1128,7 +1181,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
}
if (ret == 1) {
#if 0
- printf("PF exception: NIP=0x%08x error=0x%x %p\n",
+ 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
@@ -1150,11 +1203,11 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
{
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",
+ 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 */
@@ -1177,7 +1230,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
cpu_restore_state(tb, env, pc, puc);
}
#if 0
- printf("PF exception: NIP=0x%08x error=0x%x %p\n",
+ 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
@@ -1194,7 +1247,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
#if defined(__i386__)
#if defined(USE_CODE_COPY)
-static void cpu_send_trap(unsigned long pc, int trap,
+static void cpu_send_trap(unsigned long pc, int trap,
struct ucontext *uc)
{
TranslationBlock *tb;
@@ -1213,7 +1266,7 @@ static void cpu_send_trap(unsigned long pc, int trap,
}
#endif
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
@@ -1235,8 +1288,8 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
return 1;
} else
#endif
- return handle_cpu_signal(pc, (unsigned long)info->si_addr,
- trapno == 0xe ?
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ trapno == 0xe ?
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
&uc->uc_sigmask, puc);
}
@@ -1250,8 +1303,8 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
unsigned long pc;
pc = uc->uc_mcontext.gregs[REG_RIP];
- return handle_cpu_signal(pc, (unsigned long)info->si_addr,
- uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
&uc->uc_sigmask, puc);
}
@@ -1307,7 +1360,7 @@ typedef struct ucontext SIGCONTEXT;
# 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, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
@@ -1324,13 +1377,13 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
if (TRAP_sig(uc) != 0x400 && (DSISR_sig(uc) & 0x02000000))
is_write = 1;
#endif
- return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, &uc->uc_sigmask, puc);
}
#elif defined(__alpha__)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
@@ -1354,12 +1407,12 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
is_write = 1;
}
- return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, &uc->uc_sigmask, puc);
}
#elif defined(__sparc__)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
uint32_t *regs = (uint32_t *)(info + 1);
@@ -1367,7 +1420,7 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
unsigned long pc;
int is_write;
uint32_t insn;
-
+
/* XXX: is there a standard glibc define ? */
pc = regs[1];
/* XXX: need kernel patch to get write flag faster */
@@ -1386,40 +1439,40 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
break;
}
}
- return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write, sigmask, NULL);
}
#elif defined(__arm__)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
-
+
pc = uc->uc_mcontext.gregs[R15];
/* XXX: compute is_write */
is_write = 0;
- return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask);
}
#elif defined(__mc68000)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
-
+
pc = uc->uc_mcontext.gregs[16];
/* XXX: compute is_write */
is_write = 0;
- return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask, puc);
}
@@ -1459,17 +1512,17 @@ int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
#elif defined(__s390__)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+int cpu_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
struct ucontext *uc = puc;
unsigned long pc;
int is_write;
-
+
pc = uc->uc_mcontext.psw.addr;
/* XXX: compute is_write */
is_write = 0;
- return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
is_write,
&uc->uc_sigmask, puc);
}
diff --git a/dcache.c b/dcache.c
new file mode 100644
index 0000000..7a55d0c
--- /dev/null
+++ b/dcache.c
@@ -0,0 +1,342 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "dcache.h"
+#include "cpu.h"
+#include "exec-all.h"
+#include "trace.h"
+#include "varint.h"
+
+extern FILE *ftrace_debug;
+
+typedef struct Dcache {
+ int size;
+ int ways;
+ int line_size;
+ int log_line_size;
+ int rows;
+ uint32_t addr_mask;
+ int replace_policy;
+ int next_way;
+ int extra_increment_counter;
+ int *replace;
+ uint32_t **table;
+ int load_miss_penalty;
+ int store_miss_penalty;
+ uint64_t load_hits;
+ uint64_t load_misses;
+ uint64_t store_hits;
+ uint64_t store_misses;
+} Dcache;
+
+Dcache dcache;
+
+void dcache_cleanup();
+
+// Returns the log2 of "num" rounded up to the nearest integer.
+int log2_roundup(int num)
+{
+ int power2;
+ int exp;
+
+ for (exp = 0, power2 = 1; power2 < num; power2 <<= 1) {
+ exp += 1;
+ }
+ return exp;
+}
+
+void dcache_init(int size, int ways, int line_size, int replace_policy,
+ int load_miss_penalty, int store_miss_penalty)
+{
+ int ii;
+
+ // Compute the logs of the params, rounded up
+ int log_size = log2_roundup(size);
+ int log_ways = log2_roundup(ways);
+ int log_line_size = log2_roundup(line_size);
+
+ // The number of rows in the table = size / (line_size * ways)
+ int log_rows = log_size - log_line_size - log_ways;
+
+ dcache.size = 1 << log_size;
+ dcache.ways = 1 << log_ways;
+ dcache.line_size = 1 << log_line_size;
+ dcache.log_line_size = log_line_size;
+ dcache.rows = 1 << log_rows;
+ dcache.addr_mask = (1 << log_rows) - 1;
+
+ // Allocate an array of pointers, one for each row
+ uint32_t **table = malloc(sizeof(uint32_t *) << log_rows);
+
+ // Allocate the data for the whole cache in one call to malloc()
+ int data_size = sizeof(uint32_t) << (log_rows + log_ways);
+ uint32_t *data = malloc(data_size);
+
+ // Fill the cache with invalid addresses
+ memset(data, ~0, data_size);
+
+ // Assign the pointers into the data array
+ int rows = dcache.rows;
+ for (ii = 0; ii < rows; ++ii) {
+ table[ii] = &data[ii << log_ways];
+ }
+ dcache.table = table;
+ dcache.replace_policy = replace_policy;
+ dcache.next_way = 0;
+ dcache.extra_increment_counter = 0;
+
+ dcache.replace = NULL;
+ if (replace_policy == kPolicyRoundRobin) {
+ dcache.replace = malloc(sizeof(int) << log_rows);
+ memset(dcache.replace, 0, sizeof(int) << log_rows);
+ }
+ dcache.load_miss_penalty = load_miss_penalty;
+ dcache.store_miss_penalty = store_miss_penalty;
+ dcache.load_hits = 0;
+ dcache.load_misses = 0;
+ dcache.store_hits = 0;
+ dcache.store_misses = 0;
+
+ atexit(dcache_cleanup);
+}
+
+void dcache_stats()
+{
+ uint64_t hits = dcache.load_hits + dcache.store_hits;
+ uint64_t misses = dcache.load_misses + dcache.store_misses;
+ uint64_t total = hits + misses;
+ double hit_per = 0;
+ double miss_per = 0;
+ if (total) {
+ hit_per = 100.0 * hits / total;
+ miss_per = 100.0 * misses / total;
+ }
+ printf("\n");
+ printf("Dcache hits %10llu %6.2f%%\n", hits, hit_per);
+ printf("Dcache misses %10llu %6.2f%%\n", misses, miss_per);
+ printf("Dcache total %10llu\n", hits + misses);
+}
+
+void dcache_free()
+{
+ free(dcache.table[0]);
+ free(dcache.table);
+ free(dcache.replace);
+ dcache.table = NULL;
+}
+
+void dcache_cleanup()
+{
+ dcache_stats();
+ dcache_free();
+}
+
+void compress_trace_addresses(TraceAddr *trace_addr)
+{
+ AddrRec *ptr;
+ char *comp_ptr = trace_addr->compressed_ptr;
+ uint32_t prev_addr = trace_addr->prev_addr;
+ uint64_t prev_time = trace_addr->prev_time;
+ AddrRec *last = &trace_addr->buffer[kMaxNumAddrs];
+ for (ptr = trace_addr->buffer; ptr != last; ++ptr) {
+ if (comp_ptr >= trace_addr->high_water_ptr) {
+ uint32_t size = comp_ptr - trace_addr->compressed;
+ fwrite(trace_addr->compressed, sizeof(char), size, trace_addr->fstream);
+ comp_ptr = trace_addr->compressed;
+ }
+
+ int addr_diff = ptr->addr - prev_addr;
+ uint64_t time_diff = ptr->time - prev_time;
+ prev_addr = ptr->addr;
+ prev_time = ptr->time;
+
+ comp_ptr = varint_encode_signed(addr_diff, comp_ptr);
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ }
+ trace_addr->compressed_ptr = comp_ptr;
+ trace_addr->prev_addr = prev_addr;
+ trace_addr->prev_time = prev_time;
+}
+
+// This function is called by the generated code to simulate
+// a dcache load access.
+void dcache_load(uint32_t addr)
+{
+ int ii;
+ int ways = dcache.ways;
+ uint32_t cache_addr = addr >> dcache.log_line_size;
+ int row = cache_addr & dcache.addr_mask;
+ //printf("ld %lld 0x%x\n", sim_time, addr);
+ for (ii = 0; ii < ways; ++ii) {
+ if (cache_addr == dcache.table[row][ii]) {
+ dcache.load_hits += 1;
+#if 0
+ printf("dcache load hit addr: 0x%x cache_addr: 0x%x row %d way %d\n",
+ addr, cache_addr, row, ii);
+#endif
+ // If we are tracing all addresses, then include this in the trace.
+ if (trace_all_addr) {
+ AddrRec *next = trace_load.next;
+ next->addr = addr;
+ next->time = sim_time;
+ next += 1;
+ if (next == &trace_load.buffer[kMaxNumAddrs]) {
+ // Compress the trace
+ compress_trace_addresses(&trace_load);
+ next = &trace_load.buffer[0];
+ }
+ trace_load.next = next;
+ }
+ return;
+ }
+ }
+ // This is a cache miss
+
+#if 0
+ if (ftrace_debug)
+ fprintf(ftrace_debug, "t%lld %08x\n", sim_time, addr);
+#endif
+ if (trace_load.fstream) {
+ AddrRec *next = trace_load.next;
+ next->addr = addr;
+ next->time = sim_time;
+ next += 1;
+ if (next == &trace_load.buffer[kMaxNumAddrs]) {
+ // Compress the trace
+ compress_trace_addresses(&trace_load);
+ next = &trace_load.buffer[0];
+ }
+ trace_load.next = next;
+ }
+
+ dcache.load_misses += 1;
+ sim_time += dcache.load_miss_penalty;
+
+ // Pick a way to replace
+ int way;
+ if (dcache.replace_policy == kPolicyRoundRobin) {
+ // Round robin replacement policy
+ way = dcache.replace[row];
+ int next_way = way + 1;
+ if (next_way == dcache.ways)
+ next_way = 0;
+ dcache.replace[row] = next_way;
+ } else {
+ // Random replacement policy
+ way = dcache.next_way;
+ dcache.next_way += 1;
+ if (dcache.next_way >= dcache.ways)
+ dcache.next_way = 0;
+
+ // Every 13 replacements, add an extra increment to the next way
+ dcache.extra_increment_counter += 1;
+ if (dcache.extra_increment_counter == 13) {
+ dcache.extra_increment_counter = 0;
+ dcache.next_way += 1;
+ if (dcache.next_way >= dcache.ways)
+ dcache.next_way = 0;
+ }
+ }
+#if 0
+ printf("dcache load miss addr: 0x%x cache_addr: 0x%x row %d replacing way %d\n",
+ addr, cache_addr, row, way);
+#endif
+ dcache.table[row][way] = cache_addr;
+}
+
+// This function is called by the generated code to simulate
+// a dcache store access.
+void dcache_store(uint32_t addr, uint32_t val)
+{
+ // Check for a write to a magic address (this is a virtual address)
+ //printf("st %lld 0x%08x val 0x%x\n", sim_time, addr, val);
+ if ((addr & kMagicBaseMask) == kMagicBaseAddr) {
+ uint32_t offset = addr & kMagicOffsetMask;
+ switch (offset) {
+ case kMethodTraceEnterOffset:
+ trace_interpreted_method(val, kMethodEnter);
+ break;
+ case kMethodTraceExitOffset:
+ trace_interpreted_method(val, kMethodExit);
+ break;
+ case kMethodTraceExceptionOffset:
+ trace_interpreted_method(val, kMethodException);
+ break;
+ }
+ }
+
+ int ii;
+ int ways = dcache.ways;
+ uint32_t cache_addr = addr >> dcache.log_line_size;
+ int row = cache_addr & dcache.addr_mask;
+ for (ii = 0; ii < ways; ++ii) {
+ if (cache_addr == dcache.table[row][ii]) {
+ dcache.store_hits += 1;
+#if 0
+ printf("dcache store hit addr: 0x%x cache_addr: 0x%x row %d way %d\n",
+ addr, cache_addr, row, ii);
+#endif
+ // If we are tracing all addresses, then include this in the trace.
+ if (trace_all_addr) {
+ AddrRec *next = trace_store.next;
+ next->addr = addr;
+ next->time = sim_time;
+ next += 1;
+ if (next == &trace_store.buffer[kMaxNumAddrs]) {
+ // Compress the trace
+ compress_trace_addresses(&trace_store);
+ next = &trace_store.buffer[0];
+ }
+ trace_store.next = next;
+ }
+ return;
+ }
+ }
+ // This is a cache miss
+#if 0
+ printf("dcache store miss addr: 0x%x cache_addr: 0x%x row %d\n",
+ addr, cache_addr, row);
+#endif
+
+#if 0
+ if (ftrace_debug)
+ fprintf(ftrace_debug, "t%lld %08x\n", sim_time, addr);
+#endif
+
+ if (trace_store.fstream) {
+ AddrRec *next = trace_store.next;
+ next->addr = addr;
+ next->time = sim_time;
+ next += 1;
+ if (next == &trace_store.buffer[kMaxNumAddrs]) {
+ // Compress the trace
+ compress_trace_addresses(&trace_store);
+ next = &trace_store.buffer[0];
+ }
+ trace_store.next = next;
+ }
+
+ dcache.store_misses += 1;
+ sim_time += dcache.store_miss_penalty;
+
+ // Assume no write-allocate for now
+}
+
+// This function is called by the generated code to simulate
+// a dcache load and store (swp) access.
+void dcache_swp(uint32_t addr)
+{
+ dcache_load(addr);
+ dcache_store(addr, 0);
+}
diff --git a/dcache.h b/dcache.h
new file mode 100644
index 0000000..15e249b
--- /dev/null
+++ b/dcache.h
@@ -0,0 +1,24 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef DCACHE_H
+#define DCACHE_H
+
+#include <inttypes.h>
+
+// Define constants for the replacement policies
+#define kPolicyRoundRobin 1
+#define kPolicyRandom 2
+
+extern void dcache_init(int size, int ways, int line_size, int replace_policy,
+ int load_miss_penalty, int store_miss_penalty);
+
+#endif /* DCACHE_H */
diff --git a/distrib/Makefile b/distrib/Makefile
new file mode 100644
index 0000000..677b0bb
--- /dev/null
+++ b/distrib/Makefile
@@ -0,0 +1,8 @@
+ZLIB_VERSION := zlib-1.2.3
+LIBPNG_VERSION := libpng-1.2.19
+
+ZLIB_DIR = $(SRC_PATH)/distrib/$(ZLIB_VERSION)
+LIBPNG_DIR := $(SRC_PATH)/distrib/$(LIBPNG_VERSION)
+
+include $(ZLIB_DIR)/Makefile
+include $(LIBPNG_DIR)/Makefile
diff --git a/distrib/README b/distrib/README
new file mode 100644
index 0000000..8a2cf52
--- /dev/null
+++ b/distrib/README
@@ -0,0 +1,50 @@
+This is source release of the Android emulator. simply run the "build-emulator.sh" script to
+generate a statically linked "emulator" binary in the current directory.
+
+you can also use the "--target=<path>" option to install the executable into a different location,
+
+At the moment, only Linux and Mac OS X are supported.
+
+This emulator is probably not usable without other support files provided by the Android project,
+like a specific kernel image, ramdisk, system and user disk images. Please go to the Android web
+site for more details.
+
+This emulator is licensed under the GNU General Public License (GPL) version 2, which can be
+found in the file "qemu/COPYING".
+
+it is based on QEMU 0.8.2 with many changes used to support the following features:
+
+ - additionnal hardware support for some Android reference boards.
+
+ - various OS-X related patches to make everything compile cleanly with GCC 4.1 and
+ beyond. this includes better support for the Mach-O binary format
+
+ - support for instruction-level profiling and data cache simulation. this allows the
+ emulator to generate "profile" files that can later be analyzed with external tools
+ to provide accurate information about what's happening in the system
+
+ - changes in the dynamic code generators, mainly to support concurrent generators in
+ a single binary (this allows us to use different generators for profiling and
+ non-profiling modes, and switch between them dynamically at runtime when needed)
+
+ - support for network throttling and latency simulation, used to better emulate the
+ network conditions of radio networks.
+
+ - a new graphical user interface capable of displaying and rotating "device skins"
+
+ - an optional (and disabled by default) "polling" runtime mode that doesn't use
+ SIGALRM signals to implement timers. this makes for much better timing accuracy
+ when using "old" emukated Linux kernels, at the cost of using 100% CPU, even when
+ the guest system is idle. This is now disabled since Linux 2.6.21 and beyond use
+ "dynamic ticks" that make this mode un-necessary for Android.
+
+
+it also uses a patched version of LibSDL-1.2.12 which implements the following:
+
+ - prevent a fatal bug in Quartz Extreme's QuickDraw emulation to crash the program
+ whenever SDL_WINDOW_POS is set in the environment before starting the program.
+ the patch implements a simple workaround to this system-level problem.
+
+ - new APIs: SDL_WM_GetPos() and SDL_WM_SetPos() are used to retrieve and set the emulator
+ window position. this allows us to implement a simple-yet-useful feature: the emulator remembers
+ its position among restarts.
diff --git a/distrib/build-emulator.sh b/distrib/build-emulator.sh
new file mode 100755
index 0000000..a904fad
--- /dev/null
+++ b/distrib/build-emulator.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+# this script is used to build a static version of the Android emulator
+# from our distribution package.
+#
+cd $(dirname $0)
+CURDIR=$(pwd)
+
+show_help=
+TARGET=emulator
+for opt; do
+ optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
+ case "$opt" in
+ --help|-h|-\?) show_help=yes
+ ;;
+ --target=*) TARGET=$optarg
+ ;;
+ esac
+done
+
+if [ -n "$show_help" ] ; then
+ echo "usage: build-emulator [--target=FILEPATH]"
+ exit 1
+fi
+
+# directory where we'll place the temporary SDL binaries
+LOCAL=$CURDIR/local
+
+cd $CURDIR/sdl
+if ! (./android-configure --prefix=$LOCAL && make && make install); then
+ echo "ERROR: could not build SDL library, please check their sources"
+fi
+
+cd $CURDIR/qemu
+if ! (./android-rebuild.sh --sdl-config=$LOCAL/bin/sdl-config --install=$CURDIR/emulator); then
+ echo "ERROR: could not build SDL library"
+fi
diff --git a/distrib/build_gcc_qemu_darwin.sh b/distrib/build_gcc_qemu_darwin.sh
new file mode 100755
index 0000000..4c82af4
--- /dev/null
+++ b/distrib/build_gcc_qemu_darwin.sh
@@ -0,0 +1,482 @@
+#!/bin/sh
+# APPLE LOCAL file B&I
+
+set -x
+
+# set BUILD_CPLUSPLUS to 'true' if you want to compile support for C++
+BUILD_CPLUSPLUS=false
+
+# set BUILD_DOCS to 'true' to build and install the documentation
+BUILD_DOCS=false
+
+# set BUILD_SYM to 'true' to build and install symbolic binaries
+BUILD_SYM=false
+
+# -arch arguments are different than configure arguments. We need to
+# translate them.
+
+TRANSLATE_ARCH="sed -e s/ppc/powerpc/ -e s/i386/i686/"
+
+# Build GCC the "Apple way".
+# Parameters:
+
+# The first parameter is a space-separated list of the architectures
+# the compilers will run on. For instance, "ppc i386". If the
+# current machine isn't in the list, it will (effectively) be added.
+#HOSTS=`echo $1 | $TRANSLATE_ARCH `
+HOSTS=i686
+
+# The second parameter is a space-separated list of the architectures the
+# compilers will generate code for. If the current machine isn't in
+# the list, a compiler for it will get built anyway, but won't be
+# installed.
+#TARGETS=`echo $2 | $TRANSLATE_ARCH`
+TARGETS=i686
+
+# The GNU makefile target ('bootstrap' by default).
+BOOTSTRAP=${BOOTSTRAP-bootstrap}
+
+# The B&I build srcript (~rc/bin/buildit) accepts an '-othercflags'
+# command-line flag, and captures the argument to that flag in
+# $RC_NONARCH_CFLAGS (and mysteriously prepends '-pipe' thereto).
+# We will allow this to override the default $CFLAGS and $CXXFLAGS.
+
+CFLAGS="-g -O2 ${RC_NONARCH_CFLAGS/-pipe/}"
+
+# This isn't a parameter; it is the architecture of the current machine.
+BUILD=`arch | $TRANSLATE_ARCH`
+
+# The third parameter is the path to the compiler sources. There should
+# be a shell script named 'configure' in this directory. This script
+# makes a copy...
+#ORIG_SRC_DIR="$3"
+ORIG_SRC_DIR=`dirname $0`
+ORIG_SRC_DIR=`pwd`/$ORIG_SRC_DIR
+
+# The fourth parameter is the location where the compiler will be installed,
+# normally "/usr". You can move it once it's built, so this mostly controls
+# the layout of $DEST_DIR.
+#DEST_ROOT="$4"
+DEST_ROOT=/
+
+# The fifth parameter is the place where the compiler will be copied once
+# it's built.
+#DEST_DIR="$5"
+DEST_DIR=/Volumes/Android/device/prebuilt/darwin-x86/gcc-qemu
+
+# The sixth parameter is a directory in which to place information (like
+# unstripped executables and generated source files) helpful in debugging
+# the resulting compiler.
+#SYM_DIR="$6"
+SYM_DIR=`pwd`/sym
+
+# The current working directory is where the build will happen.
+# It may already contain a partial result of an interrupted build,
+# in which case this script will continue where it left off.
+DIR=`pwd`
+
+# This isn't a parameter; it's the version of the compiler that we're
+# about to build. It's included in the names of various files and
+# directories in the installed image.
+VERS=`sed -n -e '/version_string/s/.*\"\([^ \"]*\)[ \"].*/\1/p' \
+ < $ORIG_SRC_DIR/gcc/version.c || exit 1`
+
+# This isn't a parameter either, it's the major version of the compiler
+# to be built. It's VERS but only up to the second '.' (if there is one).
+MAJ_VERS=`echo $VERS | sed 's/\([0-9]*\.[0-9]*\)[.-].*/\1/'`
+
+# This is the default architecture for i386 configurations.
+I386_CPU="--with-arch=pentium-m --with-tune=prescott"
+
+# This is the libstdc++ version to use.
+LIBSTDCXX_VERSION=4.0.0
+
+# Sniff to see if we can do ppc64 building.
+DARWIN_VERS=8
+if [ x"`file /usr/lib/crt1.o | grep 'architecture ppc64'`" == x ]; then
+ DARWIN_VERS=7
+fi
+
+echo DARWIN_VERS = $DARWIN_VERS
+
+########################################
+# Run the build.
+
+# Create the source tree we'll actually use to build, deleting
+# tcl since it doesn't actually build properly in a cross environment
+# and we don't really need it.
+SRC_DIR=$DIR/src
+rm -rf $SRC_DIR || exit 1
+mkdir $SRC_DIR || exit 1
+ln -s $ORIG_SRC_DIR/* $SRC_DIR/ || exit 1
+rm -rf $SRC_DIR/tcl $SRC_DIR/expect $SRC_DIR/dejagnu || exit 1
+# Also remove libstdc++ since it is built from a separate project.
+rm -rf $SRC_DIR/libstdc++-v3 || exit 1
+# Clean out old specs files
+rm -f /usr/lib/gcc/*/4.0.0/specs
+
+ENABLE_LANGUAGES="--enable-languages=c,objc"
+if [ $BUILD_CPLUSPLUS = true ] ; then
+ ENABLE_LANGUAGES="$ENABLE_LANGUAGES,c++,obj-c++"
+fi
+
+# These are the configure and build flags that are used.
+CONFIGFLAGS="--disable-checking -enable-werror \
+ --prefix=$DEST_ROOT \
+ --mandir=\${prefix}/share/man \
+ $ENABLE_LANGUAGES \
+ --program-transform-name=/^[cg][^.-]*$/s/$/-$MAJ_VERS/ \
+ --with-gxx-include-dir=\${prefix}/include/c++/$LIBSTDCXX_VERSION \
+ --with-slibdir=/usr/lib \
+ --build=$BUILD-apple-darwin$DARWIN_VERS
+ --disable-nls"
+
+# Figure out how many make processes to run.
+SYSCTL=`sysctl -n hw.activecpu`
+
+# hw.activecpu only available in 10.2.6 and later
+if [ -z "$SYSCTL" ]; then
+ SYSCTL=`sysctl -n hw.ncpu`
+fi
+
+# sysctl -n hw.* does not work when invoked via B&I chroot /BuildRoot.
+# Builders can default to 2, since even if they are single processor,
+# nothing else is running on the machine.
+if [ -z "$SYSCTL" ]; then
+ SYSCTL=2
+fi
+
+# The $LOCAL_MAKEFLAGS variable can be used to override $MAKEFLAGS.
+MAKEFLAGS=${LOCAL_MAKEFLAGS-"-j $SYSCTL"}
+
+# Build the native GCC. Do this even if the user didn't ask for it
+# because it'll be needed for the bootstrap.
+mkdir -p $DIR/obj-$BUILD-$BUILD $DIR/dst-$BUILD-$BUILD || exit 1
+cd $DIR/obj-$BUILD-$BUILD || exit 1
+if [ \! -f Makefile ]; then
+ $SRC_DIR/configure $CONFIGFLAGS \
+ `if [ $BUILD = i686 ] ; then echo $I386_CPU ; fi` \
+ --host=$BUILD-apple-darwin$DARWIN_VERS --target=$BUILD-apple-darwin$DARWIN_VERS || exit 1
+fi
+make $MAKEFLAGS $BOOTSTRAP CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS" || exit 1
+if [ $BUILD_DOCS = "true" ] ; then
+make $MAKEFLAGS html CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS" || exit 1
+fi
+make $MAKEFLAGS DESTDIR=$DIR/dst-$BUILD-$BUILD install-gcc install-target \
+ CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS" || exit 1
+
+# Add the compiler we just built to the path, giving it appropriate names.
+D=$DIR/dst-$BUILD-$BUILD/$DEST_ROOT/bin
+ln -f $D/gcc-$MAJ_VERS $D/gcc || exit 1
+ln -f $D/gcc $D/$BUILD-apple-darwin$DARWIN_VERS-gcc || exit 1
+PATH=$DIR/dst-$BUILD-$BUILD/$DEST_ROOT/bin:$PATH
+
+# The cross-tools' build process expects to find certain programs
+# under names like 'i386-apple-darwin$DARWIN_VERS-ar'; so make them.
+# Annoyingly, ranlib changes behaviour depending on what you call it,
+# so we have to use a shell script for indirection, grrr.
+rm -rf $DIR/bin || exit 1
+mkdir $DIR/bin || exit 1
+for prog in ar nm ranlib strip lipo ; do
+ for t in `echo $TARGETS $HOSTS | sort -u`; do
+ P=$DIR/bin/${t}-apple-darwin$DARWIN_VERS-${prog}
+ echo '#!/bin/sh' > $P || exit 1
+ echo 'exec /usr/bin/'${prog}' $*' >> $P || exit 1
+ chmod a+x $P || exit 1
+ done
+done
+for t in `echo $1 $2 | sort -u`; do
+ gt=`echo $t | $TRANSLATE_ARCH`
+ P=$DIR/bin/${gt}-apple-darwin$DARWIN_VERS-as
+ echo '#!/bin/sh' > $P || exit 1
+ echo 'exec /usr/bin/as -arch '${t}' $*' >> $P || exit 1
+ chmod a+x $P || exit 1
+done
+PATH=$DIR/bin:$PATH
+
+# Build the cross-compilers, using the compiler we just built.
+for t in $TARGETS ; do
+ if [ $t != $BUILD ] ; then
+ mkdir -p $DIR/obj-$BUILD-$t $DIR/dst-$BUILD-$t || exit 1
+ cd $DIR/obj-$BUILD-$t || exit 1
+ if [ \! -f Makefile ]; then
+ $SRC_DIR/configure $CONFIGFLAGS --enable-werror-always \
+ `if [ $t = i686 ] ; then echo $I386_CPU ; fi` \
+ --program-prefix=$t-apple-darwin$DARWIN_VERS- \
+ --host=$BUILD-apple-darwin$DARWIN_VERS --target=$t-apple-darwin$DARWIN_VERS || exit 1
+ fi
+ make $MAKEFLAGS all CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS" || exit 1
+ make $MAKEFLAGS DESTDIR=$DIR/dst-$BUILD-$t install-gcc install-target \
+ CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS" || exit 1
+
+ # Add the compiler we just built to the path.
+ PATH=$DIR/dst-$BUILD-$t/$DEST_ROOT/bin:$PATH
+ fi
+done
+
+# Rearrange various libraries, for no really good reason.
+for t in $TARGETS ; do
+ DT=$DIR/dst-$BUILD-$t
+ D=`echo $DT/$DEST_ROOT/lib/gcc/$t-apple-darwin$DARWIN_VERS/$VERS`
+ mv $D/static/libgcc.a $D/libgcc_static.a || exit 1
+ mv $D/kext/libgcc.a $D/libcc_kext.a || exit 1
+ rm -r $D/static $D/kext || exit 1
+done
+
+# Build the cross-hosted compilers.
+for h in $HOSTS ; do
+ if [ $h != $BUILD ] ; then
+ for t in $TARGETS ; do
+ mkdir -p $DIR/obj-$h-$t $DIR/dst-$h-$t || exit 1
+ cd $DIR/obj-$h-$t || exit 1
+ if [ $h = $t ] ; then
+ pp=
+ else
+ pp=$t-apple-darwin$DARWIN_VERS-
+ fi
+
+ if [ \! -f Makefile ]; then
+ $SRC_DIR/configure $CONFIGFLAGS \
+ `if [ $t = i686 ] ; then echo $I386_CPU ; fi` \
+ --program-prefix=$pp \
+ --host=$h-apple-darwin$DARWIN_VERS --target=$t-apple-darwin$DARWIN_VERS || exit 1
+ fi
+ make $MAKEFLAGS all-gcc CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS" || exit 1
+ make $MAKEFLAGS DESTDIR=$DIR/dst-$h-$t install-gcc \
+ CFLAGS="$CFLAGS" CXXFLAGS="$CFLAGS" || exit 1
+ done
+ fi
+done
+
+########################################
+# Construct the actual destination root, by copying stuff from
+# $DIR/dst-* to $DEST_DIR, with occasional 'lipo' commands.
+
+cd $DEST_DIR || exit 1
+
+# Clean out DEST_DIR in case -noclean was passed to buildit.
+rm -rf * || exit 1
+
+if [ $BUILD_DOCS = "true" ] ; then
+# HTML documentation
+HTMLDIR="/Developer/ADC Reference Library/documentation/DeveloperTools"
+mkdir -p ".$HTMLDIR" || exit 1
+cp -Rp $DIR/obj-$BUILD-$BUILD/gcc/HTML/* ".$HTMLDIR/" || exit 1
+
+# Manual pages
+mkdir -p .$DEST_ROOT/share || exit 1
+cp -Rp $DIR/dst-$BUILD-$BUILD$DEST_ROOT/share/man .$DEST_ROOT/share/ \
+ || exit 1
+fi
+
+# libexec
+cd $DIR/dst-$BUILD-$BUILD$DEST_ROOT/libexec/gcc/$BUILD-apple-darwin$DARWIN_VERS/$VERS \
+ || exit 1
+LIBEXEC_FILES=`find . -type f -print || exit 1`
+LIBEXEC_DIRS=`find . -type d -print || exit 1`
+cd $DEST_DIR || exit 1
+for t in $TARGETS ; do
+ DL=$DEST_ROOT/libexec/gcc/$t-apple-darwin$DARWIN_VERS/$VERS
+ for d in $LIBEXEC_DIRS ; do
+ mkdir -p .$DL/$d || exit 1
+ done
+ for f in $LIBEXEC_FILES ; do
+ if file $DIR/dst-*-$t$DL/$f | grep -q 'Mach-O executable' ; then
+ lipo -output .$DL/$f -create $DIR/dst-*-$t$DL/$f || exit 1
+ else
+ cp -p $DIR/dst-$BUILD-$t$DL/$f .$DL/$f || exit 1
+ fi
+ done
+done
+
+# bin
+# The native drivers ('native' is different in different architectures).
+BIN_FILES=`ls $DIR/dst-$BUILD-$BUILD$DEST_ROOT/bin | grep '^[^-]*-[0-9.]*$' \
+ | grep -v gccbug | grep -v gcov || exit 1`
+mkdir .$DEST_ROOT/bin
+for f in $BIN_FILES ; do
+ lipo -output .$DEST_ROOT/bin/$f -create $DIR/dst-*$DEST_ROOT/bin/$f || exit 1
+done
+# gcov, which is special only because it gets built multiple times and lipo
+# will complain if we try to add two architectures into the same output.
+TARG0=`echo $TARGETS | cut -d ' ' -f 1`
+lipo -output .$DEST_ROOT/bin/gcov-$MAJ_VERS -create \
+ $DIR/dst-*-$TARG0$DEST_ROOT/bin/*gcov* || exit 1
+# The fully-named drivers, which have the same target on every host.
+for t in $TARGETS ; do
+ lipo -output .$DEST_ROOT/bin/$t-apple-darwin$DARWIN_VERS-gcc-$VERS -create \
+ $DIR/dst-*-$t$DEST_ROOT/bin/$t-apple-darwin$DARWIN_VERS-gcc-$VERS || exit 1
+ if [ $BUILD_CPLUSPLUS = "true" ] ; then
+ lipo -output .$DEST_ROOT/bin/$t-apple-darwin$DARWIN_VERS-g++-$VERS -create \
+ $DIR/dst-*-$t$DEST_ROOT/bin/$t-apple-darwin$DARWIN_VERS-g++* || exit 1
+ fi
+done
+
+# lib
+mkdir -p .$DEST_ROOT/lib/gcc || exit 1
+for t in $TARGETS ; do
+ cp -Rp $DIR/dst-$BUILD-$t$DEST_ROOT/lib/gcc/$t-apple-darwin$DARWIN_VERS \
+ .$DEST_ROOT/lib/gcc || exit 1
+done
+
+SHARED_LIBS="libgcc_s.1.dylib libgcc_s.10.4.dylib libgcc_s.10.5.dylib"
+if echo $HOSTS | grep -q powerpc ; then
+ SHARED_LIBS="${SHARED_LIBS} libgcc_s_ppc64.1.dylib"
+fi
+for l in $SHARED_LIBS ; do
+ CANDIDATES=()
+ for t in $TARGETS ; do
+ if [ -e $DIR/dst-$t-$t$DEST_ROOT/lib/$l ] ; then
+ CANDIDATES[${#CANDIDATES[*]}]=$DIR/dst-$t-$t$DEST_ROOT/lib/$l
+ fi
+ done
+ if [ -L ${CANDIDATES[0]} ] ; then
+ ln -s `readlink ${CANDIDATES[0]}` .$DEST_ROOT/lib/$l || exit 1
+ else
+ lipo -output .$DEST_ROOT/lib/$l -create "${CANDIDATES[@]}" || exit 1
+ fi
+done
+
+if [ $BUILD_CPLUSPLUS = "true" ] ; then
+for t in $TARGETS ; do
+ ln -s ../../../libstdc++.6.dylib \
+ .$DEST_ROOT/lib/gcc/$t-apple-darwin$DARWIN_VERS/$VERS/libstdc++.dylib \
+ || exit 1
+done
+fi
+
+# include
+HEADERPATH=$DEST_ROOT/include/gcc/darwin/$MAJ_VERS
+mkdir -p .$HEADERPATH || exit 1
+
+# Some headers are installed from more-hdrs/. They all share
+# one common feature: they shouldn't be installed here. Sometimes,
+# they should be part of FSF GCC and installed from there; sometimes,
+# they should be installed by some completely different package; sometimes,
+# they only exist for codewarrior compatibility and codewarrior should provide
+# its own. We take care not to install the headers if Libc is already
+# providing them.
+cd $SRC_DIR/more-hdrs
+for h in `echo *.h` ; do
+ if [ ! -f /usr/include/$h -o -L /usr/include/$h ] ; then
+ cp -R $h $DEST_DIR$HEADERPATH/$h || exit 1
+ for t in $TARGETS ; do
+ THEADERPATH=$DEST_DIR$DEST_ROOT/lib/gcc/${t}-apple-darwin$DARWIN_VERS/$VERS/include
+ [ -f $THEADERPATH/$h ] || \
+ ln -s ../../../../../include/gcc/darwin/$MAJ_VERS/$h $THEADERPATH/$h || \
+ exit 1
+ done
+ fi
+done
+mkdir -p $DEST_DIR$HEADERPATH/machine
+for h in `echo */*.h` ; do
+ if [ ! -f /usr/include/$h -o -L /usr/include/$h ] ; then
+ cp -R $h $DEST_DIR$HEADERPATH/$h || exit 1
+ for t in $TARGETS ; do
+ THEADERPATH=$DEST_DIR$DEST_ROOT/lib/gcc/${t}-apple-darwin$DARWIN_VERS/$VERS/include
+ mkdir -p $THEADERPATH/machine
+ # In fixincludes/fixinc.in we created this file... always link for now
+ [ -f /disable/$THEADERPATH/$h ] || \
+ ln -f -s ../../../../../../include/gcc/darwin/$MAJ_VERS/$h $THEADERPATH/$h || \
+ exit 1
+ done
+ fi
+done
+
+if [ $BUILD_DOCS = "true" ] ; then
+if [ $BUILD_CPLUSPLUS = "true" ] ; then
+# Add extra man page symlinks for 'c++' and for arch-specific names.
+MDIR=$DEST_DIR$DEST_ROOT/share/man/man1
+ln -f $MDIR/g++-$MAJ_VERS.1 $MDIR/c++-$MAJ_VERS.1 || exit 1
+for t in $TARGETS ; do
+ ln -f $MDIR/gcc-$MAJ_VERS.1 $MDIR/$t-apple-darwin$DARWIN_VERS-gcc-$VERS.1 \
+ || exit 1
+ ln -f $MDIR/g++-$MAJ_VERS.1 $MDIR/$t-apple-darwin$DARWIN_VERS-g++-$VERS.1 \
+ || exit 1
+done
+fi
+fi
+
+# Build driver-driver using fully-named drivers
+for h in $HOSTS ; do
+ $DEST_DIR$DEST_ROOT/bin/$h-apple-darwin$DARWIN_VERS-gcc-$VERS \
+ $ORIG_SRC_DIR/gcc/config/darwin-driver.c \
+ -DPDN="\"-apple-darwin$DARWIN_VERS-gcc-$VERS\"" \
+ -DIL="\"$DEST_ROOT/bin/\"" -I $ORIG_SRC_DIR/include \
+ -I $ORIG_SRC_DIR/gcc -I $ORIG_SRC_DIR/gcc/config \
+ -liberty -L$DIR/dst-$BUILD-$h$DEST_ROOT/lib/ \
+ -L$DIR/dst-$BUILD-$h$DEST_ROOT/$h-apple-darwin$DARWIN_VERS/lib/ \
+ -L$DIR/obj-$h-$BUILD/libiberty/ \
+ -o $DEST_DIR/$DEST_ROOT/bin/tmp-$h-gcc-$MAJ_VERS || exit 1
+
+ if [ $BUILD_CPLUSPLUS = "true" ] ; then
+ $DEST_DIR$DEST_ROOT/bin/$h-apple-darwin$DARWIN_VERS-gcc-$VERS \
+ $ORIG_SRC_DIR/gcc/config/darwin-driver.c \
+ -DPDN="\"-apple-darwin$DARWIN_VERS-g++-$VERS\"" \
+ -DIL="\"$DEST_ROOT/bin/\"" -I $ORIG_SRC_DIR/include \
+ -I $ORIG_SRC_DIR/gcc -I $ORIG_SRC_DIR/gcc/config \
+ -liberty -L$DIR/dst-$BUILD-$h$DEST_ROOT/lib/ \
+ -L$DIR/dst-$BUILD-$h$DEST_ROOT/$h-apple-darwin$DARWIN_VERS/lib/ \
+ -L$DIR/obj-$h-$BUILD/libiberty/ \
+ -o $DEST_DIR/$DEST_ROOT/bin/tmp-$h-g++-$MAJ_VERS || exit 1
+ fi
+done
+
+lipo -output $DEST_DIR/$DEST_ROOT/bin/gcc-$MAJ_VERS -create \
+ $DEST_DIR/$DEST_ROOT/bin/tmp-*-gcc-$MAJ_VERS || exit 1
+
+if [ $BUILD_CPLUSPLUS = "true" ] ; then
+lipo -output $DEST_DIR/$DEST_ROOT/bin/g++-$MAJ_VERS -create \
+ $DEST_DIR/$DEST_ROOT/bin/tmp-*-g++-$MAJ_VERS || exit 1
+
+ln -f $DEST_DIR/$DEST_ROOT/bin/g++-$MAJ_VERS $DEST_DIR/$DEST_ROOT/bin/c++-$MAJ_VERS || exit 1
+fi
+
+rm $DEST_DIR/$DEST_ROOT/bin/tmp-*-gcc-$MAJ_VERS || exit 1
+if [ $BUILD_CPLUPLUS = "true" ] ; then
+rm $DEST_DIR/$DEST_ROOT/bin/tmp-*-g++-$MAJ_VERS || exit 1
+fi
+
+########################################
+# Save the source files and objects needed for debugging
+if [ $BUILD_SYM = "true" ] ; then
+cd $SYM_DIR || exit 1
+
+# Clean out SYM_DIR in case -noclean was passed to buildit.
+rm -rf * || exit 1
+
+# Save executables and libraries.
+cd $DEST_DIR || exit 1
+find . \( -perm -0111 -or -name \*.a -or -name \*.dylib \) -type f -print \
+ | cpio -pdml $SYM_DIR || exit 1
+# Save source files.
+mkdir $SYM_DIR/src || exit 1
+cd $DIR || exit 1
+find obj-* -name \*.\[chy\] -print | cpio -pdml $SYM_DIR/src || exit 1
+fi
+
+########################################
+# Strip the executables and libraries
+find $DEST_DIR -perm -0111 \! -name \*.dylib \! -name fixinc.sh \
+ \! -name mkheaders -type f -print \
+ | xargs strip || exit 1
+find $DEST_DIR \( -name \*.a -or -name \*.dylib \) \
+ \! -name libgcc_s.10.*.dylib -type f -print \
+ | xargs strip -SX || exit 1
+find $DEST_DIR -name \*.a -type f -print \
+ | xargs ranlib || exit 1
+chgrp -h -R wheel $DEST_DIR
+chgrp -R wheel $DEST_DIR
+
+#########################################3
+# Rename the executables
+FILES="gcc cpp"
+if [ $BUILD_CPLUSPLUS = "true" ] ; then
+ FILES="$FILES g++"
+fi
+for ff in $FILES; do
+ ln -f $DEST_DIR/bin/$ff-$MAJ_VERS $DEST_DIR/bin/$ff || exit 1
+done
+
+# Done!
+exit 0
diff --git a/distrib/libpng-1.2.19/Makefile b/distrib/libpng-1.2.19/Makefile
new file mode 100644
index 0000000..ba59f45
--- /dev/null
+++ b/distrib/libpng-1.2.19/Makefile
@@ -0,0 +1,25 @@
+# Makefile used to compile libpng statically
+# you need to define ZLIB_INCLUDE to the Zlib include path
+# and PREFIX to the installation path
+#
+LIBPNG_LIB := $(SRC_PATH)/libpng.a
+LIBPNG_CFLAGS := -I$(LIBPNG_DIR)
+
+HOST_ARCH := $(shell uname -p)
+HOST_OS := $(shell uname -s)
+ifeq ($(HOST_OS),Darwin)
+ HOST_OS := darwin
+endif
+
+include $(LIBPNG_DIR)/sources.make
+
+LIBPNG_OBJS := $(LIBPNG_SOURCES:%.c=%.o)
+
+$(LIBPNG_LIB): $(LIBPNG_OBJS)
+ ar ru $@ $(LIBPNG_OBJS)
+
+$(LIBPNG_OBJS): CFLAGS += $(ZLIB_CFLAGS) $(LIBPNG_CFLAGS)
+
+clean-libpng:
+ rm -f $(LIBPNG_OBJS) $(LIBPNG_LIB)
+
diff --git a/distrib/libpng-1.2.19/png.c b/distrib/libpng-1.2.19/png.c
new file mode 100644
index 0000000..8aa4131
--- /dev/null
+++ b/distrib/libpng-1.2.19/png.c
@@ -0,0 +1,895 @@
+
+/* png.c - location for general purpose libpng functions
+ *
+ * Last changed in libpng 1.2.19 August 18, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#define PNG_NO_EXTERN
+#include "png.h"
+
+/* Generate a compiler error if there is an old png.h in the search path. */
+typedef version_1_2_19 Your_png_h_is_not_version_1_2_19;
+
+/* Version information for C files. This had better match the version
+ * string defined in png.h. */
+
+#ifdef PNG_USE_GLOBAL_ARRAYS
+/* png_libpng_ver was changed to a function in version 1.0.5c */
+PNG_CONST char png_libpng_ver[18] = PNG_LIBPNG_VER_STRING;
+
+#ifdef PNG_READ_SUPPORTED
+
+/* png_sig was changed to a function in version 1.0.5c */
+/* Place to hold the signature string for a PNG file. */
+PNG_CONST png_byte FARDATA png_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+#endif /* PNG_READ_SUPPORTED */
+
+/* Invoke global declarations for constant strings for known chunk types */
+PNG_IHDR;
+PNG_IDAT;
+PNG_IEND;
+PNG_PLTE;
+PNG_bKGD;
+PNG_cHRM;
+PNG_gAMA;
+PNG_hIST;
+PNG_iCCP;
+PNG_iTXt;
+PNG_oFFs;
+PNG_pCAL;
+PNG_sCAL;
+PNG_pHYs;
+PNG_sBIT;
+PNG_sPLT;
+PNG_sRGB;
+PNG_tEXt;
+PNG_tIME;
+PNG_tRNS;
+PNG_zTXt;
+
+#ifdef PNG_READ_SUPPORTED
+/* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+/* start of interlace block */
+PNG_CONST int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
+
+/* offset to next interlace block */
+PNG_CONST int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+
+/* start of interlace block in the y direction */
+PNG_CONST int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
+
+/* offset to next interlace block in the y direction */
+PNG_CONST int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
+
+/* width of interlace block (used in assembler routines only) */
+#if defined(PNG_HAVE_MMX_COMBINE_ROW) || defined(PNG_OPTIMIZED_CODE_SUPPORTED)
+PNG_CONST int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1};
+#endif
+
+/* Height of interlace block. This is not currently used - if you need
+ * it, uncomment it here and in png.h
+PNG_CONST int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
+*/
+
+/* Mask to determine which pixels are valid in a pass */
+PNG_CONST int FARDATA png_pass_mask[] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
+
+/* Mask to determine which pixels to overwrite while displaying */
+PNG_CONST int FARDATA png_pass_dsp_mask[]
+ = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
+
+#endif /* PNG_READ_SUPPORTED */
+#endif /* PNG_USE_GLOBAL_ARRAYS */
+
+/* Tells libpng that we have already handled the first "num_bytes" bytes
+ * of the PNG file signature. If the PNG data is embedded into another
+ * stream we can set num_bytes = 8 so that libpng will not attempt to read
+ * or write any of the magic bytes before it starts on the IHDR.
+ */
+
+#ifdef PNG_READ_SUPPORTED
+void PNGAPI
+png_set_sig_bytes(png_structp png_ptr, int num_bytes)
+{
+ if(png_ptr == NULL) return;
+ png_debug(1, "in png_set_sig_bytes\n");
+ if (num_bytes > 8)
+ png_error(png_ptr, "Too many bytes for PNG signature.");
+
+ png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes);
+}
+
+/* Checks whether the supplied bytes match the PNG signature. We allow
+ * checking less than the full 8-byte signature so that those apps that
+ * already read the first few bytes of a file to determine the file type
+ * can simply check the remaining bytes for extra assurance. Returns
+ * an integer less than, equal to, or greater than zero if sig is found,
+ * respectively, to be less than, to match, or be greater than the correct
+ * PNG signature (this is the same behaviour as strcmp, memcmp, etc).
+ */
+int PNGAPI
+png_sig_cmp(png_bytep sig, png_size_t start, png_size_t num_to_check)
+{
+ png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+ if (num_to_check > 8)
+ num_to_check = 8;
+ else if (num_to_check < 1)
+ return (-1);
+
+ if (start > 7)
+ return (-1);
+
+ if (start + num_to_check > 8)
+ num_to_check = 8 - start;
+
+ return ((int)(png_memcmp(&sig[start], &png_signature[start], num_to_check)));
+}
+
+#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
+/* (Obsolete) function to check signature bytes. It does not allow one
+ * to check a partial signature. This function might be removed in the
+ * future - use png_sig_cmp(). Returns true (nonzero) if the file is PNG.
+ */
+int PNGAPI
+png_check_sig(png_bytep sig, int num)
+{
+ return ((int)!png_sig_cmp(sig, (png_size_t)0, (png_size_t)num));
+}
+#endif
+#endif /* PNG_READ_SUPPORTED */
+
+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+/* Function to allocate memory for zlib and clear it to 0. */
+#ifdef PNG_1_0_X
+voidpf PNGAPI
+#else
+voidpf /* private */
+#endif
+png_zalloc(voidpf png_ptr, uInt items, uInt size)
+{
+ png_voidp ptr;
+ png_structp p=(png_structp)png_ptr;
+ png_uint_32 save_flags=p->flags;
+ png_uint_32 num_bytes;
+
+ if(png_ptr == NULL) return (NULL);
+ if (items > PNG_UINT_32_MAX/size)
+ {
+ png_warning (p, "Potential overflow in png_zalloc()");
+ return (NULL);
+ }
+ num_bytes = (png_uint_32)items * size;
+
+ p->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK;
+ ptr = (png_voidp)png_malloc((png_structp)png_ptr, num_bytes);
+ p->flags=save_flags;
+
+#if defined(PNG_1_0_X) && !defined(PNG_NO_ZALLOC_ZERO)
+ if (ptr == NULL)
+ return ((voidpf)ptr);
+
+ if (num_bytes > (png_uint_32)0x8000L)
+ {
+ png_memset(ptr, 0, (png_size_t)0x8000L);
+ png_memset((png_bytep)ptr + (png_size_t)0x8000L, 0,
+ (png_size_t)(num_bytes - (png_uint_32)0x8000L));
+ }
+ else
+ {
+ png_memset(ptr, 0, (png_size_t)num_bytes);
+ }
+#endif
+ return ((voidpf)ptr);
+}
+
+/* function to free memory for zlib */
+#ifdef PNG_1_0_X
+void PNGAPI
+#else
+void /* private */
+#endif
+png_zfree(voidpf png_ptr, voidpf ptr)
+{
+ png_free((png_structp)png_ptr, (png_voidp)ptr);
+}
+
+/* Reset the CRC variable to 32 bits of 1's. Care must be taken
+ * in case CRC is > 32 bits to leave the top bits 0.
+ */
+void /* PRIVATE */
+png_reset_crc(png_structp png_ptr)
+{
+ png_ptr->crc = crc32(0, Z_NULL, 0);
+}
+
+/* Calculate the CRC over a section of data. We can only pass as
+ * much data to this routine as the largest single buffer size. We
+ * also check that this data will actually be used before going to the
+ * trouble of calculating it.
+ */
+void /* PRIVATE */
+png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length)
+{
+ int need_crc = 1;
+
+ if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
+ {
+ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+ (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ need_crc = 0;
+ }
+ else /* critical */
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ need_crc = 0;
+ }
+
+ if (need_crc)
+ png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
+}
+
+/* Allocate the memory for an info_struct for the application. We don't
+ * really need the png_ptr, but it could potentially be useful in the
+ * future. This should be used in favour of malloc(png_sizeof(png_info))
+ * and png_info_init() so that applications that want to use a shared
+ * libpng don't have to be recompiled if png_info changes size.
+ */
+png_infop PNGAPI
+png_create_info_struct(png_structp png_ptr)
+{
+ png_infop info_ptr;
+
+ png_debug(1, "in png_create_info_struct\n");
+ if(png_ptr == NULL) return (NULL);
+#ifdef PNG_USER_MEM_SUPPORTED
+ info_ptr = (png_infop)png_create_struct_2(PNG_STRUCT_INFO,
+ png_ptr->malloc_fn, png_ptr->mem_ptr);
+#else
+ info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
+#endif
+ if (info_ptr != NULL)
+ png_info_init_3(&info_ptr, png_sizeof(png_info));
+
+ return (info_ptr);
+}
+
+/* This function frees the memory associated with a single info struct.
+ * Normally, one would use either png_destroy_read_struct() or
+ * png_destroy_write_struct() to free an info struct, but this may be
+ * useful for some applications.
+ */
+void PNGAPI
+png_destroy_info_struct(png_structp png_ptr, png_infopp info_ptr_ptr)
+{
+ png_infop info_ptr = NULL;
+ if(png_ptr == NULL) return;
+
+ png_debug(1, "in png_destroy_info_struct\n");
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (info_ptr != NULL)
+ {
+ png_info_destroy(png_ptr, info_ptr);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)info_ptr, png_ptr->free_fn,
+ png_ptr->mem_ptr);
+#else
+ png_destroy_struct((png_voidp)info_ptr);
+#endif
+ *info_ptr_ptr = NULL;
+ }
+}
+
+/* Initialize the info structure. This is now an internal function (0.89)
+ * and applications using it are urged to use png_create_info_struct()
+ * instead.
+ */
+#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
+#undef png_info_init
+void PNGAPI
+png_info_init(png_infop info_ptr)
+{
+ /* We only come here via pre-1.0.12-compiled applications */
+ png_info_init_3(&info_ptr, 0);
+}
+#endif
+
+void PNGAPI
+png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size)
+{
+ png_infop info_ptr = *ptr_ptr;
+
+ if(info_ptr == NULL) return;
+
+ png_debug(1, "in png_info_init_3\n");
+
+ if(png_sizeof(png_info) > png_info_struct_size)
+ {
+ png_destroy_struct(info_ptr);
+ info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
+ *ptr_ptr = info_ptr;
+ }
+
+ /* set everything to 0 */
+ png_memset(info_ptr, 0, png_sizeof (png_info));
+}
+
+#ifdef PNG_FREE_ME_SUPPORTED
+void PNGAPI
+png_data_freer(png_structp png_ptr, png_infop info_ptr,
+ int freer, png_uint_32 mask)
+{
+ png_debug(1, "in png_data_freer\n");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+ if(freer == PNG_DESTROY_WILL_FREE_DATA)
+ info_ptr->free_me |= mask;
+ else if(freer == PNG_USER_WILL_FREE_DATA)
+ info_ptr->free_me &= ~mask;
+ else
+ png_warning(png_ptr,
+ "Unknown freer parameter in png_data_freer.");
+}
+#endif
+
+void PNGAPI
+png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
+ int num)
+{
+ png_debug(1, "in png_free_data\n");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+#if defined(PNG_TEXT_SUPPORTED)
+/* free text item num or (if num == -1) all text items */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_TEXT)
+#endif
+{
+ if (num != -1)
+ {
+ if (info_ptr->text && info_ptr->text[num].key)
+ {
+ png_free(png_ptr, info_ptr->text[num].key);
+ info_ptr->text[num].key = NULL;
+ }
+ }
+ else
+ {
+ int i;
+ for (i = 0; i < info_ptr->num_text; i++)
+ png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);
+ png_free(png_ptr, info_ptr->text);
+ info_ptr->text = NULL;
+ info_ptr->num_text=0;
+ }
+}
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+/* free any tRNS entry */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
+#else
+if ((mask & PNG_FREE_TRNS) && (png_ptr->flags & PNG_FLAG_FREE_TRNS))
+#endif
+{
+ png_free(png_ptr, info_ptr->trans);
+ info_ptr->valid &= ~PNG_INFO_tRNS;
+#ifndef PNG_FREE_ME_SUPPORTED
+ png_ptr->flags &= ~PNG_FLAG_FREE_TRNS;
+#endif
+ info_ptr->trans = NULL;
+}
+#endif
+
+#if defined(PNG_sCAL_SUPPORTED)
+/* free any sCAL entry */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_SCAL)
+#endif
+{
+#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
+ png_free(png_ptr, info_ptr->scal_s_width);
+ png_free(png_ptr, info_ptr->scal_s_height);
+ info_ptr->scal_s_width = NULL;
+ info_ptr->scal_s_height = NULL;
+#endif
+ info_ptr->valid &= ~PNG_INFO_sCAL;
+}
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+/* free any pCAL entry */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_PCAL)
+#endif
+{
+ png_free(png_ptr, info_ptr->pcal_purpose);
+ png_free(png_ptr, info_ptr->pcal_units);
+ info_ptr->pcal_purpose = NULL;
+ info_ptr->pcal_units = NULL;
+ if (info_ptr->pcal_params != NULL)
+ {
+ int i;
+ for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
+ {
+ png_free(png_ptr, info_ptr->pcal_params[i]);
+ info_ptr->pcal_params[i]=NULL;
+ }
+ png_free(png_ptr, info_ptr->pcal_params);
+ info_ptr->pcal_params = NULL;
+ }
+ info_ptr->valid &= ~PNG_INFO_pCAL;
+}
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+/* free any iCCP entry */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_ICCP)
+#endif
+{
+ png_free(png_ptr, info_ptr->iccp_name);
+ png_free(png_ptr, info_ptr->iccp_profile);
+ info_ptr->iccp_name = NULL;
+ info_ptr->iccp_profile = NULL;
+ info_ptr->valid &= ~PNG_INFO_iCCP;
+}
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+/* free a given sPLT entry, or (if num == -1) all sPLT entries */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_SPLT)
+#endif
+{
+ if (num != -1)
+ {
+ if(info_ptr->splt_palettes)
+ {
+ png_free(png_ptr, info_ptr->splt_palettes[num].name);
+ png_free(png_ptr, info_ptr->splt_palettes[num].entries);
+ info_ptr->splt_palettes[num].name = NULL;
+ info_ptr->splt_palettes[num].entries = NULL;
+ }
+ }
+ else
+ {
+ if(info_ptr->splt_palettes_num)
+ {
+ int i;
+ for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
+ png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i);
+
+ png_free(png_ptr, info_ptr->splt_palettes);
+ info_ptr->splt_palettes = NULL;
+ info_ptr->splt_palettes_num = 0;
+ }
+ info_ptr->valid &= ~PNG_INFO_sPLT;
+ }
+}
+#endif
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ if(png_ptr->unknown_chunk.data)
+ {
+ png_free(png_ptr, png_ptr->unknown_chunk.data);
+ png_ptr->unknown_chunk.data = NULL;
+ }
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_UNKN)
+#endif
+{
+ if (num != -1)
+ {
+ if(info_ptr->unknown_chunks)
+ {
+ png_free(png_ptr, info_ptr->unknown_chunks[num].data);
+ info_ptr->unknown_chunks[num].data = NULL;
+ }
+ }
+ else
+ {
+ int i;
+
+ if(info_ptr->unknown_chunks_num)
+ {
+ for (i = 0; i < (int)info_ptr->unknown_chunks_num; i++)
+ png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i);
+
+ png_free(png_ptr, info_ptr->unknown_chunks);
+ info_ptr->unknown_chunks = NULL;
+ info_ptr->unknown_chunks_num = 0;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+/* free any hIST entry */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_HIST) & info_ptr->free_me)
+#else
+if ((mask & PNG_FREE_HIST) && (png_ptr->flags & PNG_FLAG_FREE_HIST))
+#endif
+{
+ png_free(png_ptr, info_ptr->hist);
+ info_ptr->hist = NULL;
+ info_ptr->valid &= ~PNG_INFO_hIST;
+#ifndef PNG_FREE_ME_SUPPORTED
+ png_ptr->flags &= ~PNG_FLAG_FREE_HIST;
+#endif
+}
+#endif
+
+/* free any PLTE entry that was internally allocated */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)
+#else
+if ((mask & PNG_FREE_PLTE) && (png_ptr->flags & PNG_FLAG_FREE_PLTE))
+#endif
+{
+ png_zfree(png_ptr, info_ptr->palette);
+ info_ptr->palette = NULL;
+ info_ptr->valid &= ~PNG_INFO_PLTE;
+#ifndef PNG_FREE_ME_SUPPORTED
+ png_ptr->flags &= ~PNG_FLAG_FREE_PLTE;
+#endif
+ info_ptr->num_palette = 0;
+}
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+/* free any image bits attached to the info structure */
+#ifdef PNG_FREE_ME_SUPPORTED
+if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)
+#else
+if (mask & PNG_FREE_ROWS)
+#endif
+{
+ if(info_ptr->row_pointers)
+ {
+ int row;
+ for (row = 0; row < (int)info_ptr->height; row++)
+ {
+ png_free(png_ptr, info_ptr->row_pointers[row]);
+ info_ptr->row_pointers[row]=NULL;
+ }
+ png_free(png_ptr, info_ptr->row_pointers);
+ info_ptr->row_pointers=NULL;
+ }
+ info_ptr->valid &= ~PNG_INFO_IDAT;
+}
+#endif
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ if(num == -1)
+ info_ptr->free_me &= ~mask;
+ else
+ info_ptr->free_me &= ~(mask & ~PNG_FREE_MUL);
+#endif
+}
+
+/* This is an internal routine to free any memory that the info struct is
+ * pointing to before re-using it or freeing the struct itself. Recall
+ * that png_free() checks for NULL pointers for us.
+ */
+void /* PRIVATE */
+png_info_destroy(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_info_destroy\n");
+
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ if (png_ptr->num_chunk_list)
+ {
+ png_free(png_ptr, png_ptr->chunk_list);
+ png_ptr->chunk_list=NULL;
+ png_ptr->num_chunk_list=0;
+ }
+#endif
+
+ png_info_init_3(&info_ptr, png_sizeof(png_info));
+}
+#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
+
+/* This function returns a pointer to the io_ptr associated with the user
+ * functions. The application should free any memory associated with this
+ * pointer before png_write_destroy() or png_read_destroy() are called.
+ */
+png_voidp PNGAPI
+png_get_io_ptr(png_structp png_ptr)
+{
+ if(png_ptr == NULL) return (NULL);
+ return (png_ptr->io_ptr);
+}
+
+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+#if !defined(PNG_NO_STDIO)
+/* Initialize the default input/output functions for the PNG file. If you
+ * use your own read or write routines, you can call either png_set_read_fn()
+ * or png_set_write_fn() instead of png_init_io(). If you have defined
+ * PNG_NO_STDIO, you must use a function of your own because "FILE *" isn't
+ * necessarily available.
+ */
+void PNGAPI
+png_init_io(png_structp png_ptr, png_FILE_p fp)
+{
+ png_debug(1, "in png_init_io\n");
+ if(png_ptr == NULL) return;
+ png_ptr->io_ptr = (png_voidp)fp;
+}
+#endif
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+/* Convert the supplied time into an RFC 1123 string suitable for use in
+ * a "Creation Time" or other text-based time string.
+ */
+png_charp PNGAPI
+png_convert_to_rfc1123(png_structp png_ptr, png_timep ptime)
+{
+ static PNG_CONST char short_months[12][4] =
+ {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+ if(png_ptr == NULL) return (NULL);
+ if (png_ptr->time_buffer == NULL)
+ {
+ png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29*
+ png_sizeof(char)));
+ }
+
+#if defined(_WIN32_WCE)
+ {
+ wchar_t time_buf[29];
+ wsprintf(time_buf, TEXT("%d %S %d %02d:%02d:%02d +0000"),
+ ptime->day % 32, short_months[(ptime->month - 1) % 12],
+ ptime->year, ptime->hour % 24, ptime->minute % 60,
+ ptime->second % 61);
+ WideCharToMultiByte(CP_ACP, 0, time_buf, -1, png_ptr->time_buffer, 29,
+ NULL, NULL);
+ }
+#else
+#ifdef USE_FAR_KEYWORD
+ {
+ char near_time_buf[29];
+ png_snprintf6(near_time_buf,29,"%d %s %d %02d:%02d:%02d +0000",
+ ptime->day % 32, short_months[(ptime->month - 1) % 12],
+ ptime->year, ptime->hour % 24, ptime->minute % 60,
+ ptime->second % 61);
+ png_memcpy(png_ptr->time_buffer, near_time_buf,
+ 29*png_sizeof(char));
+ }
+#else
+ png_snprintf6(png_ptr->time_buffer,29,"%d %s %d %02d:%02d:%02d +0000",
+ ptime->day % 32, short_months[(ptime->month - 1) % 12],
+ ptime->year, ptime->hour % 24, ptime->minute % 60,
+ ptime->second % 61);
+#endif
+#endif /* _WIN32_WCE */
+ return ((png_charp)png_ptr->time_buffer);
+}
+#endif /* PNG_TIME_RFC1123_SUPPORTED */
+
+#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
+
+png_charp PNGAPI
+png_get_copyright(png_structp png_ptr)
+{
+ png_ptr = png_ptr; /* silence compiler warning about unused png_ptr */
+ return ((png_charp) "\n libpng version 1.2.19 - August 18, 2007\n\
+ Copyright (c) 1998-2007 Glenn Randers-Pehrson\n\
+ Copyright (c) 1996-1997 Andreas Dilger\n\
+ Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n");
+}
+
+/* The following return the library version as a short string in the
+ * format 1.0.0 through 99.99.99zz. To get the version of *.h files
+ * used with your application, print out PNG_LIBPNG_VER_STRING, which
+ * is defined in png.h.
+ * Note: now there is no difference between png_get_libpng_ver() and
+ * png_get_header_ver(). Due to the version_nn_nn_nn typedef guard,
+ * it is guaranteed that png.c uses the correct version of png.h.
+ */
+png_charp PNGAPI
+png_get_libpng_ver(png_structp png_ptr)
+{
+ /* Version of *.c files used when building libpng */
+ png_ptr = png_ptr; /* silence compiler warning about unused png_ptr */
+ return ((png_charp) PNG_LIBPNG_VER_STRING);
+}
+
+png_charp PNGAPI
+png_get_header_ver(png_structp png_ptr)
+{
+ /* Version of *.h files used when building libpng */
+ png_ptr = png_ptr; /* silence compiler warning about unused png_ptr */
+ return ((png_charp) PNG_LIBPNG_VER_STRING);
+}
+
+png_charp PNGAPI
+png_get_header_version(png_structp png_ptr)
+{
+ /* Returns longer string containing both version and date */
+ png_ptr = png_ptr; /* silence compiler warning about unused png_ptr */
+ return ((png_charp) PNG_HEADER_VERSION_STRING
+#ifdef PNG_READ_SUPPORTED
+# ifdef PNG_USE_PNGGCCRD
+# ifdef __x86_64__
+# ifdef __PIC__
+ " (PNGGCRD x86_64, PIC)\n"
+# else
+# ifdef PNG_THREAD_UNSAFE_OK
+ " (PNGGCRD x86_64, Thread unsafe)\n"
+# else
+ " (PNGGCRD x86_64, Thread safe)\n"
+# endif
+# endif
+# else
+# ifdef PNG_THREAD_UNSAFE_OK
+ " (PNGGCRD, Thread unsafe)\n"
+# else
+ " (PNGGCRD, Thread safe)\n"
+# endif
+# endif
+# else
+# ifdef PNG_USE_PNGVCRD
+# ifdef __x86_64__
+ " (x86_64 PNGVCRD)\n"
+# else
+ " (PNGVCRD)\n"
+# endif
+# else
+# ifdef __x86_64__
+# ifdef PNG_OPTIMIZED_CODE_SUPPORTED
+ " (x86_64 OPTIMIZED)\n"
+# else
+ " (x86_64 NOT OPTIMIZED)\n"
+# endif
+# else
+# ifdef PNG_OPTIMIZED_CODE_SUPPORTED
+ " (OPTIMIZED)\n"
+# else
+ " (NOT OPTIMIZED)\n"
+# endif
+# endif
+# endif
+# endif
+#else
+ " (NO READ SUPPORT)\n"
+#endif
+ );
+}
+
+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+int PNGAPI
+png_handle_as_unknown(png_structp png_ptr, png_bytep chunk_name)
+{
+ /* check chunk_name and return "keep" value if it's on the list, else 0 */
+ int i;
+ png_bytep p;
+ if(png_ptr == NULL || chunk_name == NULL || png_ptr->num_chunk_list<=0)
+ return 0;
+ p=png_ptr->chunk_list+png_ptr->num_chunk_list*5-5;
+ for (i = png_ptr->num_chunk_list; i; i--, p-=5)
+ if (!png_memcmp(chunk_name, p, 4))
+ return ((int)*(p+4));
+ return 0;
+}
+#endif
+
+/* This function, added to libpng-1.0.6g, is untested. */
+int PNGAPI
+png_reset_zstream(png_structp png_ptr)
+{
+ if (png_ptr == NULL) return Z_STREAM_ERROR;
+ return (inflateReset(&png_ptr->zstream));
+}
+#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
+
+/* This function was added to libpng-1.0.7 */
+png_uint_32 PNGAPI
+png_access_version_number(void)
+{
+ /* Version of *.c files used when building libpng */
+ return((png_uint_32) PNG_LIBPNG_VER);
+}
+
+
+#if defined(PNG_READ_SUPPORTED) && defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+#if !defined(PNG_1_0_X)
+#if defined(PNG_MMX_CODE_SUPPORTED)
+/* this INTERNAL function was added to libpng 1.2.0 */
+void /* PRIVATE */
+png_init_mmx_flags (png_structp png_ptr)
+{
+ if(png_ptr == NULL) return;
+ png_ptr->mmx_rowbytes_threshold = 0;
+ png_ptr->mmx_bitdepth_threshold = 0;
+
+# if (defined(PNG_USE_PNGVCRD) || defined(PNG_USE_PNGGCCRD))
+
+ png_ptr->asm_flags |= PNG_ASM_FLAG_MMX_SUPPORT_COMPILED;
+
+ if (png_mmx_support() > 0) {
+ png_ptr->asm_flags |= PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU
+# ifdef PNG_HAVE_MMX_COMBINE_ROW
+ | PNG_ASM_FLAG_MMX_READ_COMBINE_ROW
+# endif
+# ifdef PNG_HAVE_MMX_READ_INTERLACE
+ | PNG_ASM_FLAG_MMX_READ_INTERLACE
+# endif
+# ifndef PNG_HAVE_MMX_READ_FILTER_ROW
+ ;
+# else
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB
+ | PNG_ASM_FLAG_MMX_READ_FILTER_UP
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
+
+ png_ptr->mmx_rowbytes_threshold = PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT;
+ png_ptr->mmx_bitdepth_threshold = PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT;
+# endif
+ } else {
+ png_ptr->asm_flags &= ~( PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU
+ | PNG_MMX_READ_FLAGS
+ | PNG_MMX_WRITE_FLAGS );
+ }
+
+# else /* !(PNGVCRD || PNGGCCRD) */
+
+ /* clear all MMX flags; no support is compiled in */
+ png_ptr->asm_flags &= ~( PNG_MMX_FLAGS );
+
+# endif /* ?(PNGVCRD || PNGGCCRD) */
+}
+
+#endif /* !(PNG_MMX_CODE_SUPPORTED) */
+
+/* this function was added to libpng 1.2.0 */
+#if !defined(PNG_USE_PNGGCCRD) && \
+ !(defined(PNG_MMX_CODE_SUPPORTED) && defined(PNG_USE_PNGVCRD))
+int PNGAPI
+png_mmx_support(void)
+{
+ return -1;
+}
+#endif
+#endif /* PNG_1_0_X */
+#endif /* PNG_READ_SUPPORTED && PNG_ASSEMBLER_CODE_SUPPORTED */
+
+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+#ifdef PNG_SIZE_T
+/* Added at libpng version 1.2.6 */
+ PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size));
+png_size_t PNGAPI
+png_convert_size(size_t size)
+{
+ if (size > (png_size_t)-1)
+ PNG_ABORT(); /* We haven't got access to png_ptr, so no png_error() */
+ return ((png_size_t)size);
+}
+#endif /* PNG_SIZE_T */
+#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
diff --git a/distrib/libpng-1.2.19/png.h b/distrib/libpng-1.2.19/png.h
new file mode 100644
index 0000000..04f786d
--- /dev/null
+++ b/distrib/libpng-1.2.19/png.h
@@ -0,0 +1,3525 @@
+
+/* png.h - header file for PNG reference library
+ *
+ * libpng version 1.2.19 - August 18, 2007
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * Authors and maintainers:
+ * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
+ * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
+ * libpng versions 0.97, January 1998, through 1.2.19 - August 18, 2007: Glenn
+ * See also "Contributing Authors", below.
+ *
+ * Note about libpng version numbers:
+ *
+ * Due to various miscommunications, unforeseen code incompatibilities
+ * and occasional factors outside the authors' control, version numbering
+ * on the library has not always been consistent and straightforward.
+ * The following table summarizes matters since version 0.89c, which was
+ * the first widely used release:
+ *
+ * source png.h png.h shared-lib
+ * version string int version
+ * ------- ------ ----- ----------
+ * 0.89c "1.0 beta 3" 0.89 89 1.0.89
+ * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90]
+ * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95]
+ * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96]
+ * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97]
+ * 0.97c 0.97 97 2.0.97
+ * 0.98 0.98 98 2.0.98
+ * 0.99 0.99 98 2.0.99
+ * 0.99a-m 0.99 99 2.0.99
+ * 1.00 1.00 100 2.1.0 [100 should be 10000]
+ * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000]
+ * 1.0.1 png.h string is 10001 2.1.0
+ * 1.0.1a-e identical to the 10002 from here on, the shared library
+ * 1.0.2 source version) 10002 is 2.V where V is the source code
+ * 1.0.2a-b 10003 version, except as noted.
+ * 1.0.3 10003
+ * 1.0.3a-d 10004
+ * 1.0.4 10004
+ * 1.0.4a-f 10005
+ * 1.0.5 (+ 2 patches) 10005
+ * 1.0.5a-d 10006
+ * 1.0.5e-r 10100 (not source compatible)
+ * 1.0.5s-v 10006 (not binary compatible)
+ * 1.0.6 (+ 3 patches) 10006 (still binary incompatible)
+ * 1.0.6d-f 10007 (still binary incompatible)
+ * 1.0.6g 10007
+ * 1.0.6h 10007 10.6h (testing xy.z so-numbering)
+ * 1.0.6i 10007 10.6i
+ * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0)
+ * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible)
+ * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible)
+ * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible)
+ * 1.0.7 1 10007 (still compatible)
+ * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4
+ * 1.0.8rc1 1 10008 2.1.0.8rc1
+ * 1.0.8 1 10008 2.1.0.8
+ * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6
+ * 1.0.9rc1 1 10009 2.1.0.9rc1
+ * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10
+ * 1.0.9rc2 1 10009 2.1.0.9rc2
+ * 1.0.9 1 10009 2.1.0.9
+ * 1.0.10beta1 1 10010 2.1.0.10beta1
+ * 1.0.10rc1 1 10010 2.1.0.10rc1
+ * 1.0.10 1 10010 2.1.0.10
+ * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3
+ * 1.0.11rc1 1 10011 2.1.0.11rc1
+ * 1.0.11 1 10011 2.1.0.11
+ * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2
+ * 1.0.12rc1 2 10012 2.1.0.12rc1
+ * 1.0.12 2 10012 2.1.0.12
+ * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned)
+ * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2
+ * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5
+ * 1.2.0rc1 3 10200 3.1.2.0rc1
+ * 1.2.0 3 10200 3.1.2.0
+ * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4
+ * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2
+ * 1.2.1 3 10201 3.1.2.1
+ * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6
+ * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1
+ * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1
+ * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1
+ * 1.0.13 10 10013 10.so.0.1.0.13
+ * 1.2.2 12 10202 12.so.0.1.2.2
+ * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6
+ * 1.2.3 12 10203 12.so.0.1.2.3
+ * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3
+ * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1
+ * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1
+ * 1.0.14 10 10014 10.so.0.1.0.14
+ * 1.2.4 13 10204 12.so.0.1.2.4
+ * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2
+ * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3
+ * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3
+ * 1.0.15 10 10015 10.so.0.1.0.15
+ * 1.2.5 13 10205 12.so.0.1.2.5
+ * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4
+ * 1.0.16 10 10016 10.so.0.1.0.16
+ * 1.2.6 13 10206 12.so.0.1.2.6
+ * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2
+ * 1.0.17rc1 10 10017 10.so.0.1.0.17rc1
+ * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1
+ * 1.0.17 10 10017 10.so.0.1.0.17
+ * 1.2.7 13 10207 12.so.0.1.2.7
+ * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5
+ * 1.0.18rc1-5 10 10018 10.so.0.1.0.18rc1-5
+ * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5
+ * 1.0.18 10 10018 10.so.0.1.0.18
+ * 1.2.8 13 10208 12.so.0.1.2.8
+ * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3
+ * 1.2.9beta4-11 13 10209 12.so.0.9[.0]
+ * 1.2.9rc1 13 10209 12.so.0.9[.0]
+ * 1.2.9 13 10209 12.so.0.9[.0]
+ * 1.2.10beta1-8 13 10210 12.so.0.10[.0]
+ * 1.2.10rc1-3 13 10210 12.so.0.10[.0]
+ * 1.2.10 13 10210 12.so.0.10[.0]
+ * 1.2.11beta1-4 13 10211 12.so.0.11[.0]
+ * 1.0.19rc1-5 10 10019 10.so.0.19[.0]
+ * 1.2.11rc1-5 13 10211 12.so.0.11[.0]
+ * 1.0.19 10 10019 10.so.0.19[.0]
+ * 1.2.11 13 10211 12.so.0.11[.0]
+ * 1.0.20 10 10020 10.so.0.20[.0]
+ * 1.2.12 13 10212 12.so.0.12[.0]
+ * 1.2.13beta1 13 10213 12.so.0.13[.0]
+ * 1.0.21 10 10021 10.so.0.21[.0]
+ * 1.2.13 13 10213 12.so.0.13[.0]
+ * 1.2.14beta1-2 13 10214 12.so.0.14[.0]
+ * 1.0.22rc1 10 10022 10.so.0.22[.0]
+ * 1.2.14rc1 13 10214 12.so.0.14[.0]
+ * 1.0.22 10 10022 10.so.0.22[.0]
+ * 1.2.14 13 10214 12.so.0.14[.0]
+ * 1.2.15beta1-6 13 10215 12.so.0.15[.0]
+ * 1.0.23rc1-5 10 10023 10.so.0.23[.0]
+ * 1.2.15rc1-5 13 10215 12.so.0.15[.0]
+ * 1.0.23 10 10023 10.so.0.23[.0]
+ * 1.2.15 13 10215 12.so.0.15[.0]
+ * 1.2.16beta1-2 13 10216 12.so.0.16[.0]
+ * 1.2.16rc1 13 10216 12.so.0.16[.0]
+ * 1.0.24 10 10024 10.so.0.24[.0]
+ * 1.2.16 13 10216 12.so.0.16[.0]
+ * 1.2.17beta1-2 13 10217 12.so.0.17[.0]
+ * 1.0.25rc1 10 10025 10.so.0.25[.0]
+ * 1.2.17rc1-3 13 10217 12.so.0.17[.0]
+ * 1.0.25 10 10025 10.so.0.25[.0]
+ * 1.2.17 13 10217 12.so.0.17[.0]
+ * 1.0.26 10 10026 10.so.0.26[.0]
+ * 1.2.18 13 10218 12.so.0.18[.0]
+ * 1.2.19beta1-31 13 10219 12.so.0.19[.0]
+ * 1.0.27rc1-6 10 10027 10.so.0.27[.0]
+ * 1.2.19rc1-6 13 10219 12.so.0.19[.0]
+ * 1.0.27 10 10027 10.so.0.27[.0]
+ * 1.2.19 13 10219 12.so.0.19[.0]
+ *
+ * Henceforth the source version will match the shared-library major
+ * and minor numbers; the shared-library major version number will be
+ * used for changes in backward compatibility, as it is intended. The
+ * PNG_LIBPNG_VER macro, which is not used within libpng but is available
+ * for applications, is an unsigned integer of the form xyyzz corresponding
+ * to the source version x.y.z (leading zeros in y and z). Beta versions
+ * were given the previous public release number plus a letter, until
+ * version 1.0.6j; from then on they were given the upcoming public
+ * release number plus "betaNN" or "rcN".
+ *
+ * Binary incompatibility exists only when applications make direct access
+ * to the info_ptr or png_ptr members through png.h, and the compiled
+ * application is loaded with a different version of the library.
+ *
+ * DLLNUM will change each time there are forward or backward changes
+ * in binary compatibility (e.g., when a new feature is added).
+ *
+ * See libpng.txt or libpng.3 for more information. The PNG specification
+ * is available as a W3C Recommendation and as an ISO Specification,
+ * <http://www.w3.org/TR/2003/REC-PNG-20031110/
+ */
+
+/*
+ * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE:
+ *
+ * If you modify libpng you may insert additional notices immediately following
+ * this sentence.
+ *
+ * libpng versions 1.2.6, August 15, 2004, through 1.2.19, August 18, 2007, are
+ * Copyright (c) 2004, 2006-2007 Glenn Randers-Pehrson, and are
+ * distributed according to the same disclaimer and license as libpng-1.2.5
+ * with the following individual added to the list of Contributing Authors:
+ *
+ * Cosmin Truta
+ *
+ * libpng versions 1.0.7, July 1, 2000, through 1.2.5, October 3, 2002, are
+ * Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
+ * distributed according to the same disclaimer and license as libpng-1.0.6
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ * Simon-Pierre Cadieux
+ * Eric S. Raymond
+ * Gilles Vollant
+ *
+ * and with the following additions to the disclaimer:
+ *
+ * There is no warranty against interference with your enjoyment of the
+ * library or against infringement. There is no warranty that our
+ * efforts or the library will fulfill any of your particular purposes
+ * or needs. This library is provided with all faults, and the entire
+ * risk of satisfactory quality, performance, accuracy, and effort is with
+ * the user.
+ *
+ * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
+ * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson, and are
+ * distributed according to the same disclaimer and license as libpng-0.96,
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ * Tom Lane
+ * Glenn Randers-Pehrson
+ * Willem van Schaik
+ *
+ * libpng versions 0.89, June 1996, through 0.96, May 1997, are
+ * Copyright (c) 1996, 1997 Andreas Dilger
+ * Distributed according to the same disclaimer and license as libpng-0.88,
+ * with the following individuals added to the list of Contributing Authors:
+ *
+ * John Bowler
+ * Kevin Bracey
+ * Sam Bushell
+ * Magnus Holmgren
+ * Greg Roelofs
+ * Tom Tanner
+ *
+ * libpng versions 0.5, May 1995, through 0.88, January 1996, are
+ * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ *
+ * For the purposes of this copyright and license, "Contributing Authors"
+ * is defined as the following set of individuals:
+ *
+ * Andreas Dilger
+ * Dave Martindale
+ * Guy Eric Schalnat
+ * Paul Schmidt
+ * Tim Wegner
+ *
+ * The PNG Reference Library is supplied "AS IS". The Contributing Authors
+ * and Group 42, Inc. disclaim all warranties, expressed or implied,
+ * including, without limitation, the warranties of merchantability and of
+ * fitness for any purpose. The Contributing Authors and Group 42, Inc.
+ * assume no liability for direct, indirect, incidental, special, exemplary,
+ * or consequential damages, which may result from the use of the PNG
+ * Reference Library, even if advised of the possibility of such damage.
+ *
+ * Permission is hereby granted to use, copy, modify, and distribute this
+ * source code, or portions hereof, for any purpose, without fee, subject
+ * to the following restrictions:
+ *
+ * 1. The origin of this source code must not be misrepresented.
+ *
+ * 2. Altered versions must be plainly marked as such and
+ * must not be misrepresented as being the original source.
+ *
+ * 3. This Copyright notice may not be removed or altered from
+ * any source or altered source distribution.
+ *
+ * The Contributing Authors and Group 42, Inc. specifically permit, without
+ * fee, and encourage the use of this source code as a component to
+ * supporting the PNG file format in commercial products. If you use this
+ * source code in a product, acknowledgment is not required but would be
+ * appreciated.
+ */
+
+/*
+ * A "png_get_copyright" function is available, for convenient use in "about"
+ * boxes and the like:
+ *
+ * printf("%s",png_get_copyright(NULL));
+ *
+ * Also, the PNG logo (in PNG format, of course) is supplied in the
+ * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
+ */
+
+/*
+ * Libpng is OSI Certified Open Source Software. OSI Certified is a
+ * certification mark of the Open Source Initiative.
+ */
+
+/*
+ * The contributing authors would like to thank all those who helped
+ * with testing, bug fixes, and patience. This wouldn't have been
+ * possible without all of you.
+ *
+ * Thanks to Frank J. T. Wojcik for helping with the documentation.
+ */
+
+/*
+ * Y2K compliance in libpng:
+ * =========================
+ *
+ * August 18, 2007
+ *
+ * Since the PNG Development group is an ad-hoc body, we can't make
+ * an official declaration.
+ *
+ * This is your unofficial assurance that libpng from version 0.71 and
+ * upward through 1.2.19 are Y2K compliant. It is my belief that earlier
+ * versions were also Y2K compliant.
+ *
+ * Libpng only has three year fields. One is a 2-byte unsigned integer
+ * that will hold years up to 65535. The other two hold the date in text
+ * format, and will hold years up to 9999.
+ *
+ * The integer is
+ * "png_uint_16 year" in png_time_struct.
+ *
+ * The strings are
+ * "png_charp time_buffer" in png_struct and
+ * "near_time_buffer", which is a local character string in png.c.
+ *
+ * There are seven time-related functions:
+ * png.c: png_convert_to_rfc_1123() in png.c
+ * (formerly png_convert_to_rfc_1152() in error)
+ * png_convert_from_struct_tm() in pngwrite.c, called in pngwrite.c
+ * png_convert_from_time_t() in pngwrite.c
+ * png_get_tIME() in pngget.c
+ * png_handle_tIME() in pngrutil.c, called in pngread.c
+ * png_set_tIME() in pngset.c
+ * png_write_tIME() in pngwutil.c, called in pngwrite.c
+ *
+ * All handle dates properly in a Y2K environment. The
+ * png_convert_from_time_t() function calls gmtime() to convert from system
+ * clock time, which returns (year - 1900), which we properly convert to
+ * the full 4-digit year. There is a possibility that applications using
+ * libpng are not passing 4-digit years into the png_convert_to_rfc_1123()
+ * function, or that they are incorrectly passing only a 2-digit year
+ * instead of "year - 1900" into the png_convert_from_struct_tm() function,
+ * but this is not under our control. The libpng documentation has always
+ * stated that it works with 4-digit years, and the APIs have been
+ * documented as such.
+ *
+ * The tIME chunk itself is also Y2K compliant. It uses a 2-byte unsigned
+ * integer to hold the year, and can hold years as large as 65535.
+ *
+ * zlib, upon which libpng depends, is also Y2K compliant. It contains
+ * no date-related code.
+ *
+ * Glenn Randers-Pehrson
+ * libpng maintainer
+ * PNG Development Group
+ */
+
+#ifndef PNG_H
+#define PNG_H
+
+/* This is not the place to learn how to use libpng. The file libpng.txt
+ * describes how to use libpng, and the file example.c summarizes it
+ * with some code on which to build. This file is useful for looking
+ * at the actual function definitions and structure components.
+ */
+
+/* Version information for png.h - this should match the version in png.c */
+#define PNG_LIBPNG_VER_STRING "1.2.19"
+#define PNG_HEADER_VERSION_STRING \
+ " libpng version 1.2.19 - August 18, 2007\n"
+
+#define PNG_LIBPNG_VER_SONUM 0
+#define PNG_LIBPNG_VER_DLLNUM 13
+
+/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
+#define PNG_LIBPNG_VER_MAJOR 1
+#define PNG_LIBPNG_VER_MINOR 2
+#define PNG_LIBPNG_VER_RELEASE 19
+/* This should match the numeric part of the final component of
+ * PNG_LIBPNG_VER_STRING, omitting any leading zero: */
+
+#define PNG_LIBPNG_VER_BUILD 0
+
+/* Release Status */
+#define PNG_LIBPNG_BUILD_ALPHA 1
+#define PNG_LIBPNG_BUILD_BETA 2
+#define PNG_LIBPNG_BUILD_RC 3
+#define PNG_LIBPNG_BUILD_STABLE 4
+#define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7
+
+/* Release-Specific Flags */
+#define PNG_LIBPNG_BUILD_PATCH 8 /* Can be OR'ed with
+ PNG_LIBPNG_BUILD_STABLE only */
+#define PNG_LIBPNG_BUILD_PRIVATE 16 /* Cannot be OR'ed with
+ PNG_LIBPNG_BUILD_SPECIAL */
+#define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with
+ PNG_LIBPNG_BUILD_PRIVATE */
+
+#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE
+
+/* Careful here. At one time, Guy wanted to use 082, but that would be octal.
+ * We must not include leading zeros.
+ * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only
+ * version 1.0.0 was mis-numbered 100 instead of 10000). From
+ * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */
+#define PNG_LIBPNG_VER 10219 /* 1.2.19 */
+
+#ifndef PNG_VERSION_INFO_ONLY
+/* include the compression library's header */
+#include "zlib.h"
+#endif
+
+/* include all user configurable info, including optional assembler routines */
+#include "pngconf.h"
+
+/*
+ * Added at libpng-1.2.8 */
+/* Ref MSDN: Private as priority over Special
+ * VS_FF_PRIVATEBUILD File *was not* built using standard release
+ * procedures. If this value is given, the StringFileInfo block must
+ * contain a PrivateBuild string.
+ *
+ * VS_FF_SPECIALBUILD File *was* built by the original company using
+ * standard release procedures but is a variation of the standard
+ * file of the same version number. If this value is given, the
+ * StringFileInfo block must contain a SpecialBuild string.
+ */
+
+#if defined(PNG_USER_PRIVATEBUILD)
+# define PNG_LIBPNG_BUILD_TYPE \
+ (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_PRIVATE)
+#else
+# if defined(PNG_LIBPNG_SPECIALBUILD)
+# define PNG_LIBPNG_BUILD_TYPE \
+ (PNG_LIBPNG_BUILD_BASE_TYPE | PNG_LIBPNG_BUILD_SPECIAL)
+# else
+# define PNG_LIBPNG_BUILD_TYPE (PNG_LIBPNG_BUILD_BASE_TYPE)
+# endif
+#endif
+
+#ifndef PNG_VERSION_INFO_ONLY
+
+/* Inhibit C++ name-mangling for libpng functions but not for system calls. */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* This file is arranged in several sections. The first section contains
+ * structure and type definitions. The second section contains the external
+ * library functions, while the third has the internal library functions,
+ * which applications aren't expected to use directly.
+ */
+
+#ifndef PNG_NO_TYPECAST_NULL
+#define int_p_NULL (int *)NULL
+#define png_bytep_NULL (png_bytep)NULL
+#define png_bytepp_NULL (png_bytepp)NULL
+#define png_doublep_NULL (png_doublep)NULL
+#define png_error_ptr_NULL (png_error_ptr)NULL
+#define png_flush_ptr_NULL (png_flush_ptr)NULL
+#define png_free_ptr_NULL (png_free_ptr)NULL
+#define png_infopp_NULL (png_infopp)NULL
+#define png_malloc_ptr_NULL (png_malloc_ptr)NULL
+#define png_read_status_ptr_NULL (png_read_status_ptr)NULL
+#define png_rw_ptr_NULL (png_rw_ptr)NULL
+#define png_structp_NULL (png_structp)NULL
+#define png_uint_16p_NULL (png_uint_16p)NULL
+#define png_voidp_NULL (png_voidp)NULL
+#define png_write_status_ptr_NULL (png_write_status_ptr)NULL
+#else
+#define int_p_NULL NULL
+#define png_bytep_NULL NULL
+#define png_bytepp_NULL NULL
+#define png_doublep_NULL NULL
+#define png_error_ptr_NULL NULL
+#define png_flush_ptr_NULL NULL
+#define png_free_ptr_NULL NULL
+#define png_infopp_NULL NULL
+#define png_malloc_ptr_NULL NULL
+#define png_read_status_ptr_NULL NULL
+#define png_rw_ptr_NULL NULL
+#define png_structp_NULL NULL
+#define png_uint_16p_NULL NULL
+#define png_voidp_NULL NULL
+#define png_write_status_ptr_NULL NULL
+#endif
+
+/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
+#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN)
+/* Version information for C files, stored in png.c. This had better match
+ * the version above.
+ */
+#ifdef PNG_USE_GLOBAL_ARRAYS
+PNG_EXPORT_VAR (PNG_CONST char) png_libpng_ver[18];
+ /* need room for 99.99.99beta99z */
+#else
+#define png_libpng_ver png_get_header_ver(NULL)
+#endif
+
+#ifdef PNG_USE_GLOBAL_ARRAYS
+/* This was removed in version 1.0.5c */
+/* Structures to facilitate easy interlacing. See png.c for more details */
+PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_start[7];
+PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_inc[7];
+PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_ystart[7];
+PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_yinc[7];
+PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_mask[7];
+PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_dsp_mask[7];
+#if defined(PNG_HAVE_MMX_COMBINE_ROW) || defined(PNG_OPTIMIZED_CODE_SUPPORTED)
+PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_width[7];
+#endif
+/* This isn't currently used. If you need it, see png.c for more details.
+PNG_EXPORT_VAR (PNG_CONST int FARDATA) png_pass_height[7];
+*/
+#endif
+
+#endif /* PNG_NO_EXTERN */
+
+/* Three color definitions. The order of the red, green, and blue, (and the
+ * exact size) is not important, although the size of the fields need to
+ * be png_byte or png_uint_16 (as defined below).
+ */
+typedef struct png_color_struct
+{
+ png_byte red;
+ png_byte green;
+ png_byte blue;
+} png_color;
+typedef png_color FAR * png_colorp;
+typedef png_color FAR * FAR * png_colorpp;
+
+typedef struct png_color_16_struct
+{
+ png_byte index; /* used for palette files */
+ png_uint_16 red; /* for use in red green blue files */
+ png_uint_16 green;
+ png_uint_16 blue;
+ png_uint_16 gray; /* for use in grayscale files */
+} png_color_16;
+typedef png_color_16 FAR * png_color_16p;
+typedef png_color_16 FAR * FAR * png_color_16pp;
+
+typedef struct png_color_8_struct
+{
+ png_byte red; /* for use in red green blue files */
+ png_byte green;
+ png_byte blue;
+ png_byte gray; /* for use in grayscale files */
+ png_byte alpha; /* for alpha channel files */
+} png_color_8;
+typedef png_color_8 FAR * png_color_8p;
+typedef png_color_8 FAR * FAR * png_color_8pp;
+
+/*
+ * The following two structures are used for the in-core representation
+ * of sPLT chunks.
+ */
+typedef struct png_sPLT_entry_struct
+{
+ png_uint_16 red;
+ png_uint_16 green;
+ png_uint_16 blue;
+ png_uint_16 alpha;
+ png_uint_16 frequency;
+} png_sPLT_entry;
+typedef png_sPLT_entry FAR * png_sPLT_entryp;
+typedef png_sPLT_entry FAR * FAR * png_sPLT_entrypp;
+
+/* When the depth of the sPLT palette is 8 bits, the color and alpha samples
+ * occupy the LSB of their respective members, and the MSB of each member
+ * is zero-filled. The frequency member always occupies the full 16 bits.
+ */
+
+typedef struct png_sPLT_struct
+{
+ png_charp name; /* palette name */
+ png_byte depth; /* depth of palette samples */
+ png_sPLT_entryp entries; /* palette entries */
+ png_int_32 nentries; /* number of palette entries */
+} png_sPLT_t;
+typedef png_sPLT_t FAR * png_sPLT_tp;
+typedef png_sPLT_t FAR * FAR * png_sPLT_tpp;
+
+#ifdef PNG_TEXT_SUPPORTED
+/* png_text holds the contents of a text/ztxt/itxt chunk in a PNG file,
+ * and whether that contents is compressed or not. The "key" field
+ * points to a regular zero-terminated C string. The "text", "lang", and
+ * "lang_key" fields can be regular C strings, empty strings, or NULL pointers.
+ * However, the * structure returned by png_get_text() will always contain
+ * regular zero-terminated C strings (possibly empty), never NULL pointers,
+ * so they can be safely used in printf() and other string-handling functions.
+ */
+typedef struct png_text_struct
+{
+ int compression; /* compression value:
+ -1: tEXt, none
+ 0: zTXt, deflate
+ 1: iTXt, none
+ 2: iTXt, deflate */
+ png_charp key; /* keyword, 1-79 character description of "text" */
+ png_charp text; /* comment, may be an empty string (ie "")
+ or a NULL pointer */
+ png_size_t text_length; /* length of the text string */
+#ifdef PNG_iTXt_SUPPORTED
+ png_size_t itxt_length; /* length of the itxt string */
+ png_charp lang; /* language code, 0-79 characters
+ or a NULL pointer */
+ png_charp lang_key; /* keyword translated UTF-8 string, 0 or more
+ chars or a NULL pointer */
+#endif
+} png_text;
+typedef png_text FAR * png_textp;
+typedef png_text FAR * FAR * png_textpp;
+#endif
+
+/* Supported compression types for text in PNG files (tEXt, and zTXt).
+ * The values of the PNG_TEXT_COMPRESSION_ defines should NOT be changed. */
+#define PNG_TEXT_COMPRESSION_NONE_WR -3
+#define PNG_TEXT_COMPRESSION_zTXt_WR -2
+#define PNG_TEXT_COMPRESSION_NONE -1
+#define PNG_TEXT_COMPRESSION_zTXt 0
+#define PNG_ITXT_COMPRESSION_NONE 1
+#define PNG_ITXT_COMPRESSION_zTXt 2
+#define PNG_TEXT_COMPRESSION_LAST 3 /* Not a valid value */
+
+/* png_time is a way to hold the time in an machine independent way.
+ * Two conversions are provided, both from time_t and struct tm. There
+ * is no portable way to convert to either of these structures, as far
+ * as I know. If you know of a portable way, send it to me. As a side
+ * note - PNG has always been Year 2000 compliant!
+ */
+typedef struct png_time_struct
+{
+ png_uint_16 year; /* full year, as in, 1995 */
+ png_byte month; /* month of year, 1 - 12 */
+ png_byte day; /* day of month, 1 - 31 */
+ png_byte hour; /* hour of day, 0 - 23 */
+ png_byte minute; /* minute of hour, 0 - 59 */
+ png_byte second; /* second of minute, 0 - 60 (for leap seconds) */
+} png_time;
+typedef png_time FAR * png_timep;
+typedef png_time FAR * FAR * png_timepp;
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+/* png_unknown_chunk is a structure to hold queued chunks for which there is
+ * no specific support. The idea is that we can use this to queue
+ * up private chunks for output even though the library doesn't actually
+ * know about their semantics.
+ */
+typedef struct png_unknown_chunk_t
+{
+ png_byte name[5];
+ png_byte *data;
+ png_size_t size;
+
+ /* libpng-using applications should NOT directly modify this byte. */
+ png_byte location; /* mode of operation at read time */
+}
+png_unknown_chunk;
+typedef png_unknown_chunk FAR * png_unknown_chunkp;
+typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp;
+#endif
+
+/* png_info is a structure that holds the information in a PNG file so
+ * that the application can find out the characteristics of the image.
+ * If you are reading the file, this structure will tell you what is
+ * in the PNG file. If you are writing the file, fill in the information
+ * you want to put into the PNG file, then call png_write_info().
+ * The names chosen should be very close to the PNG specification, so
+ * consult that document for information about the meaning of each field.
+ *
+ * With libpng < 0.95, it was only possible to directly set and read the
+ * the values in the png_info_struct, which meant that the contents and
+ * order of the values had to remain fixed. With libpng 0.95 and later,
+ * however, there are now functions that abstract the contents of
+ * png_info_struct from the application, so this makes it easier to use
+ * libpng with dynamic libraries, and even makes it possible to use
+ * libraries that don't have all of the libpng ancillary chunk-handing
+ * functionality.
+ *
+ * In any case, the order of the parameters in png_info_struct should NOT
+ * be changed for as long as possible to keep compatibility with applications
+ * that use the old direct-access method with png_info_struct.
+ *
+ * The following members may have allocated storage attached that should be
+ * cleaned up before the structure is discarded: palette, trans, text,
+ * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile,
+ * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these
+ * are automatically freed when the info structure is deallocated, if they were
+ * allocated internally by libpng. This behavior can be changed by means
+ * of the png_data_freer() function.
+ *
+ * More allocation details: all the chunk-reading functions that
+ * change these members go through the corresponding png_set_*
+ * functions. A function to clear these members is available: see
+ * png_free_data(). The png_set_* functions do not depend on being
+ * able to point info structure members to any of the storage they are
+ * passed (they make their own copies), EXCEPT that the png_set_text
+ * functions use the same storage passed to them in the text_ptr or
+ * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns
+ * functions do not make their own copies.
+ */
+typedef struct png_info_struct
+{
+ /* the following are necessary for every PNG file */
+ png_uint_32 width; /* width of image in pixels (from IHDR) */
+ png_uint_32 height; /* height of image in pixels (from IHDR) */
+ png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */
+ png_uint_32 rowbytes; /* bytes needed to hold an untransformed row */
+ png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */
+ png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */
+ png_uint_16 num_trans; /* number of transparent palette color (tRNS) */
+ png_byte bit_depth; /* 1, 2, 4, 8, or 16 bits/channel (from IHDR) */
+ png_byte color_type; /* see PNG_COLOR_TYPE_ below (from IHDR) */
+ /* The following three should have been named *_method not *_type */
+ png_byte compression_type; /* must be PNG_COMPRESSION_TYPE_BASE (IHDR) */
+ png_byte filter_type; /* must be PNG_FILTER_TYPE_BASE (from IHDR) */
+ png_byte interlace_type; /* One of PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+
+ /* The following is informational only on read, and not used on writes. */
+ png_byte channels; /* number of data channels per pixel (1, 2, 3, 4) */
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte spare_byte; /* to align the data, and for future use */
+ png_byte signature[8]; /* magic bytes read by libpng from start of file */
+
+ /* The rest of the data is optional. If you are reading, check the
+ * valid field to see if the information in these are valid. If you
+ * are writing, set the valid field to those chunks you want written,
+ * and initialize the appropriate fields below.
+ */
+
+#if defined(PNG_gAMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
+ /* The gAMA chunk describes the gamma characteristics of the system
+ * on which the image was created, normally in the range [1.0, 2.5].
+ * Data is valid if (valid & PNG_INFO_gAMA) is non-zero.
+ */
+ float gamma; /* gamma value of image, if (valid & PNG_INFO_gAMA) */
+#endif
+
+#if defined(PNG_sRGB_SUPPORTED)
+ /* GR-P, 0.96a */
+ /* Data valid if (valid & PNG_INFO_sRGB) non-zero. */
+ png_byte srgb_intent; /* sRGB rendering intent [0, 1, 2, or 3] */
+#endif
+
+#if defined(PNG_TEXT_SUPPORTED)
+ /* The tEXt, and zTXt chunks contain human-readable textual data in
+ * uncompressed, compressed, and optionally compressed forms, respectively.
+ * The data in "text" is an array of pointers to uncompressed,
+ * null-terminated C strings. Each chunk has a keyword that describes the
+ * textual data contained in that chunk. Keywords are not required to be
+ * unique, and the text string may be empty. Any number of text chunks may
+ * be in an image.
+ */
+ int num_text; /* number of comments read/to write */
+ int max_text; /* current size of text array */
+ png_textp text; /* array of comments read/to write */
+#endif /* PNG_TEXT_SUPPORTED */
+
+#if defined(PNG_tIME_SUPPORTED)
+ /* The tIME chunk holds the last time the displayed image data was
+ * modified. See the png_time struct for the contents of this struct.
+ */
+ png_time mod_time;
+#endif
+
+#if defined(PNG_sBIT_SUPPORTED)
+ /* The sBIT chunk specifies the number of significant high-order bits
+ * in the pixel data. Values are in the range [1, bit_depth], and are
+ * only specified for the channels in the pixel data. The contents of
+ * the low-order bits is not specified. Data is valid if
+ * (valid & PNG_INFO_sBIT) is non-zero.
+ */
+ png_color_8 sig_bit; /* significant bits in color channels */
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_EXPAND_SUPPORTED) || \
+defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* The tRNS chunk supplies transparency data for paletted images and
+ * other image types that don't need a full alpha channel. There are
+ * "num_trans" transparency values for a paletted image, stored in the
+ * same order as the palette colors, starting from index 0. Values
+ * for the data are in the range [0, 255], ranging from fully transparent
+ * to fully opaque, respectively. For non-paletted images, there is a
+ * single color specified that should be treated as fully transparent.
+ * Data is valid if (valid & PNG_INFO_tRNS) is non-zero.
+ */
+ png_bytep trans; /* transparent values for paletted image */
+ png_color_16 trans_values; /* transparent color for non-palette image */
+#endif
+
+#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* The bKGD chunk gives the suggested image background color if the
+ * display program does not have its own background color and the image
+ * is needs to composited onto a background before display. The colors
+ * in "background" are normally in the same color space/depth as the
+ * pixel data. Data is valid if (valid & PNG_INFO_bKGD) is non-zero.
+ */
+ png_color_16 background;
+#endif
+
+#if defined(PNG_oFFs_SUPPORTED)
+ /* The oFFs chunk gives the offset in "offset_unit_type" units rightwards
+ * and downwards from the top-left corner of the display, page, or other
+ * application-specific co-ordinate space. See the PNG_OFFSET_ defines
+ * below for the unit types. Valid if (valid & PNG_INFO_oFFs) non-zero.
+ */
+ png_int_32 x_offset; /* x offset on page */
+ png_int_32 y_offset; /* y offset on page */
+ png_byte offset_unit_type; /* offset units type */
+#endif
+
+#if defined(PNG_pHYs_SUPPORTED)
+ /* The pHYs chunk gives the physical pixel density of the image for
+ * display or printing in "phys_unit_type" units (see PNG_RESOLUTION_
+ * defines below). Data is valid if (valid & PNG_INFO_pHYs) is non-zero.
+ */
+ png_uint_32 x_pixels_per_unit; /* horizontal pixel density */
+ png_uint_32 y_pixels_per_unit; /* vertical pixel density */
+ png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+ /* The hIST chunk contains the relative frequency or importance of the
+ * various palette entries, so that a viewer can intelligently select a
+ * reduced-color palette, if required. Data is an array of "num_palette"
+ * values in the range [0,65535]. Data valid if (valid & PNG_INFO_hIST)
+ * is non-zero.
+ */
+ png_uint_16p hist;
+#endif
+
+#ifdef PNG_cHRM_SUPPORTED
+ /* The cHRM chunk describes the CIE color characteristics of the monitor
+ * on which the PNG was created. This data allows the viewer to do gamut
+ * mapping of the input image to ensure that the viewer sees the same
+ * colors in the image as the creator. Values are in the range
+ * [0.0, 0.8]. Data valid if (valid & PNG_INFO_cHRM) non-zero.
+ */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float x_white;
+ float y_white;
+ float x_red;
+ float y_red;
+ float x_green;
+ float y_green;
+ float x_blue;
+ float y_blue;
+#endif
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+ /* The pCAL chunk describes a transformation between the stored pixel
+ * values and original physical data values used to create the image.
+ * The integer range [0, 2^bit_depth - 1] maps to the floating-point
+ * range given by [pcal_X0, pcal_X1], and are further transformed by a
+ * (possibly non-linear) transformation function given by "pcal_type"
+ * and "pcal_params" into "pcal_units". Please see the PNG_EQUATION_
+ * defines below, and the PNG-Group's PNG extensions document for a
+ * complete description of the transformations and how they should be
+ * implemented, and for a description of the ASCII parameter strings.
+ * Data values are valid if (valid & PNG_INFO_pCAL) non-zero.
+ */
+ png_charp pcal_purpose; /* pCAL chunk description string */
+ png_int_32 pcal_X0; /* minimum value */
+ png_int_32 pcal_X1; /* maximum value */
+ png_charp pcal_units; /* Latin-1 string giving physical units */
+ png_charpp pcal_params; /* ASCII strings containing parameter values */
+ png_byte pcal_type; /* equation type (see PNG_EQUATION_ below) */
+ png_byte pcal_nparams; /* number of parameters given in pcal_params */
+#endif
+
+/* New members added in libpng-1.0.6 */
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_uint_32 free_me; /* flags items libpng is responsible for freeing */
+#endif
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ /* storage for unknown chunks that the library doesn't recognize. */
+ png_unknown_chunkp unknown_chunks;
+ png_size_t unknown_chunks_num;
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+ /* iCCP chunk data. */
+ png_charp iccp_name; /* profile name */
+ png_charp iccp_profile; /* International Color Consortium profile data */
+ /* Note to maintainer: should be png_bytep */
+ png_uint_32 iccp_proflen; /* ICC profile data length */
+ png_byte iccp_compression; /* Always zero */
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+ /* data on sPLT chunks (there may be more than one). */
+ png_sPLT_tp splt_palettes;
+ png_uint_32 splt_palettes_num;
+#endif
+
+#if defined(PNG_sCAL_SUPPORTED)
+ /* The sCAL chunk describes the actual physical dimensions of the
+ * subject matter of the graphic. The chunk contains a unit specification
+ * a byte value, and two ASCII strings representing floating-point
+ * values. The values are width and height corresponsing to one pixel
+ * in the image. This external representation is converted to double
+ * here. Data values are valid if (valid & PNG_INFO_sCAL) is non-zero.
+ */
+ png_byte scal_unit; /* unit of physical scale */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ double scal_pixel_width; /* width of one pixel */
+ double scal_pixel_height; /* height of one pixel */
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_charp scal_s_width; /* string containing height */
+ png_charp scal_s_height; /* string containing width */
+#endif
+#endif
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+ /* Memory has been allocated if (valid & PNG_ALLOCATED_INFO_ROWS) non-zero */
+ /* Data valid if (valid & PNG_INFO_IDAT) non-zero */
+ png_bytepp row_pointers; /* the image bits */
+#endif
+
+#if defined(PNG_FIXED_POINT_SUPPORTED) && defined(PNG_gAMA_SUPPORTED)
+ png_fixed_point int_gamma; /* gamma of image, if (valid & PNG_INFO_gAMA) */
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED) && defined(PNG_FIXED_POINT_SUPPORTED)
+ png_fixed_point int_x_white;
+ png_fixed_point int_y_white;
+ png_fixed_point int_x_red;
+ png_fixed_point int_y_red;
+ png_fixed_point int_x_green;
+ png_fixed_point int_y_green;
+ png_fixed_point int_x_blue;
+ png_fixed_point int_y_blue;
+#endif
+
+} png_info;
+
+typedef png_info FAR * png_infop;
+typedef png_info FAR * FAR * png_infopp;
+
+/* Maximum positive integer used in PNG is (2^31)-1 */
+#define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL)
+#define PNG_UINT_32_MAX ((png_uint_32)(-1))
+#define PNG_SIZE_MAX ((png_size_t)(-1))
+#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
+/* PNG_MAX_UINT is deprecated; use PNG_UINT_31_MAX instead. */
+#define PNG_MAX_UINT PNG_UINT_31_MAX
+#endif
+
+/* These describe the color_type field in png_info. */
+/* color type masks */
+#define PNG_COLOR_MASK_PALETTE 1
+#define PNG_COLOR_MASK_COLOR 2
+#define PNG_COLOR_MASK_ALPHA 4
+
+/* color types. Note that not all combinations are legal */
+#define PNG_COLOR_TYPE_GRAY 0
+#define PNG_COLOR_TYPE_PALETTE (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_PALETTE)
+#define PNG_COLOR_TYPE_RGB (PNG_COLOR_MASK_COLOR)
+#define PNG_COLOR_TYPE_RGB_ALPHA (PNG_COLOR_MASK_COLOR | PNG_COLOR_MASK_ALPHA)
+#define PNG_COLOR_TYPE_GRAY_ALPHA (PNG_COLOR_MASK_ALPHA)
+/* aliases */
+#define PNG_COLOR_TYPE_RGBA PNG_COLOR_TYPE_RGB_ALPHA
+#define PNG_COLOR_TYPE_GA PNG_COLOR_TYPE_GRAY_ALPHA
+
+/* This is for compression type. PNG 1.0-1.2 only define the single type. */
+#define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */
+#define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE
+
+/* This is for filter type. PNG 1.0-1.2 only define the single type. */
+#define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */
+#define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */
+#define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE
+
+/* These are for the interlacing type. These values should NOT be changed. */
+#define PNG_INTERLACE_NONE 0 /* Non-interlaced image */
+#define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */
+#define PNG_INTERLACE_LAST 2 /* Not a valid value */
+
+/* These are for the oFFs chunk. These values should NOT be changed. */
+#define PNG_OFFSET_PIXEL 0 /* Offset in pixels */
+#define PNG_OFFSET_MICROMETER 1 /* Offset in micrometers (1/10^6 meter) */
+#define PNG_OFFSET_LAST 2 /* Not a valid value */
+
+/* These are for the pCAL chunk. These values should NOT be changed. */
+#define PNG_EQUATION_LINEAR 0 /* Linear transformation */
+#define PNG_EQUATION_BASE_E 1 /* Exponential base e transform */
+#define PNG_EQUATION_ARBITRARY 2 /* Arbitrary base exponential transform */
+#define PNG_EQUATION_HYPERBOLIC 3 /* Hyperbolic sine transformation */
+#define PNG_EQUATION_LAST 4 /* Not a valid value */
+
+/* These are for the sCAL chunk. These values should NOT be changed. */
+#define PNG_SCALE_UNKNOWN 0 /* unknown unit (image scale) */
+#define PNG_SCALE_METER 1 /* meters per pixel */
+#define PNG_SCALE_RADIAN 2 /* radians per pixel */
+#define PNG_SCALE_LAST 3 /* Not a valid value */
+
+/* These are for the pHYs chunk. These values should NOT be changed. */
+#define PNG_RESOLUTION_UNKNOWN 0 /* pixels/unknown unit (aspect ratio) */
+#define PNG_RESOLUTION_METER 1 /* pixels/meter */
+#define PNG_RESOLUTION_LAST 2 /* Not a valid value */
+
+/* These are for the sRGB chunk. These values should NOT be changed. */
+#define PNG_sRGB_INTENT_PERCEPTUAL 0
+#define PNG_sRGB_INTENT_RELATIVE 1
+#define PNG_sRGB_INTENT_SATURATION 2
+#define PNG_sRGB_INTENT_ABSOLUTE 3
+#define PNG_sRGB_INTENT_LAST 4 /* Not a valid value */
+
+/* This is for text chunks */
+#define PNG_KEYWORD_MAX_LENGTH 79
+
+/* Maximum number of entries in PLTE/sPLT/tRNS arrays */
+#define PNG_MAX_PALETTE_LENGTH 256
+
+/* These determine if an ancillary chunk's data has been successfully read
+ * from the PNG header, or if the application has filled in the corresponding
+ * data in the info_struct to be written into the output file. The values
+ * of the PNG_INFO_<chunk> defines should NOT be changed.
+ */
+#define PNG_INFO_gAMA 0x0001
+#define PNG_INFO_sBIT 0x0002
+#define PNG_INFO_cHRM 0x0004
+#define PNG_INFO_PLTE 0x0008
+#define PNG_INFO_tRNS 0x0010
+#define PNG_INFO_bKGD 0x0020
+#define PNG_INFO_hIST 0x0040
+#define PNG_INFO_pHYs 0x0080
+#define PNG_INFO_oFFs 0x0100
+#define PNG_INFO_tIME 0x0200
+#define PNG_INFO_pCAL 0x0400
+#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */
+#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */
+#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */
+#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */
+#define PNG_INFO_IDAT 0x8000L /* ESR, 1.0.6 */
+
+/* This is used for the transformation routines, as some of them
+ * change these values for the row. It also should enable using
+ * the routines for other purposes.
+ */
+typedef struct png_row_info_struct
+{
+ png_uint_32 width; /* width of row */
+ png_uint_32 rowbytes; /* number of bytes in row */
+ png_byte color_type; /* color type of row */
+ png_byte bit_depth; /* bit depth of row */
+ png_byte channels; /* number of channels (1, 2, 3, or 4) */
+ png_byte pixel_depth; /* bits per pixel (depth * channels) */
+} png_row_info;
+
+typedef png_row_info FAR * png_row_infop;
+typedef png_row_info FAR * FAR * png_row_infopp;
+
+/* These are the function types for the I/O functions and for the functions
+ * that allow the user to override the default I/O functions with his or her
+ * own. The png_error_ptr type should match that of user-supplied warning
+ * and error functions, while the png_rw_ptr type should match that of the
+ * user read/write data functions.
+ */
+typedef struct png_struct_def png_struct;
+typedef png_struct FAR * png_structp;
+
+typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp));
+typedef void (PNGAPI *png_rw_ptr) PNGARG((png_structp, png_bytep, png_size_t));
+typedef void (PNGAPI *png_flush_ptr) PNGARG((png_structp));
+typedef void (PNGAPI *png_read_status_ptr) PNGARG((png_structp, png_uint_32,
+ int));
+typedef void (PNGAPI *png_write_status_ptr) PNGARG((png_structp, png_uint_32,
+ int));
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+typedef void (PNGAPI *png_progressive_info_ptr) PNGARG((png_structp, png_infop));
+typedef void (PNGAPI *png_progressive_end_ptr) PNGARG((png_structp, png_infop));
+typedef void (PNGAPI *png_progressive_row_ptr) PNGARG((png_structp, png_bytep,
+ png_uint_32, int));
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+typedef void (PNGAPI *png_user_transform_ptr) PNGARG((png_structp,
+ png_row_infop, png_bytep));
+#endif
+
+#if defined(PNG_USER_CHUNKS_SUPPORTED)
+typedef int (PNGAPI *png_user_chunk_ptr) PNGARG((png_structp, png_unknown_chunkp));
+#endif
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp));
+#endif
+
+/* Transform masks for the high-level interface */
+#define PNG_TRANSFORM_IDENTITY 0x0000 /* read and write */
+#define PNG_TRANSFORM_STRIP_16 0x0001 /* read only */
+#define PNG_TRANSFORM_STRIP_ALPHA 0x0002 /* read only */
+#define PNG_TRANSFORM_PACKING 0x0004 /* read and write */
+#define PNG_TRANSFORM_PACKSWAP 0x0008 /* read and write */
+#define PNG_TRANSFORM_EXPAND 0x0010 /* read only */
+#define PNG_TRANSFORM_INVERT_MONO 0x0020 /* read and write */
+#define PNG_TRANSFORM_SHIFT 0x0040 /* read and write */
+#define PNG_TRANSFORM_BGR 0x0080 /* read and write */
+#define PNG_TRANSFORM_SWAP_ALPHA 0x0100 /* read and write */
+#define PNG_TRANSFORM_SWAP_ENDIAN 0x0200 /* read and write */
+#define PNG_TRANSFORM_INVERT_ALPHA 0x0400 /* read and write */
+#define PNG_TRANSFORM_STRIP_FILLER 0x0800 /* WRITE only */
+
+/* Flags for MNG supported features */
+#define PNG_FLAG_MNG_EMPTY_PLTE 0x01
+#define PNG_FLAG_MNG_FILTER_64 0x04
+#define PNG_ALL_MNG_FEATURES 0x05
+
+typedef png_voidp (*png_malloc_ptr) PNGARG((png_structp, png_size_t));
+typedef void (*png_free_ptr) PNGARG((png_structp, png_voidp));
+
+/* The structure that holds the information to read and write PNG files.
+ * The only people who need to care about what is inside of this are the
+ * people who will be modifying the library for their own special needs.
+ * It should NOT be accessed directly by an application, except to store
+ * the jmp_buf.
+ */
+
+struct png_struct_def
+{
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf jmpbuf; /* used in png_error */
+#endif
+ png_error_ptr error_fn; /* function for printing errors and aborting */
+ png_error_ptr warning_fn; /* function for printing warnings */
+ png_voidp error_ptr; /* user supplied struct for error functions */
+ png_rw_ptr write_data_fn; /* function for writing output data */
+ png_rw_ptr read_data_fn; /* function for reading input data */
+ png_voidp io_ptr; /* ptr to application struct for I/O functions */
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ png_user_transform_ptr read_user_transform_fn; /* user read transform */
+#endif
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ png_user_transform_ptr write_user_transform_fn; /* user write transform */
+#endif
+
+/* These were added in libpng-1.0.2 */
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ png_voidp user_transform_ptr; /* user supplied struct for user transform */
+ png_byte user_transform_depth; /* bit depth of user transformed pixels */
+ png_byte user_transform_channels; /* channels in user transformed pixels */
+#endif
+#endif
+
+ png_uint_32 mode; /* tells us where we are in the PNG file */
+ png_uint_32 flags; /* flags indicating various things to libpng */
+ png_uint_32 transformations; /* which transformations to perform */
+
+ z_stream zstream; /* pointer to decompression structure (below) */
+ png_bytep zbuf; /* buffer for zlib */
+ png_size_t zbuf_size; /* size of zbuf */
+ int zlib_level; /* holds zlib compression level */
+ int zlib_method; /* holds zlib compression method */
+ int zlib_window_bits; /* holds zlib compression window bits */
+ int zlib_mem_level; /* holds zlib compression memory level */
+ int zlib_strategy; /* holds zlib compression strategy */
+
+ png_uint_32 width; /* width of image in pixels */
+ png_uint_32 height; /* height of image in pixels */
+ png_uint_32 num_rows; /* number of rows in current pass */
+ png_uint_32 usr_width; /* width of row at start of write */
+ png_uint_32 rowbytes; /* size of row in bytes */
+ png_uint_32 irowbytes; /* size of current interlaced row in bytes */
+ png_uint_32 iwidth; /* width of current interlaced row in pixels */
+ png_uint_32 row_number; /* current row in interlace pass */
+ png_bytep prev_row; /* buffer to save previous (unfiltered) row */
+ png_bytep row_buf; /* buffer to save current (unfiltered) row */
+ png_bytep sub_row; /* buffer to save "sub" row when filtering */
+ png_bytep up_row; /* buffer to save "up" row when filtering */
+ png_bytep avg_row; /* buffer to save "avg" row when filtering */
+ png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */
+ png_row_info row_info; /* used for transformation routines */
+
+ png_uint_32 idat_size; /* current IDAT size for read */
+ png_uint_32 crc; /* current chunk CRC value */
+ png_colorp palette; /* palette from the input file */
+ png_uint_16 num_palette; /* number of color entries in palette */
+ png_uint_16 num_trans; /* number of transparency values */
+ png_byte chunk_name[5]; /* null-terminated name of current chunk */
+ png_byte compression; /* file compression type (always 0) */
+ png_byte filter; /* file filter type (always 0) */
+ png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */
+ png_byte pass; /* current interlace pass (0 - 6) */
+ png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */
+ png_byte color_type; /* color type of file */
+ png_byte bit_depth; /* bit depth of file */
+ png_byte usr_bit_depth; /* bit depth of users row */
+ png_byte pixel_depth; /* number of bits per pixel */
+ png_byte channels; /* number of channels in file */
+ png_byte usr_channels; /* channels at start of write */
+ png_byte sig_bytes; /* magic bytes read/written from start of file */
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+#ifdef PNG_LEGACY_SUPPORTED
+ png_byte filler; /* filler byte for pixel expansion */
+#else
+ png_uint_16 filler; /* filler bytes for pixel expansion */
+#endif
+#endif
+
+#if defined(PNG_bKGD_SUPPORTED)
+ png_byte background_gamma_type;
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+ float background_gamma;
+# endif
+ png_color_16 background; /* background color in screen gamma space */
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ png_color_16 background_1; /* background normalized to gamma 1.0 */
+#endif
+#endif /* PNG_bKGD_SUPPORTED */
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_flush_ptr output_flush_fn;/* Function for flushing output */
+ png_uint_32 flush_dist; /* how many rows apart to flush, 0 - no flush */
+ png_uint_32 flush_rows; /* number of rows written since last flush */
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ int gamma_shift; /* number of "insignificant" bits 16-bit gamma */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float gamma; /* file gamma value */
+ float screen_gamma; /* screen gamma value (display_exponent) */
+#endif
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_bytep gamma_table; /* gamma table for 8-bit depth files */
+ png_bytep gamma_from_1; /* converts from 1.0 to screen */
+ png_bytep gamma_to_1; /* converts from file to 1.0 */
+ png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */
+ png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */
+ png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED)
+ png_color_8 sig_bit; /* significant bits in each available channel */
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+ png_color_8 shift; /* shift for significant bit tranformation */
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \
+ || defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_bytep trans; /* transparency values for paletted files */
+ png_color_16 trans_values; /* transparency values for non-paletted files */
+#endif
+
+ png_read_status_ptr read_row_fn; /* called after each row is decoded */
+ png_write_status_ptr write_row_fn; /* called after each row is encoded */
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ png_progressive_info_ptr info_fn; /* called after header data fully read */
+ png_progressive_row_ptr row_fn; /* called after each prog. row is decoded */
+ png_progressive_end_ptr end_fn; /* called after image is complete */
+ png_bytep save_buffer_ptr; /* current location in save_buffer */
+ png_bytep save_buffer; /* buffer for previously read data */
+ png_bytep current_buffer_ptr; /* current location in current_buffer */
+ png_bytep current_buffer; /* buffer for recently used data */
+ png_uint_32 push_length; /* size of current input chunk */
+ png_uint_32 skip_length; /* bytes to skip in input data */
+ png_size_t save_buffer_size; /* amount of data now in save_buffer */
+ png_size_t save_buffer_max; /* total size of save_buffer */
+ png_size_t buffer_size; /* total amount of available input data */
+ png_size_t current_buffer_size; /* amount of data now in current_buffer */
+ int process_mode; /* what push library is currently doing */
+ int cur_palette; /* current push library palette index */
+
+# if defined(PNG_TEXT_SUPPORTED)
+ png_size_t current_text_size; /* current size of text input data */
+ png_size_t current_text_left; /* how much text left to read in input */
+ png_charp current_text; /* current text chunk buffer */
+ png_charp current_text_ptr; /* current location in current_text */
+# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */
+
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
+/* for the Borland special 64K segment handler */
+ png_bytepp offset_table_ptr;
+ png_bytep offset_table;
+ png_uint_16 offset_table_number;
+ png_uint_16 offset_table_count;
+ png_uint_16 offset_table_count_free;
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ png_bytep palette_lookup; /* lookup table for dithering */
+ png_bytep dither_index; /* index translation for palette files */
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED) || defined(PNG_hIST_SUPPORTED)
+ png_uint_16p hist; /* histogram */
+#endif
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_byte heuristic_method; /* heuristic for row filter selection */
+ png_byte num_prev_filters; /* number of weights for previous rows */
+ png_bytep prev_filters; /* filter type(s) of previous row(s) */
+ png_uint_16p filter_weights; /* weight(s) for previous line(s) */
+ png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */
+ png_uint_16p filter_costs; /* relative filter calculation cost */
+ png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */
+#endif
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ png_charp time_buffer; /* String to hold RFC 1123 time text */
+#endif
+
+/* New members added in libpng-1.0.6 */
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_uint_32 free_me; /* flags items libpng is responsible for freeing */
+#endif
+
+#if defined(PNG_USER_CHUNKS_SUPPORTED)
+ png_voidp user_chunk_ptr;
+ png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */
+#endif
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ int num_chunk_list;
+ png_bytep chunk_list;
+#endif
+
+/* New members added in libpng-1.0.3 */
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ png_byte rgb_to_gray_status;
+ /* These were changed from png_byte in libpng-1.0.6 */
+ png_uint_16 rgb_to_gray_red_coeff;
+ png_uint_16 rgb_to_gray_green_coeff;
+ png_uint_16 rgb_to_gray_blue_coeff;
+#endif
+
+/* New member added in libpng-1.0.4 (renamed in 1.0.9) */
+#if defined(PNG_MNG_FEATURES_SUPPORTED) || \
+ defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
+ defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
+/* changed from png_byte to png_uint_32 at version 1.2.0 */
+#ifdef PNG_1_0_X
+ png_byte mng_features_permitted;
+#else
+ png_uint_32 mng_features_permitted;
+#endif /* PNG_1_0_X */
+#endif
+
+/* New member added in libpng-1.0.7 */
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_fixed_point int_gamma;
+#endif
+
+/* New member added in libpng-1.0.9, ifdef'ed out in 1.0.12, enabled in 1.2.0 */
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ png_byte filter_type;
+#endif
+
+#if defined(PNG_1_0_X)
+/* New member added in libpng-1.0.10, ifdef'ed out in 1.2.0 */
+ png_uint_32 row_buf_size;
+#endif
+
+/* New members added in libpng-1.2.0 */
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+# if !defined(PNG_1_0_X)
+# if defined(PNG_MMX_CODE_SUPPORTED)
+ png_byte mmx_bitdepth_threshold;
+ png_uint_32 mmx_rowbytes_threshold;
+# endif
+ png_uint_32 asm_flags;
+# endif
+#endif
+
+/* New members added in libpng-1.0.2 but first enabled by default in 1.2.0 */
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_voidp mem_ptr; /* user supplied struct for mem functions */
+ png_malloc_ptr malloc_fn; /* function for allocating memory */
+ png_free_ptr free_fn; /* function for freeing memory */
+#endif
+
+/* New member added in libpng-1.0.13 and 1.2.0 */
+ png_bytep big_row_buf; /* buffer to save current (unfiltered) row */
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+/* The following three members were added at version 1.0.14 and 1.2.4 */
+ png_bytep dither_sort; /* working sort array */
+ png_bytep index_to_palette; /* where the original index currently is */
+ /* in the palette */
+ png_bytep palette_to_index; /* which original index points to this */
+ /* palette color */
+#endif
+
+/* New members added in libpng-1.0.16 and 1.2.6 */
+ png_byte compression_type;
+
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ png_uint_32 user_width_max;
+ png_uint_32 user_height_max;
+#endif
+
+/* New member added in libpng-1.0.25 and 1.2.17 */
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ /* storage for unknown chunk that the library doesn't recognize. */
+ png_unknown_chunk unknown_chunk;
+#endif
+};
+
+
+/* This triggers a compiler error in png.c, if png.c and png.h
+ * do not agree upon the version number.
+ */
+typedef png_structp version_1_2_19;
+
+typedef png_struct FAR * FAR * png_structpp;
+
+/* Here are the function definitions most commonly used. This is not
+ * the place to find out how to use libpng. See libpng.txt for the
+ * full explanation, see example.c for the summary. This just provides
+ * a simple one line description of the use of each function.
+ */
+
+/* Returns the version number of the library */
+extern PNG_EXPORT(png_uint_32,png_access_version_number) PNGARG((void));
+
+/* Tell lib we have already handled the first <num_bytes> magic bytes.
+ * Handling more than 8 bytes from the beginning of the file is an error.
+ */
+extern PNG_EXPORT(void,png_set_sig_bytes) PNGARG((png_structp png_ptr,
+ int num_bytes));
+
+/* Check sig[start] through sig[start + num_to_check - 1] to see if it's a
+ * PNG file. Returns zero if the supplied bytes match the 8-byte PNG
+ * signature, and non-zero otherwise. Having num_to_check == 0 or
+ * start > 7 will always fail (ie return non-zero).
+ */
+extern PNG_EXPORT(int,png_sig_cmp) PNGARG((png_bytep sig, png_size_t start,
+ png_size_t num_to_check));
+
+/* Simple signature checking function. This is the same as calling
+ * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n).
+ */
+extern PNG_EXPORT(int,png_check_sig) PNGARG((png_bytep sig, int num));
+
+/* Allocate and initialize png_ptr struct for reading, and any other memory. */
+extern PNG_EXPORT(png_structp,png_create_read_struct)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn));
+
+/* Allocate and initialize png_ptr struct for writing, and any other memory */
+extern PNG_EXPORT(png_structp,png_create_write_struct)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn));
+
+#ifdef PNG_WRITE_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_compression_buffer_size)
+ PNGARG((png_structp png_ptr));
+#endif
+
+#ifdef PNG_WRITE_SUPPORTED
+extern PNG_EXPORT(void,png_set_compression_buffer_size)
+ PNGARG((png_structp png_ptr, png_uint_32 size));
+#endif
+
+/* Reset the compression stream */
+extern PNG_EXPORT(int,png_reset_zstream) PNGARG((png_structp png_ptr));
+
+/* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */
+#ifdef PNG_USER_MEM_SUPPORTED
+extern PNG_EXPORT(png_structp,png_create_read_struct_2)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+extern PNG_EXPORT(png_structp,png_create_write_struct_2)
+ PNGARG((png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+#endif
+
+/* Write a PNG chunk - size, type, (optional) data, CRC. */
+extern PNG_EXPORT(void,png_write_chunk) PNGARG((png_structp png_ptr,
+ png_bytep chunk_name, png_bytep data, png_size_t length));
+
+/* Write the start of a PNG chunk - length and chunk name. */
+extern PNG_EXPORT(void,png_write_chunk_start) PNGARG((png_structp png_ptr,
+ png_bytep chunk_name, png_uint_32 length));
+
+/* Write the data of a PNG chunk started with png_write_chunk_start(). */
+extern PNG_EXPORT(void,png_write_chunk_data) PNGARG((png_structp png_ptr,
+ png_bytep data, png_size_t length));
+
+/* Finish a chunk started with png_write_chunk_start() (includes CRC). */
+extern PNG_EXPORT(void,png_write_chunk_end) PNGARG((png_structp png_ptr));
+
+/* Allocate and initialize the info structure */
+extern PNG_EXPORT(png_infop,png_create_info_struct)
+ PNGARG((png_structp png_ptr));
+
+#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
+/* Initialize the info structure (old interface - DEPRECATED) */
+extern PNG_EXPORT(void,png_info_init) PNGARG((png_infop info_ptr));
+#undef png_info_init
+#define png_info_init(info_ptr) png_info_init_3(&info_ptr,\
+ png_sizeof(png_info));
+#endif
+
+extern PNG_EXPORT(void,png_info_init_3) PNGARG((png_infopp info_ptr,
+ png_size_t png_info_struct_size));
+
+/* Writes all the PNG information before the image. */
+extern PNG_EXPORT(void,png_write_info_before_PLTE) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+extern PNG_EXPORT(void,png_write_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+/* read the information before the actual image data. */
+extern PNG_EXPORT(void,png_read_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+extern PNG_EXPORT(png_charp,png_convert_to_rfc1123)
+ PNGARG((png_structp png_ptr, png_timep ptime));
+#endif
+
+#if !defined(_WIN32_WCE)
+/* "time.h" functions are not supported on WindowsCE */
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+/* convert from a struct tm to png_time */
+extern PNG_EXPORT(void,png_convert_from_struct_tm) PNGARG((png_timep ptime,
+ struct tm FAR * ttime));
+
+/* convert from time_t to png_time. Uses gmtime() */
+extern PNG_EXPORT(void,png_convert_from_time_t) PNGARG((png_timep ptime,
+ time_t ttime));
+#endif /* PNG_WRITE_tIME_SUPPORTED */
+#endif /* _WIN32_WCE */
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */
+extern PNG_EXPORT(void,png_set_expand) PNGARG((png_structp png_ptr));
+#if !defined(PNG_1_0_X)
+extern PNG_EXPORT(void,png_set_expand_gray_1_2_4_to_8) PNGARG((png_structp
+ png_ptr));
+#endif
+extern PNG_EXPORT(void,png_set_palette_to_rgb) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(void,png_set_tRNS_to_alpha) PNGARG((png_structp png_ptr));
+#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
+/* Deprecated */
+extern PNG_EXPORT(void,png_set_gray_1_2_4_to_8) PNGARG((png_structp png_ptr));
+#endif
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* Use blue, green, red order for pixels. */
+extern PNG_EXPORT(void,png_set_bgr) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+/* Expand the grayscale to 24-bit RGB if necessary. */
+extern PNG_EXPORT(void,png_set_gray_to_rgb) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+/* Reduce RGB to grayscale. */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_rgb_to_gray) PNGARG((png_structp png_ptr,
+ int error_action, double red, double green ));
+#endif
+extern PNG_EXPORT(void,png_set_rgb_to_gray_fixed) PNGARG((png_structp png_ptr,
+ int error_action, png_fixed_point red, png_fixed_point green ));
+extern PNG_EXPORT(png_byte,png_get_rgb_to_gray_status) PNGARG((png_structp
+ png_ptr));
+#endif
+
+extern PNG_EXPORT(void,png_build_grayscale_palette) PNGARG((int bit_depth,
+ png_colorp palette));
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_strip_alpha) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */
+extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr,
+ png_uint_32 filler, int flags));
+/* The values of the PNG_FILLER_ defines should NOT be changed */
+#define PNG_FILLER_BEFORE 0
+#define PNG_FILLER_AFTER 1
+/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */
+#if !defined(PNG_1_0_X)
+extern PNG_EXPORT(void,png_set_add_alpha) PNGARG((png_structp png_ptr,
+ png_uint_32 filler, int flags));
+#endif
+#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* Swap bytes in 16-bit depth files. */
+extern PNG_EXPORT(void,png_set_swap) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
+/* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */
+extern PNG_EXPORT(void,png_set_packing) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+/* Swap packing order of pixels in bytes. */
+extern PNG_EXPORT(void,png_set_packswap) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+/* Converts files to legal bit depths. */
+extern PNG_EXPORT(void,png_set_shift) PNGARG((png_structp png_ptr,
+ png_color_8p true_bits));
+#endif
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
+ defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* Have the code handle the interlacing. Returns the number of passes. */
+extern PNG_EXPORT(int,png_set_interlace_handling) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+/* Invert monochrome files */
+extern PNG_EXPORT(void,png_set_invert_mono) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+/* Handle alpha and tRNS by replacing with a background color. */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_background) PNGARG((png_structp png_ptr,
+ png_color_16p background_color, int background_gamma_code,
+ int need_expand, double background_gamma));
+#endif
+#define PNG_BACKGROUND_GAMMA_UNKNOWN 0
+#define PNG_BACKGROUND_GAMMA_SCREEN 1
+#define PNG_BACKGROUND_GAMMA_FILE 2
+#define PNG_BACKGROUND_GAMMA_UNIQUE 3
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* strip the second byte of information from a 16-bit depth file. */
+extern PNG_EXPORT(void,png_set_strip_16) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+/* Turn on dithering, and reduce the palette to the number of colors available. */
+extern PNG_EXPORT(void,png_set_dither) PNGARG((png_structp png_ptr,
+ png_colorp palette, int num_palette, int maximum_colors,
+ png_uint_16p histogram, int full_dither));
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+/* Handle gamma correction. Screen_gamma=(display_exponent) */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_gamma) PNGARG((png_structp png_ptr,
+ double screen_gamma, double default_file_gamma));
+#endif
+#endif
+
+#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
+#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
+ defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
+/* Permit or disallow empty PLTE (0: not permitted, 1: permitted) */
+/* Deprecated and will be removed. Use png_permit_mng_features() instead. */
+extern PNG_EXPORT(void,png_permit_empty_plte) PNGARG((png_structp png_ptr,
+ int empty_plte_permitted));
+#endif
+#endif
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+/* Set how many lines between output flushes - 0 for no flushing */
+extern PNG_EXPORT(void,png_set_flush) PNGARG((png_structp png_ptr, int nrows));
+/* Flush the current PNG output buffer */
+extern PNG_EXPORT(void,png_write_flush) PNGARG((png_structp png_ptr));
+#endif
+
+/* optional update palette with requested transformations */
+extern PNG_EXPORT(void,png_start_read_image) PNGARG((png_structp png_ptr));
+
+/* optional call to update the users info structure */
+extern PNG_EXPORT(void,png_read_update_info) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+/* read one or more rows of image data. */
+extern PNG_EXPORT(void,png_read_rows) PNGARG((png_structp png_ptr,
+ png_bytepp row, png_bytepp display_row, png_uint_32 num_rows));
+#endif
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+/* read a row of data. */
+extern PNG_EXPORT(void,png_read_row) PNGARG((png_structp png_ptr,
+ png_bytep row,
+ png_bytep display_row));
+#endif
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+/* read the whole image into memory at once. */
+extern PNG_EXPORT(void,png_read_image) PNGARG((png_structp png_ptr,
+ png_bytepp image));
+#endif
+
+/* write a row of image data */
+extern PNG_EXPORT(void,png_write_row) PNGARG((png_structp png_ptr,
+ png_bytep row));
+
+/* write a few rows of image data */
+extern PNG_EXPORT(void,png_write_rows) PNGARG((png_structp png_ptr,
+ png_bytepp row, png_uint_32 num_rows));
+
+/* write the image data */
+extern PNG_EXPORT(void,png_write_image) PNGARG((png_structp png_ptr,
+ png_bytepp image));
+
+/* writes the end of the PNG file. */
+extern PNG_EXPORT(void,png_write_end) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+/* read the end of the PNG file. */
+extern PNG_EXPORT(void,png_read_end) PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+
+/* free any memory associated with the png_info_struct */
+extern PNG_EXPORT(void,png_destroy_info_struct) PNGARG((png_structp png_ptr,
+ png_infopp info_ptr_ptr));
+
+/* free any memory associated with the png_struct and the png_info_structs */
+extern PNG_EXPORT(void,png_destroy_read_struct) PNGARG((png_structpp
+ png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr));
+
+/* free all memory used by the read (old method - NOT DLL EXPORTED) */
+extern void png_read_destroy PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_infop end_info_ptr));
+
+/* free any memory associated with the png_struct and the png_info_structs */
+extern PNG_EXPORT(void,png_destroy_write_struct)
+ PNGARG((png_structpp png_ptr_ptr, png_infopp info_ptr_ptr));
+
+/* free any memory used in png_ptr struct (old method - NOT DLL EXPORTED) */
+extern void png_write_destroy PNGARG((png_structp png_ptr));
+
+/* set the libpng method of handling chunk CRC errors */
+extern PNG_EXPORT(void,png_set_crc_action) PNGARG((png_structp png_ptr,
+ int crit_action, int ancil_action));
+
+/* Values for png_set_crc_action() to say how to handle CRC errors in
+ * ancillary and critical chunks, and whether to use the data contained
+ * therein. Note that it is impossible to "discard" data in a critical
+ * chunk. For versions prior to 0.90, the action was always error/quit,
+ * whereas in version 0.90 and later, the action for CRC errors in ancillary
+ * chunks is warn/discard. These values should NOT be changed.
+ *
+ * value action:critical action:ancillary
+ */
+#define PNG_CRC_DEFAULT 0 /* error/quit warn/discard data */
+#define PNG_CRC_ERROR_QUIT 1 /* error/quit error/quit */
+#define PNG_CRC_WARN_DISCARD 2 /* (INVALID) warn/discard data */
+#define PNG_CRC_WARN_USE 3 /* warn/use data warn/use data */
+#define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */
+#define PNG_CRC_NO_CHANGE 5 /* use current value use current value */
+
+/* These functions give the user control over the scan-line filtering in
+ * libpng and the compression methods used by zlib. These functions are
+ * mainly useful for testing, as the defaults should work with most users.
+ * Those users who are tight on memory or want faster performance at the
+ * expense of compression can modify them. See the compression library
+ * header file (zlib.h) for an explination of the compression functions.
+ */
+
+/* set the filtering method(s) used by libpng. Currently, the only valid
+ * value for "method" is 0.
+ */
+extern PNG_EXPORT(void,png_set_filter) PNGARG((png_structp png_ptr, int method,
+ int filters));
+
+/* Flags for png_set_filter() to say which filters to use. The flags
+ * are chosen so that they don't conflict with real filter types
+ * below, in case they are supplied instead of the #defined constants.
+ * These values should NOT be changed.
+ */
+#define PNG_NO_FILTERS 0x00
+#define PNG_FILTER_NONE 0x08
+#define PNG_FILTER_SUB 0x10
+#define PNG_FILTER_UP 0x20
+#define PNG_FILTER_AVG 0x40
+#define PNG_FILTER_PAETH 0x80
+#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \
+ PNG_FILTER_AVG | PNG_FILTER_PAETH)
+
+/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now.
+ * These defines should NOT be changed.
+ */
+#define PNG_FILTER_VALUE_NONE 0
+#define PNG_FILTER_VALUE_SUB 1
+#define PNG_FILTER_VALUE_UP 2
+#define PNG_FILTER_VALUE_AVG 3
+#define PNG_FILTER_VALUE_PAETH 4
+#define PNG_FILTER_VALUE_LAST 5
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* EXPERIMENTAL */
+/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_
+ * defines, either the default (minimum-sum-of-absolute-differences), or
+ * the experimental method (weighted-minimum-sum-of-absolute-differences).
+ *
+ * Weights are factors >= 1.0, indicating how important it is to keep the
+ * filter type consistent between rows. Larger numbers mean the current
+ * filter is that many times as likely to be the same as the "num_weights"
+ * previous filters. This is cumulative for each previous row with a weight.
+ * There needs to be "num_weights" values in "filter_weights", or it can be
+ * NULL if the weights aren't being specified. Weights have no influence on
+ * the selection of the first row filter. Well chosen weights can (in theory)
+ * improve the compression for a given image.
+ *
+ * Costs are factors >= 1.0 indicating the relative decoding costs of a
+ * filter type. Higher costs indicate more decoding expense, and are
+ * therefore less likely to be selected over a filter with lower computational
+ * costs. There needs to be a value in "filter_costs" for each valid filter
+ * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't
+ * setting the costs. Costs try to improve the speed of decompression without
+ * unduly increasing the compressed image size.
+ *
+ * A negative weight or cost indicates the default value is to be used, and
+ * values in the range [0.0, 1.0) indicate the value is to remain unchanged.
+ * The default values for both weights and costs are currently 1.0, but may
+ * change if good general weighting/cost heuristics can be found. If both
+ * the weights and costs are set to 1.0, this degenerates the WEIGHTED method
+ * to the UNWEIGHTED method, but with added encoding time/computation.
+ */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_filter_heuristics) PNGARG((png_structp png_ptr,
+ int heuristic_method, int num_weights, png_doublep filter_weights,
+ png_doublep filter_costs));
+#endif
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+/* Heuristic used for row filter selection. These defines should NOT be
+ * changed.
+ */
+#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */
+#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */
+#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */
+#define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */
+
+/* Set the library compression level. Currently, valid values range from
+ * 0 - 9, corresponding directly to the zlib compression levels 0 - 9
+ * (0 - no compression, 9 - "maximal" compression). Note that tests have
+ * shown that zlib compression levels 3-6 usually perform as well as level 9
+ * for PNG images, and do considerably fewer caclulations. In the future,
+ * these values may not correspond directly to the zlib compression levels.
+ */
+extern PNG_EXPORT(void,png_set_compression_level) PNGARG((png_structp png_ptr,
+ int level));
+
+extern PNG_EXPORT(void,png_set_compression_mem_level)
+ PNGARG((png_structp png_ptr, int mem_level));
+
+extern PNG_EXPORT(void,png_set_compression_strategy)
+ PNGARG((png_structp png_ptr, int strategy));
+
+extern PNG_EXPORT(void,png_set_compression_window_bits)
+ PNGARG((png_structp png_ptr, int window_bits));
+
+extern PNG_EXPORT(void,png_set_compression_method) PNGARG((png_structp png_ptr,
+ int method));
+
+/* These next functions are called for input/output, memory, and error
+ * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c,
+ * and call standard C I/O routines such as fread(), fwrite(), and
+ * fprintf(). These functions can be made to use other I/O routines
+ * at run time for those applications that need to handle I/O in a
+ * different manner by calling png_set_???_fn(). See libpng.txt for
+ * more information.
+ */
+
+#if !defined(PNG_NO_STDIO)
+/* Initialize the input/output for the PNG file to the default functions. */
+extern PNG_EXPORT(void,png_init_io) PNGARG((png_structp png_ptr, png_FILE_p fp));
+#endif
+
+/* Replace the (error and abort), and warning functions with user
+ * supplied functions. If no messages are to be printed you must still
+ * write and use replacement functions. The replacement error_fn should
+ * still do a longjmp to the last setjmp location if you are using this
+ * method of error handling. If error_fn or warning_fn is NULL, the
+ * default function will be used.
+ */
+
+extern PNG_EXPORT(void,png_set_error_fn) PNGARG((png_structp png_ptr,
+ png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn));
+
+/* Return the user pointer associated with the error functions */
+extern PNG_EXPORT(png_voidp,png_get_error_ptr) PNGARG((png_structp png_ptr));
+
+/* Replace the default data output functions with a user supplied one(s).
+ * If buffered output is not used, then output_flush_fn can be set to NULL.
+ * If PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile time
+ * output_flush_fn will be ignored (and thus can be NULL).
+ */
+extern PNG_EXPORT(void,png_set_write_fn) PNGARG((png_structp png_ptr,
+ png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn));
+
+/* Replace the default data input function with a user supplied one. */
+extern PNG_EXPORT(void,png_set_read_fn) PNGARG((png_structp png_ptr,
+ png_voidp io_ptr, png_rw_ptr read_data_fn));
+
+/* Return the user pointer associated with the I/O functions */
+extern PNG_EXPORT(png_voidp,png_get_io_ptr) PNGARG((png_structp png_ptr));
+
+extern PNG_EXPORT(void,png_set_read_status_fn) PNGARG((png_structp png_ptr,
+ png_read_status_ptr read_row_fn));
+
+extern PNG_EXPORT(void,png_set_write_status_fn) PNGARG((png_structp png_ptr,
+ png_write_status_ptr write_row_fn));
+
+#ifdef PNG_USER_MEM_SUPPORTED
+/* Replace the default memory allocation functions with user supplied one(s). */
+extern PNG_EXPORT(void,png_set_mem_fn) PNGARG((png_structp png_ptr,
+ png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn));
+/* Return the user pointer associated with the memory functions */
+extern PNG_EXPORT(png_voidp,png_get_mem_ptr) PNGARG((png_structp png_ptr));
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+extern PNG_EXPORT(void,png_set_read_user_transform_fn) PNGARG((png_structp
+ png_ptr, png_user_transform_ptr read_user_transform_fn));
+#endif
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+extern PNG_EXPORT(void,png_set_write_user_transform_fn) PNGARG((png_structp
+ png_ptr, png_user_transform_ptr write_user_transform_fn));
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+extern PNG_EXPORT(void,png_set_user_transform_info) PNGARG((png_structp
+ png_ptr, png_voidp user_transform_ptr, int user_transform_depth,
+ int user_transform_channels));
+/* Return the user pointer associated with the user transform functions */
+extern PNG_EXPORT(png_voidp,png_get_user_transform_ptr)
+ PNGARG((png_structp png_ptr));
+#endif
+
+#ifdef PNG_USER_CHUNKS_SUPPORTED
+extern PNG_EXPORT(void,png_set_read_user_chunk_fn) PNGARG((png_structp png_ptr,
+ png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn));
+extern PNG_EXPORT(png_voidp,png_get_user_chunk_ptr) PNGARG((png_structp
+ png_ptr));
+#endif
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+/* Sets the function callbacks for the push reader, and a pointer to a
+ * user-defined structure available to the callback functions.
+ */
+extern PNG_EXPORT(void,png_set_progressive_read_fn) PNGARG((png_structp png_ptr,
+ png_voidp progressive_ptr,
+ png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
+ png_progressive_end_ptr end_fn));
+
+/* returns the user pointer associated with the push read functions */
+extern PNG_EXPORT(png_voidp,png_get_progressive_ptr)
+ PNGARG((png_structp png_ptr));
+
+/* function to be called when data becomes available */
+extern PNG_EXPORT(void,png_process_data) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep buffer, png_size_t buffer_size));
+
+/* function that combines rows. Not very much different than the
+ * png_combine_row() call. Is this even used?????
+ */
+extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr,
+ png_bytep old_row, png_bytep new_row));
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr,
+ png_uint_32 size));
+
+#if defined(PNG_1_0_X)
+# define png_malloc_warn png_malloc
+#else
+/* Added at libpng version 1.2.4 */
+extern PNG_EXPORT(png_voidp,png_malloc_warn) PNGARG((png_structp png_ptr,
+ png_uint_32 size));
+#endif
+
+/* frees a pointer allocated by png_malloc() */
+extern PNG_EXPORT(void,png_free) PNGARG((png_structp png_ptr, png_voidp ptr));
+
+#if defined(PNG_1_0_X)
+/* Function to allocate memory for zlib. */
+extern PNG_EXPORT(voidpf,png_zalloc) PNGARG((voidpf png_ptr, uInt items,
+ uInt size));
+
+/* Function to free memory for zlib */
+extern PNG_EXPORT(void,png_zfree) PNGARG((voidpf png_ptr, voidpf ptr));
+#endif
+
+/* Free data that was allocated internally */
+extern PNG_EXPORT(void,png_free_data) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 free_me, int num));
+#ifdef PNG_FREE_ME_SUPPORTED
+/* Reassign responsibility for freeing existing data, whether allocated
+ * by libpng or by the application */
+extern PNG_EXPORT(void,png_data_freer) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int freer, png_uint_32 mask));
+#endif
+/* assignments for png_data_freer */
+#define PNG_DESTROY_WILL_FREE_DATA 1
+#define PNG_SET_WILL_FREE_DATA 1
+#define PNG_USER_WILL_FREE_DATA 2
+/* Flags for png_ptr->free_me and info_ptr->free_me */
+#define PNG_FREE_HIST 0x0008
+#define PNG_FREE_ICCP 0x0010
+#define PNG_FREE_SPLT 0x0020
+#define PNG_FREE_ROWS 0x0040
+#define PNG_FREE_PCAL 0x0080
+#define PNG_FREE_SCAL 0x0100
+#define PNG_FREE_UNKN 0x0200
+#define PNG_FREE_LIST 0x0400
+#define PNG_FREE_PLTE 0x1000
+#define PNG_FREE_TRNS 0x2000
+#define PNG_FREE_TEXT 0x4000
+#define PNG_FREE_ALL 0x7fff
+#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */
+
+#ifdef PNG_USER_MEM_SUPPORTED
+extern PNG_EXPORT(png_voidp,png_malloc_default) PNGARG((png_structp png_ptr,
+ png_uint_32 size));
+extern PNG_EXPORT(void,png_free_default) PNGARG((png_structp png_ptr,
+ png_voidp ptr));
+#endif
+
+extern PNG_EXPORT(png_voidp,png_memcpy_check) PNGARG((png_structp png_ptr,
+ png_voidp s1, png_voidp s2, png_uint_32 size));
+
+extern PNG_EXPORT(png_voidp,png_memset_check) PNGARG((png_structp png_ptr,
+ png_voidp s1, int value, png_uint_32 size));
+
+#if defined(USE_FAR_KEYWORD) /* memory model conversion function */
+extern void *png_far_to_near PNGARG((png_structp png_ptr,png_voidp ptr,
+ int check));
+#endif /* USE_FAR_KEYWORD */
+
+/* Fatal error in PNG image of libpng - can't continue */
+extern PNG_EXPORT(void,png_error) PNGARG((png_structp png_ptr,
+ png_const_charp error_message));
+
+/* The same, but the chunk name is prepended to the error string. */
+extern PNG_EXPORT(void,png_chunk_error) PNGARG((png_structp png_ptr,
+ png_const_charp error_message));
+
+#ifndef PNG_NO_WARNINGS
+/* Non-fatal error in libpng. Can continue, but may have a problem. */
+extern PNG_EXPORT(void,png_warning) PNGARG((png_structp png_ptr,
+ png_const_charp warning_message));
+
+#ifdef PNG_READ_SUPPORTED
+/* Non-fatal error in libpng, chunk name is prepended to message. */
+extern PNG_EXPORT(void,png_chunk_warning) PNGARG((png_structp png_ptr,
+ png_const_charp warning_message));
+#endif /* PNG_READ_SUPPORTED */
+#endif /* PNG_NO_WARNINGS */
+
+/* The png_set_<chunk> functions are for storing values in the png_info_struct.
+ * Similarly, the png_get_<chunk> calls are used to read values from the
+ * png_info_struct, either storing the parameters in the passed variables, or
+ * setting pointers into the png_info_struct where the data is stored. The
+ * png_get_<chunk> functions return a non-zero value if the data was available
+ * in info_ptr, or return zero and do not change any of the parameters if the
+ * data was not available.
+ *
+ * These functions should be used instead of directly accessing png_info
+ * to avoid problems with future changes in the size and internal layout of
+ * png_info_struct.
+ */
+/* Returns "flag" if chunk data is valid in info_ptr. */
+extern PNG_EXPORT(png_uint_32,png_get_valid) PNGARG((png_structp png_ptr,
+png_infop info_ptr, png_uint_32 flag));
+
+/* Returns number of bytes needed to hold a transformed row. */
+extern PNG_EXPORT(png_uint_32,png_get_rowbytes) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+/* Returns row_pointers, which is an array of pointers to scanlines that was
+returned from png_read_png(). */
+extern PNG_EXPORT(png_bytepp,png_get_rows) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+/* Set row_pointers, which is an array of pointers to scanlines for use
+by png_write_png(). */
+extern PNG_EXPORT(void,png_set_rows) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytepp row_pointers));
+#endif
+
+/* Returns number of color channels in image. */
+extern PNG_EXPORT(png_byte,png_get_channels) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#ifdef PNG_EASY_ACCESS_SUPPORTED
+/* Returns image width in pixels. */
+extern PNG_EXPORT(png_uint_32, png_get_image_width) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image height in pixels. */
+extern PNG_EXPORT(png_uint_32, png_get_image_height) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image bit_depth. */
+extern PNG_EXPORT(png_byte, png_get_bit_depth) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image color_type. */
+extern PNG_EXPORT(png_byte, png_get_color_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image filter_type. */
+extern PNG_EXPORT(png_byte, png_get_filter_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image interlace_type. */
+extern PNG_EXPORT(png_byte, png_get_interlace_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image compression_type. */
+extern PNG_EXPORT(png_byte, png_get_compression_type) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns image resolution in pixels per meter, from pHYs chunk data. */
+extern PNG_EXPORT(png_uint_32, png_get_pixels_per_meter) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32, png_get_x_pixels_per_meter) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_uint_32, png_get_y_pixels_per_meter) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+/* Returns pixel aspect ratio, computed from pHYs chunk data. */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(float, png_get_pixel_aspect_ratio) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+#endif
+
+/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */
+extern PNG_EXPORT(png_int_32, png_get_x_offset_pixels) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_int_32, png_get_y_offset_pixels) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_int_32, png_get_x_offset_microns) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+extern PNG_EXPORT(png_int_32, png_get_y_offset_microns) PNGARG((png_structp
+png_ptr, png_infop info_ptr));
+
+#endif /* PNG_EASY_ACCESS_SUPPORTED */
+
+/* Returns pointer to signature string read from PNG header */
+extern PNG_EXPORT(png_bytep,png_get_signature) PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#if defined(PNG_bKGD_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_bKGD) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_16p *background));
+#endif
+
+#if defined(PNG_bKGD_SUPPORTED)
+extern PNG_EXPORT(void,png_set_bKGD) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_16p background));
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double *white_x, double *white_y, double *red_x,
+ double *red_y, double *green_x, double *green_y, double *blue_x,
+ double *blue_y));
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_cHRM_fixed) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point *int_white_x, png_fixed_point
+ *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y,
+ png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point
+ *int_blue_x, png_fixed_point *int_blue_y));
+#endif
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double white_x, double white_y, double red_x,
+ double red_y, double green_x, double green_y, double blue_x, double blue_y));
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_cHRM_fixed) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point int_white_x, png_fixed_point int_white_y,
+ png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point
+ int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x,
+ png_fixed_point int_blue_y));
+#endif
+#endif
+
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_gAMA) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double *file_gamma));
+#endif
+extern PNG_EXPORT(png_uint_32,png_get_gAMA_fixed) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point *int_file_gamma));
+#endif
+
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_gAMA) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, double file_gamma));
+#endif
+extern PNG_EXPORT(void,png_set_gAMA_fixed) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point int_file_gamma));
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_hIST) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_16p *hist));
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+extern PNG_EXPORT(void,png_set_hIST) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_16p hist));
+#endif
+
+extern PNG_EXPORT(png_uint_32,png_get_IHDR) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *width, png_uint_32 *height,
+ int *bit_depth, int *color_type, int *interlace_method,
+ int *compression_method, int *filter_method));
+
+extern PNG_EXPORT(void,png_set_IHDR) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_method, int compression_method,
+ int filter_method));
+
+#if defined(PNG_oFFs_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_oFFs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_int_32 *offset_x, png_int_32 *offset_y,
+ int *unit_type));
+#endif
+
+#if defined(PNG_oFFs_SUPPORTED)
+extern PNG_EXPORT(void,png_set_oFFs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_int_32 offset_x, png_int_32 offset_y,
+ int unit_type));
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_pCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charp *purpose, png_int_32 *X0, png_int_32 *X1,
+ int *type, int *nparams, png_charp *units, png_charpp *params));
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+extern PNG_EXPORT(void,png_set_pCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1,
+ int type, int nparams, png_charp units, png_charpp params));
+#endif
+
+#if defined(PNG_pHYs_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_pHYs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type));
+#endif
+
+#if defined(PNG_pHYs_SUPPORTED)
+extern PNG_EXPORT(void,png_set_pHYs) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type));
+#endif
+
+extern PNG_EXPORT(png_uint_32,png_get_PLTE) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_colorp *palette, int *num_palette));
+
+extern PNG_EXPORT(void,png_set_PLTE) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_colorp palette, int num_palette));
+
+#if defined(PNG_sBIT_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_sBIT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_8p *sig_bit));
+#endif
+
+#if defined(PNG_sBIT_SUPPORTED)
+extern PNG_EXPORT(void,png_set_sBIT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_color_8p sig_bit));
+#endif
+
+#if defined(PNG_sRGB_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_sRGB) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int *intent));
+#endif
+
+#if defined(PNG_sRGB_SUPPORTED)
+extern PNG_EXPORT(void,png_set_sRGB) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int intent));
+extern PNG_EXPORT(void,png_set_sRGB_gAMA_and_cHRM) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int intent));
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_iCCP) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charpp name, int *compression_type,
+ png_charpp profile, png_uint_32 *proflen));
+ /* Note to maintainer: profile should be png_bytepp */
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+extern PNG_EXPORT(void,png_set_iCCP) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_charp name, int compression_type,
+ png_charp profile, png_uint_32 proflen));
+ /* Note to maintainer: profile should be png_bytep */
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_sPLT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_sPLT_tpp entries));
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+extern PNG_EXPORT(void,png_set_sPLT) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_sPLT_tp entries, int nentries));
+#endif
+
+#if defined(PNG_TEXT_SUPPORTED)
+/* png_get_text also returns the number of text chunks in *num_text */
+extern PNG_EXPORT(png_uint_32,png_get_text) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_textp *text_ptr, int *num_text));
+#endif
+
+/*
+ * Note while png_set_text() will accept a structure whose text,
+ * language, and translated keywords are NULL pointers, the structure
+ * returned by png_get_text will always contain regular
+ * zero-terminated C strings. They might be empty strings but
+ * they will never be NULL pointers.
+ */
+
+#if defined(PNG_TEXT_SUPPORTED)
+extern PNG_EXPORT(void,png_set_text) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_textp text_ptr, int num_text));
+#endif
+
+#if defined(PNG_tIME_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_tIME) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_timep *mod_time));
+#endif
+
+#if defined(PNG_tIME_SUPPORTED)
+extern PNG_EXPORT(void,png_set_tIME) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_timep mod_time));
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+extern PNG_EXPORT(png_uint_32,png_get_tRNS) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep *trans, int *num_trans,
+ png_color_16p *trans_values));
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+extern PNG_EXPORT(void,png_set_tRNS) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_bytep trans, int num_trans,
+ png_color_16p trans_values));
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+#endif
+
+#if defined(PNG_sCAL_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_sCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int *unit, double *width, double *height));
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_get_sCAL_s) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int *unit, png_charpp swidth, png_charpp sheight));
+#endif
+#endif
+#endif /* PNG_sCAL_SUPPORTED */
+
+#if defined(PNG_sCAL_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_sCAL) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int unit, double width, double height));
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+extern PNG_EXPORT(void,png_set_sCAL_s) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int unit, png_charp swidth, png_charp sheight));
+#endif
+#endif
+#endif /* PNG_sCAL_SUPPORTED || PNG_WRITE_sCAL_SUPPORTED */
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+/* provide a list of chunks and how they are to be handled, if the built-in
+ handling or default unknown chunk handling is not desired. Any chunks not
+ listed will be handled in the default manner. The IHDR and IEND chunks
+ must not be listed.
+ keep = 0: follow default behaviour
+ = 1: do not keep
+ = 2: keep only if safe-to-copy
+ = 3: keep even if unsafe-to-copy
+*/
+extern PNG_EXPORT(void, png_set_keep_unknown_chunks) PNGARG((png_structp
+ png_ptr, int keep, png_bytep chunk_list, int num_chunks));
+extern PNG_EXPORT(void, png_set_unknown_chunks) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns));
+extern PNG_EXPORT(void, png_set_unknown_chunk_location)
+ PNGARG((png_structp png_ptr, png_infop info_ptr, int chunk, int location));
+extern PNG_EXPORT(png_uint_32,png_get_unknown_chunks) PNGARG((png_structp
+ png_ptr, png_infop info_ptr, png_unknown_chunkpp entries));
+#endif
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+PNG_EXPORT(int,png_handle_as_unknown) PNGARG((png_structp png_ptr, png_bytep
+ chunk_name));
+#endif
+
+/* Png_free_data() will turn off the "valid" flag for anything it frees.
+ If you need to turn it off for a chunk that your application has freed,
+ you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */
+extern PNG_EXPORT(void, png_set_invalid) PNGARG((png_structp png_ptr,
+ png_infop info_ptr, int mask));
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+/* The "params" pointer is currently not used and is for future expansion. */
+extern PNG_EXPORT(void, png_read_png) PNGARG((png_structp png_ptr,
+ png_infop info_ptr,
+ int transforms,
+ png_voidp params));
+extern PNG_EXPORT(void, png_write_png) PNGARG((png_structp png_ptr,
+ png_infop info_ptr,
+ int transforms,
+ png_voidp params));
+#endif
+
+/* Define PNG_DEBUG at compile time for debugging information. Higher
+ * numbers for PNG_DEBUG mean more debugging information. This has
+ * only been added since version 0.95 so it is not implemented throughout
+ * libpng yet, but more support will be added as needed.
+ */
+#ifdef PNG_DEBUG
+#if (PNG_DEBUG > 0)
+#if !defined(PNG_DEBUG_FILE) && defined(_MSC_VER)
+#include <crtdbg.h>
+#if (PNG_DEBUG > 1)
+#define png_debug(l,m) _RPT0(_CRT_WARN,m)
+#define png_debug1(l,m,p1) _RPT1(_CRT_WARN,m,p1)
+#define png_debug2(l,m,p1,p2) _RPT2(_CRT_WARN,m,p1,p2)
+#endif
+#else /* PNG_DEBUG_FILE || !_MSC_VER */
+#ifndef PNG_DEBUG_FILE
+#define PNG_DEBUG_FILE stderr
+#endif /* PNG_DEBUG_FILE */
+#if (PNG_DEBUG > 1)
+#define png_debug(l,m) \
+{ \
+ int num_tabs=l; \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \
+ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \
+}
+#define png_debug1(l,m,p1) \
+{ \
+ int num_tabs=l; \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \
+ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \
+}
+#define png_debug2(l,m,p1,p2) \
+{ \
+ int num_tabs=l; \
+ fprintf(PNG_DEBUG_FILE,"%s"m,(num_tabs==1 ? "\t" : \
+ (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \
+}
+#endif /* (PNG_DEBUG > 1) */
+#endif /* _MSC_VER */
+#endif /* (PNG_DEBUG > 0) */
+#endif /* PNG_DEBUG */
+#ifndef png_debug
+#define png_debug(l, m)
+#endif
+#ifndef png_debug1
+#define png_debug1(l, m, p1)
+#endif
+#ifndef png_debug2
+#define png_debug2(l, m, p1, p2)
+#endif
+
+extern PNG_EXPORT(png_charp,png_get_copyright) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(png_charp,png_get_header_ver) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(png_charp,png_get_header_version) PNGARG((png_structp png_ptr));
+extern PNG_EXPORT(png_charp,png_get_libpng_ver) PNGARG((png_structp png_ptr));
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+extern PNG_EXPORT(png_uint_32,png_permit_mng_features) PNGARG((png_structp
+ png_ptr, png_uint_32 mng_features_permitted));
+#endif
+
+/* For use in png_set_keep_unknown, added to version 1.2.6 */
+#define PNG_HANDLE_CHUNK_AS_DEFAULT 0
+#define PNG_HANDLE_CHUNK_NEVER 1
+#define PNG_HANDLE_CHUNK_IF_SAFE 2
+#define PNG_HANDLE_CHUNK_ALWAYS 3
+
+/* Added to version 1.2.0 */
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+#if defined(PNG_MMX_CODE_SUPPORTED)
+#define PNG_ASM_FLAG_MMX_SUPPORT_COMPILED 0x01 /* not user-settable */
+#define PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU 0x02 /* not user-settable */
+#define PNG_ASM_FLAG_MMX_READ_COMBINE_ROW 0x04
+#define PNG_ASM_FLAG_MMX_READ_INTERLACE 0x08
+#define PNG_ASM_FLAG_MMX_READ_FILTER_SUB 0x10
+#define PNG_ASM_FLAG_MMX_READ_FILTER_UP 0x20
+#define PNG_ASM_FLAG_MMX_READ_FILTER_AVG 0x40
+#define PNG_ASM_FLAG_MMX_READ_FILTER_PAETH 0x80
+#define PNG_ASM_FLAGS_INITIALIZED 0x80000000 /* not user-settable */
+
+#define PNG_MMX_READ_FLAGS ( PNG_ASM_FLAG_MMX_READ_COMBINE_ROW \
+ | PNG_ASM_FLAG_MMX_READ_INTERLACE \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_SUB \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_UP \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_AVG \
+ | PNG_ASM_FLAG_MMX_READ_FILTER_PAETH )
+#define PNG_MMX_WRITE_FLAGS ( 0 )
+
+#define PNG_MMX_FLAGS ( PNG_ASM_FLAG_MMX_SUPPORT_COMPILED \
+ | PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU \
+ | PNG_MMX_READ_FLAGS \
+ | PNG_MMX_WRITE_FLAGS )
+
+#define PNG_SELECT_READ 1
+#define PNG_SELECT_WRITE 2
+#endif /* PNG_MMX_CODE_SUPPORTED */
+
+#if !defined(PNG_1_0_X)
+/* pngget.c */
+extern PNG_EXPORT(png_uint_32,png_get_mmx_flagmask)
+ PNGARG((int flag_select, int *compilerID));
+
+/* pngget.c */
+extern PNG_EXPORT(png_uint_32,png_get_asm_flagmask)
+ PNGARG((int flag_select));
+
+/* pngget.c */
+extern PNG_EXPORT(png_uint_32,png_get_asm_flags)
+ PNGARG((png_structp png_ptr));
+
+/* pngget.c */
+extern PNG_EXPORT(png_byte,png_get_mmx_bitdepth_threshold)
+ PNGARG((png_structp png_ptr));
+
+/* pngget.c */
+extern PNG_EXPORT(png_uint_32,png_get_mmx_rowbytes_threshold)
+ PNGARG((png_structp png_ptr));
+
+/* pngset.c */
+extern PNG_EXPORT(void,png_set_asm_flags)
+ PNGARG((png_structp png_ptr, png_uint_32 asm_flags));
+
+/* pngset.c */
+extern PNG_EXPORT(void,png_set_mmx_thresholds)
+ PNGARG((png_structp png_ptr, png_byte mmx_bitdepth_threshold,
+ png_uint_32 mmx_rowbytes_threshold));
+
+#endif /* PNG_1_0_X */
+
+#if !defined(PNG_1_0_X)
+/* png.c, pnggccrd.c, or pngvcrd.c */
+extern PNG_EXPORT(int,png_mmx_support) PNGARG((void));
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED */
+
+/* Strip the prepended error numbers ("#nnn ") from error and warning
+ * messages before passing them to the error or warning handler. */
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+extern PNG_EXPORT(void,png_set_strip_error_numbers) PNGARG((png_structp
+ png_ptr, png_uint_32 strip_mode));
+#endif
+
+#endif /* PNG_1_0_X */
+
+/* Added at libpng-1.2.6 */
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+extern PNG_EXPORT(void,png_set_user_limits) PNGARG((png_structp
+ png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max));
+extern PNG_EXPORT(png_uint_32,png_get_user_width_max) PNGARG((png_structp
+ png_ptr));
+extern PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp
+ png_ptr));
+#endif
+
+/* Maintainer: Put new public prototypes here ^, in libpng.3, and project defs */
+
+#ifdef PNG_READ_COMPOSITE_NODIV_SUPPORTED
+/* With these routines we avoid an integer divide, which will be slower on
+ * most machines. However, it does take more operations than the corresponding
+ * divide method, so it may be slower on a few RISC systems. There are two
+ * shifts (by 8 or 16 bits) and an addition, versus a single integer divide.
+ *
+ * Note that the rounding factors are NOT supposed to be the same! 128 and
+ * 32768 are correct for the NODIV code; 127 and 32767 are correct for the
+ * standard method.
+ *
+ * [Optimized code by Greg Roelofs and Mark Adler...blame us for bugs. :-) ]
+ */
+
+ /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */
+
+# define png_composite(composite, fg, alpha, bg) \
+ { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) * (png_uint_16)(alpha) \
+ + (png_uint_16)(bg)*(png_uint_16)(255 - \
+ (png_uint_16)(alpha)) + (png_uint_16)128); \
+ (composite) = (png_byte)((temp + (temp >> 8)) >> 8); }
+
+# define png_composite_16(composite, fg, alpha, bg) \
+ { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) * (png_uint_32)(alpha) \
+ + (png_uint_32)(bg)*(png_uint_32)(65535L - \
+ (png_uint_32)(alpha)) + (png_uint_32)32768L); \
+ (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); }
+
+#else /* standard method using integer division */
+
+# define png_composite(composite, fg, alpha, bg) \
+ (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \
+ (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \
+ (png_uint_16)127) / 255)
+
+# define png_composite_16(composite, fg, alpha, bg) \
+ (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \
+ (png_uint_32)(bg)*(png_uint_32)(65535L - (png_uint_32)(alpha)) + \
+ (png_uint_32)32767) / (png_uint_32)65535L)
+
+#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */
+
+/* Inline macros to do direct reads of bytes from the input buffer. These
+ * require that you are using an architecture that uses PNG byte ordering
+ * (MSB first) and supports unaligned data storage. I think that PowerPC
+ * in big-endian mode and 680x0 are the only ones that will support this.
+ * The x86 line of processors definitely do not. The png_get_int_32()
+ * routine also assumes we are using two's complement format for negative
+ * values, which is almost certainly true.
+ */
+#if defined(PNG_READ_BIG_ENDIAN_SUPPORTED)
+# define png_get_uint_32(buf) ( *((png_uint_32p) (buf)))
+# define png_get_uint_16(buf) ( *((png_uint_16p) (buf)))
+# define png_get_int_32(buf) ( *((png_int_32p) (buf)))
+#else
+extern PNG_EXPORT(png_uint_32,png_get_uint_32) PNGARG((png_bytep buf));
+extern PNG_EXPORT(png_uint_16,png_get_uint_16) PNGARG((png_bytep buf));
+extern PNG_EXPORT(png_int_32,png_get_int_32) PNGARG((png_bytep buf));
+#endif /* !PNG_READ_BIG_ENDIAN_SUPPORTED */
+extern PNG_EXPORT(png_uint_32,png_get_uint_31)
+ PNGARG((png_structp png_ptr, png_bytep buf));
+/* No png_get_int_16 -- may be added if there's a real need for it. */
+
+/* Place a 32-bit number into a buffer in PNG byte order (big-endian).
+ */
+extern PNG_EXPORT(void,png_save_uint_32)
+ PNGARG((png_bytep buf, png_uint_32 i));
+extern PNG_EXPORT(void,png_save_int_32)
+ PNGARG((png_bytep buf, png_int_32 i));
+
+/* Place a 16-bit number into a buffer in PNG byte order.
+ * The parameter is declared unsigned int, not png_uint_16,
+ * just to avoid potential problems on pre-ANSI C compilers.
+ */
+extern PNG_EXPORT(void,png_save_uint_16)
+ PNGARG((png_bytep buf, unsigned int i));
+/* No png_save_int_16 -- may be added if there's a real need for it. */
+
+/* ************************************************************************* */
+
+/* These next functions are used internally in the code. They generally
+ * shouldn't be used unless you are writing code to add or replace some
+ * functionality in libpng. More information about most functions can
+ * be found in the files where the functions are located.
+ */
+
+
+/* Various modes of operation, that are visible to applications because
+ * they are used for unknown chunk location.
+ */
+#define PNG_HAVE_IHDR 0x01
+#define PNG_HAVE_PLTE 0x02
+#define PNG_HAVE_IDAT 0x04
+#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */
+#define PNG_HAVE_IEND 0x10
+
+#if defined(PNG_INTERNAL)
+
+/* More modes of operation. Note that after an init, mode is set to
+ * zero automatically when the structure is created.
+ */
+#define PNG_HAVE_gAMA 0x20
+#define PNG_HAVE_cHRM 0x40
+#define PNG_HAVE_sRGB 0x80
+#define PNG_HAVE_CHUNK_HEADER 0x100
+#define PNG_WROTE_tIME 0x200
+#define PNG_WROTE_INFO_BEFORE_PLTE 0x400
+#define PNG_BACKGROUND_IS_GRAY 0x800
+#define PNG_HAVE_PNG_SIGNATURE 0x1000
+#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
+
+/* flags for the transformations the PNG library does on the image data */
+#define PNG_BGR 0x0001
+#define PNG_INTERLACE 0x0002
+#define PNG_PACK 0x0004
+#define PNG_SHIFT 0x0008
+#define PNG_SWAP_BYTES 0x0010
+#define PNG_INVERT_MONO 0x0020
+#define PNG_DITHER 0x0040
+#define PNG_BACKGROUND 0x0080
+#define PNG_BACKGROUND_EXPAND 0x0100
+ /* 0x0200 unused */
+#define PNG_16_TO_8 0x0400
+#define PNG_RGBA 0x0800
+#define PNG_EXPAND 0x1000
+#define PNG_GAMMA 0x2000
+#define PNG_GRAY_TO_RGB 0x4000
+#define PNG_FILLER 0x8000L
+#define PNG_PACKSWAP 0x10000L
+#define PNG_SWAP_ALPHA 0x20000L
+#define PNG_STRIP_ALPHA 0x40000L
+#define PNG_INVERT_ALPHA 0x80000L
+#define PNG_USER_TRANSFORM 0x100000L
+#define PNG_RGB_TO_GRAY_ERR 0x200000L
+#define PNG_RGB_TO_GRAY_WARN 0x400000L
+#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */
+ /* 0x800000L Unused */
+#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */
+#define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */
+ /* 0x4000000L unused */
+ /* 0x8000000L unused */
+ /* 0x10000000L unused */
+ /* 0x20000000L unused */
+ /* 0x40000000L unused */
+
+/* flags for png_create_struct */
+#define PNG_STRUCT_PNG 0x0001
+#define PNG_STRUCT_INFO 0x0002
+
+/* Scaling factor for filter heuristic weighting calculations */
+#define PNG_WEIGHT_SHIFT 8
+#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT))
+#define PNG_COST_SHIFT 3
+#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT))
+
+/* flags for the png_ptr->flags rather than declaring a byte for each one */
+#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001
+#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002
+#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004
+#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008
+#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010
+#define PNG_FLAG_ZLIB_FINISHED 0x0020
+#define PNG_FLAG_ROW_INIT 0x0040
+#define PNG_FLAG_FILLER_AFTER 0x0080
+#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100
+#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200
+#define PNG_FLAG_CRC_CRITICAL_USE 0x0400
+#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800
+#define PNG_FLAG_FREE_PLTE 0x1000
+#define PNG_FLAG_FREE_TRNS 0x2000
+#define PNG_FLAG_FREE_HIST 0x4000
+#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L
+#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L
+#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L
+#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L
+#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L
+#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L
+#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */
+#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */
+ /* 0x800000L unused */
+ /* 0x1000000L unused */
+ /* 0x2000000L unused */
+ /* 0x4000000L unused */
+ /* 0x8000000L unused */
+ /* 0x10000000L unused */
+ /* 0x20000000L unused */
+ /* 0x40000000L unused */
+
+#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
+ PNG_FLAG_CRC_ANCILLARY_NOWARN)
+
+#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \
+ PNG_FLAG_CRC_CRITICAL_IGNORE)
+
+#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \
+ PNG_FLAG_CRC_CRITICAL_MASK)
+
+/* save typing and make code easier to understand */
+
+#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \
+ abs((int)((c1).green) - (int)((c2).green)) + \
+ abs((int)((c1).blue) - (int)((c2).blue)))
+
+/* Added to libpng-1.2.6 JB */
+#define PNG_ROWBYTES(pixel_bits, width) \
+ ((pixel_bits) >= 8 ? \
+ ((width) * (((png_uint_32)(pixel_bits)) >> 3)) : \
+ (( ((width) * ((png_uint_32)(pixel_bits))) + 7) >> 3) )
+
+/* PNG_OUT_OF_RANGE returns true if value is outside the range
+ ideal-delta..ideal+delta. Each argument is evaluated twice.
+ "ideal" and "delta" should be constants, normally simple
+ integers, "value" a variable. Added to libpng-1.2.6 JB */
+#define PNG_OUT_OF_RANGE(value, ideal, delta) \
+ ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) )
+
+/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */
+#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN)
+/* place to hold the signature string for a PNG file. */
+#ifdef PNG_USE_GLOBAL_ARRAYS
+ PNG_EXPORT_VAR (PNG_CONST png_byte FARDATA) png_sig[8];
+#else
+#endif
+#endif /* PNG_NO_EXTERN */
+
+/* Constant strings for known chunk types. If you need to add a chunk,
+ * define the name here, and add an invocation of the macro in png.c and
+ * wherever it's needed.
+ */
+#define PNG_IHDR png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'}
+#define PNG_IDAT png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'}
+#define PNG_IEND png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'}
+#define PNG_PLTE png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'}
+#define PNG_bKGD png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'}
+#define PNG_cHRM png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'}
+#define PNG_gAMA png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'}
+#define PNG_hIST png_byte png_hIST[5] = {104, 73, 83, 84, '\0'}
+#define PNG_iCCP png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'}
+#define PNG_iTXt png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'}
+#define PNG_oFFs png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'}
+#define PNG_pCAL png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'}
+#define PNG_sCAL png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'}
+#define PNG_pHYs png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'}
+#define PNG_sBIT png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'}
+#define PNG_sPLT png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'}
+#define PNG_sRGB png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'}
+#define PNG_tEXt png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'}
+#define PNG_tIME png_byte png_tIME[5] = {116, 73, 77, 69, '\0'}
+#define PNG_tRNS png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'}
+#define PNG_zTXt png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'}
+
+#ifdef PNG_USE_GLOBAL_ARRAYS
+PNG_EXPORT_VAR (png_byte FARDATA) png_IHDR[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_IDAT[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_IEND[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_PLTE[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_bKGD[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_cHRM[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_gAMA[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_hIST[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_iCCP[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_iTXt[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_oFFs[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_pCAL[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_sCAL[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_pHYs[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_sBIT[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_sPLT[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_sRGB[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_tEXt[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_tIME[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_tRNS[5];
+PNG_EXPORT_VAR (png_byte FARDATA) png_zTXt[5];
+#endif /* PNG_USE_GLOBAL_ARRAYS */
+
+#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
+/* Initialize png_ptr struct for reading, and allocate any other memory.
+ * (old interface - DEPRECATED - use png_create_read_struct instead).
+ */
+extern PNG_EXPORT(void,png_read_init) PNGARG((png_structp png_ptr));
+#undef png_read_init
+#define png_read_init(png_ptr) png_read_init_3(&png_ptr, \
+ PNG_LIBPNG_VER_STRING, png_sizeof(png_struct));
+#endif
+
+extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr,
+ png_const_charp user_png_ver, png_size_t png_struct_size));
+#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
+extern PNG_EXPORT(void,png_read_init_2) PNGARG((png_structp png_ptr,
+ png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t
+ png_info_size));
+#endif
+
+#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
+/* Initialize png_ptr struct for writing, and allocate any other memory.
+ * (old interface - DEPRECATED - use png_create_write_struct instead).
+ */
+extern PNG_EXPORT(void,png_write_init) PNGARG((png_structp png_ptr));
+#undef png_write_init
+#define png_write_init(png_ptr) png_write_init_3(&png_ptr, \
+ PNG_LIBPNG_VER_STRING, png_sizeof(png_struct));
+#endif
+
+extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr,
+ png_const_charp user_png_ver, png_size_t png_struct_size));
+extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr,
+ png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t
+ png_info_size));
+
+/* Allocate memory for an internal libpng struct */
+PNG_EXTERN png_voidp png_create_struct PNGARG((int type));
+
+/* Free memory from internal libpng struct */
+PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr));
+
+PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr
+ malloc_fn, png_voidp mem_ptr));
+PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr,
+ png_free_ptr free_fn, png_voidp mem_ptr));
+
+/* Free any memory that info_ptr points to and reset struct. */
+PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+#ifndef PNG_1_0_X
+/* Function to allocate memory for zlib. */
+PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size));
+
+/* Function to free memory for zlib */
+PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr));
+
+#ifdef PNG_SIZE_T
+/* Function to convert a sizeof an item to png_sizeof item */
+ PNG_EXTERN png_size_t PNGAPI png_convert_size PNGARG((size_t size));
+#endif
+
+/* Next four functions are used internally as callbacks. PNGAPI is required
+ * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. */
+
+PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr,
+ png_bytep data, png_size_t length));
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t length));
+#endif
+
+PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr,
+ png_bytep data, png_size_t length));
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+#if !defined(PNG_NO_STDIO)
+PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr));
+#endif
+#endif
+#else /* PNG_1_0_X */
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+PNG_EXTERN void png_push_fill_buffer PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t length));
+#endif
+#endif /* PNG_1_0_X */
+
+/* Reset the CRC variable */
+PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr));
+
+/* Write the "data" buffer to whatever output you are using. */
+PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+/* Read data from whatever input you are using into the "data" buffer */
+PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+/* Read bytes into buf, and update png_ptr->crc */
+PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf,
+ png_size_t length));
+
+/* Decompress data in a chunk that uses compression */
+#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \
+ defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
+PNG_EXTERN png_charp png_decompress_chunk PNGARG((png_structp png_ptr,
+ int comp_type, png_charp chunkdata, png_size_t chunklength,
+ png_size_t prefix_length, png_size_t *data_length));
+#endif
+
+/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */
+PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip));
+
+/* Read the CRC from the file and compare it to the libpng calculated CRC */
+PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr));
+
+/* Calculate the CRC over a section of data. Note that we are only
+ * passing a maximum of 64K on systems that have this as a memory limit,
+ * since this is the maximum buffer size we can specify.
+ */
+PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr,
+ png_size_t length));
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+PNG_EXTERN void png_flush PNGARG((png_structp png_ptr));
+#endif
+
+/* simple function to write the signature */
+PNG_EXTERN void png_write_sig PNGARG((png_structp png_ptr));
+
+/* write various chunks */
+
+/* Write the IHDR chunk, and update the png_struct with the necessary
+ * information.
+ */
+PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width,
+ png_uint_32 height,
+ int bit_depth, int color_type, int compression_method, int filter_method,
+ int interlace_method));
+
+PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette,
+ png_uint_32 num_pal));
+
+PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data,
+ png_size_t length));
+
+PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr));
+
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma));
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point
+ file_gamma));
+#endif
+#endif
+
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit,
+ int color_type));
+#endif
+
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr,
+ double white_x, double white_y,
+ double red_x, double red_y, double green_x, double green_y,
+ double blue_x, double blue_y));
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr,
+ png_fixed_point int_white_x, png_fixed_point int_white_y,
+ png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point
+ int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x,
+ png_fixed_point int_blue_y));
+#endif
+#endif
+
+#if defined(PNG_WRITE_sRGB_SUPPORTED)
+PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr,
+ int intent));
+#endif
+
+#if defined(PNG_WRITE_iCCP_SUPPORTED)
+PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr,
+ png_charp name, int compression_type,
+ png_charp profile, int proflen));
+ /* Note to maintainer: profile should be png_bytep */
+#endif
+
+#if defined(PNG_WRITE_sPLT_SUPPORTED)
+PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr,
+ png_sPLT_tp palette));
+#endif
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans,
+ png_color_16p values, int number, int color_type));
+#endif
+
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr,
+ png_color_16p values, int color_type));
+#endif
+
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist,
+ int num_hist));
+#endif
+
+#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
+ defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
+PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr,
+ png_charp key, png_charpp new_key));
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key,
+ png_charp text, png_size_t text_len));
+#endif
+
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key,
+ png_charp text, png_size_t text_len, int compression));
+#endif
+
+#if defined(PNG_WRITE_iTXt_SUPPORTED)
+PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr,
+ int compression, png_charp key, png_charp lang, png_charp lang_key,
+ png_charp text));
+#endif
+
+#if defined(PNG_TEXT_SUPPORTED) /* Added at version 1.0.14 and 1.2.4 */
+PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_textp text_ptr, int num_text));
+#endif
+
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr,
+ png_int_32 x_offset, png_int_32 y_offset, int unit_type));
+#endif
+
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose,
+ png_int_32 X0, png_int_32 X1, int type, int nparams,
+ png_charp units, png_charpp params));
+#endif
+
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr,
+ png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit,
+ int unit_type));
+#endif
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr,
+ png_timep mod_time));
+#endif
+
+#if defined(PNG_WRITE_sCAL_SUPPORTED)
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
+PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr,
+ int unit, double width, double height));
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr,
+ int unit, png_charp width, png_charp height));
+#endif
+#endif
+#endif
+
+/* Called when finished processing a row of data */
+PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr));
+
+/* Internal use only. Called before first row of data */
+PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr));
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr));
+#endif
+
+/* combine a row of data, dealing with alpha, etc. if requested */
+PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row,
+ int mask));
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+/* expand an interlaced row */
+/* OLD pre-1.0.9 interface:
+PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info,
+ png_bytep row, int pass, png_uint_32 transformations));
+ */
+PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr));
+#endif
+
+/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* grab pixels out of a row for an interlaced pass */
+PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info,
+ png_bytep row, int pass));
+#endif
+
+/* unfilter a row */
+PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr,
+ png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter));
+
+/* Choose the best filter to use and filter the row data */
+PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr,
+ png_row_infop row_info));
+
+/* Write out the filtered row. */
+PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr,
+ png_bytep filtered_row));
+/* finish a row while reading, dealing with interlacing passes, etc. */
+PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr));
+
+/* initialize the row buffers, etc. */
+PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr));
+/* optional call to update the users info structure */
+PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+
+/* these are the functions that do the transformations */
+#if defined(PNG_READ_FILLER_SUPPORTED)
+PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 filler, png_uint_32 flags));
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+ defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 flags));
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop
+ row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_8p sig_bits));
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info,
+ png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup));
+
+# if defined(PNG_CORRECT_PALETTE_SUPPORTED)
+PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr,
+ png_colorp palette, int num_palette));
+# endif
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row));
+#endif
+
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info,
+ png_bytep row, png_uint_32 bit_depth));
+#endif
+
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_8p bit_depth));
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_16p trans_values, png_color_16p background,
+ png_color_16p background_1,
+ png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
+ png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
+ png_uint_16pp gamma_16_to_1, int gamma_shift));
+#else
+PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row,
+ png_color_16p trans_values, png_color_16p background));
+#endif
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row,
+ png_bytep gamma_table, png_uint_16pp gamma_16_table,
+ int gamma_shift));
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info,
+ png_bytep row, png_colorp palette, png_bytep trans, int num_trans));
+PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info,
+ png_bytep row, png_color_16p trans_value));
+#endif
+
+/* The following decodes the appropriate chunks, and does error correction,
+ * then calls the appropriate callback for the chunk if it is valid.
+ */
+
+/* decode the IHDR chunk */
+PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_iCCP_SUPPORTED)
+extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif /* PNG_READ_iCCP_SUPPORTED */
+
+#if defined(PNG_READ_iTXt_SUPPORTED)
+PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_sCAL_SUPPORTED)
+PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_sPLT_SUPPORTED)
+extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif /* PNG_READ_sPLT_SUPPORTED */
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 length));
+#endif
+
+PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+
+PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr,
+ png_bytep chunk_name));
+
+/* handle the transformations for reading and writing */
+PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr));
+
+PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr));
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr,
+ png_uint_32 length));
+PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t buffer_length));
+PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr,
+ png_bytep buffer, png_size_t buffer_length));
+PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr));
+PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row));
+PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr));
+#if defined(PNG_READ_tEXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_uint_32 length));
+PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr,
+ png_infop info_ptr));
+#endif
+
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info,
+ png_bytep row));
+PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info,
+ png_bytep row));
+#endif
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED)
+#if defined(PNG_MMX_CODE_SUPPORTED)
+/* png.c */ /* PRIVATE */
+PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr));
+#endif
+#endif
+
+#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED)
+PNG_EXTERN png_uint_32 png_get_pixels_per_inch PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+PNG_EXTERN png_uint_32 png_get_x_pixels_per_inch PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+PNG_EXTERN png_uint_32 png_get_y_pixels_per_inch PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+PNG_EXTERN float png_get_x_offset_inches PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+PNG_EXTERN float png_get_y_offset_inches PNGARG((png_structp png_ptr,
+png_infop info_ptr));
+
+#if defined(PNG_pHYs_SUPPORTED)
+PNG_EXTERN png_uint_32 png_get_pHYs_dpi PNGARG((png_structp png_ptr,
+png_infop info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type));
+#endif /* PNG_pHYs_SUPPORTED */
+#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */
+
+/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */
+
+#endif /* PNG_INTERNAL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PNG_VERSION_INFO_ONLY */
+/* do not put anything past this line */
+#endif /* PNG_H */
diff --git a/distrib/libpng-1.2.19/pngconf.h b/distrib/libpng-1.2.19/pngconf.h
new file mode 100644
index 0000000..43dfe04
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngconf.h
@@ -0,0 +1,1535 @@
+
+/* pngconf.h - machine configurable file for libpng
+ *
+ * libpng version 1.2.19 - August 18, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+/* Any machine specific code is near the front of this file, so if you
+ * are configuring libpng for a machine, you may want to read the section
+ * starting here down to where it starts to typedef png_color, png_text,
+ * and png_info.
+ */
+
+#ifndef PNGCONF_H
+#define PNGCONF_H
+
+#define PNG_1_2_X
+
+/*
+ * PNG_USER_CONFIG has to be defined on the compiler command line. This
+ * includes the resource compiler for Windows DLL configurations.
+ */
+#ifdef PNG_USER_CONFIG
+# ifndef PNG_USER_PRIVATEBUILD
+# define PNG_USER_PRIVATEBUILD
+# endif
+#include "pngusr.h"
+#endif
+
+/* PNG_CONFIGURE_LIBPNG is set by the "configure" script. */
+#ifdef PNG_CONFIGURE_LIBPNG
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#endif
+
+/*
+ * Added at libpng-1.2.8
+ *
+ * If you create a private DLL you need to define in "pngusr.h" the followings:
+ * #define PNG_USER_PRIVATEBUILD <Describes by whom and why this version of
+ * the DLL was built>
+ * e.g. #define PNG_USER_PRIVATEBUILD "Build by MyCompany for xyz reasons."
+ * #define PNG_USER_DLLFNAME_POSTFIX <two-letter postfix that serve to
+ * distinguish your DLL from those of the official release. These
+ * correspond to the trailing letters that come after the version
+ * number and must match your private DLL name>
+ * e.g. // private DLL "libpng13gx.dll"
+ * #define PNG_USER_DLLFNAME_POSTFIX "gx"
+ *
+ * The following macros are also at your disposal if you want to complete the
+ * DLL VERSIONINFO structure.
+ * - PNG_USER_VERSIONINFO_COMMENTS
+ * - PNG_USER_VERSIONINFO_COMPANYNAME
+ * - PNG_USER_VERSIONINFO_LEGALTRADEMARKS
+ */
+
+#ifdef __STDC__
+#ifdef SPECIALBUILD
+# pragma message("PNG_LIBPNG_SPECIALBUILD (and deprecated SPECIALBUILD)\
+ are now LIBPNG reserved macros. Use PNG_USER_PRIVATEBUILD instead.")
+#endif
+
+#ifdef PRIVATEBUILD
+# pragma message("PRIVATEBUILD is deprecated.\
+ Use PNG_USER_PRIVATEBUILD instead.")
+# define PNG_USER_PRIVATEBUILD PRIVATEBUILD
+#endif
+#endif /* __STDC__ */
+
+#ifndef PNG_VERSION_INFO_ONLY
+
+/* End of material added to libpng-1.2.8 */
+
+/* Added at libpng-1.2.19 */
+#ifndef PNG_NO_WARN_UNINITIALIZED_ROW
+# ifndef PNG_WARN_UNINITIALIZED_ROW
+# define PNG_WARN_UNINITIALIZED_ROW 1 /* 0: warning; 1: error */
+# endif
+#endif
+/* End of material added at libpng-1.2.19 */
+
+/* This is the size of the compression buffer, and thus the size of
+ * an IDAT chunk. Make this whatever size you feel is best for your
+ * machine. One of these will be allocated per png_struct. When this
+ * is full, it writes the data to the disk, and does some other
+ * calculations. Making this an extremely small size will slow
+ * the library down, but you may want to experiment to determine
+ * where it becomes significant, if you are concerned with memory
+ * usage. Note that zlib allocates at least 32Kb also. For readers,
+ * this describes the size of the buffer available to read the data in.
+ * Unless this gets smaller than the size of a row (compressed),
+ * it should not make much difference how big this is.
+ */
+
+#ifndef PNG_ZBUF_SIZE
+# define PNG_ZBUF_SIZE 8192
+#endif
+
+/* Enable if you want a write-only libpng */
+
+#ifndef PNG_NO_READ_SUPPORTED
+# define PNG_READ_SUPPORTED
+#endif
+
+/* Enable if you want a read-only libpng */
+
+#ifndef PNG_NO_WRITE_SUPPORTED
+# define PNG_WRITE_SUPPORTED
+#endif
+
+/* Enabled by default in 1.2.0. You can disable this if you don't need to
+ support PNGs that are embedded in MNG datastreams */
+#if !defined(PNG_1_0_X) && !defined(PNG_NO_MNG_FEATURES)
+# ifndef PNG_MNG_FEATURES_SUPPORTED
+# define PNG_MNG_FEATURES_SUPPORTED
+# endif
+#endif
+
+#ifndef PNG_NO_FLOATING_POINT_SUPPORTED
+# ifndef PNG_FLOATING_POINT_SUPPORTED
+# define PNG_FLOATING_POINT_SUPPORTED
+# endif
+#endif
+
+/* If you are running on a machine where you cannot allocate more
+ * than 64K of memory at once, uncomment this. While libpng will not
+ * normally need that much memory in a chunk (unless you load up a very
+ * large file), zlib needs to know how big of a chunk it can use, and
+ * libpng thus makes sure to check any memory allocation to verify it
+ * will fit into memory.
+#define PNG_MAX_MALLOC_64K
+ */
+#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K)
+# define PNG_MAX_MALLOC_64K
+#endif
+
+/* Special munging to support doing things the 'cygwin' way:
+ * 'Normal' png-on-win32 defines/defaults:
+ * PNG_BUILD_DLL -- building dll
+ * PNG_USE_DLL -- building an application, linking to dll
+ * (no define) -- building static library, or building an
+ * application and linking to the static lib
+ * 'Cygwin' defines/defaults:
+ * PNG_BUILD_DLL -- (ignored) building the dll
+ * (no define) -- (ignored) building an application, linking to the dll
+ * PNG_STATIC -- (ignored) building the static lib, or building an
+ * application that links to the static lib.
+ * ALL_STATIC -- (ignored) building various static libs, or building an
+ * application that links to the static libs.
+ * Thus,
+ * a cygwin user should define either PNG_BUILD_DLL or PNG_STATIC, and
+ * this bit of #ifdefs will define the 'correct' config variables based on
+ * that. If a cygwin user *wants* to define 'PNG_USE_DLL' that's okay, but
+ * unnecessary.
+ *
+ * Also, the precedence order is:
+ * ALL_STATIC (since we can't #undef something outside our namespace)
+ * PNG_BUILD_DLL
+ * PNG_STATIC
+ * (nothing) == PNG_USE_DLL
+ *
+ * CYGWIN (2002-01-20): The preceding is now obsolete. With the advent
+ * of auto-import in binutils, we no longer need to worry about
+ * __declspec(dllexport) / __declspec(dllimport) and friends. Therefore,
+ * we don't need to worry about PNG_STATIC or ALL_STATIC when it comes
+ * to __declspec() stuff. However, we DO need to worry about
+ * PNG_BUILD_DLL and PNG_STATIC because those change some defaults
+ * such as CONSOLE_IO and whether GLOBAL_ARRAYS are allowed.
+ */
+#if defined(__CYGWIN__)
+# if defined(ALL_STATIC)
+# if defined(PNG_BUILD_DLL)
+# undef PNG_BUILD_DLL
+# endif
+# if defined(PNG_USE_DLL)
+# undef PNG_USE_DLL
+# endif
+# if defined(PNG_DLL)
+# undef PNG_DLL
+# endif
+# if !defined(PNG_STATIC)
+# define PNG_STATIC
+# endif
+# else
+# if defined (PNG_BUILD_DLL)
+# if defined(PNG_STATIC)
+# undef PNG_STATIC
+# endif
+# if defined(PNG_USE_DLL)
+# undef PNG_USE_DLL
+# endif
+# if !defined(PNG_DLL)
+# define PNG_DLL
+# endif
+# else
+# if defined(PNG_STATIC)
+# if defined(PNG_USE_DLL)
+# undef PNG_USE_DLL
+# endif
+# if defined(PNG_DLL)
+# undef PNG_DLL
+# endif
+# else
+# if !defined(PNG_USE_DLL)
+# define PNG_USE_DLL
+# endif
+# if !defined(PNG_DLL)
+# define PNG_DLL
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* This protects us against compilers that run on a windowing system
+ * and thus don't have or would rather us not use the stdio types:
+ * stdin, stdout, and stderr. The only one currently used is stderr
+ * in png_error() and png_warning(). #defining PNG_NO_CONSOLE_IO will
+ * prevent these from being compiled and used. #defining PNG_NO_STDIO
+ * will also prevent these, plus will prevent the entire set of stdio
+ * macros and functions (FILE *, printf, etc.) from being compiled and used,
+ * unless (PNG_DEBUG > 0) has been #defined.
+ *
+ * #define PNG_NO_CONSOLE_IO
+ * #define PNG_NO_STDIO
+ */
+
+#if defined(_WIN32_WCE)
+# include <windows.h>
+ /* Console I/O functions are not supported on WindowsCE */
+# define PNG_NO_CONSOLE_IO
+# ifdef PNG_DEBUG
+# undef PNG_DEBUG
+# endif
+#endif
+
+#ifdef PNG_BUILD_DLL
+# ifndef PNG_CONSOLE_IO_SUPPORTED
+# ifndef PNG_NO_CONSOLE_IO
+# define PNG_NO_CONSOLE_IO
+# endif
+# endif
+#endif
+
+# ifdef PNG_NO_STDIO
+# ifndef PNG_NO_CONSOLE_IO
+# define PNG_NO_CONSOLE_IO
+# endif
+# ifdef PNG_DEBUG
+# if (PNG_DEBUG > 0)
+# include <stdio.h>
+# endif
+# endif
+# else
+# if !defined(_WIN32_WCE)
+/* "stdio.h" functions are not supported on WindowsCE */
+# include <stdio.h>
+# endif
+# endif
+
+/* This macro protects us against machines that don't have function
+ * prototypes (ie K&R style headers). If your compiler does not handle
+ * function prototypes, define this macro and use the included ansi2knr.
+ * I've always been able to use _NO_PROTO as the indicator, but you may
+ * need to drag the empty declaration out in front of here, or change the
+ * ifdef to suit your own needs.
+ */
+#ifndef PNGARG
+
+#ifdef OF /* zlib prototype munger */
+# define PNGARG(arglist) OF(arglist)
+#else
+
+#ifdef _NO_PROTO
+# define PNGARG(arglist) ()
+# ifndef PNG_TYPECAST_NULL
+# define PNG_TYPECAST_NULL
+# endif
+#else
+# define PNGARG(arglist) arglist
+#endif /* _NO_PROTO */
+
+
+#endif /* OF */
+
+#endif /* PNGARG */
+
+/* Try to determine if we are compiling on a Mac. Note that testing for
+ * just __MWERKS__ is not good enough, because the Codewarrior is now used
+ * on non-Mac platforms.
+ */
+#ifndef MACOS
+# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \
+ defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC)
+# define MACOS
+# endif
+#endif
+
+/* enough people need this for various reasons to include it here */
+#if !defined(MACOS) && !defined(RISCOS) && !defined(_WIN32_WCE)
+# include <sys/types.h>
+#endif
+
+#if !defined(PNG_SETJMP_NOT_SUPPORTED) && !defined(PNG_NO_SETJMP_SUPPORTED)
+# define PNG_SETJMP_SUPPORTED
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+/* This is an attempt to force a single setjmp behaviour on Linux. If
+ * the X config stuff didn't define _BSD_SOURCE we wouldn't need this.
+ */
+
+# ifdef __linux__
+# ifdef _BSD_SOURCE
+# define PNG_SAVE_BSD_SOURCE
+# undef _BSD_SOURCE
+# endif
+# ifdef _SETJMP_H
+ /* If you encounter a compiler error here, see the explanation
+ * near the end of INSTALL.
+ */
+ __png.h__ already includes setjmp.h;
+ __dont__ include it again.;
+# endif
+# endif /* __linux__ */
+
+ /* include setjmp.h for error handling */
+# include <setjmp.h>
+
+# ifdef __linux__
+# ifdef PNG_SAVE_BSD_SOURCE
+# define _BSD_SOURCE
+# undef PNG_SAVE_BSD_SOURCE
+# endif
+# endif /* __linux__ */
+#endif /* PNG_SETJMP_SUPPORTED */
+
+#ifdef BSD
+# include <strings.h>
+#else
+# include <string.h>
+#endif
+
+/* Other defines for things like memory and the like can go here. */
+#ifdef PNG_INTERNAL
+
+#include <stdlib.h>
+
+/* The functions exported by PNG_EXTERN are PNG_INTERNAL functions, which
+ * aren't usually used outside the library (as far as I know), so it is
+ * debatable if they should be exported at all. In the future, when it is
+ * possible to have run-time registry of chunk-handling functions, some of
+ * these will be made available again.
+#define PNG_EXTERN extern
+ */
+#define PNG_EXTERN
+
+/* Other defines specific to compilers can go here. Try to keep
+ * them inside an appropriate ifdef/endif pair for portability.
+ */
+
+#if defined(PNG_FLOATING_POINT_SUPPORTED)
+# if defined(MACOS)
+ /* We need to check that <math.h> hasn't already been included earlier
+ * as it seems it doesn't agree with <fp.h>, yet we should really use
+ * <fp.h> if possible.
+ */
+# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__)
+# include <fp.h>
+# endif
+# else
+# include <math.h>
+# endif
+# if defined(_AMIGA) && defined(__SASC) && defined(_M68881)
+ /* Amiga SAS/C: We must include builtin FPU functions when compiling using
+ * MATH=68881
+ */
+# include <m68881.h>
+# endif
+#endif
+
+/* Codewarrior on NT has linking problems without this. */
+#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__)
+# define PNG_ALWAYS_EXTERN
+#endif
+
+/* This provides the non-ANSI (far) memory allocation routines. */
+#if defined(__TURBOC__) && defined(__MSDOS__)
+# include <mem.h>
+# include <alloc.h>
+#endif
+
+/* I have no idea why is this necessary... */
+#if defined(_MSC_VER) && (defined(WIN32) || defined(_Windows) || \
+ defined(_WINDOWS) || defined(_WIN32) || defined(__WIN32__))
+# include <malloc.h>
+#endif
+
+/* This controls how fine the dithering gets. As this allocates
+ * a largish chunk of memory (32K), those who are not as concerned
+ * with dithering quality can decrease some or all of these.
+ */
+#ifndef PNG_DITHER_RED_BITS
+# define PNG_DITHER_RED_BITS 5
+#endif
+#ifndef PNG_DITHER_GREEN_BITS
+# define PNG_DITHER_GREEN_BITS 5
+#endif
+#ifndef PNG_DITHER_BLUE_BITS
+# define PNG_DITHER_BLUE_BITS 5
+#endif
+
+/* This controls how fine the gamma correction becomes when you
+ * are only interested in 8 bits anyway. Increasing this value
+ * results in more memory being used, and more pow() functions
+ * being called to fill in the gamma tables. Don't set this value
+ * less then 8, and even that may not work (I haven't tested it).
+ */
+
+#ifndef PNG_MAX_GAMMA_8
+# define PNG_MAX_GAMMA_8 11
+#endif
+
+/* This controls how much a difference in gamma we can tolerate before
+ * we actually start doing gamma conversion.
+ */
+#ifndef PNG_GAMMA_THRESHOLD
+# define PNG_GAMMA_THRESHOLD 0.05
+#endif
+
+#endif /* PNG_INTERNAL */
+
+/* The following uses const char * instead of char * for error
+ * and warning message functions, so some compilers won't complain.
+ * If you do not want to use const, define PNG_NO_CONST here.
+ */
+
+#ifndef PNG_NO_CONST
+# define PNG_CONST const
+#else
+# define PNG_CONST
+#endif
+
+/* The following defines give you the ability to remove code from the
+ * library that you will not be using. I wish I could figure out how to
+ * automate this, but I can't do that without making it seriously hard
+ * on the users. So if you are not using an ability, change the #define
+ * to and #undef, and that part of the library will not be compiled. If
+ * your linker can't find a function, you may want to make sure the
+ * ability is defined here. Some of these depend upon some others being
+ * defined. I haven't figured out all the interactions here, so you may
+ * have to experiment awhile to get everything to compile. If you are
+ * creating or using a shared library, you probably shouldn't touch this,
+ * as it will affect the size of the structures, and this will cause bad
+ * things to happen if the library and/or application ever change.
+ */
+
+/* Any features you will not be using can be undef'ed here */
+
+/* GR-P, 0.96a: Set "*TRANSFORMS_SUPPORTED as default but allow user
+ * to turn it off with "*TRANSFORMS_NOT_SUPPORTED" or *PNG_NO_*_TRANSFORMS
+ * on the compile line, then pick and choose which ones to define without
+ * having to edit this file. It is safe to use the *TRANSFORMS_NOT_SUPPORTED
+ * if you only want to have a png-compliant reader/writer but don't need
+ * any of the extra transformations. This saves about 80 kbytes in a
+ * typical installation of the library. (PNG_NO_* form added in version
+ * 1.0.1c, for consistency)
+ */
+
+/* The size of the png_text structure changed in libpng-1.0.6 when
+ * iTXt support was added. iTXt support was turned off by default through
+ * libpng-1.2.x, to support old apps that malloc the png_text structure
+ * instead of calling png_set_text() and letting libpng malloc it. It
+ * was turned on by default in libpng-1.3.0.
+ */
+
+#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
+# ifndef PNG_NO_iTXt_SUPPORTED
+# define PNG_NO_iTXt_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_iTXt
+# define PNG_NO_READ_iTXt
+# endif
+# ifndef PNG_NO_WRITE_iTXt
+# define PNG_NO_WRITE_iTXt
+# endif
+#endif
+
+#if !defined(PNG_NO_iTXt_SUPPORTED)
+# if !defined(PNG_READ_iTXt_SUPPORTED) && !defined(PNG_NO_READ_iTXt)
+# define PNG_READ_iTXt
+# endif
+# if !defined(PNG_WRITE_iTXt_SUPPORTED) && !defined(PNG_NO_WRITE_iTXt)
+# define PNG_WRITE_iTXt
+# endif
+#endif
+
+/* The following support, added after version 1.0.0, can be turned off here en
+ * masse by defining PNG_LEGACY_SUPPORTED in case you need binary compatibility
+ * with old applications that require the length of png_struct and png_info
+ * to remain unchanged.
+ */
+
+#ifdef PNG_LEGACY_SUPPORTED
+# define PNG_NO_FREE_ME
+# define PNG_NO_READ_UNKNOWN_CHUNKS
+# define PNG_NO_WRITE_UNKNOWN_CHUNKS
+# define PNG_NO_READ_USER_CHUNKS
+# define PNG_NO_READ_iCCP
+# define PNG_NO_WRITE_iCCP
+# define PNG_NO_READ_iTXt
+# define PNG_NO_WRITE_iTXt
+# define PNG_NO_READ_sCAL
+# define PNG_NO_WRITE_sCAL
+# define PNG_NO_READ_sPLT
+# define PNG_NO_WRITE_sPLT
+# define PNG_NO_INFO_IMAGE
+# define PNG_NO_READ_RGB_TO_GRAY
+# define PNG_NO_READ_USER_TRANSFORM
+# define PNG_NO_WRITE_USER_TRANSFORM
+# define PNG_NO_USER_MEM
+# define PNG_NO_READ_EMPTY_PLTE
+# define PNG_NO_MNG_FEATURES
+# define PNG_NO_FIXED_POINT_SUPPORTED
+#endif
+
+/* Ignore attempt to turn off both floating and fixed point support */
+#if !defined(PNG_FLOATING_POINT_SUPPORTED) || \
+ !defined(PNG_NO_FIXED_POINT_SUPPORTED)
+# define PNG_FIXED_POINT_SUPPORTED
+#endif
+
+#ifndef PNG_NO_FREE_ME
+# define PNG_FREE_ME_SUPPORTED
+#endif
+
+#if defined(PNG_READ_SUPPORTED)
+
+#if !defined(PNG_READ_TRANSFORMS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_READ_TRANSFORMS)
+# define PNG_READ_TRANSFORMS_SUPPORTED
+#endif
+
+#ifdef PNG_READ_TRANSFORMS_SUPPORTED
+# ifndef PNG_NO_READ_EXPAND
+# define PNG_READ_EXPAND_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_SHIFT
+# define PNG_READ_SHIFT_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_PACK
+# define PNG_READ_PACK_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_BGR
+# define PNG_READ_BGR_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_SWAP
+# define PNG_READ_SWAP_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_PACKSWAP
+# define PNG_READ_PACKSWAP_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_INVERT
+# define PNG_READ_INVERT_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_DITHER
+# define PNG_READ_DITHER_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_BACKGROUND
+# define PNG_READ_BACKGROUND_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_16_TO_8
+# define PNG_READ_16_TO_8_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_FILLER
+# define PNG_READ_FILLER_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_GAMMA
+# define PNG_READ_GAMMA_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_GRAY_TO_RGB
+# define PNG_READ_GRAY_TO_RGB_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_SWAP_ALPHA
+# define PNG_READ_SWAP_ALPHA_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_INVERT_ALPHA
+# define PNG_READ_INVERT_ALPHA_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_STRIP_ALPHA
+# define PNG_READ_STRIP_ALPHA_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_USER_TRANSFORM
+# define PNG_READ_USER_TRANSFORM_SUPPORTED
+# endif
+# ifndef PNG_NO_READ_RGB_TO_GRAY
+# define PNG_READ_RGB_TO_GRAY_SUPPORTED
+# endif
+#endif /* PNG_READ_TRANSFORMS_SUPPORTED */
+
+#if !defined(PNG_NO_PROGRESSIVE_READ) && \
+ !defined(PNG_PROGRESSIVE_READ_NOT_SUPPORTED) /* if you don't do progressive */
+# define PNG_PROGRESSIVE_READ_SUPPORTED /* reading. This is not talking */
+#endif /* about interlacing capability! You'll */
+ /* still have interlacing unless you change the following line: */
+
+#define PNG_READ_INTERLACING_SUPPORTED /* required in PNG-compliant decoders */
+
+#ifndef PNG_NO_READ_COMPOSITE_NODIV
+# ifndef PNG_NO_READ_COMPOSITED_NODIV /* libpng-1.0.x misspelling */
+# define PNG_READ_COMPOSITE_NODIV_SUPPORTED /* well tested on Intel, SGI */
+# endif
+#endif
+
+#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
+/* Deprecated, will be removed from version 2.0.0.
+ Use PNG_MNG_FEATURES_SUPPORTED instead. */
+#ifndef PNG_NO_READ_EMPTY_PLTE
+# define PNG_READ_EMPTY_PLTE_SUPPORTED
+#endif
+#endif
+
+#endif /* PNG_READ_SUPPORTED */
+
+#if defined(PNG_WRITE_SUPPORTED)
+
+# if !defined(PNG_WRITE_TRANSFORMS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_WRITE_TRANSFORMS)
+# define PNG_WRITE_TRANSFORMS_SUPPORTED
+#endif
+
+#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
+# ifndef PNG_NO_WRITE_SHIFT
+# define PNG_WRITE_SHIFT_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_PACK
+# define PNG_WRITE_PACK_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_BGR
+# define PNG_WRITE_BGR_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_SWAP
+# define PNG_WRITE_SWAP_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_PACKSWAP
+# define PNG_WRITE_PACKSWAP_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_INVERT
+# define PNG_WRITE_INVERT_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_FILLER
+# define PNG_WRITE_FILLER_SUPPORTED /* same as WRITE_STRIP_ALPHA */
+# endif
+# ifndef PNG_NO_WRITE_SWAP_ALPHA
+# define PNG_WRITE_SWAP_ALPHA_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_INVERT_ALPHA
+# define PNG_WRITE_INVERT_ALPHA_SUPPORTED
+# endif
+# ifndef PNG_NO_WRITE_USER_TRANSFORM
+# define PNG_WRITE_USER_TRANSFORM_SUPPORTED
+# endif
+#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */
+
+#if !defined(PNG_NO_WRITE_INTERLACING_SUPPORTED) && \
+ !defined(PNG_WRITE_INTERLACING_SUPPORTED)
+#define PNG_WRITE_INTERLACING_SUPPORTED /* not required for PNG-compliant
+ encoders, but can cause trouble
+ if left undefined */
+#endif
+
+#if !defined(PNG_NO_WRITE_WEIGHTED_FILTER) && \
+ !defined(PNG_WRITE_WEIGHTED_FILTER) && \
+ defined(PNG_FLOATING_POINT_SUPPORTED)
+# define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
+#endif
+
+#ifndef PNG_NO_WRITE_FLUSH
+# define PNG_WRITE_FLUSH_SUPPORTED
+#endif
+
+#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
+/* Deprecated, see PNG_MNG_FEATURES_SUPPORTED, above */
+#ifndef PNG_NO_WRITE_EMPTY_PLTE
+# define PNG_WRITE_EMPTY_PLTE_SUPPORTED
+#endif
+#endif
+
+#endif /* PNG_WRITE_SUPPORTED */
+
+#ifndef PNG_1_0_X
+# ifndef PNG_NO_ERROR_NUMBERS
+# define PNG_ERROR_NUMBERS_SUPPORTED
+# endif
+#endif /* PNG_1_0_X */
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+# ifndef PNG_NO_USER_TRANSFORM_PTR
+# define PNG_USER_TRANSFORM_PTR_SUPPORTED
+# endif
+#endif
+
+#ifndef PNG_NO_STDIO
+# define PNG_TIME_RFC1123_SUPPORTED
+#endif
+
+/* This adds extra functions in pngget.c for accessing data from the
+ * info pointer (added in version 0.99)
+ * png_get_image_width()
+ * png_get_image_height()
+ * png_get_bit_depth()
+ * png_get_color_type()
+ * png_get_compression_type()
+ * png_get_filter_type()
+ * png_get_interlace_type()
+ * png_get_pixel_aspect_ratio()
+ * png_get_pixels_per_meter()
+ * png_get_x_offset_pixels()
+ * png_get_y_offset_pixels()
+ * png_get_x_offset_microns()
+ * png_get_y_offset_microns()
+ */
+#if !defined(PNG_NO_EASY_ACCESS) && !defined(PNG_EASY_ACCESS_SUPPORTED)
+# define PNG_EASY_ACCESS_SUPPORTED
+#endif
+
+/* PNG_ASSEMBLER_CODE was enabled by default in version 1.2.0
+ * even when PNG_USE_PNGVCRD or PNG_USE_PNGGCCRD is not defined.
+ *
+ * PNG_NO_ASSEMBLER_CODE disables use of all assembler code,
+ * and removes several functions from the API.
+ *
+ * PNG_NO_MMX_CODE disables the use of MMX code without changing the API.
+ * When MMX code is off, then optimized C replacement functions are used,
+ * if PNG_NO_OPTIMIZED_CODE is not enabled. This was added in version
+ * 1.2.19.
+*/
+
+#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_OPTIMIZED_CODE)
+# ifndef PNG_OPTIMIZED_CODE_SUPPORTED
+# define PNG_OPTIMIZED_CODE_SUPPORTED
+# endif
+#endif
+
+#if defined(PNG_READ_SUPPORTED) && !defined(PNG_NO_ASSEMBLER_CODE)
+# ifndef PNG_ASSEMBLER_CODE_SUPPORTED
+# define PNG_ASSEMBLER_CODE_SUPPORTED
+# endif
+
+# if !defined(PNG_MMX_CODE_SUPPORTED) && !defined(PNG_NO_MMX_CODE)
+# define PNG_MMX_CODE_SUPPORTED
+# endif
+
+# if !defined(PNG_USE_PNGVCRD) && defined(PNG_MMX_CODE_SUPPORTED) && \
+ defined(_MSC_VER)
+# define PNG_USE_PNGVCRD
+# endif
+
+# if !defined(PNG_USE_PNGGCCRD) && defined(PNG_MMX_CODE_SUPPORTED) && \
+ !defined(PNG_USE_PNGVCRD)
+# define PNG_USE_PNGGCCRD
+ /* If you are sure that you don't need thread safety and you are compiling
+ with PNG_USE_PNGCCRD for an MMX application, you can define this for
+ faster execution. See pnggccrd.c.
+# define PNG_THREAD_UNSAFE_OK
+ */
+# endif
+
+#endif
+
+#if !defined(PNG_1_0_X)
+#if !defined(PNG_NO_USER_MEM) && !defined(PNG_USER_MEM_SUPPORTED)
+# define PNG_USER_MEM_SUPPORTED
+#endif
+#endif /* PNG_1_0_X */
+
+/* Added at libpng-1.2.6 */
+#if !defined(PNG_1_0_X)
+#ifndef PNG_SET_USER_LIMITS_SUPPORTED
+#if !defined(PNG_NO_SET_USER_LIMITS) && !defined(PNG_SET_USER_LIMITS_SUPPORTED)
+# define PNG_SET_USER_LIMITS_SUPPORTED
+#endif
+#endif
+#endif /* PNG_1_0_X */
+
+/* Added at libpng-1.0.16 and 1.2.6. To accept all valid PNGS no matter
+ * how large, set these limits to 0x7fffffffL
+ */
+#ifndef PNG_USER_WIDTH_MAX
+# define PNG_USER_WIDTH_MAX 1000000L
+#endif
+#ifndef PNG_USER_HEIGHT_MAX
+# define PNG_USER_HEIGHT_MAX 1000000L
+#endif
+
+/* These are currently experimental features, define them if you want */
+
+/* very little testing */
+/*
+#ifdef PNG_READ_SUPPORTED
+# ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+# define PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED
+# endif
+#endif
+*/
+
+/* This is only for PowerPC big-endian and 680x0 systems */
+/* some testing */
+/*
+#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
+# define PNG_READ_BIG_ENDIAN_SUPPORTED
+#endif
+*/
+
+/* Buggy compilers (e.g., gcc 2.7.2.2) need this */
+/*
+#define PNG_NO_POINTER_INDEXING
+*/
+
+/* These functions are turned off by default, as they will be phased out. */
+/*
+#define PNG_USELESS_TESTS_SUPPORTED
+#define PNG_CORRECT_PALETTE_SUPPORTED
+*/
+
+/* Any chunks you are not interested in, you can undef here. The
+ * ones that allocate memory may be expecially important (hIST,
+ * tEXt, zTXt, tRNS, pCAL). Others will just save time and make png_info
+ * a bit smaller.
+ */
+
+#if defined(PNG_READ_SUPPORTED) && \
+ !defined(PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_READ_ANCILLARY_CHUNKS)
+# define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
+#endif
+
+#if defined(PNG_WRITE_SUPPORTED) && \
+ !defined(PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED) && \
+ !defined(PNG_NO_WRITE_ANCILLARY_CHUNKS)
+# define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
+#endif
+
+#ifdef PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
+
+#ifdef PNG_NO_READ_TEXT
+# define PNG_NO_READ_iTXt
+# define PNG_NO_READ_tEXt
+# define PNG_NO_READ_zTXt
+#endif
+#ifndef PNG_NO_READ_bKGD
+# define PNG_READ_bKGD_SUPPORTED
+# define PNG_bKGD_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_cHRM
+# define PNG_READ_cHRM_SUPPORTED
+# define PNG_cHRM_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_gAMA
+# define PNG_READ_gAMA_SUPPORTED
+# define PNG_gAMA_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_hIST
+# define PNG_READ_hIST_SUPPORTED
+# define PNG_hIST_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_iCCP
+# define PNG_READ_iCCP_SUPPORTED
+# define PNG_iCCP_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_iTXt
+# ifndef PNG_READ_iTXt_SUPPORTED
+# define PNG_READ_iTXt_SUPPORTED
+# endif
+# ifndef PNG_iTXt_SUPPORTED
+# define PNG_iTXt_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_READ_oFFs
+# define PNG_READ_oFFs_SUPPORTED
+# define PNG_oFFs_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_pCAL
+# define PNG_READ_pCAL_SUPPORTED
+# define PNG_pCAL_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_sCAL
+# define PNG_READ_sCAL_SUPPORTED
+# define PNG_sCAL_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_pHYs
+# define PNG_READ_pHYs_SUPPORTED
+# define PNG_pHYs_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_sBIT
+# define PNG_READ_sBIT_SUPPORTED
+# define PNG_sBIT_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_sPLT
+# define PNG_READ_sPLT_SUPPORTED
+# define PNG_sPLT_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_sRGB
+# define PNG_READ_sRGB_SUPPORTED
+# define PNG_sRGB_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_tEXt
+# define PNG_READ_tEXt_SUPPORTED
+# define PNG_tEXt_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_tIME
+# define PNG_READ_tIME_SUPPORTED
+# define PNG_tIME_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_tRNS
+# define PNG_READ_tRNS_SUPPORTED
+# define PNG_tRNS_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_zTXt
+# define PNG_READ_zTXt_SUPPORTED
+# define PNG_zTXt_SUPPORTED
+#endif
+#ifndef PNG_NO_READ_UNKNOWN_CHUNKS
+# define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
+# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
+# define PNG_UNKNOWN_CHUNKS_SUPPORTED
+# endif
+# ifndef PNG_NO_HANDLE_AS_UNKNOWN
+# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+# endif
+#endif
+#if !defined(PNG_NO_READ_USER_CHUNKS) && \
+ defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+# define PNG_READ_USER_CHUNKS_SUPPORTED
+# define PNG_USER_CHUNKS_SUPPORTED
+# ifdef PNG_NO_READ_UNKNOWN_CHUNKS
+# undef PNG_NO_READ_UNKNOWN_CHUNKS
+# endif
+# ifdef PNG_NO_HANDLE_AS_UNKNOWN
+# undef PNG_NO_HANDLE_AS_UNKNOWN
+# endif
+#endif
+#ifndef PNG_NO_READ_OPT_PLTE
+# define PNG_READ_OPT_PLTE_SUPPORTED /* only affects support of the */
+#endif /* optional PLTE chunk in RGB and RGBA images */
+#if defined(PNG_READ_iTXt_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) || \
+ defined(PNG_READ_zTXt_SUPPORTED)
+# define PNG_READ_TEXT_SUPPORTED
+# define PNG_TEXT_SUPPORTED
+#endif
+
+#endif /* PNG_READ_ANCILLARY_CHUNKS_SUPPORTED */
+
+#ifdef PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
+
+#ifdef PNG_NO_WRITE_TEXT
+# define PNG_NO_WRITE_iTXt
+# define PNG_NO_WRITE_tEXt
+# define PNG_NO_WRITE_zTXt
+#endif
+#ifndef PNG_NO_WRITE_bKGD
+# define PNG_WRITE_bKGD_SUPPORTED
+# ifndef PNG_bKGD_SUPPORTED
+# define PNG_bKGD_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_cHRM
+# define PNG_WRITE_cHRM_SUPPORTED
+# ifndef PNG_cHRM_SUPPORTED
+# define PNG_cHRM_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_gAMA
+# define PNG_WRITE_gAMA_SUPPORTED
+# ifndef PNG_gAMA_SUPPORTED
+# define PNG_gAMA_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_hIST
+# define PNG_WRITE_hIST_SUPPORTED
+# ifndef PNG_hIST_SUPPORTED
+# define PNG_hIST_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_iCCP
+# define PNG_WRITE_iCCP_SUPPORTED
+# ifndef PNG_iCCP_SUPPORTED
+# define PNG_iCCP_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_iTXt
+# ifndef PNG_WRITE_iTXt_SUPPORTED
+# define PNG_WRITE_iTXt_SUPPORTED
+# endif
+# ifndef PNG_iTXt_SUPPORTED
+# define PNG_iTXt_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_oFFs
+# define PNG_WRITE_oFFs_SUPPORTED
+# ifndef PNG_oFFs_SUPPORTED
+# define PNG_oFFs_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_pCAL
+# define PNG_WRITE_pCAL_SUPPORTED
+# ifndef PNG_pCAL_SUPPORTED
+# define PNG_pCAL_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_sCAL
+# define PNG_WRITE_sCAL_SUPPORTED
+# ifndef PNG_sCAL_SUPPORTED
+# define PNG_sCAL_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_pHYs
+# define PNG_WRITE_pHYs_SUPPORTED
+# ifndef PNG_pHYs_SUPPORTED
+# define PNG_pHYs_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_sBIT
+# define PNG_WRITE_sBIT_SUPPORTED
+# ifndef PNG_sBIT_SUPPORTED
+# define PNG_sBIT_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_sPLT
+# define PNG_WRITE_sPLT_SUPPORTED
+# ifndef PNG_sPLT_SUPPORTED
+# define PNG_sPLT_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_sRGB
+# define PNG_WRITE_sRGB_SUPPORTED
+# ifndef PNG_sRGB_SUPPORTED
+# define PNG_sRGB_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_tEXt
+# define PNG_WRITE_tEXt_SUPPORTED
+# ifndef PNG_tEXt_SUPPORTED
+# define PNG_tEXt_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_tIME
+# define PNG_WRITE_tIME_SUPPORTED
+# ifndef PNG_tIME_SUPPORTED
+# define PNG_tIME_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_tRNS
+# define PNG_WRITE_tRNS_SUPPORTED
+# ifndef PNG_tRNS_SUPPORTED
+# define PNG_tRNS_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_zTXt
+# define PNG_WRITE_zTXt_SUPPORTED
+# ifndef PNG_zTXt_SUPPORTED
+# define PNG_zTXt_SUPPORTED
+# endif
+#endif
+#ifndef PNG_NO_WRITE_UNKNOWN_CHUNKS
+# define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+# ifndef PNG_UNKNOWN_CHUNKS_SUPPORTED
+# define PNG_UNKNOWN_CHUNKS_SUPPORTED
+# endif
+# ifndef PNG_NO_HANDLE_AS_UNKNOWN
+# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+# define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+# endif
+# endif
+#endif
+#if defined(PNG_WRITE_iTXt_SUPPORTED) || defined(PNG_WRITE_tEXt_SUPPORTED) || \
+ defined(PNG_WRITE_zTXt_SUPPORTED)
+# define PNG_WRITE_TEXT_SUPPORTED
+# ifndef PNG_TEXT_SUPPORTED
+# define PNG_TEXT_SUPPORTED
+# endif
+#endif
+
+#endif /* PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED */
+
+/* Turn this off to disable png_read_png() and
+ * png_write_png() and leave the row_pointers member
+ * out of the info structure.
+ */
+#ifndef PNG_NO_INFO_IMAGE
+# define PNG_INFO_IMAGE_SUPPORTED
+#endif
+
+/* need the time information for reading tIME chunks */
+#if defined(PNG_tIME_SUPPORTED)
+# if !defined(_WIN32_WCE)
+ /* "time.h" functions are not supported on WindowsCE */
+# include <time.h>
+# endif
+#endif
+
+/* Some typedefs to get us started. These should be safe on most of the
+ * common platforms. The typedefs should be at least as large as the
+ * numbers suggest (a png_uint_32 must be at least 32 bits long), but they
+ * don't have to be exactly that size. Some compilers dislike passing
+ * unsigned shorts as function parameters, so you may be better off using
+ * unsigned int for png_uint_16. Likewise, for 64-bit systems, you may
+ * want to have unsigned int for png_uint_32 instead of unsigned long.
+ */
+
+typedef unsigned long png_uint_32;
+typedef long png_int_32;
+typedef unsigned short png_uint_16;
+typedef short png_int_16;
+typedef unsigned char png_byte;
+
+/* This is usually size_t. It is typedef'ed just in case you need it to
+ change (I'm not sure if you will or not, so I thought I'd be safe) */
+#ifdef PNG_SIZE_T
+ typedef PNG_SIZE_T png_size_t;
+# define png_sizeof(x) png_convert_size(sizeof (x))
+#else
+ typedef size_t png_size_t;
+# define png_sizeof(x) sizeof (x)
+#endif
+
+/* The following is needed for medium model support. It cannot be in the
+ * PNG_INTERNAL section. Needs modification for other compilers besides
+ * MSC. Model independent support declares all arrays and pointers to be
+ * large using the far keyword. The zlib version used must also support
+ * model independent data. As of version zlib 1.0.4, the necessary changes
+ * have been made in zlib. The USE_FAR_KEYWORD define triggers other
+ * changes that are needed. (Tim Wegner)
+ */
+
+/* Separate compiler dependencies (problem here is that zlib.h always
+ defines FAR. (SJT) */
+#ifdef __BORLANDC__
+# if defined(__LARGE__) || defined(__HUGE__) || defined(__COMPACT__)
+# define LDATA 1
+# else
+# define LDATA 0
+# endif
+ /* GRR: why is Cygwin in here? Cygwin is not Borland C... */
+# if !defined(__WIN32__) && !defined(__FLAT__) && !defined(__CYGWIN__)
+# define PNG_MAX_MALLOC_64K
+# if (LDATA != 1)
+# ifndef FAR
+# define FAR __far
+# endif
+# define USE_FAR_KEYWORD
+# endif /* LDATA != 1 */
+ /* Possibly useful for moving data out of default segment.
+ * Uncomment it if you want. Could also define FARDATA as
+ * const if your compiler supports it. (SJT)
+# define FARDATA FAR
+ */
+# endif /* __WIN32__, __FLAT__, __CYGWIN__ */
+#endif /* __BORLANDC__ */
+
+
+/* Suggest testing for specific compiler first before testing for
+ * FAR. The Watcom compiler defines both __MEDIUM__ and M_I86MM,
+ * making reliance oncertain keywords suspect. (SJT)
+ */
+
+/* MSC Medium model */
+#if defined(FAR)
+# if defined(M_I86MM)
+# define USE_FAR_KEYWORD
+# define FARDATA FAR
+# include <dos.h>
+# endif
+#endif
+
+/* SJT: default case */
+#ifndef FAR
+# define FAR
+#endif
+
+/* At this point FAR is always defined */
+#ifndef FARDATA
+# define FARDATA
+#endif
+
+/* Typedef for floating-point numbers that are converted
+ to fixed-point with a multiple of 100,000, e.g., int_gamma */
+typedef png_int_32 png_fixed_point;
+
+/* Add typedefs for pointers */
+typedef void FAR * png_voidp;
+typedef png_byte FAR * png_bytep;
+typedef png_uint_32 FAR * png_uint_32p;
+typedef png_int_32 FAR * png_int_32p;
+typedef png_uint_16 FAR * png_uint_16p;
+typedef png_int_16 FAR * png_int_16p;
+typedef PNG_CONST char FAR * png_const_charp;
+typedef char FAR * png_charp;
+typedef png_fixed_point FAR * png_fixed_point_p;
+
+#ifndef PNG_NO_STDIO
+#if defined(_WIN32_WCE)
+typedef HANDLE png_FILE_p;
+#else
+typedef FILE * png_FILE_p;
+#endif
+#endif
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+typedef double FAR * png_doublep;
+#endif
+
+/* Pointers to pointers; i.e. arrays */
+typedef png_byte FAR * FAR * png_bytepp;
+typedef png_uint_32 FAR * FAR * png_uint_32pp;
+typedef png_int_32 FAR * FAR * png_int_32pp;
+typedef png_uint_16 FAR * FAR * png_uint_16pp;
+typedef png_int_16 FAR * FAR * png_int_16pp;
+typedef PNG_CONST char FAR * FAR * png_const_charpp;
+typedef char FAR * FAR * png_charpp;
+typedef png_fixed_point FAR * FAR * png_fixed_point_pp;
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+typedef double FAR * FAR * png_doublepp;
+#endif
+
+/* Pointers to pointers to pointers; i.e., pointer to array */
+typedef char FAR * FAR * FAR * png_charppp;
+
+#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
+/* SPC - Is this stuff deprecated? */
+/* It'll be removed as of libpng-1.3.0 - GR-P */
+/* libpng typedefs for types in zlib. If zlib changes
+ * or another compression library is used, then change these.
+ * Eliminates need to change all the source files.
+ */
+typedef charf * png_zcharp;
+typedef charf * FAR * png_zcharpp;
+typedef z_stream FAR * png_zstreamp;
+#endif /* (PNG_1_0_X) || defined(PNG_1_2_X) */
+
+/*
+ * Define PNG_BUILD_DLL if the module being built is a Windows
+ * LIBPNG DLL.
+ *
+ * Define PNG_USE_DLL if you want to *link* to the Windows LIBPNG DLL.
+ * It is equivalent to Microsoft predefined macro _DLL that is
+ * automatically defined when you compile using the share
+ * version of the CRT (C Run-Time library)
+ *
+ * The cygwin mods make this behavior a little different:
+ * Define PNG_BUILD_DLL if you are building a dll for use with cygwin
+ * Define PNG_STATIC if you are building a static library for use with cygwin,
+ * -or- if you are building an application that you want to link to the
+ * static library.
+ * PNG_USE_DLL is defined by default (no user action needed) unless one of
+ * the other flags is defined.
+ */
+
+#if !defined(PNG_DLL) && (defined(PNG_BUILD_DLL) || defined(PNG_USE_DLL))
+# define PNG_DLL
+#endif
+/* If CYGWIN, then disallow GLOBAL ARRAYS unless building a static lib.
+ * When building a static lib, default to no GLOBAL ARRAYS, but allow
+ * command-line override
+ */
+#if defined(__CYGWIN__)
+# if !defined(PNG_STATIC)
+# if defined(PNG_USE_GLOBAL_ARRAYS)
+# undef PNG_USE_GLOBAL_ARRAYS
+# endif
+# if !defined(PNG_USE_LOCAL_ARRAYS)
+# define PNG_USE_LOCAL_ARRAYS
+# endif
+# else
+# if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNG_NO_GLOBAL_ARRAYS)
+# if defined(PNG_USE_GLOBAL_ARRAYS)
+# undef PNG_USE_GLOBAL_ARRAYS
+# endif
+# endif
+# endif
+# if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS)
+# define PNG_USE_LOCAL_ARRAYS
+# endif
+#endif
+
+/* Do not use global arrays (helps with building DLL's)
+ * They are no longer used in libpng itself, since version 1.0.5c,
+ * but might be required for some pre-1.0.5c applications.
+ */
+#if !defined(PNG_USE_LOCAL_ARRAYS) && !defined(PNG_USE_GLOBAL_ARRAYS)
+# if defined(PNG_NO_GLOBAL_ARRAYS) || \
+ (defined(__GNUC__) && defined(PNG_DLL)) || defined(_MSC_VER)
+# define PNG_USE_LOCAL_ARRAYS
+# else
+# define PNG_USE_GLOBAL_ARRAYS
+# endif
+#endif
+
+#if defined(__CYGWIN__)
+# undef PNGAPI
+# define PNGAPI __cdecl
+# undef PNG_IMPEXP
+# define PNG_IMPEXP
+#endif
+
+/* If you define PNGAPI, e.g., with compiler option "-DPNGAPI=__stdcall",
+ * you may get warnings regarding the linkage of png_zalloc and png_zfree.
+ * Don't ignore those warnings; you must also reset the default calling
+ * convention in your compiler to match your PNGAPI, and you must build
+ * zlib and your applications the same way you build libpng.
+ */
+
+#if defined(__MINGW32__) && !defined(PNG_MODULEDEF)
+# ifndef PNG_NO_MODULEDEF
+# define PNG_NO_MODULEDEF
+# endif
+#endif
+
+#if !defined(PNG_IMPEXP) && defined(PNG_BUILD_DLL) && !defined(PNG_NO_MODULEDEF)
+# define PNG_IMPEXP
+#endif
+
+#if defined(PNG_DLL) || defined(_DLL) || defined(__DLL__ ) || \
+ (( defined(_Windows) || defined(_WINDOWS) || \
+ defined(WIN32) || defined(_WIN32) || defined(__WIN32__) ))
+
+# ifndef PNGAPI
+# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800))
+# define PNGAPI __cdecl
+# else
+# define PNGAPI _cdecl
+# endif
+# endif
+
+# if !defined(PNG_IMPEXP) && (!defined(PNG_DLL) || \
+ 0 /* WINCOMPILER_WITH_NO_SUPPORT_FOR_DECLIMPEXP */)
+# define PNG_IMPEXP
+# endif
+
+# if !defined(PNG_IMPEXP)
+
+# define PNG_EXPORT_TYPE1(type,symbol) PNG_IMPEXP type PNGAPI symbol
+# define PNG_EXPORT_TYPE2(type,symbol) type PNG_IMPEXP PNGAPI symbol
+
+ /* Borland/Microsoft */
+# if defined(_MSC_VER) || defined(__BORLANDC__)
+# if (_MSC_VER >= 800) || (__BORLANDC__ >= 0x500)
+# define PNG_EXPORT PNG_EXPORT_TYPE1
+# else
+# define PNG_EXPORT PNG_EXPORT_TYPE2
+# if defined(PNG_BUILD_DLL)
+# define PNG_IMPEXP __export
+# else
+# define PNG_IMPEXP /*__import */ /* doesn't exist AFAIK in
+ VC++ */
+# endif /* Exists in Borland C++ for
+ C++ classes (== huge) */
+# endif
+# endif
+
+# if !defined(PNG_IMPEXP)
+# if defined(PNG_BUILD_DLL)
+# define PNG_IMPEXP __declspec(dllexport)
+# else
+# define PNG_IMPEXP __declspec(dllimport)
+# endif
+# endif
+# endif /* PNG_IMPEXP */
+#else /* !(DLL || non-cygwin WINDOWS) */
+# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
+# ifndef PNGAPI
+# define PNGAPI _System
+# endif
+# else
+# if 0 /* ... other platforms, with other meanings */
+# endif
+# endif
+#endif
+
+#ifndef PNGAPI
+# define PNGAPI
+#endif
+#ifndef PNG_IMPEXP
+# define PNG_IMPEXP
+#endif
+
+#ifdef PNG_BUILDSYMS
+# ifndef PNG_EXPORT
+# define PNG_EXPORT(type,symbol) PNG_FUNCTION_EXPORT symbol END
+# endif
+# ifdef PNG_USE_GLOBAL_ARRAYS
+# ifndef PNG_EXPORT_VAR
+# define PNG_EXPORT_VAR(type) PNG_DATA_EXPORT
+# endif
+# endif
+#endif
+
+#ifndef PNG_EXPORT
+# define PNG_EXPORT(type,symbol) PNG_IMPEXP type PNGAPI symbol
+#endif
+
+#ifdef PNG_USE_GLOBAL_ARRAYS
+# ifndef PNG_EXPORT_VAR
+# define PNG_EXPORT_VAR(type) extern PNG_IMPEXP type
+# endif
+#endif
+
+/* User may want to use these so they are not in PNG_INTERNAL. Any library
+ * functions that are passed far data must be model independent.
+ */
+
+#ifndef PNG_ABORT
+# define PNG_ABORT() abort()
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
+#else
+# define png_jmpbuf(png_ptr) \
+ (LIBPNG_WAS_COMPILED_WITH__PNG_SETJMP_NOT_SUPPORTED)
+#endif
+
+#if defined(USE_FAR_KEYWORD) /* memory model independent fns */
+/* use this to make far-to-near assignments */
+# define CHECK 1
+# define NOCHECK 0
+# define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK))
+# define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK))
+# define png_snprintf _fsnprintf /* Added to v 1.2.19 */
+# define png_strcpy _fstrcpy
+# define png_strncpy _fstrncpy /* Added to v 1.2.6 */
+# define png_strlen _fstrlen
+# define png_memcmp _fmemcmp /* SJT: added */
+# define png_memcpy _fmemcpy
+# define png_memset _fmemset
+#else /* use the usual functions */
+# define CVT_PTR(ptr) (ptr)
+# define CVT_PTR_NOCHECK(ptr) (ptr)
+# ifndef PNG_NO_SNPRINTF
+# ifdef _MSC_VER
+# define png_snprintf _snprintf /* Added to v 1.2.19 */
+# define png_snprintf2 _snprintf
+# define png_snprintf6 _snprintf
+# else
+# define png_snprintf snprintf /* Added to v 1.2.19 */
+# define png_snprintf2 snprintf
+# define png_snprintf6 snprintf
+# endif
+# else
+ /* You don't have or don't want to use snprintf(). Caution: Using
+ * sprintf instead of snprintf exposes your application to accidental
+ * or malevolent buffer overflows. If you don't have snprintf()
+ * as a general rule you should provide one (you can get one from
+ * Portable OpenSSH). */
+# define png_snprintf(s1,n,fmt,x1) sprintf(s1,fmt,x1)
+# define png_snprintf2(s1,n,fmt,x1,x2) sprintf(s1,fmt,x1,x2)
+# define png_snprintf6(s1,n,fmt,x1,x2,x3,x4,x5,x6) \
+ sprintf(s1,fmt,x1,x2,x3,x4,x5,x6)
+# endif
+# define png_strcpy strcpy
+# define png_strncpy strncpy /* Added to v 1.2.6 */
+# define png_strlen strlen
+# define png_memcmp memcmp /* SJT: added */
+# define png_memcpy memcpy
+# define png_memset memset
+#endif
+/* End of memory model independent support */
+
+/* Just a little check that someone hasn't tried to define something
+ * contradictory.
+ */
+#if (PNG_ZBUF_SIZE > 65536L) && defined(PNG_MAX_MALLOC_64K)
+# undef PNG_ZBUF_SIZE
+# define PNG_ZBUF_SIZE 65536L
+#endif
+
+#ifdef PNG_READ_SUPPORTED
+/* Prior to libpng-1.0.9, this block was in pngasmrd.h */
+#if defined(PNG_INTERNAL)
+
+#if defined(PNG_USE_PNGGCCRD) || defined(PNG_USE_PNGVCRD)
+ /* Platform must be Pentium. Makefile must assemble and load
+ * pnggccrd.c or pngvcrd.c. MMX will be detected at run time and
+ * used if present.
+ */
+# ifndef PNG_NO_MMX_COMBINE_ROW
+# define PNG_HAVE_MMX_COMBINE_ROW
+# endif
+# ifndef PNG_NO_MMX_READ_INTERLACE
+# define PNG_HAVE_MMX_READ_INTERLACE
+# endif
+# ifndef PNG_NO_MMX_READ_FILTER_ROW
+# define PNG_HAVE_MMX_READ_FILTER_ROW
+# ifndef PNG_NO_MMX_FILTER_SUB
+# define PNG_MMX_READ_FILTER_SUB_SUPPORTED
+# endif
+# if !(defined(__GNUC__) && defined(__x86_64__) && (__GNUC__ < 4))
+ /* work around 64-bit gcc compiler bugs in gcc-3.x */
+# ifndef PNG_NO_MMX_FILTER_UP
+# define PNG_MMX_READ_FILTER_UP_SUPPORTED
+# endif
+# ifndef PNG_NO_MMX_FILTER_AVG
+# define PNG_MMX_READ_FILTER_AVG_SUPPORTED
+# endif
+# ifndef PNG_NO_MMX_FILTER_PAETH
+# define PNG_MMX_READ_FILTER_PAETH_SUPPORTED
+# endif
+# endif /* !((__x86_64__) && (GNUC < 4)) */
+# endif
+ /* These are the default thresholds before the MMX code kicks in; if either
+ * rowbytes or bitdepth is below the threshold, plain C code is used. These
+ * can be overridden at runtime via the png_set_mmx_thresholds() call in
+ * libpng 1.2.0 and later. The values below were chosen by Intel.
+ */
+# ifndef PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT
+# define PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT 128 /* >= */
+# endif
+# ifndef PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT
+# define PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT 9 /* >= */
+# endif
+#endif /* PNG_USE_PNGGCCRD || PNG_USE_PNGVCRD */
+/* - see pngvcrd.c or pnggccrd.c for info about what is currently enabled */
+
+#endif /* PNG_INTERNAL */
+#endif /* PNG_READ_SUPPORTED */
+
+/* Added at libpng-1.2.8 */
+#endif /* PNG_VERSION_INFO_ONLY */
+
+#endif /* PNGCONF_H */
diff --git a/distrib/libpng-1.2.19/pngerror.c b/distrib/libpng-1.2.19/pngerror.c
new file mode 100644
index 0000000..b1d5fbe
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngerror.c
@@ -0,0 +1,326 @@
+
+/* pngerror.c - stub functions for i/o and memory allocation
+ *
+ * Last changed in libpng 1.2.19 August 18, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file provides a location for all error handling. Users who
+ * need special error handling are expected to write replacement functions
+ * and use png_set_error_fn() to use those functions. See the instructions
+ * at each function.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+static void /* PRIVATE */
+png_default_error PNGARG((png_structp png_ptr,
+ png_const_charp error_message));
+#ifndef PNG_NO_WARNINGS
+static void /* PRIVATE */
+png_default_warning PNGARG((png_structp png_ptr,
+ png_const_charp warning_message));
+#endif /* PNG_NO_WARNINGS */
+
+/* This function is called whenever there is a fatal error. This function
+ * should not be changed. If there is a need to handle errors differently,
+ * you should supply a replacement error function and use png_set_error_fn()
+ * to replace the error function at run-time.
+ */
+void PNGAPI
+png_error(png_structp png_ptr, png_const_charp error_message)
+{
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ char msg[16];
+ if (png_ptr != NULL)
+ {
+ if (png_ptr->flags&
+ (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))
+ {
+ if (*error_message == '#')
+ {
+ int offset;
+ for (offset=1; offset<15; offset++)
+ if (*(error_message+offset) == ' ')
+ break;
+ if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)
+ {
+ int i;
+ for (i=0; i<offset-1; i++)
+ msg[i]=error_message[i+1];
+ msg[i]='\0';
+ error_message=msg;
+ }
+ else
+ error_message+=offset;
+ }
+ else
+ {
+ if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)
+ {
+ msg[0]='0';
+ msg[1]='\0';
+ error_message=msg;
+ }
+ }
+ }
+ }
+#endif
+ if (png_ptr != NULL && png_ptr->error_fn != NULL)
+ (*(png_ptr->error_fn))(png_ptr, error_message);
+
+ /* If the custom handler doesn't exist, or if it returns,
+ use the default handler, which will not return. */
+ png_default_error(png_ptr, error_message);
+}
+
+#ifndef PNG_NO_WARNINGS
+/* This function is called whenever there is a non-fatal error. This function
+ * should not be changed. If there is a need to handle warnings differently,
+ * you should supply a replacement warning function and use
+ * png_set_error_fn() to replace the warning function at run-time.
+ */
+void PNGAPI
+png_warning(png_structp png_ptr, png_const_charp warning_message)
+{
+ int offset = 0;
+ if (png_ptr != NULL)
+ {
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ if (png_ptr->flags&
+ (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))
+#endif
+ {
+ if (*warning_message == '#')
+ {
+ for (offset=1; offset<15; offset++)
+ if (*(warning_message+offset) == ' ')
+ break;
+ }
+ }
+ if (png_ptr != NULL && png_ptr->warning_fn != NULL)
+ (*(png_ptr->warning_fn))(png_ptr, warning_message+offset);
+ }
+ else
+ png_default_warning(png_ptr, warning_message+offset);
+}
+#endif /* PNG_NO_WARNINGS */
+
+
+/* These utilities are used internally to build an error message that relates
+ * to the current chunk. The chunk name comes from png_ptr->chunk_name,
+ * this is used to prefix the message. The message is limited in length
+ * to 63 bytes, the name characters are output as hex digits wrapped in []
+ * if the character is invalid.
+ */
+#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
+static PNG_CONST char png_digit[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+ 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+static void /* PRIVATE */
+png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp
+ error_message)
+{
+ int iout = 0, iin = 0;
+
+ while (iin < 4)
+ {
+ int c = png_ptr->chunk_name[iin++];
+ if (isnonalpha(c))
+ {
+ buffer[iout++] = '[';
+ buffer[iout++] = png_digit[(c & 0xf0) >> 4];
+ buffer[iout++] = png_digit[c & 0x0f];
+ buffer[iout++] = ']';
+ }
+ else
+ {
+ buffer[iout++] = (png_byte)c;
+ }
+ }
+
+ if (error_message == NULL)
+ buffer[iout] = 0;
+ else
+ {
+ buffer[iout++] = ':';
+ buffer[iout++] = ' ';
+ png_strncpy(buffer+iout, error_message, 63);
+ buffer[iout+63] = 0;
+ }
+}
+
+#ifdef PNG_READ_SUPPORTED
+void PNGAPI
+png_chunk_error(png_structp png_ptr, png_const_charp error_message)
+{
+ char msg[18+64];
+ if (png_ptr == NULL)
+ png_error(png_ptr, error_message);
+ else
+ {
+ png_format_buffer(png_ptr, msg, error_message);
+ png_error(png_ptr, msg);
+ }
+}
+
+#ifndef PNG_NO_WARNINGS
+void PNGAPI
+png_chunk_warning(png_structp png_ptr, png_const_charp warning_message)
+{
+ char msg[18+64];
+ if (png_ptr == NULL)
+ png_warning(png_ptr, warning_message);
+ else
+ {
+ png_format_buffer(png_ptr, msg, warning_message);
+ png_warning(png_ptr, msg);
+ }
+}
+#endif /* PNG_NO_WARNINGS */
+
+#endif /* PNG_READ_SUPPORTED */
+
+/* This is the default error handling function. Note that replacements for
+ * this function MUST NOT RETURN, or the program will likely crash. This
+ * function is used by default, or if the program supplies NULL for the
+ * error function pointer in png_set_error_fn().
+ */
+static void /* PRIVATE */
+png_default_error(png_structp png_ptr, png_const_charp error_message)
+{
+#ifndef PNG_NO_CONSOLE_IO
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ if (*error_message == '#')
+ {
+ int offset;
+ char error_number[16];
+ for (offset=0; offset<15; offset++)
+ {
+ error_number[offset] = *(error_message+offset+1);
+ if (*(error_message+offset) == ' ')
+ break;
+ }
+ if((offset > 1) && (offset < 15))
+ {
+ error_number[offset-1]='\0';
+ fprintf(stderr, "libpng error no. %s: %s\n", error_number,
+ error_message+offset);
+ }
+ else
+ fprintf(stderr, "libpng error: %s, offset=%d\n", error_message,offset);
+ }
+ else
+#endif
+ fprintf(stderr, "libpng error: %s\n", error_message);
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+ if (png_ptr)
+ {
+# ifdef USE_FAR_KEYWORD
+ {
+ jmp_buf jmpbuf;
+ png_memcpy(jmpbuf, png_ptr->jmpbuf, png_sizeof(jmp_buf));
+ longjmp(jmpbuf, 1);
+ }
+# else
+ longjmp(png_ptr->jmpbuf, 1);
+# endif
+ }
+#else
+ PNG_ABORT();
+#endif
+#ifdef PNG_NO_CONSOLE_IO
+ error_message = error_message; /* make compiler happy */
+#endif
+}
+
+#ifndef PNG_NO_WARNINGS
+/* This function is called when there is a warning, but the library thinks
+ * it can continue anyway. Replacement functions don't have to do anything
+ * here if you don't want them to. In the default configuration, png_ptr is
+ * not used, but it is passed in case it may be useful.
+ */
+static void /* PRIVATE */
+png_default_warning(png_structp png_ptr, png_const_charp warning_message)
+{
+#ifndef PNG_NO_CONSOLE_IO
+# ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ if (*warning_message == '#')
+ {
+ int offset;
+ char warning_number[16];
+ for (offset=0; offset<15; offset++)
+ {
+ warning_number[offset]=*(warning_message+offset+1);
+ if (*(warning_message+offset) == ' ')
+ break;
+ }
+ if((offset > 1) && (offset < 15))
+ {
+ warning_number[offset-1]='\0';
+ fprintf(stderr, "libpng warning no. %s: %s\n", warning_number,
+ warning_message+offset);
+ }
+ else
+ fprintf(stderr, "libpng warning: %s\n", warning_message);
+ }
+ else
+# endif
+ fprintf(stderr, "libpng warning: %s\n", warning_message);
+#else
+ warning_message = warning_message; /* make compiler happy */
+#endif
+ png_ptr = png_ptr; /* make compiler happy */
+}
+#endif /* PNG_NO_WARNINGS */
+
+/* This function is called when the application wants to use another method
+ * of handling errors and warnings. Note that the error function MUST NOT
+ * return to the calling routine or serious problems will occur. The return
+ * method used in the default routine calls longjmp(png_ptr->jmpbuf, 1)
+ */
+void PNGAPI
+png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warning_fn)
+{
+ if (png_ptr == NULL)
+ return;
+ png_ptr->error_ptr = error_ptr;
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+}
+
+
+/* This function returns a pointer to the error_ptr associated with the user
+ * functions. The application should free any memory associated with this
+ * pointer before png_write_destroy and png_read_destroy are called.
+ */
+png_voidp PNGAPI
+png_get_error_ptr(png_structp png_ptr)
+{
+ if (png_ptr == NULL)
+ return NULL;
+ return ((png_voidp)png_ptr->error_ptr);
+}
+
+
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+void PNGAPI
+png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode)
+{
+ if(png_ptr != NULL)
+ {
+ png_ptr->flags &=
+ ((~(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
+ }
+}
+#endif
+#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pnggccrd.c b/distrib/libpng-1.2.19/pnggccrd.c
new file mode 100644
index 0000000..f63867c
--- /dev/null
+++ b/distrib/libpng-1.2.19/pnggccrd.c
@@ -0,0 +1,6041 @@
+
+/* pnggccrd.c - mixed C/assembler version of utilities to read a PNG file
+ *
+ * For Intel/AMD x86 or x86-64 CPU (Pentium-MMX or later) and GNU C compiler.
+ *
+ * Last changed in libpng 1.2.19 August 18, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998 Intel Corporation
+ * Copyright (c) 1999-2002,2007 Greg Roelofs
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ *
+ * Based on MSVC code contributed by Nirav Chhatrapati, Intel Corp., 1998.
+ * Interface to libpng contributed by Gilles Vollant, 1999.
+ * GNU C port by Greg Roelofs, 1999-2001.
+ *
+ * References:
+ *
+ * http://www.intel.com/drg/pentiumII/appnotes/916/916.htm
+ * http://www.intel.com/drg/pentiumII/appnotes/923/923.htm
+ * [Intel's performance analysis of the MMX vs. non-MMX code;
+ * moved/deleted as of 2006, but text and some graphs still
+ * available via WayBack Machine at archive.org]
+ *
+ * http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html
+ * http://sam.zoy.org/blog/2007-04-13-shlib-with-non-pic-code-have-inline-assembly-and-pic-mix-well
+ * http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
+ * http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html
+ * http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
+ * AMD64 Architecture Programmer's Manual, volumes 1 and 5
+ * [http://www.amd.com/us-en/Processors/TechnicalResources/0,,30_182_739_7044,00.html]
+ * Intel 64 and IA-32 Software Developer's Manuals
+ * [http://developer.intel.com/products/processor/manuals/]
+ *
+ * png_read_filter_row_mmx_*() were converted in place with intel2gas 1.3.1:
+ *
+ * intel2gas -mdI pnggccrd.c.partially-msvc -o pnggccrd.c
+ *
+ * and then cleaned up by hand. See http://hermes.terminal.at/intel2gas/ .
+ *
+ * NOTE: A sufficiently recent version of GNU as (or as.exe under DOS/Windows)
+ * is required to assemble the newer asm instructions such as movq. (Version
+ * 2.5.2l.15 is definitely too old.) See ftp://ftp.gnu.org/pub/gnu/binutils/ .
+ */
+
+/*
+ * PORTING NOTES AND CHANGELOG (mostly by Greg Roelofs)
+ * ===========================
+ *
+ * 19991006:
+ * - fixed sign error in post-MMX cleanup code (16- & 32-bit cases)
+ *
+ * 19991007:
+ * - additional optimizations (possible or definite):
+ * x [DONE] write MMX code for 64-bit case (pixel_bytes == 8) [not tested]
+ * - write MMX code for 48-bit case (pixel_bytes == 6)
+ * - figure out what's up with 24-bit case (pixel_bytes == 3):
+ * why subtract 8 from width_mmx in the pass 4/5 case?
+ * (only width_mmx case) (near line 2335)
+ * x [DONE] replace pixel_bytes within each block with the true
+ * constant value (or are compilers smart enough to do that?)
+ * - rewrite all MMX interlacing code so it's aligned with
+ * the *beginning* of the row buffer, not the end. This
+ * would not only allow one to eliminate half of the memory
+ * writes for odd passes (that is, pass == odd), it may also
+ * eliminate some unaligned-data-access exceptions (assuming
+ * there's a penalty for not aligning 64-bit accesses on
+ * 64-bit boundaries). The only catch is that the "leftover"
+ * pixel(s) at the end of the row would have to be saved,
+ * but there are enough unused MMX registers in every case,
+ * so this is not a problem. A further benefit is that the
+ * post-MMX cleanup code (C code) in at least some of the
+ * cases could be done within the assembler block.
+ * x [DONE] the "v3 v2 v1 v0 v7 v6 v5 v4" comments are confusing,
+ * inconsistent, and don't match the MMX Programmer's Reference
+ * Manual conventions anyway. They should be changed to
+ * "b7 b6 b5 b4 b3 b2 b1 b0," where b0 indicates the byte that
+ * was lowest in memory (i.e., corresponding to a left pixel)
+ * and b7 is the byte that was highest (i.e., a right pixel).
+ *
+ * 19991016:
+ * - Brennan's Guide notwithstanding, gcc under Linux does *not*
+ * want globals prefixed by underscores when referencing them--
+ * i.e., if the variable is const4, then refer to it as const4,
+ * not _const4. This seems to be a djgpp-specific requirement.
+ * Also, such variables apparently *must* be declared outside
+ * of functions; neither static nor automatic variables work if
+ * defined within the scope of a single function, but both
+ * static and truly global (multi-module) variables work fine.
+ *
+ * 19991017:
+ * - replaced pixel_bytes in each png_memcpy() call with constant value for
+ * inlining (png_do_read_interlace() "non-MMX/modified C code" block)
+ *
+ * 19991023:
+ * - fixed png_combine_row() non-MMX replication bug (odd passes only?)
+ * - switched from string-concatenation-with-macros to cleaner method of
+ * renaming global variables for djgpp--i.e., always use prefixes in
+ * inlined assembler code (== strings) and conditionally rename the
+ * variables, not the other way around. Hence _const4, _mask8_0, etc.
+ *
+ * 19991024:
+ * - fixed mmxsupport()/png_do_read_interlace() first-row bug
+ * This one was severely weird: even though mmxsupport() doesn't touch
+ * ebx (where "row" pointer was stored), it nevertheless managed to zero
+ * the register (even in static/non-fPIC code--see below), which in turn
+ * caused png_do_read_interlace() to return prematurely on the first row of
+ * interlaced images (i.e., without expanding the interlaced pixels).
+ * Inspection of the generated assembly code didn't turn up any clues,
+ * although it did point at a minor optimization (i.e., get rid of
+ * mmx_supported_local variable and just use eax). Possibly the CPUID
+ * instruction is more destructive than it looks? (Not yet checked.)
+ * - "info gcc" was next to useless, so compared fPIC and non-fPIC assembly
+ * listings... Apparently register spillage has to do with ebx, since
+ * it's used to index the global offset table. Commenting it out of the
+ * input-reg lists in png_combine_row() eliminated compiler barfage, so
+ * ifdef'd with __PIC__ macro: if defined, use a global for unmask
+ *
+ * 19991107:
+ * - verified CPUID clobberage: 12-char string constant ("GenuineIntel",
+ * "AuthenticAMD", etc.) placed in ebx:ecx:edx. Still need to polish.
+ *
+ * 19991120:
+ * - made "diff" variable (now "_dif") global to simplify conversion of
+ * filtering routines (running out of regs, sigh). "diff" is still used
+ * in interlacing routines, however.
+ * - fixed up both versions of mmxsupport() (ORIG_THAT_USED_TO_CLOBBER_EBX
+ * macro determines which is used); original not yet tested.
+ *
+ * 20000213:
+ * - when compiling with gcc, be sure to use -fomit-frame-pointer
+ *
+ * 20000319:
+ * - fixed a register-name typo in png_do_read_interlace(), default (MMX) case,
+ * pass == 4 or 5, that caused visible corruption of interlaced images
+ *
+ * 20000623:
+ * - Various problems were reported with gcc 2.95.2 in the Cygwin environment,
+ * many of the form "forbidden register 0 (ax) was spilled for class AREG."
+ * This is explained at http://gcc.gnu.org/fom_serv/cache/23.html, and
+ * Chuck Wilson supplied a patch involving dummy output registers. See
+ * http://sourceforge.net/bugs/?func=detailbug&bug_id=108741&group_id=5624
+ * for the original (anonymous) SourceForge bug report.
+ *
+ * 20000706:
+ * - Chuck Wilson passed along these remaining gcc 2.95.2 errors:
+ * pnggccrd.c: In function `png_combine_row':
+ * pnggccrd.c:525: more than 10 operands in `asm'
+ * pnggccrd.c:669: more than 10 operands in `asm'
+ * pnggccrd.c:828: more than 10 operands in `asm'
+ * pnggccrd.c:994: more than 10 operands in `asm'
+ * pnggccrd.c:1177: more than 10 operands in `asm'
+ * They are all the same problem and can be worked around by using the
+ * global _unmask variable unconditionally, not just in the -fPIC case.
+ * Reportedly earlier versions of gcc also have the problem with more than
+ * 10 operands; they just don't report it. Much strangeness ensues, etc.
+ *
+ * 20000729:
+ * - enabled png_read_filter_row_mmx_up() (shortest remaining unconverted
+ * MMX routine); began converting png_read_filter_row_mmx_sub()
+ * - to finish remaining sections:
+ * - clean up indentation and comments
+ * - preload local variables
+ * - add output and input regs (order of former determines numerical
+ * mapping of latter)
+ * - avoid all usage of ebx (including bx, bh, bl) register [20000823]
+ * - remove "$" from addressing of Shift and Mask variables [20000823]
+ *
+ * 20000731:
+ * - global union vars causing segfaults in png_read_filter_row_mmx_sub()?
+ *
+ * 20000822:
+ * - ARGH, stupid png_read_filter_row_mmx_sub() segfault only happens with
+ * shared-library (-fPIC) version! Code works just fine as part of static
+ * library. Should have tested that sooner.
+ * ebx is getting clobbered again (explicitly this time); need to save it
+ * on stack or rewrite asm code to avoid using it altogether. Blargh!
+ *
+ * 20000823:
+ * - first section was trickiest; all remaining sections have ebx -> edx now.
+ * (-fPIC works again.) Also added missing underscores to various Shift*
+ * and *Mask* globals and got rid of leading "$" signs.
+ *
+ * 20000826:
+ * - added visual separators to help navigate microscopic printed copies
+ * (http://pobox.com/~newt/code/gpr-latest.zip, mode 10); started working
+ * on png_read_filter_row_mmx_avg()
+ *
+ * 20000828:
+ * - finished png_read_filter_row_mmx_avg(): only Paeth left! (930 lines...)
+ * What the hell, did png_read_filter_row_mmx_paeth(), too. Comments not
+ * cleaned up/shortened in either routine, but functionality is complete
+ * and seems to be working fine.
+ *
+ * 20000829:
+ * - ahhh, figured out last(?) bit of gcc/gas asm-fu: if register is listed
+ * as an input reg (with dummy output variables, etc.), then it *cannot*
+ * also appear in the clobber list or gcc 2.95.2 will barf. The solution
+ * is simple enough...
+ *
+ * 20000914:
+ * - bug in png_read_filter_row_mmx_avg(): 16-bit grayscale not handled
+ * correctly (but 48-bit RGB just fine)
+ *
+ * 20000916:
+ * - fixed bug in png_read_filter_row_mmx_avg(), bpp == 2 case; three errors:
+ * - "_ShiftBpp.use = 24;" should have been "_ShiftBpp.use = 16;"
+ * - "_ShiftRem.use = 40;" should have been "_ShiftRem.use = 48;"
+ * - "psllq _ShiftRem, %%mm2" should have been "psrlq _ShiftRem, %%mm2"
+ *
+ * 20010101:
+ * - added new png_init_mmx_flags() function (here only because it needs to
+ * call mmxsupport(), which should probably become global png_mmxsupport());
+ * modified other MMX routines to run conditionally (png_ptr->asm_flags)
+ *
+ * 20010103:
+ * - renamed mmxsupport() to png_mmx_support(), with auto-set of mmx_supported,
+ * and made it public; moved png_init_mmx_flags() to png.c as internal func
+ *
+ * 20010104:
+ * - removed dependency on png_read_filter_row_c() (C code already duplicated
+ * within MMX version of png_read_filter_row()) so no longer necessary to
+ * compile it into pngrutil.o
+ *
+ * 20010310:
+ * - fixed buffer-overrun bug in png_combine_row() C code (non-MMX)
+ *
+ * 20010808:
+ * - added PNG_THREAD_UNSAFE_OK around code using global variables [GR-P]
+ *
+ * 20011124:
+ * - fixed missing save of Eflag in png_mmx_support() [Maxim Sobolev]
+ *
+ * 20020304:
+ * - eliminated incorrect use of width_mmx in pixel_bytes == 8 case
+ *
+ * 20020407:
+ * - fixed insufficient preservation of ebx register [Sami Farin]
+ *
+ * 20040724:
+ * - more tinkering with clobber list at lines 4529 and 5033 to get it to
+ * compile with gcc 3.4 [GR-P]
+ *
+ * 20040809:
+ * - added "rim" definitions for CONST4 and CONST6 [GR-P]
+ *
+ * 20060303:
+ * - added "OS2" to list of systems that don't need leading underscores [GR-P]
+ *
+ * 20060320:
+ * - made PIC-compliant [Christian Aichinger]
+ *
+ * 20070313:
+ * - finally applied Giuseppe Ghibò's 64-bit patch of 20060803 (completely
+ * overlooked Dylan Alex Simon's similar patch of 20060414, oops...)
+ *
+ * 20070524:
+ * - fixed link failure caused by asm-only variables being optimized out
+ * (identified by Dimitri of Trolltech) with __attribute__((used)), which
+ * also gets rid of warnings => nuked ugly png_squelch_warnings() hack
+ * - dropped redundant ifdef
+ * - moved png_mmx_support() back up where originally intended (as in
+ * pngvcrd.c), using __attribute__((noinline)) in extra prototype
+ *
+ * 20070527:
+ * - revised png_combine_row() to reuse mask in lieu of external _unmask
+ * - moved 32-bit (RGBA) case to top of png_combine_row(): most common
+ * - just about ready to give up on x86-64 -fPIC mode; can't even access 16
+ * _mask*_* constants without triggering link error on shared library:
+ * /usr/bin/ld: pnggccrd.pic.o: relocation R_X86_64_32S against `a local
+ * symbol' can not be used when making a shared object; recompile with
+ * -fPIC
+ * pnggccrd.pic.o: could not read symbols: Bad value
+ * ("objdump -x pnggccrd.pic.o | grep rodata" to verify)
+ * [might be able to work around by doing within assembly code whatever
+ * -fPIC does, but given problems to date, seems like long shot...]
+ * [relevant ifdefs: __x86_64__ && __PIC__ => C code only]
+ * - changed #if 0 to #ifdef PNG_CLOBBER_MMX_REGS_SUPPORTED in case gcc ever
+ * supports MMX regs (%mm0, etc.) in clobber list (not supported by gcc
+ * 2.7.2.3, 2.91.66 (egcs 1.1.2), 3.x, or 4.1.2)
+ *
+ * 20070603:
+ * - revised png_combine_row() to use @GOTPCREL(%%rip) addressing on _c64
+ * struct of _mask*_* constants for x86-64 -fPIC; see sam.zoy.org link
+ * above for details
+ * - moved _const4 and _const6 into _c64 struct, renamed to _amask5_3_0 and
+ * _amask7_1_0, respectively
+ * - can't figure out how to use _c64._mask*_* vars within asm code, so still
+ * need single variables for non-x86-64/-fPIC half :-(
+ * - replaced various __PIC__ ifdefs with *_GOT_ebx macros
+ * - moved _LBCarryMask and _HBClearMask into _c64 struct
+ * - conditionally replaced _p*temp variables with %r11d-%r13d (via p*_TEMP
+ * and CLOBBER_r1*d macros)
+ *
+ * 20070604:
+ * - replaced all _ActiveMask and _ActiveMaskEnd with new _amask*_*_* consts
+ * (_amask naming convention: numbers of 00-bytes, ff-bytes, 00-bytes)
+ * - _ActiveMask // (10) // avg/paeth/sub; read-only; consts; movq/pand
+ * 0x0000000000ffffffLL (bpp 3, avg) _amask5_3_0
+ * 0xffffffffffffffffLL (bpp 4, 6, avg) _amask0_8_0
+ * 0x000000000000ffffLL (bpp 2, avg) _amask6_2_0
+ * 0x0000000000ffffffLL (bpp 3, paeth) _amask5_3_0
+ * 0x00000000ffffffffLL (bpp 6, paeth) _amask4_4_0
+ * 0x00000000ffffffffLL (bpp 4, paeth) _amask4_4_0
+ * 0x00000000ffffffffLL (bpp 8, paeth) _amask4_4_0
+ * 0x0000ffffff000000LL (bpp 3, sub) _amask2_3_3
+ * 0x00000000ffff0000LL (bpp 2, sub) _amask4_2_2
+ * - _ActiveMaskEnd // (1) // paeth only; read-only; const; pand
+ * 0xffff000000000000LL (bpp 3, paeth) _amask0_2_6
+ * - changed all "#if defined(__x86_64__) // later // && defined(__PIC__)"
+ * lines to "#ifdef PNG_x86_64_USE_GOTPCREL" for easier/safer testing
+ *
+ * 20070605:
+ * - merged PNG_x86_64_USE_GOTPCREL, non-PNG_x86_64_USE_GOTPCREL code via
+ * *MASK* and LOAD/RESTORE macros
+ *
+ * 20070607:
+ * - replaced all constant instances of _ShiftBpp, _ShiftRem with immediates
+ * (still have two shared cases in avg, sub routines)
+ *
+ * 20070609:
+ * - replaced remaining instances of _ShiftBpp, _ShiftRem with immediates
+ * (split sub and avg 4/6-bpp cases into separate blocks)
+ * - fixed paeth bug due to clobbered r11/r12/r13 regs
+ *
+ * 20070610:
+ * - made global "_dif" variable (avg/paeth/sub routines) local again (now
+ * "diff"--see 19991120 entry above), using register constraints
+ * - note that %ebp in clobber list doesn't actually work, at least for 32-bit
+ * version and gcc 4.1.2; must save and restore manually. (Seems to work
+ * OK for 64-bit version and gcc 3.4.3, but gcc may not be using ebp/rbp
+ * in that case.)
+ * - started replacing direct _MMXLength accesses with register constraints
+ *
+ * 20070612:
+ * - continued replacing direct _MMXLength accesses with register constraints
+ *
+ * 20070613:
+ * - finished replacing direct _MMXLength accesses with register constraints;
+ * switched to local variable (and renamed back to MMXLength)
+ *
+ * 20070614:
+ * - fixed sub bpp = 1 bug
+ * - started replacing direct _FullLength accesses with register constraints
+ *
+ * 20070615:
+ * - fixed 64-bit paeth bpp 3 crash bug (misplaced LOAD_GOT_rbp)
+ * - fixed 64-bit paeth bpp 1/2 and cleanup-block crash bugs (misplaced
+ * RESTORE_r11_r12_r13)
+ * - slightly optimized avg/paeth cleanup blocks and paeth bpp 1/2 block
+ * (save/restore ebx only if needed)
+ * - continued replacing direct _FullLength accesses with register constraints
+ *
+ * 20070616:
+ * - finished replacing direct _FullLength accesses with register constraints
+ * (*ugly* conditional clobber-separator macros for avg and paeth, sigh)
+ *
+ * 20070618:
+ * - fixed misplaced PNG_THREAD_UNSAFE_OK endif (was missing LOAD_GOT_rbp/
+ * RESTORE_rbp in 32-bit thread-safe case)
+ * - changed all "ifdef *" to "if defined(*)" [GR-P]
+ *
+ * 20070619:
+ * - rearranged most bitdepth-related case statements to put most frequent
+ * cases at top (24-bit, 32-bit, 8-bit, rest)
+ *
+ * 20070623:
+ * - cleaned up png_debug() warnings/formatting
+ * - removed PNG_MMX_CODE_SUPPORTED ifdefs and added outer __GNUC__ ifdef
+ * (module no longer used by non-x86/non-GCC builds as of libpng 1.2.19)
+ * - removed single libpng-1.2.x PNG_DEBUG dependency on 1.0.x png_struct
+ * member (row_buf_size)
+ * - rearranged pass-related if-blocks in png_do_read_interlace() to put most
+ * frequent cases (4, 5) at top [GR-P suggestion]
+ *
+ * 20070624-29:
+ * - fixed 64-bit crash bug: pointers -> rsi/rdi, not esi/edi (switched to
+ * %0/%1/%2/%3/%4 notation; eliminated size suffixes from relevant add/
+ * inc/sub/mov instructions; changed dummy vars to pointers)
+ * - png_combine_row()
+ * - png_do_read_interlace()
+ * - png_read_filter_row_mmx_avg()
+ * - png_read_filter_row_mmx_paeth()
+ * - png_read_filter_row_mmx_sub()
+ * - png_read_filter_row_mmx_up()
+ * - NOTE: this fix makes use of the fact that modifying a 32-bit reg (e.g.,
+ * %%ebx) clears the top half of its corresponding 64-bit reg (%%rbx), so
+ * it's safe to mix 32-bit operations with 64-bit base/index addressing
+ * (see new PSI/PAX/PBX/PDX/PBP/etc. "pointer-register" macros); applies
+ * also to clobber lists
+ *
+ * 20070630:
+ * - cleaned up formatting, macros, minor png_read_filter_row_mmx_sub() 8-bpp
+ * register-usage inefficiency
+ * - fixed 32-bit png_do_read_interlace() bug (was using pointer size for
+ * 64-bit dummy values)
+ *
+ * 20070703:
+ * - added check for (manual) PIC macro to fix OpenBSD crash bug
+ *
+ * 20070717:
+ * - fixed 48-bit png_combine_row() bug (was acting like 32-bit): copy 6
+ * bytes per pixel, not 4, and use stride of 6, not 4, in the second loop
+ * of interlace processing of 48-bit pixels [GR-P]
+ *
+ * 20070722:
+ * - fixed 64-bit png_uint_32 bug with MMXLength/FullLength temp vars
+ *
+ * [still broken: tops of all row-filter blocks (input/output constraints);
+ * shows up on 64-bit dynamic (-fPIC) version with -O2, especially if debug-
+ * printfs enabled, but at right edge of odd-width images even if disabled]
+ *
+ *
+ * STILL TO DO:
+ * - fix final thread-unsafe code using stack vars and pointer? (paeth top,
+ * default, bottom only: default, bottom already 5 reg constraints; could
+ * replace bpp with pointer and group bpp/patemp/pbtemp/pctemp in array)
+ * - fix ebp/no-reg-constraint inefficiency (avg/paeth/sub top)
+ * - test png_do_read_interlace() 64-bit case (pixel_bytes == 8)
+ * - write MMX code for 48-bit case (pixel_bytes == 6)
+ * - figure out what's up with 24-bit case (pixel_bytes == 3):
+ * why subtract 8 from width_mmx in the pass 4/5 case? due to
+ * odd number of bytes? (only width_mmx case) (near line 2335)
+ * - rewrite all MMX interlacing code so it's aligned with beginning
+ * of the row buffer, not the end (see 19991007 for details)
+ * - add error messages to any remaining bogus default cases
+ * - enable pixel_depth == 8 cases in png_read_filter_row()? (test speed)
+ * - try =r, etc., as reg constraints? (would gcc use 64-bit ones on x86-64?)
+ * - need full, non-graphical, CRC-based test suite... maybe autogenerate
+ * random data of various height/width/depth, compute CRCs, write (C
+ * funcs), read (asm/MMX), recompute CRCs, and compare?
+ * - write true x86-64 version using 128-bit "media instructions", %xmm0-15,
+ * and extra general-purpose registers
+ */
+
+#if defined(__GNUC__)
+
+#define PNG_INTERNAL
+#include "png.h"
+
+
+/* for some inexplicable reason, gcc 3.3.5 on OpenBSD (and elsewhere?) does
+ * *not* define __PIC__ when the -fPIC option is used, so we have to rely on
+ * makefiles and whatnot to define the PIC macro explicitly */
+#if defined(PIC) && !defined(__PIC__) // (this can/should move to pngconf.h)
+# define __PIC__
+#endif
+
+#if defined(PNG_ASSEMBLER_CODE_SUPPORTED) && defined(PNG_USE_PNGGCCRD)
+
+/* if you want/need full thread-safety on x86-64 even when linking statically,
+ * comment out the "&& defined(__PIC__)" part here: */
+#if defined(__x86_64__) && defined(__PIC__)
+# define PNG_x86_64_USE_GOTPCREL // GOTPCREL => full thread-safety
+# define PNG_CLOBBER_x86_64_REGS_SUPPORTED // works as of gcc 3.4.3 ...
+#endif
+
+int PNGAPI png_mmx_support(void);
+
+#if defined(PNG_USE_LOCAL_ARRAYS)
+static PNG_CONST int FARDATA png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+static PNG_CONST int FARDATA png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+static PNG_CONST int FARDATA png_pass_width[7] = {8, 4, 4, 2, 2, 1, 1};
+#endif
+
+/* djgpp, Win32, Cygwin, and OS2 add their own underscores to global variables,
+ * so define them without: */
+#if defined(__DJGPP__) || defined(WIN32) || defined(__CYGWIN__) || \
+ defined(__OS2__)
+# define _mmx_supported mmx_supported
+# define _mask8_0 mask8_0
+# define _mask16_1 mask16_1
+# define _mask16_0 mask16_0
+# define _mask24_2 mask24_2
+# define _mask24_1 mask24_1
+# define _mask24_0 mask24_0
+# define _mask32_3 mask32_3
+# define _mask32_2 mask32_2
+# define _mask32_1 mask32_1
+# define _mask32_0 mask32_0
+# define _mask48_5 mask48_5
+# define _mask48_4 mask48_4
+# define _mask48_3 mask48_3
+# define _mask48_2 mask48_2
+# define _mask48_1 mask48_1
+# define _mask48_0 mask48_0
+# define _amask5_3_0 amask5_3_0
+# define _amask7_1_0 amask7_1_0
+# define _LBCarryMask LBCarryMask
+# define _HBClearMask HBClearMask
+# define _amask0_8_0 amask0_8_0
+# define _amask6_2_0 amask6_2_0
+# define _amask4_4_0 amask4_4_0
+# define _amask0_2_6 amask0_2_6
+# define _amask2_3_3 amask2_3_3
+# define _amask4_2_2 amask4_2_2
+# if defined(PNG_THREAD_UNSAFE_OK)
+# define _patemp patemp
+# define _pbtemp pbtemp
+# define _pctemp pctemp
+# endif
+#endif // djgpp, Win32, Cygwin, OS2
+
+
+/* These constants are used in the inlined MMX assembly code. */
+
+typedef unsigned long long ull;
+
+#if defined(PNG_x86_64_USE_GOTPCREL)
+static PNG_CONST struct {
+ //ull _mask_array[26];
+
+ // png_combine_row() constants:
+ ull _mask8_0;
+ ull _mask16_0, _mask16_1;
+ ull _mask24_0, _mask24_1, _mask24_2;
+ ull _mask32_0, _mask32_1, _mask32_2, _mask32_3;
+ ull _mask48_0, _mask48_1, _mask48_2, _mask48_3, _mask48_4, _mask48_5;
+
+ // png_do_read_interlace() constants:
+ ull _amask5_3_0, _amask7_1_0; // was _const4 and _const6, respectively
+
+ // png_read_filter_row_mmx_avg() constants (also uses _amask5_3_0):
+ ull _LBCarryMask, _HBClearMask;
+ ull _amask0_8_0, _amask6_2_0; // was ActiveMask for bpp 4/6 and 2 cases
+
+ // png_read_filter_row_mmx_paeth() constants (also uses _amask5_3_0):
+ ull _amask4_4_0, _amask0_2_6; // was ActiveMask{,End} for bpp 6/4/8 and 3
+
+ // png_read_filter_row_mmx_sub() constants:
+ ull _amask2_3_3, _amask4_2_2; // was ActiveMask for bpp 3 and 2 cases
+
+} _c64 __attribute__((used, aligned(8))) = {
+
+ // png_combine_row() constants:
+ 0x0102040810204080LL, // _mask8_0 offset 0
+
+ 0x1010202040408080LL, // _mask16_0 offset 8
+ 0x0101020204040808LL, // _mask16_1 offset 16
+
+ 0x2020404040808080LL, // _mask24_0 offset 24
+ 0x0408080810101020LL, // _mask24_1 offset 32
+ 0x0101010202020404LL, // _mask24_2 offset 40
+
+ 0x4040404080808080LL, // _mask32_0 offset 48
+ 0x1010101020202020LL, // _mask32_1 offset 56
+ 0x0404040408080808LL, // _mask32_2 offset 64
+ 0x0101010102020202LL, // _mask32_3 offset 72
+
+ 0x4040808080808080LL, // _mask48_0 offset 80
+ 0x2020202040404040LL, // _mask48_1 offset 88
+ 0x1010101010102020LL, // _mask48_2 offset 96
+ 0x0404080808080808LL, // _mask48_3 offset 104
+ 0x0202020204040404LL, // _mask48_4 offset 112
+ 0x0101010101010202LL, // _mask48_5 offset 120
+
+ // png_do_read_interlace() constants:
+ 0x0000000000FFFFFFLL, // _amask5_3_0 offset 128 (bpp 3, avg/paeth) const4
+ 0x00000000000000FFLL, // _amask7_1_0 offset 136 const6
+
+ // png_read_filter_row_mmx_avg() constants:
+ 0x0101010101010101LL, // _LBCarryMask offset 144
+ 0x7F7F7F7F7F7F7F7FLL, // _HBClearMask offset 152
+ 0xFFFFFFFFFFFFFFFFLL, // _amask0_8_0 offset 160 (bpp 4/6, avg)
+ 0x000000000000FFFFLL, // _amask6_2_0 offset 168 (bpp 2, avg)
+
+ // png_read_filter_row_mmx_paeth() constants:
+ 0x00000000FFFFFFFFLL, // _amask4_4_0 offset 176 (bpp 6/4/8, paeth)
+ 0xFFFF000000000000LL, // _amask0_2_6 offset 184 (bpp 3, paeth) A.M.End
+
+ // png_read_filter_row_mmx_sub() constants:
+ 0x0000FFFFFF000000LL, // _amask2_3_3 offset 192 (bpp 3, sub)
+ 0x00000000FFFF0000LL, // _amask4_2_2 offset 200 (bpp 2, sub)
+
+};
+
+#define MASK8_0 "(%%rbp)"
+#define MASK16_0 "8(%%rbp)"
+#define MASK16_1 "16(%%rbp)"
+#define MASK24_0 "24(%%rbp)"
+#define MASK24_1 "32(%%rbp)"
+#define MASK24_2 "40(%%rbp)"
+#define MASK32_0 "48(%%rbp)"
+#define MASK32_1 "56(%%rbp)"
+#define MASK32_2 "64(%%rbp)"
+#define MASK32_3 "72(%%rbp)"
+#define MASK48_0 "80(%%rbp)"
+#define MASK48_1 "88(%%rbp)"
+#define MASK48_2 "96(%%rbp)"
+#define MASK48_3 "104(%%rbp)"
+#define MASK48_4 "112(%%rbp)"
+#define MASK48_5 "120(%%rbp)"
+#define AMASK5_3_0 "128(%%rbp)"
+#define AMASK7_1_0 "136(%%rbp)"
+#define LB_CARRY_MASK "144(%%rbp)"
+#define HB_CLEAR_MASK "152(%%rbp)"
+#define AMASK0_8_0 "160(%%rbp)"
+#define AMASK6_2_0 "168(%%rbp)"
+#define AMASK4_4_0 "176(%%rbp)"
+#define AMASK0_2_6 "184(%%rbp)"
+#define AMASK2_3_3 "192(%%rbp)"
+#define AMASK4_2_2 "200(%%rbp)"
+
+#else // !PNG_x86_64_USE_GOTPCREL
+
+static PNG_CONST ull _mask8_0 __attribute__((used, aligned(8))) = 0x0102040810204080LL;
+
+static PNG_CONST ull _mask16_1 __attribute__((used, aligned(8))) = 0x0101020204040808LL;
+static PNG_CONST ull _mask16_0 __attribute__((used, aligned(8))) = 0x1010202040408080LL;
+
+static PNG_CONST ull _mask24_2 __attribute__((used, aligned(8))) = 0x0101010202020404LL;
+static PNG_CONST ull _mask24_1 __attribute__((used, aligned(8))) = 0x0408080810101020LL;
+static PNG_CONST ull _mask24_0 __attribute__((used, aligned(8))) = 0x2020404040808080LL;
+
+static PNG_CONST ull _mask32_3 __attribute__((used, aligned(8))) = 0x0101010102020202LL;
+static PNG_CONST ull _mask32_2 __attribute__((used, aligned(8))) = 0x0404040408080808LL;
+static PNG_CONST ull _mask32_1 __attribute__((used, aligned(8))) = 0x1010101020202020LL;
+static PNG_CONST ull _mask32_0 __attribute__((used, aligned(8))) = 0x4040404080808080LL;
+
+static PNG_CONST ull _mask48_5 __attribute__((used, aligned(8))) = 0x0101010101010202LL;
+static PNG_CONST ull _mask48_4 __attribute__((used, aligned(8))) = 0x0202020204040404LL;
+static PNG_CONST ull _mask48_3 __attribute__((used, aligned(8))) = 0x0404080808080808LL;
+static PNG_CONST ull _mask48_2 __attribute__((used, aligned(8))) = 0x1010101010102020LL;
+static PNG_CONST ull _mask48_1 __attribute__((used, aligned(8))) = 0x2020202040404040LL;
+static PNG_CONST ull _mask48_0 __attribute__((used, aligned(8))) = 0x4040808080808080LL;
+
+// png_do_read_interlace() constants:
+static PNG_CONST ull _amask5_3_0 __attribute__((aligned(8))) = 0x0000000000FFFFFFLL; // was _const4
+static PNG_CONST ull _amask7_1_0 __attribute__((aligned(8))) = 0x00000000000000FFLL; // was _const6
+
+// png_read_filter_row_mmx_avg() constants:
+static PNG_CONST ull _LBCarryMask __attribute__((used, aligned(8))) = 0x0101010101010101LL;
+static PNG_CONST ull _HBClearMask __attribute__((used, aligned(8))) = 0x7f7f7f7f7f7f7f7fLL;
+static PNG_CONST ull _amask0_8_0 __attribute__((used, aligned(8))) = 0xFFFFFFFFFFFFFFFFLL;
+static PNG_CONST ull _amask6_2_0 __attribute__((used, aligned(8))) = 0x000000000000FFFFLL;
+
+// png_read_filter_row_mmx_paeth() constants:
+static PNG_CONST ull _amask4_4_0 __attribute__((used, aligned(8))) = 0x00000000FFFFFFFFLL;
+static PNG_CONST ull _amask0_2_6 __attribute__((used, aligned(8))) = 0xFFFF000000000000LL;
+
+// png_read_filter_row_mmx_sub() constants:
+static PNG_CONST ull _amask2_3_3 __attribute__((used, aligned(8))) = 0x0000FFFFFF000000LL;
+static PNG_CONST ull _amask4_2_2 __attribute__((used, aligned(8))) = 0x00000000FFFF0000LL;
+
+#define MASK8_0 "_mask8_0"
+#define MASK16_0 "_mask16_0"
+#define MASK16_1 "_mask16_1"
+#define MASK24_0 "_mask24_0"
+#define MASK24_1 "_mask24_1"
+#define MASK24_2 "_mask24_2"
+#define MASK32_0 "_mask32_0"
+#define MASK32_1 "_mask32_1"
+#define MASK32_2 "_mask32_2"
+#define MASK32_3 "_mask32_3"
+#define MASK48_0 "_mask48_0"
+#define MASK48_1 "_mask48_1"
+#define MASK48_2 "_mask48_2"
+#define MASK48_3 "_mask48_3"
+#define MASK48_4 "_mask48_4"
+#define MASK48_5 "_mask48_5"
+#define AMASK5_3_0 "_amask5_3_0"
+#define AMASK7_1_0 "_amask7_1_0"
+#define LB_CARRY_MASK "_LBCarryMask"
+#define HB_CLEAR_MASK "_HBClearMask"
+#define AMASK0_8_0 "_amask0_8_0"
+#define AMASK6_2_0 "_amask6_2_0"
+#define AMASK4_4_0 "_amask4_4_0"
+#define AMASK0_2_6 "_amask0_2_6"
+#define AMASK2_3_3 "_amask2_3_3"
+#define AMASK4_2_2 "_amask4_2_2"
+
+#endif // ?PNG_x86_64_USE_GOTPCREL
+
+
+#if defined(PNG_HAVE_MMX_READ_FILTER_ROW) || defined(PNG_HAVE_MMX_COMBINE_ROW)
+
+// this block is specific to png_read_filter_row_mmx_paeth() except for
+// LOAD_GOT_rbp and RESTORE_rbp, which are also used in png_combine_row()
+#if defined(PNG_x86_64_USE_GOTPCREL)
+# define pa_TEMP "%%r11d"
+# define pb_TEMP "%%r12d"
+# define pc_TEMP "%%r13d"
+# if defined(PNG_CLOBBER_x86_64_REGS_SUPPORTED) // works as of gcc 3.4.3 ...
+# define SAVE_r11_r12_r13
+# define RESTORE_r11_r12_r13
+# define _CLOBBER_r11_r12_r13 ,"%r11", "%r12", "%r13"
+# define CLOBBER_r11_r12_r13 "%r11", "%r12", "%r13"
+# else // !PNG_CLOBBER_x86_64_REGS_SUPPORTED
+# define SAVE_r11_r12_r13 "pushq %%r11 \n\t" \
+ "pushq %%r12 \n\t" \
+ "pushq %%r13 \n\t" // "normally 0-extended"
+# define RESTORE_r11_r12_r13 "popq %%r13 \n\t" \
+ "popq %%r12 \n\t" \
+ "popq %%r11 \n\t"
+# define _CLOBBER_r11_r12_r13
+# define CLOBBER_r11_r12_r13
+# endif
+# define LOAD_GOT_rbp "pushq %%rbp \n\t" \
+ "movq _c64@GOTPCREL(%%rip), %%rbp \n\t"
+# define RESTORE_rbp "popq %%rbp \n\t"
+#else // 32-bit and/or non-PIC
+# if defined(PNG_THREAD_UNSAFE_OK)
+ // These variables are used in png_read_filter_row_mmx_paeth() and would be
+ // local variables if not for gcc-inline-assembly addressing limitations
+ // (some apparently related to ELF format, others to CPU type).
+ //
+ // WARNING: Their presence defeats the thread-safety of libpng.
+ static int _patemp __attribute__((used));
+ static int _pbtemp __attribute__((used));
+ static int _pctemp __attribute__((used));
+# define pa_TEMP "_patemp"
+# define pb_TEMP "_pbtemp" // temp variables for
+# define pc_TEMP "_pctemp" // Paeth routine
+# define SAVE_r11_r12_r13
+# define RESTORE_r11_r12_r13
+# define _CLOBBER_r11_r12_r13 // not using regs => not clobbering
+# define CLOBBER_r11_r12_r13
+# endif // PNG_THREAD_UNSAFE_OK
+# define LOAD_GOT_rbp
+# define RESTORE_rbp
+#endif
+
+#if defined(__x86_64__)
+# define SAVE_ebp
+# define RESTORE_ebp
+# define _CLOBBER_ebp ,"%ebp"
+# define CLOBBER_ebp "%ebp"
+# define SAVE_FullLength "movl %%eax, %%r15d \n\t"
+# define RESTORE_FullLength "movl %%r15d, " // may go into eax or ecx
+# if defined(PNG_CLOBBER_x86_64_REGS_SUPPORTED) // works as of gcc 3.4.3 ...
+# define SAVE_r15
+# define RESTORE_r15
+# define _CLOBBER_r15 ,"%r15"
+# else
+# define SAVE_r15 "pushq %%r15 \n\t"
+# define RESTORE_r15 "popq %%r15 \n\t"
+# define _CLOBBER_r15
+# endif
+# define PBP "%%rbp" // regs used for 64-bit
+# define PAX "%%rax" // pointers or in
+# define PBX "%%rbx" // combination with
+# define PCX "%%rcx" // 64-bit pointer-regs
+# define PDX "%%rdx" // (base/index pairs,
+# define PSI "%%rsi" // add/sub/mov pairs)
+# define CLEAR_BOTTOM_3_BITS "and $0xfffffffffffffff8, "
+#else
+# define SAVE_ebp "pushl %%ebp \n\t" // clobber list doesn't work
+# define RESTORE_ebp "popl %%ebp \n\t" // for %ebp on 32-bit; not
+# define _CLOBBER_ebp // clear why not
+# define CLOBBER_ebp
+# define SAVE_FullLength "pushl %%eax \n\t"
+# define RESTORE_FullLength "popl " // eax (avg) or ecx (paeth)
+# define SAVE_r15
+# define RESTORE_r15
+# define _CLOBBER_r15
+# define PBP "%%ebp" // regs used for or in
+# define PAX "%%eax" // combination with
+# define PBX "%%ebx" // "normal," 32-bit
+# define PCX "%%ecx" // pointers
+# define PDX "%%edx"
+# define PSI "%%esi"
+# define CLEAR_BOTTOM_3_BITS "and $0xfffffff8, "
+#endif
+
+// CLOB_COMMA_ebx_ebp: need comma ONLY if both CLOBBER_ebp and CLOBBER_GOT_ebx
+// have values, i.e., only if __x86_64__ AND !__PIC__
+#if defined(__x86_64__) && !defined(__PIC__)
+# define CLOB_COMMA_ebx_ebp , // clobbering both ebp and ebx => need comma
+#else
+# define CLOB_COMMA_ebx_ebp
+#endif
+
+// CLOB_COMMA_ebX_r1X: need comma UNLESS both CLOBBER_ebp and CLOBBER_GOT_ebx
+// are empty OR CLOBBER_r11_r12_r13 is empty--i.e., NO comma
+// if (!__x86_64__ AND __PIC__) OR !(PNG_x86_64_USE_GOTPCREL
+// AND PNG_CLOBBER_x86_64_REGS_SUPPORTED) (double sigh...)
+#if (!defined(__x86_64__) && defined(__PIC__)) || \
+ !defined(PNG_x86_64_USE_GOTPCREL) || \
+ !defined(PNG_CLOBBER_x86_64_REGS_SUPPORTED)
+# define CLOB_COMMA_ebX_r1X
+#else
+# define CLOB_COMMA_ebX_r1X , // clobbering (ebp OR ebx) AND r11_r12_r13
+#endif
+
+// CLOB_COLON_ebx_ebp: need colon unless CLOBBER_ebp and CLOBBER_GOT_ebx are
+// BOTH empty--i.e., NO colon if (!__x86_64__ AND __PIC__)
+// CLOB_COLON_ebx_ebp_r1X: if, in addition, CLOBBER_r11_r12_r13 is empty, then
+// no colon for Paeth blocks, either--i.e., NO colon
+// if !(PNG_x86_64_USE_GOTPCREL AND
+// PNG_CLOBBER_x86_64_REGS_SUPPORTED)
+#if (!defined(__x86_64__) && defined(__PIC__))
+# define CLOB_COLON_ebx_ebp
+# if !(defined(PNG_x86_64_USE_GOTPCREL) && \
+ defined(PNG_CLOBBER_x86_64_REGS_SUPPORTED))
+# define CLOB_COLON_ebx_ebp_r1X
+# else
+# define CLOB_COLON_ebx_ebp_r1X : // clobbering ebp OR ebx OR r11_r12_r13
+# endif
+#else
+# define CLOB_COLON_ebx_ebp : // clobbering ebp OR ebx
+# define CLOB_COLON_ebx_ebp_r1X : // clobbering ebp OR ebx OR r11_r12_r13
+#endif
+
+#endif // PNG_HAVE_MMX_READ_FILTER_ROW
+
+#if defined(__PIC__) // macros to save, restore index to Global Offset Table
+# if defined(__x86_64__)
+# define SAVE_GOT_ebx "pushq %%rbx \n\t"
+# define RESTORE_GOT_ebx "popq %%rbx \n\t"
+# else
+# define SAVE_GOT_ebx "pushl %%ebx \n\t"
+# define RESTORE_GOT_ebx "popl %%ebx \n\t"
+# endif
+# define _CLOBBER_GOT_ebx // explicitly saved, restored => not clobbered
+# define CLOBBER_GOT_ebx
+#else
+# define SAVE_GOT_ebx
+# define RESTORE_GOT_ebx
+# define _CLOBBER_GOT_ebx ,"%ebx"
+# define CLOBBER_GOT_ebx "%ebx"
+#endif
+
+#if defined(PNG_HAVE_MMX_COMBINE_ROW) || defined(PNG_HAVE_MMX_READ_INTERLACE)
+# define BPP2 2
+# define BPP3 3 // bytes per pixel (a.k.a. pixel_bytes)
+# define BPP4 4 // (defined only to help avoid cut-and-paste errors)
+# define BPP6 6
+# define BPP8 8
+#endif
+
+
+
+static int _mmx_supported = 2; // 0: no MMX; 1: MMX supported; 2: not tested
+
+/*===========================================================================*/
+/* */
+/* P N G _ M M X _ S U P P O R T */
+/* */
+/*===========================================================================*/
+
+// GRR NOTES: (1) the following code assumes 386 or better (pushfl/popfl)
+// (2) all instructions compile with gcc 2.7.2.3 and later
+// x (3) the function is moved down here to prevent gcc from
+// x inlining it in multiple places and then barfing be-
+// x cause the ".NOT_SUPPORTED" label is multiply defined
+// [need to retest with gcc 2.7.2.3]
+
+// GRR 20070524: This declaration apparently is compatible with but supersedes
+// the one in png.h; in any case, the generated object file is slightly
+// smaller. It is unnecessary with gcc 4.1.2, but gcc 2.x apparently
+// replicated the ".NOT_SUPPORTED" label in each location the function was
+// inlined, leading to compilation errors due to the "multiply defined"
+// label. Old workaround was to leave the function at the end of this
+// file; new one (still testing) is to use a gcc-specific function attribute
+// to prevent local inlining.
+int PNGAPI
+png_mmx_support(void) __attribute__((noinline));
+
+int PNGAPI
+png_mmx_support(void)
+{
+#if defined(PNG_MMX_CODE_SUPPORTED) // superfluous, but what the heck
+ int result;
+ __asm__ __volatile__ (
+#if defined(__x86_64__)
+ "pushq %%rbx \n\t" // rbx gets clobbered by CPUID instruction
+ "pushq %%rcx \n\t" // so does rcx...
+ "pushq %%rdx \n\t" // ...and rdx (but rcx & rdx safe on Linux)
+ "pushfq \n\t" // save Eflag to stack
+ "popq %%rax \n\t" // get Eflag from stack into rax
+ "movq %%rax, %%rcx \n\t" // make another copy of Eflag in rcx
+ "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21)
+ "pushq %%rax \n\t" // save modified Eflag back to stack
+ "popfq \n\t" // restore modified value to Eflag reg
+ "pushfq \n\t" // save Eflag to stack
+ "popq %%rax \n\t" // get Eflag from stack
+ "pushq %%rcx \n\t" // save original Eflag to stack
+ "popfq \n\t" // restore original Eflag
+#else
+ "pushl %%ebx \n\t" // ebx gets clobbered by CPUID instruction
+ "pushl %%ecx \n\t" // so does ecx...
+ "pushl %%edx \n\t" // ...and edx (but ecx & edx safe on Linux)
+ "pushfl \n\t" // save Eflag to stack
+ "popl %%eax \n\t" // get Eflag from stack into eax
+ "movl %%eax, %%ecx \n\t" // make another copy of Eflag in ecx
+ "xorl $0x200000, %%eax \n\t" // toggle ID bit in Eflag (i.e., bit 21)
+ "pushl %%eax \n\t" // save modified Eflag back to stack
+ "popfl \n\t" // restore modified value to Eflag reg
+ "pushfl \n\t" // save Eflag to stack
+ "popl %%eax \n\t" // get Eflag from stack
+ "pushl %%ecx \n\t" // save original Eflag to stack
+ "popfl \n\t" // restore original Eflag
+#endif
+ "xorl %%ecx, %%eax \n\t" // compare new Eflag with original Eflag
+ "jz 0f \n\t" // if same, CPUID instr. is not supported
+
+ "xorl %%eax, %%eax \n\t" // set eax to zero
+// ".byte 0x0f, 0xa2 \n\t" // CPUID instruction (two-byte opcode)
+ "cpuid \n\t" // get the CPU identification info
+ "cmpl $1, %%eax \n\t" // make sure eax return non-zero value
+ "jl 0f \n\t" // if eax is zero, MMX is not supported
+
+ "xorl %%eax, %%eax \n\t" // set eax to zero and...
+ "incl %%eax \n\t" // ...increment eax to 1. This pair is
+ // faster than the instruction "mov eax, 1"
+ "cpuid \n\t" // get the CPU identification info again
+ "andl $0x800000, %%edx \n\t" // mask out all bits but MMX bit (23)
+ "cmpl $0, %%edx \n\t" // 0 = MMX not supported
+ "jz 0f \n\t" // non-zero = yes, MMX IS supported
+
+ "movl $1, %%eax \n\t" // set return value to 1
+ "jmp 1f \n\t" // DONE: have MMX support
+
+ "0: \n\t" // .NOT_SUPPORTED: target label for jump instructions
+ "movl $0, %%eax \n\t" // set return value to 0
+ "1: \n\t" // .RETURN: target label for jump instructions
+#if defined(__x86_64__)
+ "popq %%rdx \n\t" // restore rdx
+ "popq %%rcx \n\t" // restore rcx
+ "popq %%rbx \n\t" // restore rbx
+#else
+ "popl %%edx \n\t" // restore edx
+ "popl %%ecx \n\t" // restore ecx
+ "popl %%ebx \n\t" // restore ebx
+#endif
+
+// "ret \n\t" // DONE: no MMX support
+ // (fall through to standard C "ret")
+
+ : "=a" (result) // output list
+
+ : // any variables used on input (none)
+
+ // no clobber list
+// , "%ebx", "%ecx", "%edx" // GRR: we handle these manually
+// , "memory" // if write to a variable gcc thought was in a reg
+// , "cc" // "condition codes" (flag bits)
+ );
+ _mmx_supported = result;
+#else
+ _mmx_supported = 0;
+#endif /* PNG_MMX_CODE_SUPPORTED */
+
+ return _mmx_supported;
+}
+
+
+/*===========================================================================*/
+/* */
+/* P N G _ C O M B I N E _ R O W */
+/* */
+/*===========================================================================*/
+
+#if defined(PNG_HAVE_MMX_COMBINE_ROW)
+
+/* Combines the row recently read in with the previous row.
+ This routine takes care of alpha and transparency if requested.
+ This routine also handles the two methods of progressive display
+ of interlaced images, depending on the mask value.
+ The mask value describes which pixels are to be combined with
+ the row. The pattern always repeats every 8 pixels, so just 8
+ bits are needed. A one indicates the pixel is to be combined; a
+ zero indicates the pixel is to be skipped. This is in addition
+ to any alpha or transparency value associated with the pixel.
+ If you want all pixels to be combined, pass 0xff (255) in mask. */
+
+/* Use this routine for the x86 platform - it uses a faster MMX routine
+ if the machine supports MMX. */
+
+void /* PRIVATE */
+png_combine_row(png_structp png_ptr, png_bytep row, int mask)
+{
+ int dummy_value_a; // fix 'forbidden register spilled' error
+ int dummy_value_c;
+ int dummy_value_d;
+ png_bytep dummy_value_S;
+ png_bytep dummy_value_D;
+
+ png_debug(1, "in png_combine_row (pnggccrd.c)\n");
+
+ if (_mmx_supported == 2) {
+#if !defined(PNG_1_0_X)
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+#endif
+ png_mmx_support();
+ }
+
+ if (mask == 0xff)
+ {
+ png_debug(2,"mask == 0xff: doing single png_memcpy()\n");
+ png_memcpy(row, png_ptr->row_buf + 1,
+ (png_size_t)PNG_ROWBYTES(png_ptr->row_info.pixel_depth,png_ptr->width));
+ }
+ else /* (png_combine_row() is never called with mask == 0) */
+ {
+ switch (png_ptr->row_info.pixel_depth)
+ {
+ case 24: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+#if !defined(PNG_1_0_X)
+ if (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+#else
+ if (_mmx_supported)
+#endif
+ {
+ png_uint_32 len;
+ int diff;
+
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ len = png_ptr->width & ~7; // reduce to multiple of 8
+ diff = (int) (png_ptr->width & 7); // amount lost
+
+ __asm__ __volatile__ (
+ "not %%edx \n\t" // mask => unmask
+ "movd %%edx, %%mm7 \n\t" // load bit pattern
+ "not %%edx \n\t" // unmask => mask for later
+ "psubb %%mm6, %%mm6 \n\t" // zero mm6
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks
+
+ LOAD_GOT_rbp
+ "movq " MASK24_0 ", %%mm0 \n\t" // _mask24_0 -> mm0
+ "movq " MASK24_1 ", %%mm1 \n\t" // _mask24_1 -> mm1
+ "movq " MASK24_2 ", %%mm2 \n\t" // _mask24_2 -> mm2
+ RESTORE_rbp
+
+ "pand %%mm7, %%mm0 \n\t"
+ "pand %%mm7, %%mm1 \n\t"
+ "pand %%mm7, %%mm2 \n\t"
+
+ "pcmpeqb %%mm6, %%mm0 \n\t"
+ "pcmpeqb %%mm6, %%mm1 \n\t"
+ "pcmpeqb %%mm6, %%mm2 \n\t"
+
+// preload "movl len, %%ecx \n\t" // load length of line
+// preload "movl srcptr, %3 \n\t" // load source
+// preload "movl dstptr, %4 \n\t" // load dest
+
+ "cmpl $0, %%ecx \n\t"
+ "jz mainloop24end \n\t"
+
+ "mainloop24: \n\t"
+ "movq (%3), %%mm4 \n\t"
+ "pand %%mm0, %%mm4 \n\t"
+ "movq %%mm0, %%mm6 \n\t"
+ "movq (%4), %%mm7 \n\t"
+ "pandn %%mm7, %%mm6 \n\t"
+ "por %%mm6, %%mm4 \n\t"
+ "movq %%mm4, (%4) \n\t"
+
+ "movq 8(%3), %%mm5 \n\t"
+ "pand %%mm1, %%mm5 \n\t"
+ "movq %%mm1, %%mm7 \n\t"
+ "movq 8(%4), %%mm6 \n\t"
+ "pandn %%mm6, %%mm7 \n\t"
+ "por %%mm7, %%mm5 \n\t"
+ "movq %%mm5, 8(%4) \n\t"
+
+ "movq 16(%3), %%mm6 \n\t"
+ "pand %%mm2, %%mm6 \n\t"
+ "movq %%mm2, %%mm4 \n\t"
+ "movq 16(%4), %%mm7 \n\t"
+ "pandn %%mm7, %%mm4 \n\t"
+ "por %%mm4, %%mm6 \n\t"
+ "movq %%mm6, 16(%4) \n\t"
+
+ "add $24, %3 \n\t" // inc by 24 bytes processed
+ "add $24, %4 \n\t"
+ "subl $8, %%ecx \n\t" // dec by 8 pixels processed
+
+ "ja mainloop24 \n\t"
+
+ "mainloop24end: \n\t"
+// preload "movl diff, %%ecx \n\t" // (diff is in eax)
+ "movl %%eax, %%ecx \n\t"
+ "cmpl $0, %%ecx \n\t"
+ "jz end24 \n\t"
+// preload "movl mask, %%edx \n\t"
+ "sall $24, %%edx \n\t" // make low byte, high byte
+
+ "secondloop24: \n\t"
+ "sall %%edx \n\t" // move high bit to CF
+ "jnc skip24 \n\t" // if CF = 0
+ "movw (%3), %%ax \n\t"
+ "movw %%ax, (%4) \n\t"
+ "xorl %%eax, %%eax \n\t"
+ "movb 2(%3), %%al \n\t"
+ "movb %%al, 2(%4) \n\t"
+
+ "skip24: \n\t"
+ "add $3, %3 \n\t"
+ "add $3, %4 \n\t"
+ "decl %%ecx \n\t"
+ "jnz secondloop24 \n\t"
+
+ "end24: \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=a" (dummy_value_a), // output regs (dummy)
+ "=d" (dummy_value_d),
+ "=c" (dummy_value_c),
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (diff), // eax // input regs
+ "1" (mask), // edx
+ "2" (len), // ecx
+// was (unmask) "b" RESERVED // ebx // Global Offset Table idx
+ "3" (srcptr), // esi/rsi
+ "4" (dstptr) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ else /* not _mmx_supported - use modified C routine */
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP3 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP3 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP3 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP3 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff*BPP3;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 24 bpp */
+
+ // formerly claimed to be most common case (combining 32-bit RGBA),
+ // but almost certainly less common than 24-bit RGB case
+ case 32: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+#if !defined(PNG_1_0_X)
+ if (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+#else
+ if (_mmx_supported)
+#endif
+ {
+ png_uint_32 len;
+ int diff;
+
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ len = png_ptr->width & ~7; // reduce to multiple of 8
+ diff = (int) (png_ptr->width & 7); // amount lost
+
+ __asm__ __volatile__ (
+ "not %%edx \n\t" // mask => unmask
+ "movd %%edx, %%mm7 \n\t" // load bit pattern
+ "not %%edx \n\t" // unmask => mask for later
+ "psubb %%mm6, %%mm6 \n\t" // zero mm6
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks
+
+ LOAD_GOT_rbp
+ "movq " MASK32_0 ", %%mm0 \n\t" // _mask32_0
+ "movq " MASK32_1 ", %%mm1 \n\t" // _mask32_1
+ "movq " MASK32_2 ", %%mm2 \n\t" // _mask32_2
+ "movq " MASK32_3 ", %%mm3 \n\t" // _mask32_3
+ RESTORE_rbp
+
+ "pand %%mm7, %%mm0 \n\t"
+ "pand %%mm7, %%mm1 \n\t"
+ "pand %%mm7, %%mm2 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+
+ "pcmpeqb %%mm6, %%mm0 \n\t"
+ "pcmpeqb %%mm6, %%mm1 \n\t"
+ "pcmpeqb %%mm6, %%mm2 \n\t"
+ "pcmpeqb %%mm6, %%mm3 \n\t"
+
+// preload "movl len, %%ecx \n\t" // load length of line
+// preload "movl srcptr, %3 \n\t" // load source
+// preload "movl dstptr, %4 \n\t" // load dest
+
+ "cmpl $0, %%ecx \n\t" // lcr
+ "jz mainloop32end \n\t"
+
+ "mainloop32: \n\t"
+ "movq (%3), %%mm4 \n\t"
+ "pand %%mm0, %%mm4 \n\t"
+ "movq %%mm0, %%mm6 \n\t"
+ "movq (%4), %%mm7 \n\t"
+ "pandn %%mm7, %%mm6 \n\t"
+ "por %%mm6, %%mm4 \n\t"
+ "movq %%mm4, (%4) \n\t"
+
+ "movq 8(%3), %%mm5 \n\t"
+ "pand %%mm1, %%mm5 \n\t"
+ "movq %%mm1, %%mm7 \n\t"
+ "movq 8(%4), %%mm6 \n\t"
+ "pandn %%mm6, %%mm7 \n\t"
+ "por %%mm7, %%mm5 \n\t"
+ "movq %%mm5, 8(%4) \n\t"
+
+ "movq 16(%3), %%mm6 \n\t"
+ "pand %%mm2, %%mm6 \n\t"
+ "movq %%mm2, %%mm4 \n\t"
+ "movq 16(%4), %%mm7 \n\t"
+ "pandn %%mm7, %%mm4 \n\t"
+ "por %%mm4, %%mm6 \n\t"
+ "movq %%mm6, 16(%4) \n\t"
+
+ "movq 24(%3), %%mm7 \n\t"
+ "pand %%mm3, %%mm7 \n\t"
+ "movq %%mm3, %%mm5 \n\t"
+ "movq 24(%4), %%mm4 \n\t"
+ "pandn %%mm4, %%mm5 \n\t"
+ "por %%mm5, %%mm7 \n\t"
+ "movq %%mm7, 24(%4) \n\t"
+
+ "add $32, %3 \n\t" // inc by 32 bytes processed
+ "add $32, %4 \n\t"
+ "subl $8, %%ecx \n\t" // dec by 8 pixels processed
+ "ja mainloop32 \n\t"
+
+ "mainloop32end: \n\t"
+// preload "movl diff, %%ecx \n\t" // (diff is in eax)
+ "movl %%eax, %%ecx \n\t"
+ "cmpl $0, %%ecx \n\t"
+ "jz end32 \n\t"
+// preload "movl mask, %%edx \n\t"
+ "sall $24, %%edx \n\t" // low byte => high byte
+
+ "secondloop32: \n\t"
+ "sall %%edx \n\t" // move high bit to CF
+ "jnc skip32 \n\t" // if CF = 0
+ "movl (%3), %%eax \n\t"
+ "movl %%eax, (%4) \n\t"
+
+ "skip32: \n\t"
+ "add $4, %3 \n\t"
+ "add $4, %4 \n\t"
+ "decl %%ecx \n\t"
+ "jnz secondloop32 \n\t"
+
+ "end32: \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=a" (dummy_value_a), // output regs (dummy)
+ "=d" (dummy_value_d),
+ "=c" (dummy_value_c),
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (diff), // eax // input regs
+ "1" (mask), // edx
+ "2" (len), // ecx
+// was (unmask) "b" RESERVED // ebx // Global Offset Table idx
+ "3" (srcptr), // esi/rsi
+ "4" (dstptr) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ else /* not _mmx_supported - use modified C routine */
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP4 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP4 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP4 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP4 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff*BPP4;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 32 bpp */
+
+ case 8: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+#if !defined(PNG_1_0_X)
+ if (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+#else
+ if (_mmx_supported)
+#endif
+ {
+ png_uint_32 len;
+ int diff;
+
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ len = png_ptr->width & ~7; // reduce to multiple of 8
+ diff = (int) (png_ptr->width & 7); // amount lost
+
+ __asm__ __volatile__ (
+ "not %%edx \n\t" // mask => unmask
+ "movd %%edx, %%mm7 \n\t" // load bit pattern
+ "not %%edx \n\t" // unmask => mask for later
+ "psubb %%mm6, %%mm6 \n\t" // zero mm6
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks
+
+ LOAD_GOT_rbp
+ "movq " MASK8_0 ", %%mm0 \n\t" // _mask8_0 -> mm0
+ RESTORE_rbp
+
+ "pand %%mm7, %%mm0 \n\t" // nonzero if keep byte
+ "pcmpeqb %%mm6, %%mm0 \n\t" // zeros->1s, v versa
+
+// preload "movl len, %%ecx \n\t" // load length of line
+// preload "movl srcptr, %3 \n\t" // load source
+// preload "movl dstptr, %4 \n\t" // load dest
+
+ "cmpl $0, %%ecx \n\t" // len == 0 ?
+ "je mainloop8end \n\t"
+
+ "mainloop8: \n\t"
+ "movq (%3), %%mm4 \n\t" // *srcptr
+ "pand %%mm0, %%mm4 \n\t"
+ "movq %%mm0, %%mm6 \n\t"
+ "pandn (%4), %%mm6 \n\t" // *dstptr
+ "por %%mm6, %%mm4 \n\t"
+ "movq %%mm4, (%4) \n\t"
+ "add $8, %3 \n\t" // inc by 8 bytes processed
+ "add $8, %4 \n\t"
+ "subl $8, %%ecx \n\t" // dec by 8 pixels processed
+ "ja mainloop8 \n\t"
+
+ "mainloop8end: \n\t"
+// preload "movl diff, %%ecx \n\t" // (diff is in eax)
+ "movl %%eax, %%ecx \n\t"
+ "cmpl $0, %%ecx \n\t"
+ "jz end8 \n\t"
+// preload "movl mask, %%edx \n\t"
+ "sall $24, %%edx \n\t" // make low byte, high byte
+
+ "secondloop8: \n\t"
+ "sall %%edx \n\t" // move high bit to CF
+ "jnc skip8 \n\t" // if CF = 0
+ "movb (%3), %%al \n\t"
+ "movb %%al, (%4) \n\t"
+
+ "skip8: \n\t"
+ "inc %3 \n\t"
+ "inc %4 \n\t"
+ "decl %%ecx \n\t"
+ "jnz secondloop8 \n\t"
+
+ "end8: \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=a" (dummy_value_a), // output regs (dummy)
+ "=d" (dummy_value_d),
+ "=c" (dummy_value_c),
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (diff), // eax // input regs
+ "1" (mask), // edx
+ "2" (len), // ecx
+// was (unmask) "b" RESERVED // ebx // Global Offset Table idx
+ "3" (srcptr), // esi/rsi
+ "4" (dstptr) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm4", "%mm6", "%mm7" // clobber list
+#endif
+ );
+ }
+ else /* not _mmx_supported - use modified C routine */
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff /* *BPP1 */ ;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 8 bpp */
+
+ case 1: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_inc, s_start, s_end;
+ int m;
+ int shift;
+ png_uint_32 i;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+ else
+#endif
+ {
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ int value;
+
+ value = (*sp >> shift) & 0x1;
+ *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ } /* end 1 bpp */
+
+ case 2: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+ else
+#endif
+ {
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ } /* end 2 bpp */
+
+ case 4: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+ else
+#endif
+ {
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ } /* end 4 bpp */
+
+ case 16: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+#if !defined(PNG_1_0_X)
+ if (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+#else
+ if (_mmx_supported)
+#endif
+ {
+ png_uint_32 len;
+ int diff;
+
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ len = png_ptr->width & ~7; // reduce to multiple of 8
+ diff = (int) (png_ptr->width & 7); // amount lost
+
+ __asm__ __volatile__ (
+ "not %%edx \n\t" // mask => unmask
+ "movd %%edx, %%mm7 \n\t" // load bit pattern
+ "not %%edx \n\t" // unmask => mask for later
+ "psubb %%mm6, %%mm6 \n\t" // zero mm6
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks
+
+ LOAD_GOT_rbp
+ "movq " MASK16_0 ", %%mm0 \n\t" // _mask16_0 -> mm0
+ "movq " MASK16_1 ", %%mm1 \n\t" // _mask16_1 -> mm1
+ RESTORE_rbp
+
+ "pand %%mm7, %%mm0 \n\t"
+ "pand %%mm7, %%mm1 \n\t"
+
+ "pcmpeqb %%mm6, %%mm0 \n\t"
+ "pcmpeqb %%mm6, %%mm1 \n\t"
+
+// preload "movl len, %%ecx \n\t" // load length of line
+// preload "movl srcptr, %3 \n\t" // load source
+// preload "movl dstptr, %4 \n\t" // load dest
+
+ "cmpl $0, %%ecx \n\t"
+ "jz mainloop16end \n\t"
+
+ "mainloop16: \n\t"
+ "movq (%3), %%mm4 \n\t"
+ "pand %%mm0, %%mm4 \n\t"
+ "movq %%mm0, %%mm6 \n\t"
+ "movq (%4), %%mm7 \n\t"
+ "pandn %%mm7, %%mm6 \n\t"
+ "por %%mm6, %%mm4 \n\t"
+ "movq %%mm4, (%4) \n\t"
+
+ "movq 8(%3), %%mm5 \n\t"
+ "pand %%mm1, %%mm5 \n\t"
+ "movq %%mm1, %%mm7 \n\t"
+ "movq 8(%4), %%mm6 \n\t"
+ "pandn %%mm6, %%mm7 \n\t"
+ "por %%mm7, %%mm5 \n\t"
+ "movq %%mm5, 8(%4) \n\t"
+
+ "add $16, %3 \n\t" // inc by 16 bytes processed
+ "add $16, %4 \n\t"
+ "subl $8, %%ecx \n\t" // dec by 8 pixels processed
+ "ja mainloop16 \n\t"
+
+ "mainloop16end: \n\t"
+// preload "movl diff, %%ecx \n\t" // (diff is in eax)
+ "movl %%eax, %%ecx \n\t"
+ "cmpl $0, %%ecx \n\t"
+ "jz end16 \n\t"
+// preload "movl mask, %%edx \n\t"
+ "sall $24, %%edx \n\t" // make low byte, high byte
+
+ "secondloop16: \n\t"
+ "sall %%edx \n\t" // move high bit to CF
+ "jnc skip16 \n\t" // if CF = 0
+ "movw (%3), %%ax \n\t"
+ "movw %%ax, (%4) \n\t"
+
+ "skip16: \n\t"
+ "add $2, %3 \n\t"
+ "add $2, %4 \n\t"
+ "decl %%ecx \n\t"
+ "jnz secondloop16 \n\t"
+
+ "end16: \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=a" (dummy_value_a), // output regs (dummy)
+ "=d" (dummy_value_d),
+ "=c" (dummy_value_c),
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (diff), // eax // input regs
+ "1" (mask), // edx
+ "2" (len), // ecx
+// was (unmask) "b" RESERVED // ebx // Global Offset Table idx
+ "3" (srcptr), // esi/rsi
+ "4" (dstptr) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm4" // clobber list
+ , "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ else /* not _mmx_supported - use modified C routine */
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP2 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP2 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP2 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP2 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff*BPP2;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 16 bpp */
+
+ case 48: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+#if !defined(PNG_1_0_X)
+ if (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+#else
+ if (_mmx_supported)
+#endif
+ {
+ png_uint_32 len;
+ int diff;
+
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ len = png_ptr->width & ~7; // reduce to multiple of 8
+ diff = (int) (png_ptr->width & 7); // amount lost
+
+ __asm__ __volatile__ (
+ "not %%edx \n\t" // mask => unmask
+ "movd %%edx, %%mm7 \n\t" // load bit pattern
+ "not %%edx \n\t" // unmask => mask for later
+ "psubb %%mm6, %%mm6 \n\t" // zero mm6
+ "punpcklbw %%mm7, %%mm7 \n\t"
+ "punpcklwd %%mm7, %%mm7 \n\t"
+ "punpckldq %%mm7, %%mm7 \n\t" // fill reg with 8 masks
+
+ LOAD_GOT_rbp
+ "movq " MASK48_0 ", %%mm0 \n\t" // _mask48_0 -> mm0
+ "movq " MASK48_1 ", %%mm1 \n\t" // _mask48_1 -> mm1
+ "movq " MASK48_2 ", %%mm2 \n\t" // _mask48_2 -> mm2
+ "movq " MASK48_3 ", %%mm3 \n\t" // _mask48_3 -> mm3
+ "movq " MASK48_4 ", %%mm4 \n\t" // _mask48_4 -> mm4
+ "movq " MASK48_5 ", %%mm5 \n\t" // _mask48_5 -> mm5
+ RESTORE_rbp
+
+ "pand %%mm7, %%mm0 \n\t"
+ "pand %%mm7, %%mm1 \n\t"
+ "pand %%mm7, %%mm2 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pand %%mm7, %%mm4 \n\t"
+ "pand %%mm7, %%mm5 \n\t"
+
+ "pcmpeqb %%mm6, %%mm0 \n\t"
+ "pcmpeqb %%mm6, %%mm1 \n\t"
+ "pcmpeqb %%mm6, %%mm2 \n\t"
+ "pcmpeqb %%mm6, %%mm3 \n\t"
+ "pcmpeqb %%mm6, %%mm4 \n\t"
+ "pcmpeqb %%mm6, %%mm5 \n\t"
+
+// preload "movl len, %%ecx \n\t" // load length of line
+// preload "movl srcptr, %3 \n\t" // load source
+// preload "movl dstptr, %4 \n\t" // load dest
+
+ "cmpl $0, %%ecx \n\t"
+ "jz mainloop48end \n\t"
+
+ "mainloop48: \n\t"
+ "movq (%3), %%mm7 \n\t"
+ "pand %%mm0, %%mm7 \n\t"
+ "movq %%mm0, %%mm6 \n\t"
+ "pandn (%4), %%mm6 \n\t"
+ "por %%mm6, %%mm7 \n\t"
+ "movq %%mm7, (%4) \n\t"
+
+ "movq 8(%3), %%mm6 \n\t"
+ "pand %%mm1, %%mm6 \n\t"
+ "movq %%mm1, %%mm7 \n\t"
+ "pandn 8(%4), %%mm7 \n\t"
+ "por %%mm7, %%mm6 \n\t"
+ "movq %%mm6, 8(%4) \n\t"
+
+ "movq 16(%3), %%mm6 \n\t"
+ "pand %%mm2, %%mm6 \n\t"
+ "movq %%mm2, %%mm7 \n\t"
+ "pandn 16(%4), %%mm7 \n\t"
+ "por %%mm7, %%mm6 \n\t"
+ "movq %%mm6, 16(%4) \n\t"
+
+ "movq 24(%3), %%mm7 \n\t"
+ "pand %%mm3, %%mm7 \n\t"
+ "movq %%mm3, %%mm6 \n\t"
+ "pandn 24(%4), %%mm6 \n\t"
+ "por %%mm6, %%mm7 \n\t"
+ "movq %%mm7, 24(%4) \n\t"
+
+ "movq 32(%3), %%mm6 \n\t"
+ "pand %%mm4, %%mm6 \n\t"
+ "movq %%mm4, %%mm7 \n\t"
+ "pandn 32(%4), %%mm7 \n\t"
+ "por %%mm7, %%mm6 \n\t"
+ "movq %%mm6, 32(%4) \n\t"
+
+ "movq 40(%3), %%mm7 \n\t"
+ "pand %%mm5, %%mm7 \n\t"
+ "movq %%mm5, %%mm6 \n\t"
+ "pandn 40(%4), %%mm6 \n\t"
+ "por %%mm6, %%mm7 \n\t"
+ "movq %%mm7, 40(%4) \n\t"
+
+ "add $48, %3 \n\t" // inc by 48 bytes processed
+ "add $48, %4 \n\t"
+ "subl $8, %%ecx \n\t" // dec by 8 pixels processed
+
+ "ja mainloop48 \n\t"
+
+ "mainloop48end: \n\t"
+// preload "movl diff, %%ecx \n\t" // (diff is in eax)
+ "movl %%eax, %%ecx \n\t"
+ "cmpl $0, %%ecx \n\t"
+ "jz end48 \n\t"
+// preload "movl mask, %%edx \n\t"
+ "sall $24, %%edx \n\t" // make low byte, high byte
+
+ "secondloop48: \n\t"
+ "sall %%edx \n\t" // move high bit to CF
+ "jnc skip48 \n\t" // if CF = 0
+ "movl (%3), %%eax \n\t"
+ "movl %%eax, (%4) \n\t"
+ "movw 4(%3), %%ax \n\t" // GR-P bugfix 20070717
+ "movw %%ax, 4(%4) \n\t" // GR-P bugfix 20070717
+
+ "skip48: \n\t"
+ "add $6, %3 \n\t" // GR-P bugfix 20070717
+ "add $6, %4 \n\t" // GR-P bugfix 20070717
+ "decl %%ecx \n\t"
+ "jnz secondloop48 \n\t"
+
+ "end48: \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=a" (dummy_value_a), // output regs (dummy)
+ "=d" (dummy_value_d),
+ "=c" (dummy_value_c),
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (diff), // eax // input regs
+ "1" (mask), // edx
+ "2" (len), // ecx
+// was (unmask) "b" RESERVED // ebx // Global Offset Table idx
+ "3" (srcptr), // esi/rsi
+ "4" (dstptr) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ else /* not _mmx_supported - use modified C routine */
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP6 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP6 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP6 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP6 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff*BPP6;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 48 bpp */
+
+ case 64: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP8 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP8 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP8 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult. of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP8 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff*BPP8;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+
+ break;
+ } /* end 64 bpp */
+
+ default: /* png_ptr->row_info.pixel_depth != 1,2,4,8,16,24,32,48,64 */
+ {
+ // ERROR: SHOULD NEVER BE REACHED
+#if defined(PNG_DEBUG)
+ png_debug(1, "Internal libpng logic error (GCC "
+ "png_combine_row() pixel_depth)\n");
+#endif
+ break;
+ }
+ } /* end switch (png_ptr->row_info.pixel_depth) */
+
+ } /* end if (non-trivial mask) */
+
+} /* end png_combine_row() */
+
+#endif /* PNG_HAVE_MMX_COMBINE_ROW */
+
+
+
+
+/*===========================================================================*/
+/* */
+/* P N G _ D O _ R E A D _ I N T E R L A C E */
+/* */
+/*===========================================================================*/
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+#if defined(PNG_HAVE_MMX_READ_INTERLACE)
+
+/* png_do_read_interlace() is called after any 16-bit to 8-bit conversion
+ * has taken place. [GRR: what other steps come before and/or after?]
+ */
+
+void /* PRIVATE */
+png_do_read_interlace(png_structp png_ptr)
+{
+ png_row_infop row_info = &(png_ptr->row_info);
+ png_bytep row = png_ptr->row_buf + 1;
+ int pass = png_ptr->pass;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ png_uint_32 transformations = png_ptr->transformations;
+#endif
+
+ png_debug(1, "in png_do_read_interlace (pnggccrd.c)\n");
+
+ if (_mmx_supported == 2) {
+#if !defined(PNG_1_0_X)
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+#endif
+ png_mmx_support();
+ }
+
+ if (row != NULL && row_info != NULL)
+ {
+ png_uint_32 final_width;
+
+ final_width = row_info->width * png_pass_inc[pass];
+
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)((final_width - 1) >> 3);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)((row_info->width + 7) & 7);
+ dshift = (int)((final_width + 7) & 7);
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+ else
+#endif
+ {
+ sshift = 7 - (int)((row_info->width + 7) & 7);
+ dshift = 7 - (int)((final_width + 7) & 7);
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ v = (png_byte)((*sp >> sshift) & 0x1);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ case 2:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)((final_width - 1) >> 2);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
+ dshift = (png_size_t)(((final_width + 3) & 3) << 1);
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
+ dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0x3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ case 4:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)((final_width - 1) >> 1);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
+ dshift = (png_size_t)(((final_width + 1) & 1) << 2);
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
+ dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0xf);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ /*====================================================================*/
+
+ default: /* 8-bit or larger (this is where the routine is modified) */
+ {
+ png_bytep sptr, dp;
+ png_uint_32 i;
+ png_size_t pixel_bytes;
+ int width = (int)row_info->width;
+
+ pixel_bytes = (row_info->pixel_depth >> 3);
+
+ /* point sptr at the last pixel in the pre-expanded row: */
+ sptr = row + (width - 1) * pixel_bytes;
+
+ /* point dp at the last pixel position in the expanded row: */
+ dp = row + (final_width - 1) * pixel_bytes;
+
+ /* New code by Nirav Chhatrapati - Intel Corporation */
+
+#if !defined(PNG_1_0_X)
+ if (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE)
+#else
+ if (_mmx_supported)
+#endif
+ {
+ int dummy_value_c; // fix 'forbidden register spilled'
+ png_bytep dummy_value_S;
+ png_bytep dummy_value_D;
+ png_bytep dummy_value_a;
+ png_bytep dummy_value_d;
+
+ //--------------------------------------------------------------
+ if (pixel_bytes == BPP3)
+ {
+ if (((pass == 4) || (pass == 5)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) - 8; // GRR: huh?
+ if (width_mmx < 0)
+ width_mmx = 0;
+ width -= width_mmx; // 8 or 9 pix, 24 or 27 bytes
+ if (width_mmx)
+ {
+ // png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+ // sptr points at last pixel in pre-expanded row
+ // dp points at last pixel position in expanded row
+ __asm__ __volatile__ (
+ "sub $3, %1 \n\t"
+ "sub $9, %2 \n\t"
+ // (png_pass_inc[pass] + 1)*pixel_bytes
+
+ ".loop3_pass4: \n\t"
+ "movq (%1), %%mm0 \n\t" // x x 5 4 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // x x 5 4 3 2 1 0
+ "movq %%mm0, %%mm2 \n\t" // x x 5 4 3 2 1 0
+ "psllq $24, %%mm0 \n\t" // 4 3 2 1 0 z z z
+ "pand (%3), %%mm1 \n\t" // z z z z z 2 1 0
+ "psrlq $24, %%mm2 \n\t" // z z z x x 5 4 3
+ "por %%mm1, %%mm0 \n\t" // 4 3 2 1 0 2 1 0
+ "movq %%mm2, %%mm3 \n\t" // z z z x x 5 4 3
+ "psllq $8, %%mm2 \n\t" // z z x x 5 4 3 z
+ "movq %%mm0, (%2) \n\t"
+ "psrlq $16, %%mm3 \n\t" // z z z z z x x 5
+ "pand (%4), %%mm3 \n\t" // z z z z z z z 5
+ "por %%mm3, %%mm2 \n\t" // z z x x 5 4 3 5
+ "sub $6, %1 \n\t"
+ "movd %%mm2, 8(%2) \n\t"
+ "sub $12, %2 \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop3_pass4 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D),
+ "=a" (dummy_value_a),
+ "=d" (dummy_value_d)
+
+ : "0" (width_mmx), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp), // edi/rdi
+#if defined(PNG_x86_64_USE_GOTPCREL) // formerly _const4 and _const6:
+ "3" (&_c64._amask5_3_0), // (0x0000000000FFFFFFLL)
+ "4" (&_c64._amask7_1_0) // (0x00000000000000FFLL)
+#else
+ "3" (&_amask5_3_0), // eax (0x0000000000FFFFFFLL)
+ "4" (&_amask7_1_0) // edx (0x00000000000000FFLL)
+#endif
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1" // clobber list
+ , "%mm2", "%mm3"
+#endif
+ );
+ }
+
+ sptr -= width_mmx*BPP3;
+ dp -= width_mmx*2*BPP3;
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+
+ png_memcpy(v, sptr, BPP3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, BPP3);
+ dp -= BPP3;
+ }
+ sptr -= BPP3;
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ __asm__ __volatile__ (
+ "sub $9, %2 \n\t"
+ // (png_pass_inc[pass] - 1)*pixel_bytes
+
+ ".loop3_pass2: \n\t"
+ "movd (%1), %%mm0 \n\t" // x x x x x 2 1 0
+ "pand (%3), %%mm0 \n\t" // z z z z z 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // z z z z z 2 1 0
+ "psllq $16, %%mm0 \n\t" // z z z 2 1 0 z z
+ "movq %%mm0, %%mm2 \n\t" // z z z 2 1 0 z z
+ "psllq $24, %%mm0 \n\t" // 2 1 0 z z z z z
+ "psrlq $8, %%mm1 \n\t" // z z z z z z 2 1
+ "por %%mm2, %%mm0 \n\t" // 2 1 0 2 1 0 z z
+ "por %%mm1, %%mm0 \n\t" // 2 1 0 2 1 0 2 1
+ "movq %%mm0, 4(%2) \n\t"
+ "psrlq $16, %%mm0 \n\t" // z z 2 1 0 2 1 0
+ "sub $3, %1 \n\t"
+ "movd %%mm0, (%2) \n\t"
+ "sub $12, %2 \n\t"
+ "decl %%ecx \n\t"
+ "jnz .loop3_pass2 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D),
+ "=a" (dummy_value_a)
+
+ : "0" (width), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp), // edi/rdi
+#if defined(PNG_x86_64_USE_GOTPCREL) // formerly _const4:
+ "3" (&_c64._amask5_3_0) // (0x0000000000FFFFFFLL)
+#else
+ "3" (&_amask5_3_0) // eax (0x0000000000FFFFFFLL)
+#endif
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2" // clobber list
+#endif
+ );
+ }
+ else if (width) // && ((pass == 0) || (pass == 1))
+ {
+ __asm__ __volatile__ (
+ "sub $21, %2 \n\t"
+ // (png_pass_inc[pass] - 1)*pixel_bytes
+
+ ".loop3_pass0: \n\t"
+ "movd (%1), %%mm0 \n\t" // x x x x x 2 1 0
+ "pand (%3), %%mm0 \n\t" // z z z z z 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // z z z z z 2 1 0
+ "psllq $16, %%mm0 \n\t" // z z z 2 1 0 z z
+ "movq %%mm0, %%mm2 \n\t" // z z z 2 1 0 z z
+ "psllq $24, %%mm0 \n\t" // 2 1 0 z z z z z
+ "psrlq $8, %%mm1 \n\t" // z z z z z z 2 1
+ "por %%mm2, %%mm0 \n\t" // 2 1 0 2 1 0 z z
+ "por %%mm1, %%mm0 \n\t" // 2 1 0 2 1 0 2 1
+ "movq %%mm0, %%mm3 \n\t" // 2 1 0 2 1 0 2 1
+ "psllq $16, %%mm0 \n\t" // 0 2 1 0 2 1 z z
+ "movq %%mm3, %%mm4 \n\t" // 2 1 0 2 1 0 2 1
+ "punpckhdq %%mm0, %%mm3 \n\t" // 0 2 1 0 2 1 0 2
+ "movq %%mm4, 16(%2) \n\t"
+ "psrlq $32, %%mm0 \n\t" // z z z z 0 2 1 0
+ "movq %%mm3, 8(%2) \n\t"
+ "punpckldq %%mm4, %%mm0 \n\t" // 1 0 2 1 0 2 1 0
+ "sub $3, %1 \n\t"
+ "movq %%mm0, (%2) \n\t"
+ "sub $24, %2 \n\t"
+ "decl %%ecx \n\t"
+ "jnz .loop3_pass0 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D),
+ "=a" (dummy_value_a)
+
+ : "0" (width), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp), // edi/rdi
+#if defined(PNG_x86_64_USE_GOTPCREL) // formerly _const4:
+ "3" (&_c64._amask5_3_0) // (0x0000000000FFFFFFLL)
+#else
+ "3" (&_amask5_3_0) // eax (0x0000000000FFFFFFLL)
+#endif
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2" // clobber list
+ , "%mm3", "%mm4"
+#endif
+ );
+ }
+ } /* end of pixel_bytes == 3 */
+
+ //--------------------------------------------------------------
+ else if (pixel_bytes == BPP4)
+ {
+ if (((pass == 4) || (pass == 5)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx; // 0,1 pixels => 0,4 bytes
+ if (width_mmx)
+ {
+ __asm__ __volatile__ (
+ "sub $4, %1 \n\t"
+ "sub $12, %2 \n\t"
+
+ ".loop4_pass4: \n\t"
+ "movq (%1), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0
+ "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4
+ "movq %%mm0, (%2) \n\t"
+ "sub $8, %1 \n\t"
+ "movq %%mm1, 8(%2) \n\t"
+ "sub $16, %2 \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop4_pass4 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width_mmx), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*BPP4 - BPP4); // sign fixed
+ dp -= (width_mmx*2*BPP4 - BPP4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= BPP4;
+ png_memcpy(v, sptr, BPP4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= BPP4;
+ png_memcpy(dp, v, BPP4);
+ }
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1);
+ width -= width_mmx; // 0,1 pixels => 0,4 bytes
+ if (width_mmx)
+ {
+ __asm__ __volatile__ (
+ "sub $4, %1 \n\t"
+ "sub $28, %2 \n\t"
+
+ ".loop4_pass2: \n\t"
+ "movq (%1), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0
+ "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4
+ "movq %%mm0, (%2) \n\t"
+ "movq %%mm0, 8(%2) \n\t"
+ "movq %%mm1, 16(%2) \n\t"
+ "movq %%mm1, 24(%2) \n\t"
+ "sub $8, %1 \n\t"
+ "sub $32, %2 \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop4_pass2 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width_mmx), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*16 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+ else if (width) // && ((pass == 0) || (pass == 1))
+ {
+ int width_mmx = ((width >> 1) << 1);
+ width -= width_mmx; // 0,1 pixels => 0,4 bytes
+ if (width_mmx)
+ {
+ __asm__ __volatile__ (
+ "sub $4, %1 \n\t"
+ "sub $60, %2 \n\t"
+
+ ".loop4_pass0: \n\t"
+ "movq (%1), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 3 2 1 0 3 2 1 0
+ "punpckhdq %%mm1, %%mm1 \n\t" // 7 6 5 4 7 6 5 4
+ "movq %%mm0, (%2) \n\t"
+ "movq %%mm0, 8(%2) \n\t"
+ "movq %%mm0, 16(%2) \n\t"
+ "movq %%mm0, 24(%2) \n\t"
+ "movq %%mm1, 32(%2) \n\t"
+ "movq %%mm1, 40(%2) \n\t"
+ "movq %%mm1, 48(%2) \n\t"
+ "sub $8, %1 \n\t"
+ "movq %%mm1, 56(%2) \n\t"
+ "sub $64, %2 \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop4_pass0 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width_mmx), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*32 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+ } /* end of pixel_bytes == 4 */
+
+ //--------------------------------------------------------------
+ else if (pixel_bytes == 1)
+ {
+ if (((pass == 4) || (pass == 5)) && width)
+ {
+ int width_mmx = ((width >> 3) << 3);
+ width -= width_mmx; // 0-3 pixels => 0-3 bytes
+ if (width_mmx)
+ {
+ __asm__ __volatile__ (
+ "sub $7, %1 \n\t"
+ "sub $15, %2 \n\t"
+
+ ".loop1_pass4: \n\t"
+ "movq (%1), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // 7 6 5 4 3 2 1 0
+ "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0
+ "punpckhbw %%mm1, %%mm1 \n\t" // 7 7 6 6 5 5 4 4
+ "movq %%mm1, 8(%2) \n\t"
+ "sub $8, %1 \n\t"
+ "movq %%mm0, (%2) \n\t"
+ "sub $16, %2 \n\t"
+ "subl $8, %%ecx \n\t"
+ "jnz .loop1_pass4 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width_mmx), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*2;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ --sptr;
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 2) << 2);
+ width -= width_mmx; // 0-3 pixels => 0-3 bytes
+ if (width_mmx)
+ {
+ __asm__ __volatile__ (
+ "sub $3, %1 \n\t"
+ "sub $15, %2 \n\t"
+
+ ".loop1_pass2: \n\t"
+ "movd (%1), %%mm0 \n\t" // x x x x 3 2 1 0
+ "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0
+ "movq %%mm0, %%mm1 \n\t" // 3 3 2 2 1 1 0 0
+ "punpcklwd %%mm0, %%mm0 \n\t" // 1 1 1 1 0 0 0 0
+ "punpckhwd %%mm1, %%mm1 \n\t" // 3 3 3 3 2 2 2 2
+ "movq %%mm0, (%2) \n\t"
+ "sub $4, %1 \n\t"
+ "movq %%mm1, 8(%2) \n\t"
+ "sub $16, %2 \n\t"
+ "subl $4, %%ecx \n\t"
+ "jnz .loop1_pass2 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width_mmx), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*4;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ --sptr;
+ }
+ }
+ else if (width) // && ((pass == 0) || (pass == 1))
+ {
+ int width_mmx = ((width >> 2) << 2);
+ width -= width_mmx; // 0-3 pixels => 0-3 bytes
+ if (width_mmx)
+ {
+ __asm__ __volatile__ (
+ "sub $3, %1 \n\t"
+ "sub $31, %2 \n\t"
+
+ ".loop1_pass0: \n\t"
+ "movd (%1), %%mm0 \n\t" // x x x x 3 2 1 0
+ "movq %%mm0, %%mm1 \n\t" // x x x x 3 2 1 0
+ "punpcklbw %%mm0, %%mm0 \n\t" // 3 3 2 2 1 1 0 0
+ "movq %%mm0, %%mm2 \n\t" // 3 3 2 2 1 1 0 0
+ "punpcklwd %%mm0, %%mm0 \n\t" // 1 1 1 1 0 0 0 0
+ "movq %%mm0, %%mm3 \n\t" // 1 1 1 1 0 0 0 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 0 0 0 0 0 0 0 0
+ "punpckhdq %%mm3, %%mm3 \n\t" // 1 1 1 1 1 1 1 1
+ "movq %%mm0, (%2) \n\t"
+ "punpckhwd %%mm2, %%mm2 \n\t" // 3 3 3 3 2 2 2 2
+ "movq %%mm3, 8(%2) \n\t"
+ "movq %%mm2, %%mm4 \n\t" // 3 3 3 3 2 2 2 2
+ "punpckldq %%mm2, %%mm2 \n\t" // 2 2 2 2 2 2 2 2
+ "punpckhdq %%mm4, %%mm4 \n\t" // 3 3 3 3 3 3 3 3
+ "movq %%mm2, 16(%2) \n\t"
+ "sub $4, %1 \n\t"
+ "movq %%mm4, 24(%2) \n\t"
+ "sub $32, %2 \n\t"
+ "subl $4, %%ecx \n\t"
+ "jnz .loop1_pass0 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width_mmx), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2" // clobber list
+ , "%mm3", "%mm4"
+#endif
+ );
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*8;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ /* I simplified this part in version 1.0.4e
+ * here and in several other instances where
+ * pixel_bytes == 1 -- GR-P
+ *
+ * Original code:
+ *
+ * png_byte v[8];
+ * png_memcpy(v, sptr, pixel_bytes);
+ * for (j = 0; j < png_pass_inc[pass]; j++)
+ * {
+ * png_memcpy(dp, v, pixel_bytes);
+ * dp -= pixel_bytes;
+ * }
+ * sptr -= pixel_bytes;
+ *
+ * Replacement code is in the next three lines:
+ */
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ --sptr;
+ }
+ }
+ } /* end of pixel_bytes == 1 */
+
+ //--------------------------------------------------------------
+ else if (pixel_bytes == BPP2)
+ {
+ if (((pass == 4) || (pass == 5)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx; // 0,1 pixels => 0,2 bytes
+ if (width_mmx)
+ {
+ __asm__ __volatile__ (
+ "sub $2, %1 \n\t"
+ "sub $6, %2 \n\t"
+
+ ".loop2_pass4: \n\t"
+ "movd (%1), %%mm0 \n\t" // x x x x 3 2 1 0
+ "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0
+ "sub $4, %1 \n\t"
+ "movq %%mm0, (%2) \n\t"
+ "sub $8, %2 \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop2_pass4 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width_mmx), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*BPP2 - BPP2); // sign fixed
+ dp -= (width_mmx*2*BPP2 - BPP2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= BPP2;
+ png_memcpy(v, sptr, BPP2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= BPP2;
+ png_memcpy(dp, v, BPP2);
+ }
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx; // 0,1 pixels => 0,2 bytes
+ if (width_mmx)
+ {
+ __asm__ __volatile__ (
+ "sub $2, %1 \n\t"
+ "sub $14, %2 \n\t"
+
+ ".loop2_pass2: \n\t"
+ "movd (%1), %%mm0 \n\t" // x x x x 3 2 1 0
+ "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0
+ "movq %%mm0, %%mm1 \n\t" // 3 2 3 2 1 0 1 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 1 0 1 0 1 0 1 0
+ "punpckhdq %%mm1, %%mm1 \n\t" // 3 2 3 2 3 2 3 2
+ "movq %%mm0, (%2) \n\t"
+ "sub $4, %1 \n\t"
+ "movq %%mm1, 8(%2) \n\t"
+ "sub $16, %2 \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop2_pass2 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width_mmx), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*8 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ else if (width) // && ((pass == 0) || (pass == 1))
+ {
+ int width_mmx = ((width >> 1) << 1);
+ width -= width_mmx; // 0,1 pixels => 0,2 bytes
+ if (width_mmx)
+ {
+ __asm__ __volatile__ (
+ "sub $2, %1 \n\t"
+ "sub $30, %2 \n\t"
+
+ ".loop2_pass0: \n\t"
+ "movd (%1), %%mm0 \n\t" // x x x x 3 2 1 0
+ "punpcklwd %%mm0, %%mm0 \n\t" // 3 2 3 2 1 0 1 0
+ "movq %%mm0, %%mm1 \n\t" // 3 2 3 2 1 0 1 0
+ "punpckldq %%mm0, %%mm0 \n\t" // 1 0 1 0 1 0 1 0
+ "punpckhdq %%mm1, %%mm1 \n\t" // 3 2 3 2 3 2 3 2
+ "movq %%mm0, (%2) \n\t"
+ "movq %%mm0, 8(%2) \n\t"
+ "movq %%mm1, 16(%2) \n\t"
+ "sub $4, %1 \n\t"
+ "movq %%mm1, 24(%2) \n\t"
+ "sub $32, %2 \n\t"
+ "subl $2, %%ecx \n\t"
+ "jnz .loop2_pass0 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width_mmx), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*16 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ } /* end of pixel_bytes == 2 */
+
+ //--------------------------------------------------------------
+ else if (pixel_bytes == BPP8)
+ {
+// GRR TEST: should work, but needs testing (special 64-bit version of rpng2?)
+ // GRR NOTE: no need to combine passes here!
+ if (((pass == 4) || (pass == 5)) && width)
+ {
+ // source is 8-byte RRGGBBAA
+ // dest is 16-byte RRGGBBAA RRGGBBAA
+ __asm__ __volatile__ (
+ "sub $8, %2 \n\t" // start of last block
+
+ ".loop8_pass4: \n\t"
+ "movq (%1), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, (%2) \n\t"
+ "sub $8, %1 \n\t"
+ "movq %%mm0, 8(%2) \n\t"
+ "sub $16, %2 \n\t"
+ "decl %%ecx \n\t"
+ "jnz .loop8_pass4 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0" // clobber list
+#endif
+ );
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ // source is 8-byte RRGGBBAA
+ // dest is 32-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA
+ // (recall that expansion is _in place_: sptr and dp
+ // both point at locations within same row buffer)
+ __asm__ __volatile__ (
+ "sub $24, %2 \n\t" // start of last block
+
+ ".loop8_pass2: \n\t"
+ "movq (%1), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, (%2) \n\t"
+ "movq %%mm0, 8(%2) \n\t"
+ "movq %%mm0, 16(%2) \n\t"
+ "sub $8, %1 \n\t"
+ "movq %%mm0, 24(%2) \n\t"
+ "sub $32, %2 \n\t"
+ "decl %%ecx \n\t"
+ "jnz .loop8_pass2 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0" // clobber list
+#endif
+ );
+ }
+ else if (width) // && ((pass == 0) || (pass == 1))
+ {
+ // source is 8-byte RRGGBBAA
+ // dest is 64-byte RRGGBBAA RRGGBBAA RRGGBBAA RRGGBBAA ...
+ __asm__ __volatile__ (
+ "sub $56, %2 \n\t" // start of last block
+
+ ".loop8_pass0: \n\t"
+ "movq (%1), %%mm0 \n\t" // 7 6 5 4 3 2 1 0
+ "movq %%mm0, (%2) \n\t"
+ "movq %%mm0, 8(%2) \n\t"
+ "movq %%mm0, 16(%2) \n\t"
+ "movq %%mm0, 24(%2) \n\t"
+ "movq %%mm0, 32(%2) \n\t"
+ "movq %%mm0, 40(%2) \n\t"
+ "movq %%mm0, 48(%2) \n\t"
+ "sub $8, %1 \n\t"
+ "movq %%mm0, 56(%2) \n\t"
+ "sub $64, %2 \n\t"
+ "decl %%ecx \n\t"
+ "jnz .loop8_pass0 \n\t"
+ "EMMS \n\t" // DONE
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D)
+
+ : "0" (width), // ecx // input regs
+ "1" (sptr), // esi/rsi
+ "2" (dp) // edi/rdi
+
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0" // clobber list
+#endif
+ );
+ }
+ } /* end of pixel_bytes == 8 */
+
+ //--------------------------------------------------------------
+ else if (pixel_bytes == BPP6) // why no MMX for this case?
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, BPP6);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, BPP6);
+ dp -= BPP6;
+ }
+ sptr -= BPP6;
+ }
+ } /* end of pixel_bytes == 6 */
+
+ //--------------------------------------------------------------
+ else
+ {
+ // ERROR: SHOULD NEVER BE REACHED
+#if defined(PNG_DEBUG)
+ png_debug(1, "Internal libpng logic error (GCC "
+ "png_do_read_interlace() _mmx_supported)\n");
+#endif
+ }
+
+ } // end of _mmx_supported ========================================
+
+ else /* MMX not supported: use modified C code - takes advantage
+ * of inlining of png_memcpy for a constant */
+ {
+ if (pixel_bytes == BPP3)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, BPP3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, BPP3);
+ dp -= BPP3;
+ }
+ sptr -= BPP3;
+ }
+ }
+ else if (pixel_bytes == BPP4)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, BPP4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+#if defined(PNG_DEBUG) && defined(PNG_1_0_X) // row_buf_size gone in 1.2.x
+ if (dp < row || dp+3 > row+png_ptr->row_buf_size)
+ {
+ printf("dp out of bounds: row=%10p, dp=%10p, "
+ "rp=%10p\n", row, dp, row+png_ptr->row_buf_size);
+ printf("row_buf_size=%lu\n", png_ptr->row_buf_size);
+ }
+#endif
+ png_memcpy(dp, v, BPP4);
+ dp -= BPP4;
+ }
+ sptr -= BPP4;
+ }
+ }
+ else if (pixel_bytes == 1)
+ {
+ for (i = width; i; i--)
+ {
+ int j;
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ --sptr;
+ }
+ }
+ else if (pixel_bytes == BPP2)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, BPP2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, BPP2);
+ dp -= BPP2;
+ }
+ sptr -= BPP2;
+ }
+ }
+ else if (pixel_bytes == BPP6)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, BPP6);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, BPP6);
+ dp -= BPP6;
+ }
+ sptr -= BPP6;
+ }
+ }
+ else if (pixel_bytes == BPP8)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, BPP8);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, BPP8);
+ dp -= BPP8;
+ }
+ sptr -= BPP8;
+ }
+ }
+ else
+ {
+ // ERROR: SHOULD NEVER BE REACHED
+#if defined(PNG_DEBUG)
+ png_debug(1, "Internal libpng logic error (GCC "
+ "png_do_read_interlace() !_mmx_supported)\n");
+#endif
+ }
+
+ } /* end if (MMX not supported) */
+ break;
+ } /* end default (8-bit or larger) */
+ } /* end switch (row_info->pixel_depth) */
+
+ row_info->width = final_width;
+
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width);
+ }
+
+} /* end png_do_read_interlace() */
+
+#endif /* PNG_HAVE_MMX_READ_INTERLACE */
+#endif /* PNG_READ_INTERLACING_SUPPORTED */
+
+
+
+#if defined(PNG_HAVE_MMX_READ_FILTER_ROW)
+#if defined(PNG_MMX_READ_FILTER_AVG_SUPPORTED)
+
+//===========================================================================//
+// //
+// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ A V G //
+// //
+//===========================================================================//
+
+// Optimized code for PNG Average filter decoder
+
+static void /* PRIVATE */
+png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row,
+ png_bytep prev_row)
+{
+ unsigned FullLength, MMXLength; // png_uint_32 is actually 64-bit on x86-64
+ int bpp;
+ int dummy_value_a;
+ int dummy_value_c; // fix 'forbidden register 2 (cx) was spilled' error
+ int dummy_value_d;
+ png_bytep dummy_value_S;
+ png_bytep dummy_value_D;
+ int diff; // __attribute__((used));
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // calc number of bytes per pixel
+ FullLength = row_info->rowbytes; // number of bytes to filter
+
+ __asm__ __volatile__ (
+ "avg_top: \n\t"
+ SAVE_GOT_ebx
+ SAVE_r15
+ SAVE_ebp
+ // initialize address pointers and offset
+//pre "movl row, %5 \n\t" // edi/rdi: ptr to Avg(x)
+ "xorl %%ebx, %%ebx \n\t" // ebx: x
+//pre "movl prev_row, %4 \n\t" // esi/rsi: ptr to Prior(x)
+ "mov %5, " PDX " \n\t" // copy of row ptr...
+//pre "subl bpp, " PDX " \n\t" // (bpp is preloaded into ecx)
+ "sub " PCX "," PDX " \n\t" // edx/rdx: ptr to Raw(x-bpp)
+//pre "movl FullLength, %%eax \n\t" // bring in via eax...
+ SAVE_FullLength // ...but store for later use
+ "xorl %%eax, %%eax \n\t"
+
+ // Compute the Raw value for the first bpp bytes
+ // Raw(x) = Avg(x) + (Prior(x)/2)
+ "avg_rlp: \n\t"
+ "movb (%4," PBX ",), %%al \n\t" // load al with Prior(x)
+ "incl %%ebx \n\t"
+ "shrb %%al \n\t" // divide by 2
+ "addb -1(%5," PBX ",), %%al \n\t" // add Avg(x); -1 to offset inc ebx
+//pre "cmpl bpp, %%ebx \n\t" // (bpp is preloaded into ecx)
+ "cmpl %%ecx, %%ebx \n\t"
+ "movb %%al, -1(%5," PBX ",) \n\t" // write Raw(x); -1 to offset inc ebx
+ "jb avg_rlp \n\t" // mov does not affect flags
+
+ // get # of bytes to alignment (32-bit mask _would_ be good enough
+ // [computing delta], but 32-bit ops are zero-extended on 64-bit, argh)
+ // (if swapped edx and ebp, could do 8-bit or 16-bit mask...FIXME?)
+ "mov %5, " PBP " \n\t" // take start of row
+ "add " PBX "," PBP " \n\t" // add bpp
+ "add $0xf, " PBP " \n\t" // add 7+8 to incr past alignment bdry
+// "andl $0xfffffff8, %%ebp \n\t" // mask to alignment boundary (32-bit!)
+ CLEAR_BOTTOM_3_BITS PBP "\n\t" // mask to alignment boundary
+ "sub %5, " PBP " \n\t" // subtract row ptr again => ebp =
+ "jz avg_go \n\t" // target value of ebx at alignment
+
+ "xorl %%ecx, %%ecx \n\t"
+
+ // fix alignment
+ // Compute the Raw value for the bytes up to the alignment boundary
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ "avg_lp1: \n\t"
+ "xorl %%eax, %%eax \n\t"
+ "movb (%4," PBX ",), %%cl \n\t" // load cl with Prior(x)
+ "movb (" PDX "," PBX ",), %%al \n\t" // load al with Raw(x-bpp)
+ "addw %%cx, %%ax \n\t"
+ "incl %%ebx \n\t"
+ "shrw %%ax \n\t" // divide by 2
+ "addb -1(%5," PBX ",), %%al \n\t" // add Avg(x); -1 to offset inc ebx
+ "cmpl %%ebp, %%ebx \n\t" // check if at alignment boundary
+ "movb %%al, -1(%5," PBX ",) \n\t" // write Raw(x); -1 to offset inc ebx
+ "jb avg_lp1 \n\t" // repeat until at alignment boundary
+
+ "avg_go: \n\t"
+ RESTORE_FullLength "%%eax \n\t" // FullLength -> eax
+ "movl %%eax, %%ecx \n\t" // copy -> ecx
+ "subl %%ebx, %%eax \n\t" // subtract alignment fix
+ "andl $0x00000007, %%eax \n\t" // calc bytes over mult of 8
+ "subl %%eax, %%ecx \n\t" // sub over-bytes from original length
+//out "movl %%ecx, MMXLength \n\t"
+ "movl %%ebp, %%eax \n\t" // ebp = diff, but no reg constraint(?)
+ RESTORE_ebp // (could swap ebp and edx functions)
+ RESTORE_r15
+ RESTORE_GOT_ebx
+
+// "There is no way for you to specify that an input operand is modified
+// without also specifying it as an output operand." [makes sense]
+
+// "Unless an output operand has the `&' constraint modifier, GCC may
+// allocate it in the same register as an unrelated input operand, on the
+// assumption the inputs are consumed before the outputs are produced."
+// [trying to _force_ this]
+
+// "`=' Means that this operand is write-only for this instruction:
+// the previous value is discarded and replaced by output data."
+// [operand == variable name, presumably]
+
+ // output regs
+ // these are operands 0-1 (originally 0-3):
+ : "=c" (MMXLength), // %0 -> %0
+ "=a" (diff) // %3 -> %1
+// "=S" (dummy_value_S), // %1 -> GONE
+// "=D" (dummy_value_D), // %2 -> GONE
+
+ // input regs
+ // these are operands 2-5 (originally 4-7); two of their constraints say
+ // they must go in same places as operands 0-1 (originally 0-3) above:
+ : "0" (bpp), // %4 -> %2 ecx
+ "1" (FullLength), // %7 -> %3 eax
+ "S" (prev_row), // %5 -> %4 esi/rsi
+ "D" (row) // %6 -> %5 edi/rdi
+
+ : "%edx" // clobber list
+ _CLOBBER_r15
+ _CLOBBER_ebp
+ _CLOBBER_GOT_ebx
+ );
+
+ // now do the math for the rest of the row
+ switch (bpp)
+ {
+ case 3:
+ {
+// _ShiftBpp = 24; // == 3 * 8
+// _ShiftRem = 40; // == 64 - 24
+
+ __asm__ __volatile__ (
+ // re-init address pointers and offset
+ LOAD_GOT_rbp
+ "movq " AMASK5_3_0 ", %%mm7 \n\t" // _amask5_3_0 -> mm7
+// preload "movl diff, %%ecx \n\t" // ecx: x = offset to
+ // alignment boundary
+ "movq " LB_CARRY_MASK ", %%mm5 \n\t" // [interleave for parallel.?]
+// preload "movl row, %1 \n\t" // edi: Avg(x)
+ "movq " HB_CLEAR_MASK ", %%mm4 \n\t" // _HBClearMask -> mm4
+// preload "movl prev_row, %0 \n\t" // esi: Prior(x)
+ RESTORE_rbp
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PCX ",), %%mm2 \n\t"// load previous aligned 8 bytes
+ // (correct pos. in loop below)
+ "avg_3lp: \n\t"
+ "movq (%1," PCX ",), %%mm0 \n\t" // load mm0 with Avg(x)
+ "movq %%mm5, %%mm3 \n\t"
+ "psrlq $40, %%mm2 \n\t" // correct position Raw(x-bpp)
+ // data
+ "movq (%0," PCX ",), %%mm1 \n\t" // load mm1 with Prior(x)
+ "movq %%mm7, %%mm6 \n\t"
+ "pand %%mm1, %%mm3 \n\t" // get lsb for each prevrow byte
+ "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2
+ "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for
+ // each byte
+ // add 1st active group (Raw(x-bpp)/2) to average with LBCarry
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both lsb's were == 1
+ // (valid only for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to Raw(x-bpp)/2
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 1
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+ // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "psllq $24, %%mm6 \n\t" // shift the mm6 mask to cover
+ // bytes 3-5
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq $24, %%mm2 \n\t" // shift data to pos. correctly
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both lsb's were == 1
+ // (valid only for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to Raw(x-bpp)/2
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+
+ // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "psllq $24, %%mm6 \n\t" // shift mm6 mask to cover last
+ // two bytes
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq $24, %%mm2 \n\t" // shift data to pos. correctly
+ // Data need be shifted only once here to
+ // get the correct x-bpp offset.
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to Raw(x-bpp)/2
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "addl $8, %%ecx \n\t"
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+ // now ready to write back to memory
+ "movq %%mm0, -8(%1," PCX ",) \n\t"
+ // move updated Raw(x) to use as Raw(x-bpp) for next loop
+ "cmpl %%eax, %%ecx \n\t" // MMXLength
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raw(x) to mm2
+ "jb avg_3lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D),
+ "=c" (dummy_value_c),
+ "=a" (dummy_value_a)
+
+ : "0" (prev_row), // esi/rsi // input regs
+ "1" (row), // edi/rdi
+ "2" (diff), // ecx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 3 bpp
+
+ case 4: // formerly shared with 6 bpp case via _ShiftBpp and _ShiftRem,
+ { // but loop uses all 8 MMX regs, and psrlq/psllq require 64-bit
+ // mem (PIC/.so problems), MMX reg (none left), or immediate
+// _ShiftBpp = bpp << 3; // 32 (psllq)
+// _ShiftRem = 64 - _ShiftBpp; // 32 (psrlq)
+
+ __asm__ __volatile__ (
+ LOAD_GOT_rbp
+ "movq " HB_CLEAR_MASK ", %%mm4 \n\t" // _HBClearMask -> mm4
+ "movq " LB_CARRY_MASK ", %%mm5 \n\t" // _LBCarryMask -> mm5
+ // re-init address pointers and offset
+// preload "movl diff, %%ecx \n\t" // ecx: x = offset to
+ // alignment boundary
+ "movq " AMASK0_8_0 ", %%mm7 \n\t" // _amask0_8_0 -> mm7
+ RESTORE_rbp
+
+ // ... and clear all bytes except for 1st active group
+// preload "movl row, %1 \n\t" // edi: Avg(x)
+ "psrlq $32, %%mm7 \n\t" // was _ShiftRem
+// preload "movl prev_row, %0 \n\t" // esi: Prior(x)
+ "movq %%mm7, %%mm6 \n\t"
+ "psllq $32, %%mm6 \n\t" // mask for 2nd active group
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PCX ",), %%mm2 \n\t" // load previous aligned 8 bytes
+ // (we correct pos. in loop below)
+ "avg_4lp: \n\t"
+ "movq (%1," PCX ",), %%mm0 \n\t"
+ "psrlq $32, %%mm2 \n\t" // shift data to pos. correctly
+ "movq (%0," PCX ",), %%mm1 \n\t"
+ // add (Prev_row/2) to average
+ "movq %%mm5, %%mm3 \n\t"
+ "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte
+ "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2
+ "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for
+ // each byte
+ // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm7, %%mm2 \n\t" // leave only Active Group 1
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg
+ // for each Active
+ // byte
+ // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq $32, %%mm2 \n\t" // shift data to pos. correctly
+ "addl $8, %%ecx \n\t"
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+ "cmpl %%eax, %%ecx \n\t" // MMXLength
+ // now ready to write back to memory
+ "movq %%mm0, -8(%1," PCX ",) \n\t"
+ // prep Raw(x-bpp) for next loop
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "jb avg_4lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D),
+ "=c" (dummy_value_c),
+ "=a" (dummy_value_a)
+
+ : "0" (prev_row), // esi/rsi // input regs
+ "1" (row), // edi/rdi
+ "2" (diff), // ecx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 4 bpp
+
+ case 1:
+ {
+ __asm__ __volatile__ (
+ // re-init address pointers and offset
+// preload "movl diff, %%ecx \n\t" // ecx: x = offset to align. bdry
+// preload "movl row, %1 \n\t" // edi/rdi: Avg(x)
+// preload "movl FullLength, %%eax \n\t"
+ "cmpl %%eax, %%ecx \n\t" // test if offset at end of array
+ "jnb avg_1end \n\t"
+
+ SAVE_ebp
+
+ // do Avg decode for remaining bytes
+// preload "movl prev_row, %0 \n\t" // esi/rsi: Prior(x)
+ "mov %1, " PBP " \n\t" // copy of row pointer...
+ "dec " PBP " \n\t" // ebp/rbp: Raw(x-bpp)
+ "xorl %%edx, %%edx \n\t" // zero edx before using dl & dx
+ // in loop below
+ SAVE_GOT_ebx
+
+ "avg_1lp: \n\t"
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ "xorl %%ebx, %%ebx \n\t"
+ "movb (%0," PCX ",), %%dl \n\t" // load dl with Prior(x)
+ "movb (" PBP "," PCX ",), %%bl \n\t" // load bl with Raw(x-bpp)
+ "addw %%dx, %%bx \n\t"
+ "incl %%ecx \n\t"
+ "shrw %%bx \n\t" // divide by 2
+ "addb -1(%1," PCX ",), %%bl \n\t" // add Avg(x); -1 to offset
+ // inc ecx
+ "cmpl %%eax, %%ecx \n\t" // check if at end of array
+ "movb %%bl, -1(%1," PCX ",) \n\t" // write back Raw(x);
+ // mov does not affect flags; -1 to offset inc ecx
+ "jb avg_1lp \n\t"
+
+ RESTORE_GOT_ebx
+ RESTORE_ebp
+
+ "avg_1end: \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D),
+ "=c" (dummy_value_c),
+ "=a" (dummy_value_a)
+
+ : "0" (prev_row), // esi/rsi // input regs
+ "1" (row), // edi/rdi
+ "2" (diff), // ecx
+ "3" (FullLength) // eax
+
+ : "%edx" // clobber list
+ _CLOBBER_GOT_ebx
+ _CLOBBER_ebp
+ );
+ }
+ return; // end 1 bpp
+
+ case 2:
+ {
+// _ShiftBpp = 16; // == 2 * 8
+// _ShiftRem = 48; // == 64 - _ShiftBpp
+
+ __asm__ __volatile__ (
+ LOAD_GOT_rbp
+ // load (former) _ActiveMask
+ "movq " AMASK6_2_0 ", %%mm7 \n\t" // _amask6_2_0 -> mm7
+ // re-init address pointers and offset
+// preload "movl diff, %%ecx \n\t" // ecx: x = offset to
+ // alignment boundary
+ "movq " LB_CARRY_MASK ", %%mm5 \n\t" // _LBCarryMask -> mm5
+// preload "movl row, %1 \n\t" // edi: Avg(x)
+ "movq " HB_CLEAR_MASK ", %%mm4 \n\t" // _HBClearMask -> mm4
+// preload "movl prev_row, %0 \n\t" // esi: Prior(x)
+ RESTORE_rbp
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PCX ",), %%mm2 \n\t" // load previous aligned 8 bytes
+ // (we correct pos. in loop below)
+ "avg_2lp: \n\t"
+ "movq (%1," PCX ",), %%mm0 \n\t"
+ "psrlq $48, %%mm2 \n\t" // shift data to pos. correctly
+ "movq (%0," PCX ",), %%mm1 \n\t" // (GRR BUGFIX: was psllq)
+ // add (Prev_row/2) to average
+ "movq %%mm5, %%mm3 \n\t"
+ "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte
+ "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2
+ "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each
+ // byte
+ "movq %%mm7, %%mm6 \n\t"
+ "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for
+ // each byte
+
+ // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid
+ // for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 1
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg
+ // for each Active byte
+
+ // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "psllq $16, %%mm6 \n\t" // shift the mm6 mask to cover
+ // bytes 2 & 3
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq $16, %%mm2 \n\t" // shift data to pos. correctly
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid
+ // for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+
+ // add 3rd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "psllq $16, %%mm6 \n\t" // shift the mm6 mask to cover
+ // bytes 4 & 5
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq $16, %%mm2 \n\t" // shift data to pos. correctly
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both lsb's were == 1
+ // (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+
+ // add 4th active group (Raw(x-bpp)/2) to average with _LBCarry
+ "psllq $16, %%mm6 \n\t" // shift the mm6 mask to cover
+ // bytes 6 & 7
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq $16, %%mm2 \n\t" // shift data to pos. correctly
+ "addl $8, %%ecx \n\t"
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid
+ // for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+ "cmpl %%eax, %%ecx \n\t" // MMXLength
+ // now ready to write back to memory
+ "movq %%mm0, -8(%1," PCX ",) \n\t"
+ // prep Raw(x-bpp) for next loop
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "jb avg_2lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D),
+ "=c" (dummy_value_c),
+ "=a" (dummy_value_a)
+
+ : "0" (prev_row), // esi/rsi // input regs
+ "1" (row), // edi/rdi
+ "2" (diff), // ecx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 2 bpp
+
+ case 6: // formerly shared with 4 bpp case (see comments there)
+ {
+// _ShiftBpp = bpp << 3; // 48 (psllq)
+// _ShiftRem = 64 - _ShiftBpp; // 16 (psrlq)
+
+ __asm__ __volatile__ (
+ LOAD_GOT_rbp
+ "movq " HB_CLEAR_MASK ", %%mm4 \n\t" // _HBClearMask -> mm4
+ "movq " LB_CARRY_MASK ", %%mm5 \n\t" // _LBCarryMask -> mm5
+ // re-init address pointers and offset
+// preload "movl diff, %%ecx \n\t" // ecx: x = offset to
+ // alignment boundary
+ "movq " AMASK0_8_0 ", %%mm7 \n\t" // _amask0_8_0 -> mm7
+ RESTORE_rbp
+
+ // ... and clear all bytes except for 1st active group
+// preload "movl row, %1 \n\t" // edi: Avg(x)
+ "psrlq $16, %%mm7 \n\t"
+// preload "movl prev_row, %0 \n\t" // esi: Prior(x)
+ "movq %%mm7, %%mm6 \n\t"
+ "psllq $48, %%mm6 \n\t" // mask for 2nd active group
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PCX ",), %%mm2 \n\t" // load previous aligned 8 bytes
+ // (we correct pos. in loop below)
+ "avg_6lp: \n\t"
+ "movq (%1," PCX ",), %%mm0 \n\t"
+ "psrlq $16, %%mm2 \n\t" // shift data to pos. correctly
+ "movq (%0," PCX ",), %%mm1 \n\t"
+ // add (Prev_row/2) to average
+ "movq %%mm5, %%mm3 \n\t"
+ "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte
+ "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2
+ "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg for
+ // each byte
+ // add 1st active group (Raw(x-bpp)/2) to average with _LBCarry
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm7, %%mm2 \n\t" // leave only Active Group 1
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to Avg
+ // for each Active
+ // byte
+ // add 2nd active group (Raw(x-bpp)/2) to average with _LBCarry
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "psllq $48, %%mm2 \n\t" // shift data to pos. correctly
+ "addl $8, %%ecx \n\t"
+ "movq %%mm3, %%mm1 \n\t" // now use mm1 for getting
+ // LBCarrys
+ "pand %%mm2, %%mm1 \n\t" // get LBCarrys for each byte
+ // where both
+ // lsb's were == 1 (only valid for active group)
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7 of each
+ // byte
+ "paddb %%mm1, %%mm2 \n\t" // add LBCarrys to (Raw(x-bpp)/2)
+ // for each byte
+ "pand %%mm6, %%mm2 \n\t" // leave only Active Group 2
+ // bytes to add to Avg
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) + LBCarrys to
+ // Avg for each Active byte
+ "cmpl %%eax, %%ecx \n\t" // MMXLength
+ // now ready to write back to memory
+ "movq %%mm0, -8(%1," PCX ",) \n\t"
+ // prep Raw(x-bpp) for next loop
+ "movq %%mm0, %%mm2 \n\t" // mov updated Raws to mm2
+ "jb avg_6lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D),
+ "=c" (dummy_value_c),
+ "=a" (dummy_value_a)
+
+ : "0" (prev_row), // esi/rsi // input regs
+ "1" (row), // edi/rdi
+ "2" (diff), // ecx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 6 bpp
+
+ case 8:
+ {
+ __asm__ __volatile__ (
+ // re-init address pointers and offset
+// preload "movl diff, %%ecx \n\t" // ecx: x = offset to
+ // alignment boundary
+ LOAD_GOT_rbp
+ "movq " LB_CARRY_MASK ", %%mm5 \n\t" // [interleave for parallel.?]
+// preload "movl row, %1 \n\t" // edi: Avg(x)
+ "movq " HB_CLEAR_MASK ", %%mm4 \n\t" // _HBClearMask -> mm4
+// preload "movl prev_row, %0 \n\t" // esi: Prior(x)
+ RESTORE_rbp
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PCX ",), %%mm2 \n\t" // load previous aligned 8 bytes
+ // (NO NEED to correct pos. in loop below)
+
+ "avg_8lp: \n\t"
+ "movq (%1," PCX ",), %%mm0 \n\t"
+ "movq %%mm5, %%mm3 \n\t"
+ "movq (%0," PCX ",), %%mm1 \n\t"
+ "addl $8, %%ecx \n\t"
+ "pand %%mm1, %%mm3 \n\t" // get lsb for each prev_row byte
+ "psrlq $1, %%mm1 \n\t" // divide prev_row bytes by 2
+ "pand %%mm2, %%mm3 \n\t" // get LBCarrys for each byte
+ // where both lsb's were == 1
+ "psrlq $1, %%mm2 \n\t" // divide raw bytes by 2
+ "pand %%mm4, %%mm1 \n\t" // clear invalid bit 7, each byte
+ "paddb %%mm3, %%mm0 \n\t" // add LBCarrys to Avg, each byte
+ "pand %%mm4, %%mm2 \n\t" // clear invalid bit 7, each byte
+ "paddb %%mm1, %%mm0 \n\t" // add (Prev_row/2) to Avg, each
+ "paddb %%mm2, %%mm0 \n\t" // add (Raw/2) to Avg for each
+ "cmpl %%eax, %%ecx \n\t" // MMXLength
+ "movq %%mm0, -8(%1," PCX ",) \n\t"
+ "movq %%mm0, %%mm2 \n\t" // reuse as Raw(x-bpp)
+ "jb avg_8lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D),
+ "=c" (dummy_value_c),
+ "=a" (dummy_value_a)
+
+ : "0" (prev_row), // esi/rsi // input regs
+ "1" (row), // edi/rdi
+ "2" (diff), // ecx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2" // clobber list
+ , "%mm3", "%mm4", "%mm5"
+#endif
+ );
+ }
+ break; // end 8 bpp
+
+ default: // bpp != 1,2,3,4,6,8: doesn't exist
+ {
+ // ERROR: SHOULD NEVER BE REACHED
+#if defined(PNG_DEBUG)
+ png_debug(1, "Internal libpng logic error (GCC "
+ "png_read_filter_row_mmx_avg())\n");
+#endif
+ }
+ break;
+
+ } // end switch (bpp)
+
+ __asm__ __volatile__ (
+ // MMX acceleration complete; now do clean-up
+ // check if any remaining bytes left to decode
+//pre "movl FullLength, %%edx \n\t"
+//pre "movl MMXLength, %%eax \n\t" // eax: x == offset bytes after MMX
+//pre "movl row, %2 \n\t" // edi: Avg(x)
+ "cmpl %%edx, %%eax \n\t" // test if offset at end of array
+ "jnb avg_end \n\t"
+
+ SAVE_ebp
+
+ // do Avg decode for remaining bytes
+//pre "movl prev_row, %1 \n\t" // esi: Prior(x)
+ "mov %2, " PBP " \n\t" // copy of row pointer...
+//pre "subl bpp, " PBP " \n\t" // (bpp is preloaded into ecx)
+ "sub " PCX "," PBP " \n\t" // ebp: Raw(x-bpp)
+ "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx below
+
+ SAVE_GOT_ebx
+
+ "avg_lp2: \n\t"
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ "xorl %%ebx, %%ebx \n\t"
+ "movb (%1," PAX ",), %%cl \n\t" // load cl with Prior(x)
+ "movb (" PBP "," PAX ",), %%bl \n\t" // load bl with Raw(x-bpp)
+ "addw %%cx, %%bx \n\t"
+ "incl %%eax \n\t"
+ "shrw %%bx \n\t" // divide by 2
+ "addb -1(%2," PAX ",), %%bl \n\t" // add Avg(x); -1 to offset inc eax
+ "cmpl %%edx, %%eax \n\t" // check if at end of array
+ "movb %%bl, -1(%2," PAX ",) \n\t" // write back Raw(x) [mov does not
+ "jb avg_lp2 \n\t" // affect flags; -1 to offset inc eax]
+
+ RESTORE_GOT_ebx
+ RESTORE_ebp
+
+ "avg_end: \n\t"
+ "EMMS \n\t" // end MMX; prep for poss. FP instrs.
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D),
+ "=a" (dummy_value_a),
+ "=d" (dummy_value_d)
+
+ : "0" (bpp), // ecx // input regs
+ "1" (prev_row), // esi/rsi
+ "2" (row), // edi/rdi
+ "3" (MMXLength), // eax
+ "4" (FullLength) // edx
+
+ CLOB_COLON_ebx_ebp // clobber list
+ CLOBBER_GOT_ebx
+ CLOB_COMMA_ebx_ebp
+ CLOBBER_ebp
+ );
+
+} /* end png_read_filter_row_mmx_avg() */
+
+#endif /* PNG_MMX_READ_FILTER_AVG_SUPPORTED */
+
+
+
+#if defined(PNG_MMX_READ_FILTER_PAETH_SUPPORTED)
+#if defined(PNG_x86_64_USE_GOTPCREL) || defined(PNG_THREAD_UNSAFE_OK)
+
+//===========================================================================//
+// //
+// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ P A E T H //
+// //
+//===========================================================================//
+
+// Optimized code for PNG Paeth filter decoder
+
+static void /* PRIVATE */
+png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row,
+ png_bytep prev_row)
+{
+ unsigned FullLength, MMXLength; // png_uint_32 is actually 64-bit on x86-64
+ int bpp;
+ int dummy_value_a;
+ int dummy_value_c; // fix 'forbidden register 2 (cx) was spilled' error
+ int dummy_value_d;
+ png_charp dummy_value_S;
+ png_charp dummy_value_D;
+ int diff; // __attribute__((used));
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // calc number of bytes per pixel
+ FullLength = row_info->rowbytes; // number of bytes to filter
+
+ __asm__ __volatile__ (
+ SAVE_GOT_ebx
+ SAVE_r15
+ SAVE_ebp
+//pre "movl row, %2 \n\t" // edi/rdi
+ "xorl %%ebx, %%ebx \n\t" // ebx: x offset
+//pre "movl prev_row, %1 \n\t" // esi/rsi
+ "xorl %%edx, %%edx \n\t" // edx: x-bpp offset
+//pre "movl FullLength, %%eax \n\t" // bring in via eax...
+ SAVE_FullLength // ...but store for later use
+ "xorl %%eax, %%eax \n\t"
+
+ // Compute the Raw value for the first bpp bytes
+ // Note: the formula works out to be always
+ // Paeth(x) = Raw(x) + Prior(x) where x < bpp
+ "paeth_rlp: \n\t"
+ "movb (%2," PBX ",), %%al \n\t"
+ "addb (%1," PBX ",), %%al \n\t"
+ "incl %%ebx \n\t"
+//pre "cmpl bpp, %%ebx \n\t" (bpp is preloaded into ecx)
+ "cmpl %%ecx, %%ebx \n\t"
+ "movb %%al, -1(%2," PBX ",) \n\t"
+ "jb paeth_rlp \n\t"
+
+ // get # of bytes to alignment (note: computing _delta_ of two pointers,
+ // so hereafter %%ebp is sufficient even on 64-bit)
+ "mov %2, " PBP " \n\t" // take start of row
+ "add " PBX "," PBP " \n\t" // add bpp
+ "add $0xf, " PBP " \n\t" // add 7+8 to incr past alignment bdry
+// "andl $0xfffffff8, %%ebp \n\t" // mask to alignment boundary (32-bit!)
+ CLEAR_BOTTOM_3_BITS PBP "\n\t" // mask to alignment boundary
+ "sub %2, " PBP " \n\t" // subtract row ptr again => ebp =
+ "jz paeth_go \n\t" // target value of ebx at alignment
+
+ "xorl %%ecx, %%ecx \n\t"
+
+ SAVE_r11_r12_r13
+
+ // fix alignment
+ "paeth_lp1: \n\t"
+ "xorl %%eax, %%eax \n\t"
+ // pav = p - a = (a + b - c) - a = b - c
+ "movb (%1," PBX ",), %%al \n\t" // load Prior(x) into al
+ "movb (%1," PDX ",), %%cl \n\t" // load Prior(x-bpp) into cl
+ "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp)
+ "movl %%eax, " pa_TEMP " \n\t" // Save pav for later use
+ "xorl %%eax, %%eax \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movb (%2," PDX ",), %%al \n\t" // load Raw(x-bpp) into al
+ "subl %%ecx, %%eax \n\t" // subtract Prior(x-bpp)
+ "movl %%eax, %%ecx \n\t"
+ // pcv = p - c = (a + b - c) - c = (a - c) + (b - c) = pav + pbv
+ "addl " pa_TEMP ", %%eax \n\t" // pcv = pav + pbv
+ // pc = abs(pcv)
+ "testl $0x80000000, %%eax \n\t"
+ "jz paeth_pca \n\t"
+ "negl %%eax \n\t" // reverse sign of neg values
+
+ "paeth_pca: \n\t"
+ "movl %%eax, " pc_TEMP " \n\t" // save pc for later use
+ // pb = abs(pbv)
+ "testl $0x80000000, %%ecx \n\t"
+ "jz paeth_pba \n\t"
+ "negl %%ecx \n\t" // reverse sign of neg values
+
+ "paeth_pba: \n\t"
+ "movl %%ecx, " pb_TEMP " \n\t" // save pb for later use
+ // pa = abs(pav)
+ "movl " pa_TEMP ", %%eax \n\t"
+ "testl $0x80000000, %%eax \n\t"
+ "jz paeth_paa \n\t"
+ "negl %%eax \n\t" // reverse sign of neg values
+
+ "paeth_paa: \n\t"
+ "movl %%eax, " pa_TEMP " \n\t" // save pa for later use
+ // test if pa <= pb
+ "cmpl %%ecx, %%eax \n\t"
+ "jna paeth_abb \n\t"
+ // pa > pb; now test if pb <= pc
+ "cmpl " pc_TEMP ", %%ecx \n\t"
+ "jna paeth_bbc \n\t"
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%1," PDX ",), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_paeth \n\t"
+
+ "paeth_bbc: \n\t"
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ "movb (%1," PBX ",), %%cl \n\t" // load Prior(x) into cl
+ "jmp paeth_paeth \n\t"
+
+ "paeth_abb: \n\t"
+ // pa <= pb; now test if pa <= pc
+ "cmpl " pc_TEMP ", %%eax \n\t"
+ "jna paeth_abc \n\t"
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%1," PDX ",), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_paeth \n\t"
+
+ "paeth_abc: \n\t"
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ "movb (%2," PDX ",), %%cl \n\t" // load Raw(x-bpp) into cl
+
+ "paeth_paeth: \n\t"
+ "incl %%ebx \n\t"
+ "incl %%edx \n\t"
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ "addb %%cl, -1(%2," PBX ",) \n\t"
+ "cmpl %%ebp, %%ebx \n\t"
+ "jb paeth_lp1 \n\t"
+
+ RESTORE_r11_r12_r13
+
+ "paeth_go: \n\t"
+ RESTORE_FullLength "%%ecx \n\t" // FullLength -> ecx
+ "movl %%ecx, %%eax \n\t"
+ "subl %%ebx, %%eax \n\t" // subtract alignment fix
+ "andl $0x00000007, %%eax \n\t" // calc bytes over mult of 8
+ "subl %%eax, %%ecx \n\t" // drop over bytes from original length
+//out "movl %%ecx, MMXLength \n\t"
+ "movl %%ebp, %%eax \n\t" // ebp = diff, but no reg constraint(?)
+ RESTORE_ebp // (could swap ebp and edx functions)
+ RESTORE_r15
+ RESTORE_GOT_ebx
+
+ : "=c" (MMXLength), // output regs
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D),
+ "=a" (diff)
+
+ : "0" (bpp), // ecx // input regs
+ "1" (prev_row), // esi/rsi
+ "2" (row), // edi/rdi
+ "3" (FullLength) // eax
+
+ : "%edx" // clobber list
+ _CLOBBER_r11_r12_r13
+ _CLOBBER_r15
+ _CLOBBER_ebp
+ _CLOBBER_GOT_ebx
+ );
+
+ // now do the math for the rest of the row
+ switch (bpp)
+ {
+ case 3:
+ {
+// _ShiftBpp = 24; // == bpp * 8
+// _ShiftRem = 40; // == 64 - _ShiftBpp
+
+ __asm__ __volatile__ (
+ LOAD_GOT_rbp
+// preload "movl diff, %%ecx \n\t"
+// preload "movl row, %1 \n\t" // edi/rdi
+// preload "movl prev_row, %0 \n\t" // esi/rsi
+ "pxor %%mm0, %%mm0 \n\t"
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PCX ",), %%mm1 \n\t"
+ "paeth_3lp: \n\t"
+ "psrlq $40, %%mm1 \n\t" // shift last 3 bytes to 1st
+ // 3 bytes
+ "movq (%0," PCX ",), %%mm2 \n\t" // load b=Prior(x)
+ "punpcklbw %%mm0, %%mm1 \n\t" // unpack High bytes of a
+ "movq -8(%0," PCX ",), %%mm3 \n\t" // prep c=Prior(x-bpp) bytes
+ "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ "psrlq $40, %%mm3 \n\t" // shift last 3 bytes to 1st
+ // 3 bytes
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "packuswb %%mm1, %%mm7 \n\t"
+ "movq (%0," PCX ",), %%mm3 \n\t" // load c=Prior(x-bpp)
+ "pand " AMASK5_3_0 ", %%mm7 \n\t" // _amask5_3_0 (was _ActiveMask)
+ "movq %%mm3, %%mm2 \n\t" // load b=Prior(x) step 1
+ "paddb (%1," PCX ",), %%mm7 \n\t" // add Paeth predictor + Raw(x)
+ "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ "movq %%mm7, (%1," PCX ",) \n\t" // write back updated value
+ "movq %%mm7, %%mm1 \n\t" // now mm1 will be used as
+ // Raw(x-bpp)
+ // now do Paeth for 2nd set of bytes (3-5)
+ "psrlq $24, %%mm2 \n\t" // load b=Prior(x) step 2
+ "punpcklbw %%mm0, %%mm1 \n\t" // unpack High bytes of a
+ "pxor %%mm7, %%mm7 \n\t"
+ "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) =
+ // pav + pbv = pbv + pav
+ "movq %%mm5, %%mm6 \n\t"
+ "paddw %%mm4, %%mm6 \n\t"
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm5, %%mm0 \n\t" // create mask pbv bytes < 0
+ "pcmpgtw %%mm4, %%mm7 \n\t" // create mask pav bytes < 0
+ "pand %%mm5, %%mm0 \n\t" // only pbv bytes < 0 in mm0
+ "pand %%mm4, %%mm7 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm0, %%mm5 \n\t"
+ "psubw %%mm7, %%mm4 \n\t"
+ "psubw %%mm0, %%mm5 \n\t"
+ "psubw %%mm7, %%mm4 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "movq (%0," PCX ",), %%mm2 \n\t" // load b=Prior(x)
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "pxor %%mm1, %%mm1 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "packuswb %%mm1, %%mm7 \n\t"
+ "movq %%mm2, %%mm3 \n\t" // load c=Prior(x-bpp) step 1
+ "pand " AMASK5_3_0 ", %%mm7 \n\t" // _amask5_3_0 (was _ActiveMask)
+ "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ "psllq $24, %%mm7 \n\t" // shift bytes to 2nd group of
+ // 3 bytes
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "paddb (%1," PCX ",), %%mm7 \n\t" // add Paeth predictor + Raw(x)
+ "psllq $24, %%mm3 \n\t" // load c=Prior(x-bpp) step 2
+ "movq %%mm7, (%1," PCX ",) \n\t" // write back updated value
+ "movq %%mm7, %%mm1 \n\t"
+ "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ "psllq $24, %%mm1 \n\t" // shift bytes (was _ShiftBpp)
+ // now mm1 will be used as Raw(x-bpp)
+ // now do Paeth for 3rd, and final, set of bytes (6-7)
+ "pxor %%mm7, %%mm7 \n\t"
+ "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a
+ "psubw %%mm3, %%mm4 \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "paddw %%mm5, %%mm6 \n\t"
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm1, %%mm1 \n\t"
+ "packuswb %%mm7, %%mm1 \n\t"
+ // step ecx to next set of 8 bytes and repeat loop til done
+ "addl $8, %%ecx \n\t"
+ "pand " AMASK0_2_6 ", %%mm1 \n\t" // _amask0_2_6 (_ActiveMaskEnd)
+ "paddb -8(%1," PCX ",), %%mm1 \n\t" // add Paeth predictor + Raw(x)
+ "cmpl %%eax, %%ecx \n\t" // MMXLength
+ "pxor %%mm0, %%mm0 \n\t" // pxor does not affect flags
+ "movq %%mm1, -8(%1," PCX ",) \n\t" // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ // mm3 ready to be used as Prior(x-bpp) next loop
+ "jb paeth_3lp \n\t"
+ RESTORE_rbp
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D),
+ "=c" (dummy_value_c),
+ "=a" (dummy_value_a)
+
+ : "0" (prev_row), // esi/rsi // input regs
+ "1" (row), // edi/rdi
+ "2" (diff), // ecx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 3 bpp
+
+ case 4:
+ {
+ __asm__ __volatile__ (
+// preload "movl diff, %%ecx \n\t"
+// preload "movl row, %1 \n\t" // edi/rdi
+// preload "movl prev_row, %0 \n\t" // esi/rsi
+ "pxor %%mm0, %%mm0 \n\t"
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PCX ",), %%mm1 \n\t" // only time should need to read
+ // a=Raw(x-bpp) bytes
+ "paeth_4lp: \n\t"
+ // do first set of 4 bytes
+ "movq -8(%0," PCX ",), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
+ "punpckhbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a
+ "movq (%0," PCX ",), %%mm2 \n\t" // load b=Prior(x)
+ "punpcklbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "packuswb %%mm1, %%mm7 \n\t"
+ "movq (%0," PCX ",), %%mm3 \n\t" // load c=Prior(x-bpp)
+ LOAD_GOT_rbp
+ "pand " AMASK4_4_0 ", %%mm7 \n\t" // _amask4_4_0 (was _ActiveMask)
+ RESTORE_rbp
+ "movq %%mm3, %%mm2 \n\t" // load b=Prior(x) step 1
+ "paddb (%1," PCX ",), %%mm7 \n\t" // add Paeth predictor + Raw(x)
+ "punpcklbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ "movq %%mm7, (%1," PCX ",) \n\t" // write back updated value
+ "movq %%mm7, %%mm1 \n\t" // now mm1 will be used as
+ // Raw(x-bpp)
+ // do second set of 4 bytes
+ "punpckhbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b
+ "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "pxor %%mm1, %%mm1 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ // step ecx to next set of 8 bytes and repeat loop til done
+ "addl $8, %%ecx \n\t"
+ "packuswb %%mm7, %%mm1 \n\t"
+ "paddb -8(%1," PCX ",), %%mm1 \n\t" // add predictor with Raw(x)
+ "cmpl %%eax, %%ecx \n\t" // MMXLength
+ "movq %%mm1, -8(%1," PCX ",) \n\t" // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ "jb paeth_4lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D),
+ "=c" (dummy_value_c),
+ "=a" (dummy_value_a)
+
+ : "0" (prev_row), // esi/rsi // input regs
+ "1" (row), // edi/rdi
+ "2" (diff), // ecx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 4 bpp
+
+ case 1:
+ case 2:
+ {
+ __asm__ __volatile__ (
+// preload "movl diff, %%eax \n\t" // eax: x = offset to align. bdry
+// preload "movl FullLength, %%edx \n\t"
+ "cmpl %%edx, %%eax \n\t"
+ "jnb paeth_dend \n\t"
+
+ SAVE_ebp
+
+// preload "movl row, %2 \n\t" // edi/rdi
+ // do Paeth decode for remaining bytes
+// preload "movl prev_row, %1 \n\t" // esi/rsi
+ "movl %%eax, %%ebp \n\t"
+// preload "subl bpp, %%ebp \n\t" // (bpp is preloaded into ecx)
+ "subl %%ecx, %%ebp \n\t" // ebp = eax - bpp
+ "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx
+
+ SAVE_GOT_ebx
+ SAVE_r11_r12_r13
+
+ "paeth_dlp: \n\t"
+ "xorl %%ebx, %%ebx \n\t"
+ // pav = p - a = (a + b - c) - a = b - c
+ "movb (%1," PAX ",), %%bl \n\t" // load Prior(x) into bl
+ "movb (%1," PBP ",), %%cl \n\t" // load Prior(x-bpp) into cl
+ "subl %%ecx, %%ebx \n\t" // subtract Prior(x-bpp)
+ "movl %%ebx, " pa_TEMP " \n\t" // Save pav for later use
+ "xorl %%ebx, %%ebx \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movb (%2," PBP ",), %%bl \n\t" // load Raw(x-bpp) into bl
+ "subl %%ecx, %%ebx \n\t" // subtract Prior(x-bpp)
+ "movl %%ebx, %%ecx \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "addl " pa_TEMP ", %%ebx \n\t" // pcv = pav + pbv
+ // pc = abs(pcv)
+ "testl $0x80000000, %%ebx \n\t"
+ "jz paeth_dpca \n\t"
+ "negl %%ebx \n\t" // reverse sign of neg values
+
+ "paeth_dpca: \n\t"
+ "movl %%ebx, " pc_TEMP " \n\t" // save pc for later use
+ // pb = abs(pbv)
+ "testl $0x80000000, %%ecx \n\t"
+ "jz paeth_dpba \n\t"
+ "negl %%ecx \n\t" // reverse sign of neg values
+
+ "paeth_dpba: \n\t"
+ "movl %%ecx, " pb_TEMP " \n\t" // save pb for later use
+ // pa = abs(pav)
+ "movl " pa_TEMP ", %%ebx \n\t"
+ "testl $0x80000000, %%ebx \n\t"
+ "jz paeth_dpaa \n\t"
+ "negl %%ebx \n\t" // reverse sign of neg values
+
+ "paeth_dpaa: \n\t"
+ "movl %%ebx, " pa_TEMP " \n\t" // save pa for later use
+ // test if pa <= pb
+ "cmpl %%ecx, %%ebx \n\t"
+ "jna paeth_dabb \n\t"
+ // pa > pb; now test if pb <= pc
+ "cmpl " pc_TEMP ", %%ecx \n\t"
+ "jna paeth_dbbc \n\t"
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%1," PBP ",), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_dpaeth \n\t"
+
+ "paeth_dbbc: \n\t"
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ "movb (%1," PAX ",), %%cl \n\t" // load Prior(x) into cl
+ "jmp paeth_dpaeth \n\t"
+
+ "paeth_dabb: \n\t"
+ // pa <= pb; now test if pa <= pc
+ "cmpl " pc_TEMP ", %%ebx \n\t"
+ "jna paeth_dabc \n\t"
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%1," PBP ",), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_dpaeth \n\t"
+
+ "paeth_dabc: \n\t"
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ "movb (%2," PBP ",), %%cl \n\t" // load Raw(x-bpp) into cl
+
+ "paeth_dpaeth: \n\t"
+ "incl %%eax \n\t"
+ "incl %%ebp \n\t"
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ "addb %%cl, -1(%2," PAX ",) \n\t"
+ "cmpl %%edx, %%eax \n\t" // check against FullLength
+ "jb paeth_dlp \n\t"
+
+ RESTORE_r11_r12_r13
+ RESTORE_GOT_ebx
+ RESTORE_ebp
+
+ "paeth_dend: \n\t"
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D),
+ "=a" (dummy_value_a),
+ "=d" (dummy_value_d)
+
+ : "0" (bpp), // ecx // input regs
+ "1" (prev_row), // esi/rsi
+ "2" (row), // edi/rdi
+ "3" (diff), // eax
+ "4" (FullLength) // edx
+
+ CLOB_COLON_ebx_ebp_r1X // clobber list
+ CLOBBER_GOT_ebx
+ CLOB_COMMA_ebx_ebp
+ CLOBBER_ebp
+ CLOB_COMMA_ebX_r1X
+ CLOBBER_r11_r12_r13
+ );
+ }
+ return; // end 1 or 2 bpp (no need to go further with this one)
+
+ case 6:
+ {
+// _ActiveMask2 = 0xffffffff00000000LL; // NOT USED ("_amask_0_4_4")
+// _ShiftBpp = 48; // bpp << 3 == bpp * 8
+// _ShiftRem = 16; // 64 - _ShiftBpp
+
+ __asm__ __volatile__ (
+// preload "movl diff, %%ecx \n\t"
+// preload "movl row, %1 \n\t" // edi/rdi
+// preload "movl prev_row, %0 \n\t" // esi/rsi
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PCX ",), %%mm1 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+
+ "paeth_6lp: \n\t"
+ // must shift to position Raw(x-bpp) data
+ "psrlq $16, %%mm1 \n\t" // was _ShiftRem
+ // do first set of 4 bytes
+ "movq -8(%0," PCX ",), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
+ "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a
+ "movq (%0," PCX ",), %%mm2 \n\t" // load b=Prior(x)
+ "punpcklbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b
+ // must shift to position Prior(x-bpp) data
+ "psrlq $16, %%mm3 \n\t" // was _ShiftRem
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "punpcklbw %%mm0, %%mm3 \n\t" // unpack Low bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "packuswb %%mm1, %%mm7 \n\t"
+ "movq -8(%0," PCX ",), %%mm3 \n\t" // load c=Prior(x-bpp)
+ LOAD_GOT_rbp
+ "pand " AMASK4_4_0 ", %%mm7 \n\t" // _amask4_4_0 (was _ActiveMask)
+ RESTORE_rbp
+ "psrlq $16, %%mm3 \n\t"
+ "movq (%0," PCX ",), %%mm2 \n\t" // load b=Prior(x) step 1
+ "paddb (%1," PCX ",), %%mm7 \n\t" // add Paeth predictor + Raw(x)
+ "movq %%mm2, %%mm6 \n\t"
+ "movq %%mm7, (%1," PCX ",) \n\t" // write back updated value
+ "movq -8(%1," PCX ",), %%mm1 \n\t"
+ "psllq $48, %%mm6 \n\t" // bpp * 8 = bits per pixel
+ "movq %%mm7, %%mm5 \n\t"
+ "psrlq $16, %%mm1 \n\t" // 64 - (bpp * 8) = remainder
+ "por %%mm6, %%mm3 \n\t"
+ "psllq $48, %%mm5 \n\t" // was _ShiftBpp
+ "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ "por %%mm5, %%mm1 \n\t"
+ // do second set of 4 bytes
+ "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "pxor %%mm1, %%mm1 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ // step ecx to next set of 8 bytes and repeat loop til done
+ "addl $8, %%ecx \n\t"
+ "packuswb %%mm7, %%mm1 \n\t"
+ "paddb -8(%1," PCX ",), %%mm1 \n\t" // add Paeth predictor + Raw(x)
+ "cmpl %%eax, %%ecx \n\t" // MMXLength
+ "movq %%mm1, -8(%1," PCX ",) \n\t" // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ "jb paeth_6lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D),
+ "=c" (dummy_value_c),
+ "=a" (dummy_value_a)
+
+ : "0" (prev_row), // esi/rsi // input regs
+ "1" (row), // edi/rdi
+ "2" (diff), // ecx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 6 bpp
+
+ case 8: // bpp == 8
+ {
+ __asm__ __volatile__ (
+// preload "movl diff, %%ecx \n\t"
+// preload "movl row, %1 \n\t" // edi/rdi
+// preload "movl prev_row, %0 \n\t" // esi/rsi
+ "pxor %%mm0, %%mm0 \n\t"
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PCX ",), %%mm1 \n\t" // only time should need to read
+ // a=Raw(x-bpp) bytes
+ "paeth_8lp: \n\t"
+ // do first set of 4 bytes
+ "movq -8(%0," PCX ",), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
+ "punpcklbw %%mm0, %%mm1 \n\t" // unpack Low bytes of a
+ "movq (%0," PCX ",), %%mm2 \n\t" // load b=Prior(x)
+ "punpcklbw %%mm0, %%mm2 \n\t" // unpack Low bytes of b
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ "punpcklbw %%mm0, %%mm3 \n\t" // unpack Low bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "packuswb %%mm1, %%mm7 \n\t"
+ "movq -8(%0," PCX ",), %%mm3 \n\t" // read c=Prior(x-bpp) bytes
+ LOAD_GOT_rbp
+ "pand " AMASK4_4_0 ", %%mm7 \n\t" // _amask4_4_0 (was _ActiveMask)
+ RESTORE_rbp
+ "movq (%0," PCX ",), %%mm2 \n\t" // load b=Prior(x)
+ "paddb (%1," PCX ",), %%mm7 \n\t" // add Paeth predictor + Raw(x)
+ "punpckhbw %%mm0, %%mm3 \n\t" // unpack High bytes of c
+ "movq %%mm7, (%1," PCX ",) \n\t" // write back updated value
+ "movq -8(%1," PCX ",), %%mm1 \n\t" // read a=Raw(x-bpp) bytes
+
+ // do second set of 4 bytes
+ "punpckhbw %%mm0, %%mm2 \n\t" // unpack High bytes of b
+ "punpckhbw %%mm0, %%mm1 \n\t" // unpack High bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ "movq %%mm2, %%mm4 \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movq %%mm1, %%mm5 \n\t"
+ "psubw %%mm3, %%mm4 \n\t"
+ "pxor %%mm7, %%mm7 \n\t"
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ "movq %%mm4, %%mm6 \n\t"
+ "psubw %%mm3, %%mm5 \n\t"
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ "pcmpgtw %%mm4, %%mm0 \n\t" // create mask pav bytes < 0
+ "paddw %%mm5, %%mm6 \n\t"
+ "pand %%mm4, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "pcmpgtw %%mm5, %%mm7 \n\t" // create mask pbv bytes < 0
+ "psubw %%mm0, %%mm4 \n\t"
+ "pand %%mm5, %%mm7 \n\t" // only pbv bytes < 0 in mm0
+ "psubw %%mm0, %%mm4 \n\t"
+ "psubw %%mm7, %%mm5 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ "pcmpgtw %%mm6, %%mm0 \n\t" // create mask pcv bytes < 0
+ "pand %%mm6, %%mm0 \n\t" // only pav bytes < 0 in mm7
+ "psubw %%mm7, %%mm5 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ // test pa <= pb
+ "movq %%mm4, %%mm7 \n\t"
+ "psubw %%mm0, %%mm6 \n\t"
+ "pcmpgtw %%mm5, %%mm7 \n\t" // pa > pb?
+ "movq %%mm7, %%mm0 \n\t"
+ // use mm7 mask to merge pa & pb
+ "pand %%mm7, %%mm5 \n\t"
+ // use mm0 mask copy to merge a & b
+ "pand %%mm0, %%mm2 \n\t"
+ "pandn %%mm4, %%mm7 \n\t"
+ "pandn %%mm1, %%mm0 \n\t"
+ "paddw %%mm5, %%mm7 \n\t"
+ "paddw %%mm2, %%mm0 \n\t"
+ // test ((pa <= pb)? pa:pb) <= pc
+ "pcmpgtw %%mm6, %%mm7 \n\t" // pab > pc?
+ "pxor %%mm1, %%mm1 \n\t"
+ "pand %%mm7, %%mm3 \n\t"
+ "pandn %%mm0, %%mm7 \n\t"
+ "pxor %%mm1, %%mm1 \n\t"
+ "paddw %%mm3, %%mm7 \n\t"
+ "pxor %%mm0, %%mm0 \n\t"
+ // step ecx to next set of 8 bytes and repeat loop til done
+ "addl $8, %%ecx \n\t"
+ "packuswb %%mm7, %%mm1 \n\t"
+ "paddb -8(%1," PCX ",), %%mm1 \n\t" // add Paeth predictor + Raw(x)
+ "cmpl %%eax, %%ecx \n\t" // MMXLength
+ "movq %%mm1, -8(%1," PCX ",) \n\t" // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ "jb paeth_8lp \n\t"
+
+ : "=S" (dummy_value_S), // output regs (dummy)
+ "=D" (dummy_value_D),
+ "=c" (dummy_value_c),
+ "=a" (dummy_value_a)
+
+ : "0" (prev_row), // esi/rsi // input regs
+ "1" (row), // edi/rdi
+ "2" (diff), // ecx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm2", "%mm3" // clobber list
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 8 bpp
+
+ default: // bpp != 1,2,3,4,6,8: doesn't exist
+ {
+ // ERROR: SHOULD NEVER BE REACHED
+#if defined(PNG_DEBUG)
+ png_debug(1, "Internal libpng logic error (GCC "
+ "png_read_filter_row_mmx_paeth())\n");
+#endif
+ }
+ break;
+
+ } // end switch (bpp)
+
+ __asm__ __volatile__ (
+ // MMX acceleration complete; now do clean-up
+ // check if any remaining bytes left to decode
+//pre "movl FullLength, %%edx \n\t"
+//pre "movl MMXLength, %%eax \n\t"
+ "cmpl %%edx, %%eax \n\t"
+ "jnb paeth_end \n\t"
+
+ SAVE_ebp
+
+//pre "movl row, %2 \n\t" // edi/rdi
+//pre "movl prev_row, %1 \n\t" // esi/rsi
+ // do Paeth decode for remaining bytes
+ "movl %%eax, %%ebp \n\t"
+//pre "subl bpp, %%ebp \n\t" // (bpp is preloaded into ecx)
+ "subl %%ecx, %%ebp \n\t" // ebp = eax - bpp
+ "xorl %%ecx, %%ecx \n\t" // zero ecx before using cl & cx below
+
+ SAVE_GOT_ebx
+ SAVE_r11_r12_r13
+
+ "paeth_lp2: \n\t"
+ "xorl %%ebx, %%ebx \n\t"
+ // pav = p - a = (a + b - c) - a = b - c
+ "movb (%1," PAX ",), %%bl \n\t" // load Prior(x) into bl
+ "movb (%1," PBP ",), %%cl \n\t" // load Prior(x-bpp) into cl
+ "subl %%ecx, %%ebx \n\t" // subtract Prior(x-bpp)
+ "movl %%ebx, " pa_TEMP " \n\t" // Save pav for later use
+ "xorl %%ebx, %%ebx \n\t"
+ // pbv = p - b = (a + b - c) - b = a - c
+ "movb (%2," PBP ",), %%bl \n\t" // load Raw(x-bpp) into bl
+ "subl %%ecx, %%ebx \n\t" // subtract Prior(x-bpp)
+ "movl %%ebx, %%ecx \n\t"
+ // pcv = p - c = (a + b - c) - c = (a - c) + (b - c) = pav + pbv
+ "addl " pa_TEMP ", %%ebx \n\t" // pcv = pav + pbv
+ // pc = abs(pcv)
+ "testl $0x80000000, %%ebx \n\t"
+ "jz paeth_pca2 \n\t"
+ "negl %%ebx \n\t" // reverse sign of neg values
+
+ "paeth_pca2: \n\t"
+ "movl %%ebx, " pc_TEMP " \n\t" // save pc for later use
+ // pb = abs(pbv)
+ "testl $0x80000000, %%ecx \n\t"
+ "jz paeth_pba2 \n\t"
+ "negl %%ecx \n\t" // reverse sign of neg values
+
+ "paeth_pba2: \n\t"
+ "movl %%ecx, " pb_TEMP " \n\t" // save pb for later use
+ // pa = abs(pav)
+ "movl " pa_TEMP ", %%ebx \n\t"
+ "testl $0x80000000, %%ebx \n\t"
+ "jz paeth_paa2 \n\t"
+ "negl %%ebx \n\t" // reverse sign of neg values
+
+ "paeth_paa2: \n\t"
+ "movl %%ebx, " pa_TEMP " \n\t" // save pa for later use
+ // test if pa <= pb
+ "cmpl %%ecx, %%ebx \n\t"
+ "jna paeth_abb2 \n\t"
+ // pa > pb; now test if pb <= pc
+ "cmpl " pc_TEMP ", %%ecx \n\t"
+ "jna paeth_bbc2 \n\t"
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%1," PBP ",), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_paeth2 \n\t"
+
+ "paeth_bbc2: \n\t"
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ "movb (%1," PAX ",), %%cl \n\t" // load Prior(x) into cl
+ "jmp paeth_paeth2 \n\t"
+
+ "paeth_abb2: \n\t"
+ // pa <= pb; now test if pa <= pc
+ "cmpl " pc_TEMP ", %%ebx \n\t"
+ "jna paeth_abc2 \n\t"
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ "movb (%1," PBP ",), %%cl \n\t" // load Prior(x-bpp) into cl
+ "jmp paeth_paeth2 \n\t"
+
+ "paeth_abc2: \n\t"
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ "movb (%2," PBP ",), %%cl \n\t" // load Raw(x-bpp) into cl
+
+ "paeth_paeth2: \n\t"
+ "incl %%eax \n\t"
+ "incl %%ebp \n\t"
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ "addb %%cl, -1(%2," PAX ",) \n\t"
+ "cmpl %%edx, %%eax \n\t" // check against FullLength
+ "jb paeth_lp2 \n\t"
+
+ RESTORE_r11_r12_r13
+ RESTORE_GOT_ebx
+ RESTORE_ebp
+
+ "paeth_end: \n\t"
+ "EMMS \n\t" // end MMX; prep for poss. FP instrs.
+
+ : "=c" (dummy_value_c), // output regs (dummy)
+ "=S" (dummy_value_S),
+ "=D" (dummy_value_D),
+ "=a" (dummy_value_a),
+ "=d" (dummy_value_d)
+
+ : "0" (bpp), // ecx // input regs
+ "1" (prev_row), // esi/rsi
+ "2" (row), // edi/rdi
+ "3" (MMXLength), // eax
+ "4" (FullLength) // edx
+
+ CLOB_COLON_ebx_ebp_r1X // clobber list
+ CLOBBER_GOT_ebx
+ CLOB_COMMA_ebx_ebp
+ CLOBBER_ebp
+ CLOB_COMMA_ebX_r1X
+ CLOBBER_r11_r12_r13
+ );
+
+} /* end png_read_filter_row_mmx_paeth() */
+
+#endif // PNG_x86_64_USE_GOTPCREL || PNG_THREAD_UNSAFE_OK
+#endif /* PNG_MMX_READ_FILTER_PAETH_SUPPORTED */
+
+
+
+
+#if defined(PNG_MMX_READ_FILTER_SUB_SUPPORTED)
+
+//===========================================================================//
+// //
+// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ S U B //
+// //
+//===========================================================================//
+
+// Optimized code for PNG Sub filter decoder
+
+static void /* PRIVATE */
+png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row)
+{
+ unsigned FullLength, MMXLength; // png_uint_32 is actually 64-bit on x86-64
+ int bpp;
+ int dummy_value_a;
+ int dummy_value_c;
+ int dummy_value_d;
+ png_bytep dummy_value_D;
+ int diff; // __attribute__((used));
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // calc number of bytes per pixel
+ FullLength = row_info->rowbytes - bpp; // number of bytes to filter
+ // (why do we subtract off bpp? not so in avg or paeth...)
+
+ __asm__ __volatile__ (
+ SAVE_r15
+ SAVE_ebp
+//pre "movl row, %1 \n\t" // edi/rdi
+ "mov %1, " PSI " \n\t" // lp = row
+//pre "movl bpp, %%ecx \n\t"
+ "add " PCX ", %1 \n\t" // rp = row + bpp
+//pre "movl FullLength, %%eax \n\t" // bring in via eax...
+ SAVE_FullLength // ...but store for later use
+
+ "xorl %%eax, %%eax \n\t"
+
+ // get # of bytes to alignment (note: computing _delta_ of two pointers,
+ // so hereafter %%ebp is sufficient even on 64-bit)
+ "mov %1, " PBP " \n\t" // take start of row
+ "add $0xf, " PBP " \n\t" // add 7+8 to incr past alignment bdry
+// "andl $0xfffffff8, %%ebp \n\t" // mask to alignment boundary (32-bit!)
+ CLEAR_BOTTOM_3_BITS PBP "\n\t" // mask to alignment boundary
+ "sub %1, " PBP " \n\t" // subtract row ptr again => ebp =
+ "jz sub_go \n\t" // target value of eax at alignment
+
+ "sub_lp1: \n\t" // fix alignment
+ "movb (" PSI "," PAX ",), %%cl \n\t"
+ "addb %%cl, (%1," PAX ",) \n\t"
+ "incl %%eax \n\t"
+ "cmpl %%ebp, %%eax \n\t"
+ "jb sub_lp1 \n\t"
+
+ "sub_go: \n\t"
+ RESTORE_FullLength "%%ecx \n\t" // FullLength -> ecx
+ "movl %%ecx, %%edx \n\t"
+ "subl %%eax, %%edx \n\t" // subtract alignment fix
+ "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8
+ "subl %%edx, %%ecx \n\t" // drop over bytes from length
+//out "movl %%ecx, MMXLength \n\t"
+ "movl %%ebp, %%eax \n\t" // ebp = diff, but no reg constraint(?)
+ RESTORE_ebp // (could swap ebp and ecx functions,
+ RESTORE_r15 // but %%cl issues...)
+
+ : "=c" (MMXLength), // 0 // output regs
+ "=D" (dummy_value_D), // 1
+ "=a" (diff) // 2
+
+ : "0" (bpp), // ecx // input regs
+ "1" (row), // edi
+ "2" (FullLength) // eax
+
+ : "%esi", "%edx" // clobber list
+ _CLOBBER_r15
+ _CLOBBER_ebp
+ );
+
+ // now do the math for the rest of the row
+ switch (bpp)
+ {
+ case 3:
+ {
+// _ShiftBpp = 24; // == 3 * 8
+// _ShiftRem = 40; // == 64 - 24
+
+ __asm__ __volatile__ (
+// preload "mov row, %1 \n\t" // edi/rdi
+ LOAD_GOT_rbp
+ // load (former) _ActiveMask for 2nd active byte group
+ "movq " AMASK2_3_3 ", %%mm7 \n\t" // _amask2_3_3
+ RESTORE_rbp
+
+// notused "mov %1, " PSI " \n\t" // lp = row
+// preload "movl bpp, %%ecx \n\t"
+ "add " PCX ", %1 \n\t" // rp = row + bpp
+ "movq %%mm7, %%mm6 \n\t"
+// preload "movl diff, %%edx \n\t"
+ "psllq $24, %%mm6 \n\t" // move mask in mm6 to cover
+ // 3rd active byte group
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PDX ",), %%mm1 \n\t"
+
+ "sub_3lp: \n\t" // shift data for adding first
+ "psrlq $40, %%mm1 \n\t" // bpp bytes (no need for mask;
+ // shift clears inactive bytes)
+ // add 1st active group
+ "movq (%1," PDX ",), %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 2nd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq $24, %%mm1 \n\t" // shift data to pos. correctly
+ "pand %%mm7, %%mm1 \n\t" // mask to use 2nd active group
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 3rd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq $24, %%mm1 \n\t" // shift data to pos. correctly
+ "pand %%mm6, %%mm1 \n\t" // mask to use 3rd active group
+ "addl $8, %%edx \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "cmpl %%eax, %%edx \n\t" // MMXLength
+ "movq %%mm0, -8(%1," PDX ",) \n\t" // write updated Raws to array
+ "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop
+ "jb sub_3lp \n\t"
+
+ : "=c" (dummy_value_c), // 0 // output regs (dummy)
+ "=D" (dummy_value_D), // 1
+ "=d" (dummy_value_d), // 2
+ "=a" (dummy_value_a) // 3
+
+ : "0" (bpp), // ecx // input regs
+ "1" (row), // edi
+ "2" (diff), // edx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm6", "%mm7" // clobber list
+#endif
+ );
+ }
+ break; // end 3 bpp
+
+ case 4: // formerly shared with 6 bpp case via _ShiftBpp and _ShiftRem,
+ { // but 64-bit PIC/.so problems (could still share, moving vars
+ // into unused MMX regs via ecx/edx, but kludgy)
+// _ShiftBpp = bpp << 3; // 32 (psllq)
+// _ShiftRem = 64 - _ShiftBpp; // 32 (psrlq)
+
+ __asm__ __volatile__ (
+// preload "mov row, %1 \n\t" // edi/rdi
+// preload "movl diff, %%edx \n\t"
+// notused "mov %1, " PSI " \n\t" // lp = row
+// preload "movl bpp, %%ecx \n\t"
+ "add " PCX ", %1 \n\t" // rp = row + bpp
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PDX ",), %%mm1 \n\t"
+
+ "sub_4lp: \n\t" // shift data for adding first
+ "psrlq $32, %%mm1 \n\t" // bpp bytes (no need for mask;
+ // shift clears inactive bytes)
+ "movq (%1," PDX ",), %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 2nd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq $32, %%mm1 \n\t" // shift data to pos. correctly
+ "addl $8, %%edx \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "cmpl %%eax, %%edx \n\t" // MMXLength
+ "movq %%mm0, -8(%1," PDX ",) \n\t" // write updated Raws to array
+ "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop
+ "jb sub_4lp \n\t"
+
+ : "=c" (dummy_value_c), // 0 // output regs (dummy)
+ "=D" (dummy_value_D), // 1
+ "=d" (dummy_value_d), // 2
+ "=a" (dummy_value_a) // 3
+
+ : "0" (bpp), // ecx // input regs
+ "1" (row), // edi
+ "2" (diff), // edx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+ break; // end 4 bpp
+
+ case 1:
+ {
+ __asm__ __volatile__ (
+// preload "movl diff, %%edx \n\t"
+// preload "mov row, %1 \n\t" // edi/rdi
+// preload "cmpl FullLength, %%edx \n\t"
+ "cmpl %%eax, %%edx \n\t"
+ "jnb sub_1end \n\t"
+ "mov %1, " PSI " \n\t" // lp = row
+// irrel. "xorl %%ecx, %%ecx \n\t" // (actually bug with preload)
+// preload "movl bpp, %%ecx \n\t"
+ "add " PCX ", %1 \n\t" // rp = row + bpp
+
+ "sub_1lp: \n\t"
+ "movb (" PSI "," PDX ",), %%cl \n\t"
+ "addb %%cl, (%1," PDX ",) \n\t"
+ "incl %%edx \n\t"
+ "cmpl %%eax, %%edx \n\t" // compare with FullLength
+ "jb sub_1lp \n\t"
+
+ "sub_1end: \n\t"
+
+ : "=c" (dummy_value_c), // 0 // output regs (dummy)
+ "=D" (dummy_value_D), // 1
+ "=d" (dummy_value_d), // 2
+ "=a" (dummy_value_a) // 3
+
+ : "0" (bpp), // ecx // input regs
+ "1" (row), // edi
+ "2" (diff), // edx
+ "3" (FullLength) // eax
+
+ : "%esi" // clobber list
+ );
+ }
+ return; // end 1 bpp (bypassing cleanup block!)
+
+ case 2:
+ {
+// _ShiftBpp = 16; // == 2 * 8
+// _ShiftRem = 48; // == 64 - 16
+
+ __asm__ __volatile__ (
+ LOAD_GOT_rbp
+ // load (former) _ActiveMask for 2nd active byte group
+ "movq " AMASK4_2_2 ", %%mm7 \n\t" // _amask4_2_2
+ RESTORE_rbp
+// preload "movl diff, %%edx \n\t"
+ "movq %%mm7, %%mm6 \n\t"
+// preload "mov row, %1 \n\t" // edi/rdi
+ "psllq $16, %%mm6 \n\t" // move mask in mm6 to cover
+ // 3rd active byte group
+// notused "mov %1, " PSI " \n\t" // lp = row
+ "movq %%mm6, %%mm5 \n\t"
+// preload "movl bpp, %%ecx \n\t"
+ "add " PCX ", %1 \n\t" // rp = row + bpp
+ "psllq $16, %%mm5 \n\t" // move mask in mm5 to cover
+ // 4th active byte group
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PDX ",), %%mm1 \n\t"
+
+ "sub_2lp: \n\t" // shift data for adding first
+ "psrlq $48, %%mm1 \n\t" // bpp bytes (no need for mask;
+ // shift clears inactive bytes)
+ // add 1st active group
+ "movq (%1," PDX ",), %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 2nd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq $16, %%mm1 \n\t" // shift data to pos. correctly
+ "pand %%mm7, %%mm1 \n\t" // mask to use 2nd active group
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 3rd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq $16, %%mm1 \n\t" // shift data to pos. correctly
+ "pand %%mm6, %%mm1 \n\t" // mask to use 3rd active group
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 4th active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq $16, %%mm1 \n\t" // shift data to pos. correctly
+ "pand %%mm5, %%mm1 \n\t" // mask to use 4th active group
+ "addl $8, %%edx \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "cmpl %%eax, %%edx \n\t" // MMXLength
+ "movq %%mm0, -8(%1," PDX ",) \n\t" // write updated Raws to array
+ "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop
+ "jb sub_2lp \n\t"
+
+ : "=c" (dummy_value_c), // 0 // output regs (dummy)
+ "=D" (dummy_value_D), // 1
+ "=d" (dummy_value_d), // 2
+ "=a" (dummy_value_a) // 3
+
+ : "0" (bpp), // ecx // input regs
+ "1" (row), // edi
+ "2" (diff), // edx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1", "%mm5", "%mm6" // clobber list
+ , "%mm7"
+#endif
+ );
+ }
+ break; // end 2 bpp
+
+ case 6: // formerly shared with 4 bpp case (see comments there)
+ {
+// _ShiftBpp = bpp << 3; // 48 (psllq)
+// _ShiftRem = 64 - _ShiftBpp; // 16 (psrlq)
+
+ __asm__ __volatile__ (
+// preload "mov row, %1 \n\t" // edi/rdi
+// preload "movl diff, %%edx \n\t"
+// notused "mov %1, " PSI " \n\t" // lp = row
+// preload "movl bpp, %%ecx \n\t"
+ "add " PCX ", %1 \n\t" // rp = row + bpp
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PDX ",), %%mm1 \n\t"
+
+ "sub_6lp: \n\t" // shift data for adding first
+ "psrlq $16, %%mm1 \n\t" // bpp bytes (no need for mask;
+ // shift clears inactive bytes)
+ "movq (%1," PDX ",), %%mm0 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ // add 2nd active group
+ "movq %%mm0, %%mm1 \n\t" // mov updated Raws to mm1
+ "psllq $48, %%mm1 \n\t" // shift data to pos. correctly
+ "addl $8, %%edx \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+
+ "cmpl %%eax, %%edx \n\t" // MMXLength
+ "movq %%mm0, -8(%1," PDX ",) \n\t" // write updated Raws to array
+ "movq %%mm0, %%mm1 \n\t" // prep 1st add at top of loop
+ "jb sub_6lp \n\t"
+
+ : "=c" (dummy_value_c), // 0 // output regs (dummy)
+ "=D" (dummy_value_D), // 1
+ "=d" (dummy_value_d), // 2
+ "=a" (dummy_value_a) // 3
+
+ : "0" (bpp), // ecx // input regs
+ "1" (row), // edi
+ "2" (diff), // edx
+ "3" (MMXLength) // eax
+
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ : "%mm0", "%mm1" // clobber list
+#endif
+ );
+ }
+ break; // end 6 bpp
+
+ case 8:
+ {
+ __asm__ __volatile__ (
+// preload "mov row, %1 \n\t" // edi/rdi
+// preload "movl diff, %%edx \n\t"
+// notused "mov %1, " PSI " \n\t" // lp = row
+// preload "movl bpp, %%ecx \n\t"
+ "add " PCX ", %1 \n\t" // rp = row + bpp
+// preload "movl MMXLength, %%eax \n\t"
+
+ // prime the pump: load the first Raw(x-bpp) data set
+ "movq -8(%1," PDX ",), %%mm7 \n\t"
+ "movl %%eax, %%esi \n\t" // copy of MMXLength -> esi
+ "andl $0x0000003f, %%esi \n\t" // calc bytes over mult of 64
+
+ "sub_8lp: \n\t"
+ "movq (%1," PDX ",), %%mm0 \n\t" // load Sub(x) for 1st 8 bytes
+ "paddb %%mm7, %%mm0 \n\t"
+ "movq 8(%1," PDX ",), %%mm1 \n\t" // load Sub(x) for 2nd 8 bytes
+ "movq %%mm0, (%1," PDX ",) \n\t" // write Raw(x) for 1st 8 bytes
+
+ // Now mm0 will be used as Raw(x-bpp) for the 2nd group of 8 bytes.
+ // This will be repeated for each group of 8 bytes with the 8th
+ // group being used as the Raw(x-bpp) for the 1st group of the
+ // next loop.
+
+ "paddb %%mm0, %%mm1 \n\t"
+ "movq 16(%1," PDX ",), %%mm2 \n\t" // load Sub(x) for 3rd 8 bytes
+ "movq %%mm1, 8(%1," PDX ",) \n\t" // write Raw(x) for 2nd 8 bytes
+ "paddb %%mm1, %%mm2 \n\t"
+ "movq 24(%1," PDX ",), %%mm3 \n\t" // load Sub(x) for 4th 8 bytes
+ "movq %%mm2, 16(%1," PDX ",) \n\t" // write Raw(x) for 3rd 8 bytes
+ "paddb %%mm2, %%mm3 \n\t"
+ "movq 32(%1," PDX ",), %%mm4 \n\t" // load Sub(x) for 5th 8 bytes
+ "movq %%mm3, 24(%1," PDX ",) \n\t" // write Raw(x) for 4th 8 bytes
+ "paddb %%mm3, %%mm4 \n\t"
+ "movq 40(%1," PDX ",), %%mm5 \n\t" // load Sub(x) for 6th 8 bytes
+ "movq %%mm4, 32(%1," PDX ",) \n\t" // write Raw(x) for 5th 8 bytes
+ "paddb %%mm4, %%mm5 \n\t"
+ "movq 48(%1," PDX ",), %%mm6 \n\t" // load Sub(x) for 7th 8 bytes
+ "movq %%mm5, 40(%1," PDX ",) \n\t" // write Raw(x) for 6th 8 bytes
+ "paddb %%mm5, %%mm6 \n\t"
+ "movq 56(%1," PDX ",), %%mm7 \n\t" // load Sub(x) for 8th 8 bytes
+ "movq %%mm6, 48(%1," PDX ",) \n\t" // write Raw(x) for 7th 8 bytes
+ "addl $64, %%edx \n\t"
+ "paddb %%mm6, %%mm7 \n\t"
+ "cmpl %%esi, %%edx \n\t" // cmp to bytes over mult of 64
+ "movq %%mm7, -8(%1," PDX ",) \n\t" // write Raw(x) for 8th 8 bytes
+ "jb sub_8lp \n\t"
+
+ "cmpl %%eax, %%edx \n\t" // compare to MMXLength
+ "jnb sub_8lt8 \n\t"
+
+ "sub_8lpA: \n\t"
+ "movq (%1," PDX ",), %%mm0 \n\t"
+ "addl $8, %%edx \n\t"
+ "paddb %%mm7, %%mm0 \n\t"
+ "cmpl %%eax, %%edx \n\t" // compare to MMXLength
+ "movq %%mm0, -8(%1," PDX ",) \n\t" // -8 to offset early addl edx
+ "movq %%mm0, %%mm7 \n\t" // move calculated Raw(x) data
+ "jb sub_8lpA \n\t" // to mm7 to be new Raw(x-bpp)
+ // for next loop
+ "sub_8lt8: \n\t"
+
+ : "=c" (dummy_value_c), // 0 // output regs (dummy)
+ "=D" (dummy_value_D), // 1
+ "=d" (dummy_value_d), // 2
+ "=a" (dummy_value_a) // 3
+
+ : "0" (bpp), // ecx // input regs
+ "1" (row), // edi
+ "2" (diff), // edx
+ "3" (MMXLength) // eax
+
+ : "%esi" // clobber list
+#if defined(CLOBBER_MMX_REGS_SUPPORTED)
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+ }
+ break; // end 8 bpp
+
+ default: // bpp != 1,2,3,4,6,8: doesn't exist
+ {
+ // ERROR: SHOULD NEVER BE REACHED
+#if defined(PNG_DEBUG)
+ png_debug(1, "Internal libpng logic error (GCC "
+ "png_read_filter_row_mmx_sub())\n");
+#endif
+ }
+ break;
+
+ } // end switch (bpp)
+
+ __asm__ __volatile__ (
+//pre "movl MMXLength, %%eax \n\t"
+//pre "mov row, %1 \n\t" // edi/rdi
+//pre "cmpl FullLength, %%eax \n\t"
+ "cmpl %%edx, %%eax \n\t"
+ "jnb sub_end \n\t"
+
+ "mov %1, " PSI " \n\t" // lp = row
+//pre "movl bpp, %%ecx \n\t"
+ "add " PCX ", %1 \n\t" // rp = row + bpp
+ "xorl %%ecx, %%ecx \n\t"
+
+ "sub_lp2: \n\t"
+ "movb (" PSI "," PAX ",), %%cl \n\t"
+ "addb %%cl, (%1," PAX ",) \n\t"
+ "incl %%eax \n\t"
+ "cmpl %%edx, %%eax \n\t" // FullLength
+ "jb sub_lp2 \n\t"
+
+ "sub_end: \n\t"
+ "EMMS \n\t" // end MMX instructions
+
+ : "=c" (dummy_value_c), // 0 // output regs (dummy)
+ "=D" (dummy_value_D), // 1
+ "=a" (dummy_value_a), // 2
+ "=d" (dummy_value_d) // 3
+
+ : "0" (bpp), // ecx // input regs
+ "1" (row), // edi
+ "2" (MMXLength), // eax
+ "3" (FullLength) // edx
+
+ : "%esi" // clobber list
+ );
+
+} // end of png_read_filter_row_mmx_sub()
+
+#endif /* PNG_MMX_READ_FILTER_SUB_SUPPORTED */
+
+
+
+
+#if defined(PNG_MMX_READ_FILTER_UP_SUPPORTED)
+
+//===========================================================================//
+// //
+// P N G _ R E A D _ F I L T E R _ R O W _ M M X _ U P //
+// //
+//===========================================================================//
+
+// Optimized code for PNG Up filter decoder
+
+static void /* PRIVATE */
+png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row,
+ png_bytep prev_row)
+{
+ unsigned len; // png_uint_32 is actually 64-bit on x86-64
+ int dummy_value_d; // fix 'forbidden register 3 (dx) was spilled' error
+ png_bytep dummy_value_S;
+ png_bytep dummy_value_D;
+
+ len = row_info->rowbytes; // number of bytes to filter
+
+ __asm__ __volatile__ (
+ SAVE_GOT_ebx
+//pre "mov prev_row, %1 \n\t" // esi/rsi
+//pre "movl row, %2 \n\t" // edi/rdi
+
+ "xorl %%ebx, %%ebx \n\t"
+ "xorl %%eax, %%eax \n\t"
+
+ // get # of bytes to alignment (note: computing _delta_ of two pointers,
+ // so hereafter %%ecx is sufficient even on 64-bit)
+ "mov %2, " PCX " \n\t" // take start of row
+ "add $0x7, " PCX " \n\t" // add 7 to incr past alignment bdry
+// "andl $0xfffffff8, %%ecx \n\t" // mask to alignment boundary (32-bit!)
+ CLEAR_BOTTOM_3_BITS PCX "\n\t" // mask to alignment boundary
+ "sub %2, " PCX " \n\t" // subtract row ptr again => ebp =
+ "jz up_go \n\t" // target value of ecx at alignment
+
+ "up_lp1: \n\t" // fix alignment
+ "movb (%2," PBX ",), %%al \n\t"
+ "addb (%1," PBX ",), %%al \n\t"
+ "incl %%ebx \n\t"
+ "cmpl %%ecx, %%ebx \n\t"
+ "movb %%al, -1(%2," PBX ",) \n\t" // mov does not affect flags; -1 to
+ "jb up_lp1 \n\t" // offset incl ebx
+
+ "up_go: \n\t"
+//pre "movl len, %%edx \n\t"
+ "movl %%edx, %%ecx \n\t"
+ "subl %%ebx, %%edx \n\t" // subtract alignment fix
+ "andl $0x0000003f, %%edx \n\t" // calc bytes over mult of 64
+ "subl %%edx, %%ecx \n\t" // sub over-bytes from original length
+
+ // unrolled loop - use all MMX registers and interleave to reduce
+ // number of branch instructions (loops) and reduce partial stalls
+ "up_loop: \n\t"
+ "movq (%1," PBX ",), %%mm1 \n\t"
+ "movq (%2," PBX ",), %%mm0 \n\t"
+ "movq 8(%1," PBX ",), %%mm3 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "movq 8(%2," PBX ",), %%mm2 \n\t"
+ "movq %%mm0, (%2," PBX ",) \n\t"
+ "paddb %%mm3, %%mm2 \n\t"
+ "movq 16(%1," PBX ",), %%mm5 \n\t"
+ "movq %%mm2, 8(%2," PBX ",) \n\t"
+ "movq 16(%2," PBX ",), %%mm4 \n\t"
+ "movq 24(%1," PBX ",), %%mm7 \n\t"
+ "paddb %%mm5, %%mm4 \n\t"
+ "movq 24(%2," PBX ",), %%mm6 \n\t"
+ "movq %%mm4, 16(%2," PBX ",) \n\t"
+ "paddb %%mm7, %%mm6 \n\t"
+ "movq 32(%1," PBX ",), %%mm1 \n\t"
+ "movq %%mm6, 24(%2," PBX ",) \n\t"
+ "movq 32(%2," PBX ",), %%mm0 \n\t"
+ "movq 40(%1," PBX ",), %%mm3 \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "movq 40(%2," PBX ",), %%mm2 \n\t"
+ "movq %%mm0, 32(%2," PBX ",) \n\t"
+ "paddb %%mm3, %%mm2 \n\t"
+ "movq 48(%1," PBX ",), %%mm5 \n\t"
+ "movq %%mm2, 40(%2," PBX ",) \n\t"
+ "movq 48(%2," PBX ",), %%mm4 \n\t"
+ "movq 56(%1," PBX ",), %%mm7 \n\t"
+ "paddb %%mm5, %%mm4 \n\t"
+ "movq 56(%2," PBX ",), %%mm6 \n\t"
+ "movq %%mm4, 48(%2," PBX ",) \n\t"
+ "addl $64, %%ebx \n\t"
+ "paddb %%mm7, %%mm6 \n\t"
+ "cmpl %%ecx, %%ebx \n\t"
+ "movq %%mm6, -8(%2," PBX ",) \n\t" // (+56)movq does not affect flags;
+ "jb up_loop \n\t" // -8 to offset addl ebx
+
+ "cmpl $0, %%edx \n\t" // test for bytes over mult of 64
+ "jz up_end \n\t"
+
+ "cmpl $8, %%edx \n\t" // test for less than 8 bytes
+ "jb up_lt8 \n\t" // [added by lcreeve at netins.net]
+
+ "addl %%edx, %%ecx \n\t"
+ "andl $0x00000007, %%edx \n\t" // calc bytes over mult of 8
+ "subl %%edx, %%ecx \n\t" // drop over-bytes from length
+ "jz up_lt8 \n\t"
+
+ "up_lpA: \n\t" // use MMX regs to update 8 bytes sim.
+ "movq (%1," PBX ",), %%mm1 \n\t"
+ "movq (%2," PBX ",), %%mm0 \n\t"
+ "addl $8, %%ebx \n\t"
+ "paddb %%mm1, %%mm0 \n\t"
+ "cmpl %%ecx, %%ebx \n\t"
+ "movq %%mm0, -8(%2," PBX ",) \n\t" // movq does not affect flags; -8 to
+ "jb up_lpA \n\t" // offset add ebx
+ "cmpl $0, %%edx \n\t" // test for bytes over mult of 8
+ "jz up_end \n\t"
+
+ "up_lt8: \n\t"
+ "xorl %%eax, %%eax \n\t"
+ "addl %%edx, %%ecx \n\t" // move over byte count into counter
+
+ "up_lp2: \n\t" // use x86 regs for remaining bytes
+ "movb (%2," PBX ",), %%al \n\t"
+ "addb (%1," PBX ",), %%al \n\t"
+ "incl %%ebx \n\t"
+ "cmpl %%ecx, %%ebx \n\t"
+ "movb %%al, -1(%2," PBX ",) \n\t" // mov does not affect flags; -1 to
+ "jb up_lp2 \n\t" // offset inc ebx
+
+ "up_end: \n\t"
+ "EMMS \n\t" // conversion of filtered row complete
+ RESTORE_GOT_ebx
+
+ : "=d" (dummy_value_d), // 0 // output regs (dummy)
+ "=S" (dummy_value_S), // 1
+ "=D" (dummy_value_D) // 2
+
+ : "0" (len), // edx // input regs
+ "1" (prev_row), // esi
+ "2" (row) // edi
+
+ : "%eax", "%ecx" // clobber list (no input regs!)
+ _CLOBBER_GOT_ebx
+#if defined(PNG_CLOBBER_MMX_REGS_SUPPORTED)
+ , "%mm0", "%mm1", "%mm2", "%mm3"
+ , "%mm4", "%mm5", "%mm6", "%mm7"
+#endif
+ );
+
+} // end of png_read_filter_row_mmx_up()
+
+#endif /* PNG_MMX_READ_FILTER_UP_SUPPORTED */
+
+
+
+
+/*===========================================================================*/
+/* */
+/* P N G _ R E A D _ F I L T E R _ R O W */
+/* */
+/*===========================================================================*/
+
+/* Optimized png_read_filter_row routines */
+
+void /* PRIVATE */
+png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep
+ row, png_bytep prev_row, int filter)
+{
+#if defined(PNG_DEBUG)
+ char filtname[10];
+#endif
+
+ if (_mmx_supported == 2) {
+#if !defined(PNG_1_0_X)
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+#endif
+ png_mmx_support();
+ }
+
+#if defined(PNG_DEBUG)
+ png_debug(1, "in png_read_filter_row (pnggccrd.c)\n");
+ switch (filter)
+ {
+ case 0:
+ png_snprintf(filtname, 10, "none");
+ break;
+
+ case 1:
+ png_snprintf(filtname, 10, "sub-%s",
+#ifdef PNG_MMX_READ_FILTER_SUB_SUPPORTED
+#if !defined(PNG_1_0_X)
+ ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ _mmx_supported
+#endif
+ ? "MMX" :
+#endif
+ "C");
+ break;
+
+ case 2:
+ png_snprintf(filtname, 10, "up-%s",
+#ifdef PNG_MMX_READ_FILTER_UP_SUPPORTED
+#if !defined(PNG_1_0_X)
+ ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ _mmx_supported
+#endif
+ ? "MMX" :
+#endif
+ "C");
+ break;
+
+ case 3:
+ png_snprintf(filtname, 10, "avg-%s",
+#ifdef PNG_MMX_READ_FILTER_AVG_SUPPORTED
+#if !defined(PNG_1_0_X)
+ ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ _mmx_supported
+#endif
+ ? "MMX" :
+#endif
+ "C");
+ break;
+
+ case 4:
+ png_snprintf(filtname, 10, "paeth-%s",
+#ifdef PNG_MMX_READ_FILTER_PAETH_SUPPORTED
+#if defined(PNG_x86_64_USE_GOTPCREL) || defined(PNG_THREAD_UNSAFE_OK)
+#if !defined(PNG_1_0_X)
+ ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ _mmx_supported
+#endif
+ ? "MMX" :
+#endif /* PNG_x86_64_USE_GOTPCREL || PNG_THREAD_UNSAFE_OK */
+#endif
+ "C");
+ break;
+
+ default:
+ png_snprintf(filtname, 10, "unknown");
+ break;
+ }
+ png_debug2(2, "row_number=%ld, %s, ", png_ptr->row_number, filtname);
+ //png_debug1(0, "png_ptr=%10p, ", png_ptr);
+ //png_debug1(0, "asm_flags=0x%08lx, ", png_ptr->asm_flags);
+ png_debug1(0, "row=%10p, ", row);
+ png_debug2(0, "pixdepth=%d, bytes=%d, ", (int)row_info->pixel_depth,
+ (int)((row_info->pixel_depth + 7) >> 3));
+ png_debug1(0, "rowbytes=%ld\n", row_info->rowbytes);
+#endif /* PNG_DEBUG */
+
+ switch (filter)
+ {
+ case PNG_FILTER_VALUE_NONE:
+ break;
+
+ case PNG_FILTER_VALUE_SUB:
+#ifdef PNG_MMX_READ_FILTER_SUB_SUPPORTED
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ if (_mmx_supported)
+#endif
+ {
+ png_read_filter_row_mmx_sub(row_info, row);
+ }
+ else
+#endif
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_bytep rp = row + bpp;
+ png_bytep lp = row;
+
+ for (i = bpp; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
+ rp++;
+ }
+ } /* end !UseMMX_sub */
+ break;
+
+ case PNG_FILTER_VALUE_UP:
+#ifdef PNG_MMX_READ_FILTER_UP_SUPPORTED
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ if (_mmx_supported)
+#endif
+ {
+ png_read_filter_row_mmx_up(row_info, row, prev_row);
+ }
+ else
+#endif
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+
+ for (i = 0; i < istop; ++i)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+ } /* end !UseMMX_up */
+ break;
+
+ case PNG_FILTER_VALUE_AVG:
+#ifdef PNG_MMX_READ_FILTER_AVG_SUPPORTED
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ if (_mmx_supported)
+#endif
+ {
+ png_read_filter_row_mmx_avg(row_info, row, prev_row);
+ }
+ else
+#endif
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++) >> 1)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++ + *lp++) >> 1)) & 0xff);
+ rp++;
+ }
+ } /* end !UseMMX_avg */
+ break;
+
+ case PNG_FILTER_VALUE_PAETH:
+#ifdef PNG_MMX_READ_FILTER_PAETH_SUPPORTED
+#if defined(PNG_x86_64_USE_GOTPCREL) || defined(PNG_THREAD_UNSAFE_OK)
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ if (_mmx_supported)
+#endif
+ {
+ png_read_filter_row_mmx_paeth(row_info, row, prev_row);
+ }
+ else
+#endif /* PNG_x86_64_USE_GOTPCREL || PNG_THREAD_UNSAFE_OK */
+#endif
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_bytep cp = prev_row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++) /* use leftover rp,pp */
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ a = *lp++;
+ b = *pp++;
+ c = *cp++;
+
+ p = b - c;
+ pc = a - c;
+
+#if defined(PNG_USE_ABS)
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ /*
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+ */
+
+ p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
+
+ *rp = (png_byte)(((int)(*rp) + p) & 0xff);
+ rp++;
+ }
+ } /* end !UseMMX_paeth */
+ break;
+
+ default:
+ png_warning(png_ptr, "Ignoring bad row-filter type");
+ *row=0;
+ break;
+ }
+}
+
+#endif /* PNG_HAVE_MMX_READ_FILTER_ROW */
+
+
+#endif /* PNG_ASSEMBLER_CODE_SUPPORTED && PNG_USE_PNGGCCRD */
+#endif /* __GNUC__ */
diff --git a/distrib/libpng-1.2.19/pngget.c b/distrib/libpng-1.2.19/pngget.c
new file mode 100644
index 0000000..75d2ca0
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngget.c
@@ -0,0 +1,962 @@
+
+/* pngget.c - retrieval of values from info struct
+ *
+ * Last changed in libpng 1.2.15 January 5, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+
+png_uint_32 PNGAPI
+png_get_valid(png_structp png_ptr, png_infop info_ptr, png_uint_32 flag)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->valid & flag);
+ else
+ return(0);
+}
+
+png_uint_32 PNGAPI
+png_get_rowbytes(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->rowbytes);
+ else
+ return(0);
+}
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+png_bytepp PNGAPI
+png_get_rows(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->row_pointers);
+ else
+ return(0);
+}
+#endif
+
+#ifdef PNG_EASY_ACCESS_SUPPORTED
+/* easy access to info, added in libpng-0.99 */
+png_uint_32 PNGAPI
+png_get_image_width(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->width;
+ }
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_image_height(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->height;
+ }
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_bit_depth(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->bit_depth;
+ }
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_color_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->color_type;
+ }
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_filter_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->filter_type;
+ }
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_interlace_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->interlace_type;
+ }
+ return (0);
+}
+
+png_byte PNGAPI
+png_get_compression_type(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ {
+ return info_ptr->compression_type;
+ }
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_x_pixels_per_meter");
+ if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER)
+ return (0);
+ else return (info_ptr->x_pixels_per_unit);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_y_pixels_per_meter");
+ if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER)
+ return (0);
+ else return (info_ptr->y_pixels_per_unit);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+png_uint_32 PNGAPI
+png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_pixels_per_meter");
+ if(info_ptr->phys_unit_type != PNG_RESOLUTION_METER ||
+ info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit)
+ return (0);
+ else return (info_ptr->x_pixels_per_unit);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+float PNGAPI
+png_get_pixel_aspect_ratio(png_structp png_ptr, png_infop info_ptr)
+ {
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_aspect_ratio");
+ if (info_ptr->x_pixels_per_unit == 0)
+ return ((float)0.0);
+ else
+ return ((float)((float)info_ptr->y_pixels_per_unit
+ /(float)info_ptr->x_pixels_per_unit));
+ }
+#else
+ return (0.0);
+#endif
+ return ((float)0.0);
+}
+#endif
+
+png_int_32 PNGAPI
+png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER)
+ return (0);
+ else return (info_ptr->x_offset);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+png_int_32 PNGAPI
+png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER)
+ return (0);
+ else return (info_ptr->y_offset);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+png_int_32 PNGAPI
+png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_x_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL)
+ return (0);
+ else return (info_ptr->x_offset);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+png_int_32 PNGAPI
+png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+#if defined(PNG_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ {
+ png_debug1(1, "in %s retrieval function\n", "png_get_y_offset_microns");
+ if(info_ptr->offset_unit_type != PNG_OFFSET_PIXEL)
+ return (0);
+ else return (info_ptr->y_offset);
+ }
+#else
+ return (0);
+#endif
+ return (0);
+}
+
+#if defined(PNG_INCH_CONVERSIONS) && defined(PNG_FLOATING_POINT_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((png_uint_32)((float)png_get_pixels_per_meter(png_ptr, info_ptr)
+ *.0254 +.5));
+}
+
+png_uint_32 PNGAPI
+png_get_x_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((png_uint_32)((float)png_get_x_pixels_per_meter(png_ptr, info_ptr)
+ *.0254 +.5));
+}
+
+png_uint_32 PNGAPI
+png_get_y_pixels_per_inch(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((png_uint_32)((float)png_get_y_pixels_per_meter(png_ptr, info_ptr)
+ *.0254 +.5));
+}
+
+float PNGAPI
+png_get_x_offset_inches(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((float)png_get_x_offset_microns(png_ptr, info_ptr)
+ *.00003937);
+}
+
+float PNGAPI
+png_get_y_offset_inches(png_structp png_ptr, png_infop info_ptr)
+{
+ return ((float)png_get_y_offset_microns(png_ptr, info_ptr)
+ *.00003937);
+}
+
+#if defined(PNG_pHYs_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_pHYs_dpi(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
+{
+ png_uint_32 retval = 0;
+
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "pHYs");
+ if (res_x != NULL)
+ {
+ *res_x = info_ptr->x_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (res_y != NULL)
+ {
+ *res_y = info_ptr->y_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (unit_type != NULL)
+ {
+ *unit_type = (int)info_ptr->phys_unit_type;
+ retval |= PNG_INFO_pHYs;
+ if(*unit_type == 1)
+ {
+ if (res_x != NULL) *res_x = (png_uint_32)(*res_x * .0254 + .50);
+ if (res_y != NULL) *res_y = (png_uint_32)(*res_y * .0254 + .50);
+ }
+ }
+ }
+ return (retval);
+}
+#endif /* PNG_pHYs_SUPPORTED */
+#endif /* PNG_INCH_CONVERSIONS && PNG_FLOATING_POINT_SUPPORTED */
+
+/* png_get_channels really belongs in here, too, but it's been around longer */
+
+#endif /* PNG_EASY_ACCESS_SUPPORTED */
+
+png_byte PNGAPI
+png_get_channels(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->channels);
+ else
+ return (0);
+}
+
+png_bytep PNGAPI
+png_get_signature(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return(info_ptr->signature);
+ else
+ return (NULL);
+}
+
+#if defined(PNG_bKGD_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_bKGD(png_structp png_ptr, png_infop info_ptr,
+ png_color_16p *background)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)
+ && background != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "bKGD");
+ *background = &(info_ptr->background);
+ return (PNG_INFO_bKGD);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_cHRM(png_structp png_ptr, png_infop info_ptr,
+ double *white_x, double *white_y, double *red_x, double *red_y,
+ double *green_x, double *green_y, double *blue_x, double *blue_y)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
+ {
+ png_debug1(1, "in %s retrieval function\n", "cHRM");
+ if (white_x != NULL)
+ *white_x = (double)info_ptr->x_white;
+ if (white_y != NULL)
+ *white_y = (double)info_ptr->y_white;
+ if (red_x != NULL)
+ *red_x = (double)info_ptr->x_red;
+ if (red_y != NULL)
+ *red_y = (double)info_ptr->y_red;
+ if (green_x != NULL)
+ *green_x = (double)info_ptr->x_green;
+ if (green_y != NULL)
+ *green_y = (double)info_ptr->y_green;
+ if (blue_x != NULL)
+ *blue_x = (double)info_ptr->x_blue;
+ if (blue_y != NULL)
+ *blue_y = (double)info_ptr->y_blue;
+ return (PNG_INFO_cHRM);
+ }
+ return (0);
+}
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_cHRM_fixed(png_structp png_ptr, png_infop info_ptr,
+ png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x,
+ png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y,
+ png_fixed_point *blue_x, png_fixed_point *blue_y)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
+ {
+ png_debug1(1, "in %s retrieval function\n", "cHRM");
+ if (white_x != NULL)
+ *white_x = info_ptr->int_x_white;
+ if (white_y != NULL)
+ *white_y = info_ptr->int_y_white;
+ if (red_x != NULL)
+ *red_x = info_ptr->int_x_red;
+ if (red_y != NULL)
+ *red_y = info_ptr->int_y_red;
+ if (green_x != NULL)
+ *green_x = info_ptr->int_x_green;
+ if (green_y != NULL)
+ *green_y = info_ptr->int_y_green;
+ if (blue_x != NULL)
+ *blue_x = info_ptr->int_x_blue;
+ if (blue_y != NULL)
+ *blue_y = info_ptr->int_y_blue;
+ return (PNG_INFO_cHRM);
+ }
+ return (0);
+}
+#endif
+#endif
+
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_gAMA(png_structp png_ptr, png_infop info_ptr, double *file_gamma)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
+ && file_gamma != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "gAMA");
+ *file_gamma = (double)info_ptr->gamma;
+ return (PNG_INFO_gAMA);
+ }
+ return (0);
+}
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_gAMA_fixed(png_structp png_ptr, png_infop info_ptr,
+ png_fixed_point *int_file_gamma)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
+ && int_file_gamma != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "gAMA");
+ *int_file_gamma = info_ptr->int_gamma;
+ return (PNG_INFO_gAMA);
+ }
+ return (0);
+}
+#endif
+#endif
+
+#if defined(PNG_sRGB_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_sRGB(png_structp png_ptr, png_infop info_ptr, int *file_srgb_intent)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)
+ && file_srgb_intent != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "sRGB");
+ *file_srgb_intent = (int)info_ptr->srgb_intent;
+ return (PNG_INFO_sRGB);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_iCCP_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_iCCP(png_structp png_ptr, png_infop info_ptr,
+ png_charpp name, int *compression_type,
+ png_charpp profile, png_uint_32 *proflen)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)
+ && name != NULL && profile != NULL && proflen != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "iCCP");
+ *name = info_ptr->iccp_name;
+ *profile = info_ptr->iccp_profile;
+ /* compression_type is a dummy so the API won't have to change
+ if we introduce multiple compression types later. */
+ *proflen = (int)info_ptr->iccp_proflen;
+ *compression_type = (int)info_ptr->iccp_compression;
+ return (PNG_INFO_iCCP);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_sPLT(png_structp png_ptr, png_infop info_ptr,
+ png_sPLT_tpp spalettes)
+{
+ if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL)
+ {
+ *spalettes = info_ptr->splt_palettes;
+ return ((png_uint_32)info_ptr->splt_palettes_num);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p *hist)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)
+ && hist != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "hIST");
+ *hist = info_ptr->hist;
+ return (PNG_INFO_hIST);
+ }
+ return (0);
+}
+#endif
+
+png_uint_32 PNGAPI
+png_get_IHDR(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *width, png_uint_32 *height, int *bit_depth,
+ int *color_type, int *interlace_type, int *compression_type,
+ int *filter_type)
+
+{
+ if (png_ptr != NULL && info_ptr != NULL && width != NULL && height != NULL &&
+ bit_depth != NULL && color_type != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "IHDR");
+ *width = info_ptr->width;
+ *height = info_ptr->height;
+ *bit_depth = info_ptr->bit_depth;
+ if (info_ptr->bit_depth < 1 || info_ptr->bit_depth > 16)
+ png_error(png_ptr, "Invalid bit depth");
+ *color_type = info_ptr->color_type;
+ if (info_ptr->color_type > 6)
+ png_error(png_ptr, "Invalid color type");
+ if (compression_type != NULL)
+ *compression_type = info_ptr->compression_type;
+ if (filter_type != NULL)
+ *filter_type = info_ptr->filter_type;
+ if (interlace_type != NULL)
+ *interlace_type = info_ptr->interlace_type;
+
+ /* check for potential overflow of rowbytes */
+ if (*width == 0 || *width > PNG_UINT_31_MAX)
+ png_error(png_ptr, "Invalid image width");
+ if (*height == 0 || *height > PNG_UINT_31_MAX)
+ png_error(png_ptr, "Invalid image height");
+ if (info_ptr->width > (PNG_UINT_32_MAX
+ >> 3) /* 8-byte RGBA pixels */
+ - 64 /* bigrowbuf hack */
+ - 1 /* filter byte */
+ - 7*8 /* rounding of width to multiple of 8 pixels */
+ - 8) /* extra max_pixel_depth pad */
+ {
+ png_warning(png_ptr,
+ "Width too large for libpng to process image data.");
+ }
+ return (1);
+ }
+ return (0);
+}
+
+#if defined(PNG_oFFs_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_oFFs(png_structp png_ptr, png_infop info_ptr,
+ png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)
+ && offset_x != NULL && offset_y != NULL && unit_type != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "oFFs");
+ *offset_x = info_ptr->x_offset;
+ *offset_y = info_ptr->y_offset;
+ *unit_type = (int)info_ptr->offset_unit_type;
+ return (PNG_INFO_oFFs);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_pCAL(png_structp png_ptr, png_infop info_ptr,
+ png_charp *purpose, png_int_32 *X0, png_int_32 *X1, int *type, int *nparams,
+ png_charp *units, png_charpp *params)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)
+ && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL &&
+ nparams != NULL && units != NULL && params != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "pCAL");
+ *purpose = info_ptr->pcal_purpose;
+ *X0 = info_ptr->pcal_X0;
+ *X1 = info_ptr->pcal_X1;
+ *type = (int)info_ptr->pcal_type;
+ *nparams = (int)info_ptr->pcal_nparams;
+ *units = info_ptr->pcal_units;
+ *params = info_ptr->pcal_params;
+ return (PNG_INFO_pCAL);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_sCAL_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_sCAL(png_structp png_ptr, png_infop info_ptr,
+ int *unit, double *width, double *height)
+{
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_sCAL))
+ {
+ *unit = info_ptr->scal_unit;
+ *width = info_ptr->scal_pixel_width;
+ *height = info_ptr->scal_pixel_height;
+ return (PNG_INFO_sCAL);
+ }
+ return(0);
+}
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+png_uint_32 PNGAPI
+png_get_sCAL_s(png_structp png_ptr, png_infop info_ptr,
+ int *unit, png_charpp width, png_charpp height)
+{
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_sCAL))
+ {
+ *unit = info_ptr->scal_unit;
+ *width = info_ptr->scal_s_width;
+ *height = info_ptr->scal_s_height;
+ return (PNG_INFO_sCAL);
+ }
+ return(0);
+}
+#endif
+#endif
+#endif
+
+#if defined(PNG_pHYs_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_pHYs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)
+{
+ png_uint_32 retval = 0;
+
+ if (png_ptr != NULL && info_ptr != NULL &&
+ (info_ptr->valid & PNG_INFO_pHYs))
+ {
+ png_debug1(1, "in %s retrieval function\n", "pHYs");
+ if (res_x != NULL)
+ {
+ *res_x = info_ptr->x_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (res_y != NULL)
+ {
+ *res_y = info_ptr->y_pixels_per_unit;
+ retval |= PNG_INFO_pHYs;
+ }
+ if (unit_type != NULL)
+ {
+ *unit_type = (int)info_ptr->phys_unit_type;
+ retval |= PNG_INFO_pHYs;
+ }
+ }
+ return (retval);
+}
+#endif
+
+png_uint_32 PNGAPI
+png_get_PLTE(png_structp png_ptr, png_infop info_ptr, png_colorp *palette,
+ int *num_palette)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE)
+ && palette != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "PLTE");
+ *palette = info_ptr->palette;
+ *num_palette = info_ptr->num_palette;
+ png_debug1(3, "num_palette = %d\n", *num_palette);
+ return (PNG_INFO_PLTE);
+ }
+ return (0);
+}
+
+#if defined(PNG_sBIT_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_sBIT(png_structp png_ptr, png_infop info_ptr, png_color_8p *sig_bit)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)
+ && sig_bit != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "sBIT");
+ *sig_bit = &(info_ptr->sig_bit);
+ return (PNG_INFO_sBIT);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_TEXT_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_text(png_structp png_ptr, png_infop info_ptr, png_textp *text_ptr,
+ int *num_text)
+{
+ if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0)
+ {
+ png_debug1(1, "in %s retrieval function\n",
+ (png_ptr->chunk_name[0] == '\0' ? "text"
+ : (png_const_charp)png_ptr->chunk_name));
+ if (text_ptr != NULL)
+ *text_ptr = info_ptr->text;
+ if (num_text != NULL)
+ *num_text = info_ptr->num_text;
+ return ((png_uint_32)info_ptr->num_text);
+ }
+ if (num_text != NULL)
+ *num_text = 0;
+ return(0);
+}
+#endif
+
+#if defined(PNG_tIME_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_tIME(png_structp png_ptr, png_infop info_ptr, png_timep *mod_time)
+{
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)
+ && mod_time != NULL)
+ {
+ png_debug1(1, "in %s retrieval function\n", "tIME");
+ *mod_time = &(info_ptr->mod_time);
+ return (PNG_INFO_tIME);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_tRNS(png_structp png_ptr, png_infop info_ptr,
+ png_bytep *trans, int *num_trans, png_color_16p *trans_values)
+{
+ png_uint_32 retval = 0;
+ if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
+ {
+ png_debug1(1, "in %s retrieval function\n", "tRNS");
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (trans != NULL)
+ {
+ *trans = info_ptr->trans;
+ retval |= PNG_INFO_tRNS;
+ }
+ if (trans_values != NULL)
+ *trans_values = &(info_ptr->trans_values);
+ }
+ else /* if (info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) */
+ {
+ if (trans_values != NULL)
+ {
+ *trans_values = &(info_ptr->trans_values);
+ retval |= PNG_INFO_tRNS;
+ }
+ if(trans != NULL)
+ *trans = NULL;
+ }
+ if(num_trans != NULL)
+ {
+ *num_trans = info_ptr->num_trans;
+ retval |= PNG_INFO_tRNS;
+ }
+ }
+ return (retval);
+}
+#endif
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+png_uint_32 PNGAPI
+png_get_unknown_chunks(png_structp png_ptr, png_infop info_ptr,
+ png_unknown_chunkpp unknowns)
+{
+ if (png_ptr != NULL && info_ptr != NULL && unknowns != NULL)
+ {
+ *unknowns = info_ptr->unknown_chunks;
+ return ((png_uint_32)info_ptr->unknown_chunks_num);
+ }
+ return (0);
+}
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+png_byte PNGAPI
+png_get_rgb_to_gray_status (png_structp png_ptr)
+{
+ return (png_byte)(png_ptr? png_ptr->rgb_to_gray_status : 0);
+}
+#endif
+
+#if defined(PNG_USER_CHUNKS_SUPPORTED)
+png_voidp PNGAPI
+png_get_user_chunk_ptr(png_structp png_ptr)
+{
+ return (png_ptr? png_ptr->user_chunk_ptr : NULL);
+}
+#endif
+
+#ifdef PNG_WRITE_SUPPORTED
+png_uint_32 PNGAPI
+png_get_compression_buffer_size(png_structp png_ptr)
+{
+ return (png_uint_32)(png_ptr? png_ptr->zbuf_size : 0L);
+}
+#endif
+
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+#ifndef PNG_1_0_X
+/* this function was added to libpng 1.2.0 and should exist by default */
+png_uint_32 PNGAPI
+png_get_asm_flags (png_structp png_ptr)
+{
+#ifdef PNG_MMX_CODE_SUPPORTED
+ return (png_uint_32)(png_ptr? png_ptr->asm_flags : 0L);
+#else
+ return (png_ptr? 0L: 0L);
+#endif
+}
+
+/* this function was added to libpng 1.2.0 and should exist by default */
+png_uint_32 PNGAPI
+png_get_asm_flagmask (int flag_select)
+{
+#ifdef PNG_MMX_CODE_SUPPORTED
+ png_uint_32 settable_asm_flags = 0;
+
+ if (flag_select & PNG_SELECT_READ)
+ settable_asm_flags |=
+ PNG_ASM_FLAG_MMX_READ_COMBINE_ROW |
+ PNG_ASM_FLAG_MMX_READ_INTERLACE |
+ PNG_ASM_FLAG_MMX_READ_FILTER_SUB |
+ PNG_ASM_FLAG_MMX_READ_FILTER_UP |
+ PNG_ASM_FLAG_MMX_READ_FILTER_AVG |
+ PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
+ /* no non-MMX flags yet */
+
+#if 0
+ /* GRR: no write-flags yet, either, but someday... */
+ if (flag_select & PNG_SELECT_WRITE)
+ settable_asm_flags |=
+ PNG_ASM_FLAG_MMX_WRITE_ [whatever] ;
+#endif /* 0 */
+
+ return settable_asm_flags; /* _theoretically_ settable capabilities only */
+#else
+ return (0L);
+#endif /* PNG_MMX_CODE_SUPPORTED */
+}
+
+
+ /* GRR: could add this: && defined(PNG_MMX_CODE_SUPPORTED) */
+/* this function was added to libpng 1.2.0 */
+png_uint_32 PNGAPI
+png_get_mmx_flagmask (int flag_select, int *compilerID)
+{
+#if defined(PNG_MMX_CODE_SUPPORTED)
+ png_uint_32 settable_mmx_flags = 0;
+
+ if (flag_select & PNG_SELECT_READ)
+ settable_mmx_flags |=
+ PNG_ASM_FLAG_MMX_READ_COMBINE_ROW |
+ PNG_ASM_FLAG_MMX_READ_INTERLACE |
+ PNG_ASM_FLAG_MMX_READ_FILTER_SUB |
+ PNG_ASM_FLAG_MMX_READ_FILTER_UP |
+ PNG_ASM_FLAG_MMX_READ_FILTER_AVG |
+ PNG_ASM_FLAG_MMX_READ_FILTER_PAETH ;
+#if 0
+ /* GRR: no MMX write support yet, but someday... */
+ if (flag_select & PNG_SELECT_WRITE)
+ settable_mmx_flags |=
+ PNG_ASM_FLAG_MMX_WRITE_ [whatever] ;
+#endif /* 0 */
+
+ if (compilerID != NULL) {
+#ifdef PNG_USE_PNGVCRD
+ *compilerID = 1; /* MSVC */
+#else
+#ifdef PNG_USE_PNGGCCRD
+ *compilerID = 2; /* gcc/gas */
+#else
+ *compilerID = -1; /* unknown (i.e., no asm/MMX code compiled) */
+#endif
+#endif
+ }
+
+ return settable_mmx_flags; /* _theoretically_ settable capabilities only */
+#else
+ return (0L);
+#endif /* ?PNG_MMX_CODE_SUPPORTED */
+}
+
+/* this function was added to libpng 1.2.0 */
+png_byte PNGAPI
+png_get_mmx_bitdepth_threshold (png_structp png_ptr)
+{
+#if defined(PNG_MMX_CODE_SUPPORTED)
+ return (png_byte)(png_ptr? png_ptr->mmx_bitdepth_threshold : 0);
+#else
+ return (png_ptr? 0: 0);
+#endif /* ?PNG_MMX_CODE_SUPPORTED */
+}
+
+/* this function was added to libpng 1.2.0 */
+png_uint_32 PNGAPI
+png_get_mmx_rowbytes_threshold (png_structp png_ptr)
+{
+#if defined(PNG_MMX_CODE_SUPPORTED)
+ return (png_uint_32)(png_ptr? png_ptr->mmx_rowbytes_threshold : 0L);
+#else
+ return (png_ptr? 0L: 0L);
+#endif /* ?PNG_MMX_CODE_SUPPORTED */
+}
+#endif /* ?PNG_1_0_X */
+#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */
+
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+/* these functions were added to libpng 1.2.6 */
+png_uint_32 PNGAPI
+png_get_user_width_max (png_structp png_ptr)
+{
+ return (png_ptr? png_ptr->user_width_max : 0);
+}
+png_uint_32 PNGAPI
+png_get_user_height_max (png_structp png_ptr)
+{
+ return (png_ptr? png_ptr->user_height_max : 0);
+}
+#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */
+
+
+#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngmem.c b/distrib/libpng-1.2.19/pngmem.c
new file mode 100644
index 0000000..248060f
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngmem.c
@@ -0,0 +1,608 @@
+
+/* pngmem.c - stub functions for memory allocation
+ *
+ * Last changed in libpng 1.2.13 November 13, 2006
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2006 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file provides a location for all memory allocation. Users who
+ * need special memory handling are expected to supply replacement
+ * functions for png_malloc() and png_free(), and to use
+ * png_create_read_struct_2() and png_create_write_struct_2() to
+ * identify the replacement functions.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+
+/* Borland DOS special memory handler */
+#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
+/* if you change this, be sure to change the one in png.h also */
+
+/* Allocate memory for a png_struct. The malloc and memset can be replaced
+ by a single call to calloc() if this is thought to improve performance. */
+png_voidp /* PRIVATE */
+png_create_struct(int type)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL));
+}
+
+/* Alternate version of png_create_struct, for use with user-defined malloc. */
+png_voidp /* PRIVATE */
+png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_size_t size;
+ png_voidp struct_ptr;
+
+ if (type == PNG_STRUCT_INFO)
+ size = png_sizeof(png_info);
+ else if (type == PNG_STRUCT_PNG)
+ size = png_sizeof(png_struct);
+ else
+ return (png_get_copyright(NULL));
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(malloc_fn != NULL)
+ {
+ png_struct dummy_struct;
+ png_structp png_ptr = &dummy_struct;
+ png_ptr->mem_ptr=mem_ptr;
+ struct_ptr = (*(malloc_fn))(png_ptr, (png_uint_32)size);
+ }
+ else
+#endif /* PNG_USER_MEM_SUPPORTED */
+ struct_ptr = (png_voidp)farmalloc(size);
+ if (struct_ptr != NULL)
+ png_memset(struct_ptr, 0, size);
+ return (struct_ptr);
+}
+
+/* Free memory allocated by a png_create_struct() call */
+void /* PRIVATE */
+png_destroy_struct(png_voidp struct_ptr)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL);
+}
+
+/* Free memory allocated by a png_create_struct() call */
+void /* PRIVATE */
+png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
+ png_voidp mem_ptr)
+{
+#endif
+ if (struct_ptr != NULL)
+ {
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(free_fn != NULL)
+ {
+ png_struct dummy_struct;
+ png_structp png_ptr = &dummy_struct;
+ png_ptr->mem_ptr=mem_ptr;
+ (*(free_fn))(png_ptr, struct_ptr);
+ return;
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+ farfree (struct_ptr);
+ }
+}
+
+/* Allocate memory. For reasonable files, size should never exceed
+ * 64K. However, zlib may allocate more then 64K if you don't tell
+ * it not to. See zconf.h and png.h for more information. zlib does
+ * need to allocate exactly 64K, so whatever you call here must
+ * have the ability to do that.
+ *
+ * Borland seems to have a problem in DOS mode for exactly 64K.
+ * It gives you a segment with an offset of 8 (perhaps to store its
+ * memory stuff). zlib doesn't like this at all, so we have to
+ * detect and deal with it. This code should not be needed in
+ * Windows or OS/2 modes, and only in 16 bit mode. This code has
+ * been updated by Alexander Lehmann for version 0.89 to waste less
+ * memory.
+ *
+ * Note that we can't use png_size_t for the "size" declaration,
+ * since on some systems a png_size_t is a 16-bit quantity, and as a
+ * result, we would be truncating potentially larger memory requests
+ * (which should cause a fatal error) and introducing major problems.
+ */
+
+png_voidp PNGAPI
+png_malloc(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+
+ if (png_ptr == NULL || size == 0)
+ return (NULL);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(png_ptr->malloc_fn != NULL)
+ ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size));
+ else
+ ret = (png_malloc_default(png_ptr, size));
+ if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
+ png_error(png_ptr, "Out of memory!");
+ return (ret);
+}
+
+png_voidp PNGAPI
+png_malloc_default(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+ if (png_ptr == NULL || size == 0)
+ return (NULL);
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ {
+ png_warning(png_ptr, "Cannot Allocate > 64K");
+ ret = NULL;
+ }
+ else
+#endif
+
+ if (size != (size_t)size)
+ ret = NULL;
+ else if (size == (png_uint_32)65536L)
+ {
+ if (png_ptr->offset_table == NULL)
+ {
+ /* try to see if we need to do any of this fancy stuff */
+ ret = farmalloc(size);
+ if (ret == NULL || ((png_size_t)ret & 0xffff))
+ {
+ int num_blocks;
+ png_uint_32 total_size;
+ png_bytep table;
+ int i;
+ png_byte huge * hptr;
+
+ if (ret != NULL)
+ {
+ farfree(ret);
+ ret = NULL;
+ }
+
+ if(png_ptr->zlib_window_bits > 14)
+ num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14));
+ else
+ num_blocks = 1;
+ if (png_ptr->zlib_mem_level >= 7)
+ num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7));
+ else
+ num_blocks++;
+
+ total_size = ((png_uint_32)65536L) * (png_uint_32)num_blocks+16;
+
+ table = farmalloc(total_size);
+
+ if (table == NULL)
+ {
+#ifndef PNG_USER_MEM_SUPPORTED
+ if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
+ png_error(png_ptr, "Out Of Memory."); /* Note "O" and "M" */
+ else
+ png_warning(png_ptr, "Out Of Memory.");
+#endif
+ return (NULL);
+ }
+
+ if ((png_size_t)table & 0xfff0)
+ {
+#ifndef PNG_USER_MEM_SUPPORTED
+ if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
+ png_error(png_ptr,
+ "Farmalloc didn't return normalized pointer");
+ else
+ png_warning(png_ptr,
+ "Farmalloc didn't return normalized pointer");
+#endif
+ return (NULL);
+ }
+
+ png_ptr->offset_table = table;
+ png_ptr->offset_table_ptr = farmalloc(num_blocks *
+ png_sizeof (png_bytep));
+
+ if (png_ptr->offset_table_ptr == NULL)
+ {
+#ifndef PNG_USER_MEM_SUPPORTED
+ if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
+ png_error(png_ptr, "Out Of memory."); /* Note "O" and "M" */
+ else
+ png_warning(png_ptr, "Out Of memory.");
+#endif
+ return (NULL);
+ }
+
+ hptr = (png_byte huge *)table;
+ if ((png_size_t)hptr & 0xf)
+ {
+ hptr = (png_byte huge *)((long)(hptr) & 0xfffffff0L);
+ hptr = hptr + 16L; /* "hptr += 16L" fails on Turbo C++ 3.0 */
+ }
+ for (i = 0; i < num_blocks; i++)
+ {
+ png_ptr->offset_table_ptr[i] = (png_bytep)hptr;
+ hptr = hptr + (png_uint_32)65536L; /* "+=" fails on TC++3.0 */
+ }
+
+ png_ptr->offset_table_number = num_blocks;
+ png_ptr->offset_table_count = 0;
+ png_ptr->offset_table_count_free = 0;
+ }
+ }
+
+ if (png_ptr->offset_table_count >= png_ptr->offset_table_number)
+ {
+#ifndef PNG_USER_MEM_SUPPORTED
+ if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
+ png_error(png_ptr, "Out of Memory."); /* Note "o" and "M" */
+ else
+ png_warning(png_ptr, "Out of Memory.");
+#endif
+ return (NULL);
+ }
+
+ ret = png_ptr->offset_table_ptr[png_ptr->offset_table_count++];
+ }
+ else
+ ret = farmalloc(size);
+
+#ifndef PNG_USER_MEM_SUPPORTED
+ if (ret == NULL)
+ {
+ if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
+ png_error(png_ptr, "Out of memory."); /* Note "o" and "m" */
+ else
+ png_warning(png_ptr, "Out of memory."); /* Note "o" and "m" */
+ }
+#endif
+
+ return (ret);
+}
+
+/* free a pointer allocated by png_malloc(). In the default
+ configuration, png_ptr is not used, but is passed in case it
+ is needed. If ptr is NULL, return without taking any action. */
+void PNGAPI
+png_free(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL || ptr == NULL)
+ return;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (png_ptr->free_fn != NULL)
+ {
+ (*(png_ptr->free_fn))(png_ptr, ptr);
+ return;
+ }
+ else png_free_default(png_ptr, ptr);
+}
+
+void PNGAPI
+png_free_default(png_structp png_ptr, png_voidp ptr)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+ if(png_ptr == NULL) return;
+
+ if (png_ptr->offset_table != NULL)
+ {
+ int i;
+
+ for (i = 0; i < png_ptr->offset_table_count; i++)
+ {
+ if (ptr == png_ptr->offset_table_ptr[i])
+ {
+ ptr = NULL;
+ png_ptr->offset_table_count_free++;
+ break;
+ }
+ }
+ if (png_ptr->offset_table_count_free == png_ptr->offset_table_count)
+ {
+ farfree(png_ptr->offset_table);
+ farfree(png_ptr->offset_table_ptr);
+ png_ptr->offset_table = NULL;
+ png_ptr->offset_table_ptr = NULL;
+ }
+ }
+
+ if (ptr != NULL)
+ {
+ farfree(ptr);
+ }
+}
+
+#else /* Not the Borland DOS special memory handler */
+
+/* Allocate memory for a png_struct or a png_info. The malloc and
+ memset can be replaced by a single call to calloc() if this is thought
+ to improve performance noticably. */
+png_voidp /* PRIVATE */
+png_create_struct(int type)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_struct_2(type, png_malloc_ptr_NULL, png_voidp_NULL));
+}
+
+/* Allocate memory for a png_struct or a png_info. The malloc and
+ memset can be replaced by a single call to calloc() if this is thought
+ to improve performance noticably. */
+png_voidp /* PRIVATE */
+png_create_struct_2(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_size_t size;
+ png_voidp struct_ptr;
+
+ if (type == PNG_STRUCT_INFO)
+ size = png_sizeof(png_info);
+ else if (type == PNG_STRUCT_PNG)
+ size = png_sizeof(png_struct);
+ else
+ return (NULL);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(malloc_fn != NULL)
+ {
+ png_struct dummy_struct;
+ png_structp png_ptr = &dummy_struct;
+ png_ptr->mem_ptr=mem_ptr;
+ struct_ptr = (*(malloc_fn))(png_ptr, size);
+ if (struct_ptr != NULL)
+ png_memset(struct_ptr, 0, size);
+ return (struct_ptr);
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ struct_ptr = (png_voidp)farmalloc(size);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ struct_ptr = (png_voidp)halloc(size,1);
+# else
+ struct_ptr = (png_voidp)malloc(size);
+# endif
+#endif
+ if (struct_ptr != NULL)
+ png_memset(struct_ptr, 0, size);
+
+ return (struct_ptr);
+}
+
+
+/* Free memory allocated by a png_create_struct() call */
+void /* PRIVATE */
+png_destroy_struct(png_voidp struct_ptr)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2(struct_ptr, png_free_ptr_NULL, png_voidp_NULL);
+}
+
+/* Free memory allocated by a png_create_struct() call */
+void /* PRIVATE */
+png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
+ png_voidp mem_ptr)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ if (struct_ptr != NULL)
+ {
+#ifdef PNG_USER_MEM_SUPPORTED
+ if(free_fn != NULL)
+ {
+ png_struct dummy_struct;
+ png_structp png_ptr = &dummy_struct;
+ png_ptr->mem_ptr=mem_ptr;
+ (*(free_fn))(png_ptr, struct_ptr);
+ return;
+ }
+#endif /* PNG_USER_MEM_SUPPORTED */
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ farfree(struct_ptr);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ hfree(struct_ptr);
+# else
+ free(struct_ptr);
+# endif
+#endif
+ }
+}
+
+/* Allocate memory. For reasonable files, size should never exceed
+ 64K. However, zlib may allocate more then 64K if you don't tell
+ it not to. See zconf.h and png.h for more information. zlib does
+ need to allocate exactly 64K, so whatever you call here must
+ have the ability to do that. */
+
+png_voidp PNGAPI
+png_malloc(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (png_ptr == NULL || size == 0)
+ return (NULL);
+
+ if(png_ptr->malloc_fn != NULL)
+ ret = ((png_voidp)(*(png_ptr->malloc_fn))(png_ptr, (png_size_t)size));
+ else
+ ret = (png_malloc_default(png_ptr, size));
+ if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
+ png_error(png_ptr, "Out of Memory!");
+ return (ret);
+}
+
+png_voidp PNGAPI
+png_malloc_default(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ret;
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+ if (png_ptr == NULL || size == 0)
+ return (NULL);
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (size > (png_uint_32)65536L)
+ {
+#ifndef PNG_USER_MEM_SUPPORTED
+ if(png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
+ png_error(png_ptr, "Cannot Allocate > 64K");
+ else
+#endif
+ return NULL;
+ }
+#endif
+
+ /* Check for overflow */
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ if (size != (unsigned long)size)
+ ret = NULL;
+ else
+ ret = farmalloc(size);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ if (size != (unsigned long)size)
+ ret = NULL;
+ else
+ ret = halloc(size, 1);
+# else
+ if (size != (size_t)size)
+ ret = NULL;
+ else
+ ret = malloc((size_t)size);
+# endif
+#endif
+
+#ifndef PNG_USER_MEM_SUPPORTED
+ if (ret == NULL && (png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0)
+ png_error(png_ptr, "Out of Memory");
+#endif
+
+ return (ret);
+}
+
+/* Free a pointer allocated by png_malloc(). If ptr is NULL, return
+ without taking any action. */
+void PNGAPI
+png_free(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL || ptr == NULL)
+ return;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ if (png_ptr->free_fn != NULL)
+ {
+ (*(png_ptr->free_fn))(png_ptr, ptr);
+ return;
+ }
+ else png_free_default(png_ptr, ptr);
+}
+void PNGAPI
+png_free_default(png_structp png_ptr, png_voidp ptr)
+{
+ if (png_ptr == NULL || ptr == NULL)
+ return;
+
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+#if defined(__TURBOC__) && !defined(__FLAT__)
+ farfree(ptr);
+#else
+# if defined(_MSC_VER) && defined(MAXSEG_64K)
+ hfree(ptr);
+# else
+ free(ptr);
+# endif
+#endif
+}
+
+#endif /* Not Borland DOS special memory handler */
+
+#if defined(PNG_1_0_X)
+# define png_malloc_warn png_malloc
+#else
+/* This function was added at libpng version 1.2.3. The png_malloc_warn()
+ * function will set up png_malloc() to issue a png_warning and return NULL
+ * instead of issuing a png_error, if it fails to allocate the requested
+ * memory.
+ */
+png_voidp PNGAPI
+png_malloc_warn(png_structp png_ptr, png_uint_32 size)
+{
+ png_voidp ptr;
+ png_uint_32 save_flags;
+ if(png_ptr == NULL) return (NULL);
+
+ save_flags=png_ptr->flags;
+ png_ptr->flags|=PNG_FLAG_MALLOC_NULL_MEM_OK;
+ ptr = (png_voidp)png_malloc((png_structp)png_ptr, size);
+ png_ptr->flags=save_flags;
+ return(ptr);
+}
+#endif
+
+png_voidp PNGAPI
+png_memcpy_check (png_structp png_ptr, png_voidp s1, png_voidp s2,
+ png_uint_32 length)
+{
+ png_size_t size;
+
+ size = (png_size_t)length;
+ if ((png_uint_32)size != length)
+ png_error(png_ptr,"Overflow in png_memcpy_check.");
+
+ return(png_memcpy (s1, s2, size));
+}
+
+png_voidp PNGAPI
+png_memset_check (png_structp png_ptr, png_voidp s1, int value,
+ png_uint_32 length)
+{
+ png_size_t size;
+
+ size = (png_size_t)length;
+ if ((png_uint_32)size != length)
+ png_error(png_ptr,"Overflow in png_memset_check.");
+
+ return (png_memset (s1, value, size));
+
+}
+
+#ifdef PNG_USER_MEM_SUPPORTED
+/* This function is called when the application wants to use another method
+ * of allocating and freeing memory.
+ */
+void PNGAPI
+png_set_mem_fn(png_structp png_ptr, png_voidp mem_ptr, png_malloc_ptr
+ malloc_fn, png_free_ptr free_fn)
+{
+ if(png_ptr != NULL) {
+ png_ptr->mem_ptr = mem_ptr;
+ png_ptr->malloc_fn = malloc_fn;
+ png_ptr->free_fn = free_fn;
+ }
+}
+
+/* This function returns a pointer to the mem_ptr associated with the user
+ * functions. The application should free any memory associated with this
+ * pointer before png_write_destroy and png_read_destroy are called.
+ */
+png_voidp PNGAPI
+png_get_mem_ptr(png_structp png_ptr)
+{
+ if(png_ptr == NULL) return (NULL);
+ return ((png_voidp)png_ptr->mem_ptr);
+}
+#endif /* PNG_USER_MEM_SUPPORTED */
+#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngpread.c b/distrib/libpng-1.2.19/pngpread.c
new file mode 100644
index 0000000..7d29e98
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngpread.c
@@ -0,0 +1,1585 @@
+
+/* pngpread.c - read a png file in push mode
+ *
+ * Last changed in libpng 1.2.19 August 18, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+
+/* push model modes */
+#define PNG_READ_SIG_MODE 0
+#define PNG_READ_CHUNK_MODE 1
+#define PNG_READ_IDAT_MODE 2
+#define PNG_SKIP_MODE 3
+#define PNG_READ_tEXt_MODE 4
+#define PNG_READ_zTXt_MODE 5
+#define PNG_READ_DONE_MODE 6
+#define PNG_READ_iTXt_MODE 7
+#define PNG_ERROR_MODE 8
+
+void PNGAPI
+png_process_data(png_structp png_ptr, png_infop info_ptr,
+ png_bytep buffer, png_size_t buffer_size)
+{
+ if(png_ptr == NULL) return;
+ png_push_restore_buffer(png_ptr, buffer, buffer_size);
+
+ while (png_ptr->buffer_size)
+ {
+ png_process_some_data(png_ptr, info_ptr);
+ }
+}
+
+/* What we do with the incoming data depends on what we were previously
+ * doing before we ran out of data...
+ */
+void /* PRIVATE */
+png_process_some_data(png_structp png_ptr, png_infop info_ptr)
+{
+ if(png_ptr == NULL) return;
+ switch (png_ptr->process_mode)
+ {
+ case PNG_READ_SIG_MODE:
+ {
+ png_push_read_sig(png_ptr, info_ptr);
+ break;
+ }
+ case PNG_READ_CHUNK_MODE:
+ {
+ png_push_read_chunk(png_ptr, info_ptr);
+ break;
+ }
+ case PNG_READ_IDAT_MODE:
+ {
+ png_push_read_IDAT(png_ptr);
+ break;
+ }
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ case PNG_READ_tEXt_MODE:
+ {
+ png_push_read_tEXt(png_ptr, info_ptr);
+ break;
+ }
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ case PNG_READ_zTXt_MODE:
+ {
+ png_push_read_zTXt(png_ptr, info_ptr);
+ break;
+ }
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ case PNG_READ_iTXt_MODE:
+ {
+ png_push_read_iTXt(png_ptr, info_ptr);
+ break;
+ }
+#endif
+ case PNG_SKIP_MODE:
+ {
+ png_push_crc_finish(png_ptr);
+ break;
+ }
+ default:
+ {
+ png_ptr->buffer_size = 0;
+ break;
+ }
+ }
+}
+
+/* Read any remaining signature bytes from the stream and compare them with
+ * the correct PNG signature. It is possible that this routine is called
+ * with bytes already read from the signature, either because they have been
+ * checked by the calling application, or because of multiple calls to this
+ * routine.
+ */
+void /* PRIVATE */
+png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
+{
+ png_size_t num_checked = png_ptr->sig_bytes,
+ num_to_check = 8 - num_checked;
+
+ if (png_ptr->buffer_size < num_to_check)
+ {
+ num_to_check = png_ptr->buffer_size;
+ }
+
+ png_push_fill_buffer(png_ptr, &(info_ptr->signature[num_checked]),
+ num_to_check);
+ png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes+num_to_check);
+
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ {
+ if (num_checked < 4 &&
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_error(png_ptr, "Not a PNG file");
+ else
+ png_error(png_ptr, "PNG file corrupted by ASCII conversion");
+ }
+ else
+ {
+ if (png_ptr->sig_bytes >= 8)
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ }
+ }
+}
+
+void /* PRIVATE */
+png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_CONST PNG_IHDR;
+ PNG_CONST PNG_IDAT;
+ PNG_CONST PNG_IEND;
+ PNG_CONST PNG_PLTE;
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ PNG_CONST PNG_bKGD;
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ PNG_CONST PNG_cHRM;
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ PNG_CONST PNG_gAMA;
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ PNG_CONST PNG_hIST;
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ PNG_CONST PNG_iCCP;
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ PNG_CONST PNG_iTXt;
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ PNG_CONST PNG_oFFs;
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ PNG_CONST PNG_pCAL;
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ PNG_CONST PNG_pHYs;
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ PNG_CONST PNG_sBIT;
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ PNG_CONST PNG_sCAL;
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ PNG_CONST PNG_sRGB;
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ PNG_CONST PNG_sPLT;
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ PNG_CONST PNG_tEXt;
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ PNG_CONST PNG_tIME;
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ PNG_CONST PNG_tRNS;
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ PNG_CONST PNG_zTXt;
+#endif
+#endif /* PNG_USE_LOCAL_ARRAYS */
+ /* First we make sure we have enough data for the 4 byte chunk name
+ * and the 4 byte chunk length before proceeding with decoding the
+ * chunk data. To fully decode each of these chunks, we also make
+ * sure we have enough data in the buffer for the 4 byte CRC at the
+ * end of every chunk (except IDAT, which is handled separately).
+ */
+ if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))
+ {
+ png_byte chunk_length[4];
+
+ if (png_ptr->buffer_size < 8)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_31(png_ptr,chunk_length);
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+ }
+
+ if (!png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
+ if(png_ptr->mode & PNG_AFTER_IDAT)
+ png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
+
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length);
+
+ png_ptr->process_mode = PNG_READ_DONE_MODE;
+ png_push_have_end(png_ptr, info_ptr);
+ }
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
+ if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_ptr->mode |= PNG_HAVE_PLTE;
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before IDAT");
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ png_error(png_ptr, "Missing PLTE before IDAT");
+ }
+ }
+#endif
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
+ {
+ /* If we reach an IDAT chunk, this means we have read all of the
+ * header chunks, and we can start reading the image (or if this
+ * is called after the image has been read - we have an error).
+ */
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before IDAT");
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ png_error(png_ptr, "Missing PLTE before IDAT");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))
+ if (png_ptr->push_length == 0)
+ return;
+
+ if (png_ptr->mode & PNG_AFTER_IDAT)
+ png_error(png_ptr, "Too many IDAT's found");
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ png_ptr->process_mode = PNG_READ_IDAT_MODE;
+ png_push_have_info(png_ptr, info_ptr);
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ return;
+ }
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+ }
+#endif
+ else
+ {
+ if (png_ptr->push_length + 4 > png_ptr->buffer_size)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+ png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
+ }
+
+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+}
+
+void /* PRIVATE */
+png_push_crc_skip(png_structp png_ptr, png_uint_32 skip)
+{
+ png_ptr->process_mode = PNG_SKIP_MODE;
+ png_ptr->skip_length = skip;
+}
+
+void /* PRIVATE */
+png_push_crc_finish(png_structp png_ptr)
+{
+ if (png_ptr->skip_length && png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->skip_length < (png_uint_32)png_ptr->save_buffer_size)
+ save_size = (png_size_t)png_ptr->skip_length;
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
+
+ png_ptr->skip_length -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (png_ptr->skip_length && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->skip_length < (png_uint_32)png_ptr->current_buffer_size)
+ save_size = (png_size_t)png_ptr->skip_length;
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
+
+ png_ptr->skip_length -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+ if (!png_ptr->skip_length)
+ {
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_crc_finish(png_ptr, 0);
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ }
+}
+
+void PNGAPI
+png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
+{
+ png_bytep ptr;
+
+ if(png_ptr == NULL) return;
+ ptr = buffer;
+ if (png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (length < png_ptr->save_buffer_size)
+ save_size = length;
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_memcpy(ptr, png_ptr->save_buffer_ptr, save_size);
+ length -= save_size;
+ ptr += save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (length && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (length < png_ptr->current_buffer_size)
+ save_size = length;
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_memcpy(ptr, png_ptr->current_buffer_ptr, save_size);
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+}
+
+void /* PRIVATE */
+png_push_save_buffer(png_structp png_ptr)
+{
+ if (png_ptr->save_buffer_size)
+ {
+ if (png_ptr->save_buffer_ptr != png_ptr->save_buffer)
+ {
+ png_size_t i,istop;
+ png_bytep sp;
+ png_bytep dp;
+
+ istop = png_ptr->save_buffer_size;
+ for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer;
+ i < istop; i++, sp++, dp++)
+ {
+ *dp = *sp;
+ }
+ }
+ }
+ if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >
+ png_ptr->save_buffer_max)
+ {
+ png_size_t new_max;
+ png_bytep old_buffer;
+
+ if (png_ptr->save_buffer_size > PNG_SIZE_MAX -
+ (png_ptr->current_buffer_size + 256))
+ {
+ png_error(png_ptr, "Potential overflow of save_buffer");
+ }
+ new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;
+ old_buffer = png_ptr->save_buffer;
+ png_ptr->save_buffer = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)new_max);
+ png_memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size);
+ png_free(png_ptr, old_buffer);
+ png_ptr->save_buffer_max = new_max;
+ }
+ if (png_ptr->current_buffer_size)
+ {
+ png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,
+ png_ptr->current_buffer_ptr, png_ptr->current_buffer_size);
+ png_ptr->save_buffer_size += png_ptr->current_buffer_size;
+ png_ptr->current_buffer_size = 0;
+ }
+ png_ptr->save_buffer_ptr = png_ptr->save_buffer;
+ png_ptr->buffer_size = 0;
+}
+
+void /* PRIVATE */
+png_push_restore_buffer(png_structp png_ptr, png_bytep buffer,
+ png_size_t buffer_length)
+{
+ png_ptr->current_buffer = buffer;
+ png_ptr->current_buffer_size = buffer_length;
+ png_ptr->buffer_size = buffer_length + png_ptr->save_buffer_size;
+ png_ptr->current_buffer_ptr = png_ptr->current_buffer;
+}
+
+void /* PRIVATE */
+png_push_read_IDAT(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_CONST PNG_IDAT;
+#endif
+ if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER))
+ {
+ png_byte chunk_length[4];
+
+ if (png_ptr->buffer_size < 8)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_fill_buffer(png_ptr, chunk_length, 4);
+ png_ptr->push_length = png_get_uint_31(png_ptr,chunk_length);
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ png_ptr->mode |= PNG_HAVE_CHUNK_HEADER;
+
+ if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
+ {
+ png_ptr->process_mode = PNG_READ_CHUNK_MODE;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+ png_error(png_ptr, "Not enough compressed data");
+ return;
+ }
+
+ png_ptr->idat_size = png_ptr->push_length;
+ }
+ if (png_ptr->idat_size && png_ptr->save_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->idat_size < (png_uint_32)png_ptr->save_buffer_size)
+ {
+ save_size = (png_size_t)png_ptr->idat_size;
+ /* check for overflow */
+ if((png_uint_32)save_size != png_ptr->idat_size)
+ png_error(png_ptr, "save_size overflowed in pngpread");
+ }
+ else
+ save_size = png_ptr->save_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+ png_process_IDAT_data(png_ptr, png_ptr->save_buffer_ptr, save_size);
+ png_ptr->idat_size -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->save_buffer_size -= save_size;
+ png_ptr->save_buffer_ptr += save_size;
+ }
+ if (png_ptr->idat_size && png_ptr->current_buffer_size)
+ {
+ png_size_t save_size;
+
+ if (png_ptr->idat_size < (png_uint_32)png_ptr->current_buffer_size)
+ {
+ save_size = (png_size_t)png_ptr->idat_size;
+ /* check for overflow */
+ if((png_uint_32)save_size != png_ptr->idat_size)
+ png_error(png_ptr, "save_size overflowed in pngpread");
+ }
+ else
+ save_size = png_ptr->current_buffer_size;
+
+ png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+ png_process_IDAT_data(png_ptr, png_ptr->current_buffer_ptr, save_size);
+
+ png_ptr->idat_size -= save_size;
+ png_ptr->buffer_size -= save_size;
+ png_ptr->current_buffer_size -= save_size;
+ png_ptr->current_buffer_ptr += save_size;
+ }
+ if (!png_ptr->idat_size)
+ {
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_crc_finish(png_ptr, 0);
+ png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ }
+}
+
+void /* PRIVATE */
+png_process_IDAT_data(png_structp png_ptr, png_bytep buffer,
+ png_size_t buffer_length)
+{
+ int ret;
+
+ if ((png_ptr->flags & PNG_FLAG_ZLIB_FINISHED) && buffer_length)
+ png_error(png_ptr, "Extra compression data");
+
+ png_ptr->zstream.next_in = buffer;
+ png_ptr->zstream.avail_in = (uInt)buffer_length;
+ for(;;)
+ {
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK)
+ {
+ if (ret == Z_STREAM_END)
+ {
+ if (png_ptr->zstream.avail_in)
+ png_error(png_ptr, "Extra compressed data");
+ if (!(png_ptr->zstream.avail_out))
+ {
+ png_push_process_row(png_ptr);
+ }
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ else if (ret == Z_BUF_ERROR)
+ break;
+ else
+ png_error(png_ptr, "Decompression Error");
+ }
+ if (!(png_ptr->zstream.avail_out))
+ {
+ if ((
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ png_ptr->interlaced && png_ptr->pass > 6) ||
+ (!png_ptr->interlaced &&
+#endif
+ png_ptr->row_number == png_ptr->num_rows))
+ {
+ if (png_ptr->zstream.avail_in)
+ png_warning(png_ptr, "Too much data in IDAT chunks");
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ png_push_process_row(png_ptr);
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ }
+ else
+ break;
+ }
+}
+
+void /* PRIVATE */
+png_push_process_row(png_structp png_ptr)
+{
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->iwidth;
+ png_ptr->row_info.channels = png_ptr->channels;
+ png_ptr->row_info.bit_depth = png_ptr->bit_depth;
+ png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
+
+ png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
+ png_ptr->row_info.width);
+
+ png_read_filter_row(png_ptr, &(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->prev_row + 1,
+ (int)(png_ptr->row_buf[0]));
+
+ png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf,
+ png_ptr->rowbytes + 1);
+
+ if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA))
+ png_do_read_transformations(png_ptr);
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* blow up interlaced rows to full size */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ if (png_ptr->pass < 6)
+/* old interface (pre-1.0.9):
+ png_do_read_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
+ */
+ png_do_read_interlace(png_ptr);
+
+ switch (png_ptr->pass)
+ {
+ case 0:
+ {
+ int i;
+ for (i = 0; i < 8 && png_ptr->pass == 0; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr); /* updates png_ptr->pass */
+ }
+ if (png_ptr->pass == 2) /* pass 1 might be empty */
+ {
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ if (png_ptr->pass == 4 && png_ptr->height <= 4)
+ {
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ if (png_ptr->pass == 6 && png_ptr->height <= 4)
+ {
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 1:
+ {
+ int i;
+ for (i = 0; i < 8 && png_ptr->pass == 1; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 2) /* skip top 4 generated rows */
+ {
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ break;
+ }
+ case 2:
+ {
+ int i;
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ for (i = 0; i < 4 && png_ptr->pass == 2; i++)
+ {
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 4) /* pass 3 might be empty */
+ {
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ break;
+ }
+ case 3:
+ {
+ int i;
+ for (i = 0; i < 4 && png_ptr->pass == 3; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 4) /* skip top two generated rows */
+ {
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+ int i;
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ for (i = 0; i < 2 && png_ptr->pass == 4; i++)
+ {
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 6) /* pass 5 might be empty */
+ {
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 5:
+ {
+ int i;
+ for (i = 0; i < 2 && png_ptr->pass == 5; i++)
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+ if (png_ptr->pass == 6) /* skip top generated row */
+ {
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ break;
+ }
+ case 6:
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ if (png_ptr->pass != 6)
+ break;
+ png_push_have_row(png_ptr, png_bytep_NULL);
+ png_read_push_finish_row(png_ptr);
+ }
+ }
+ }
+ else
+#endif
+ {
+ png_push_have_row(png_ptr, png_ptr->row_buf + 1);
+ png_read_push_finish_row(png_ptr);
+ }
+}
+
+void /* PRIVATE */
+png_read_push_finish_row(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ PNG_CONST int FARDATA png_pass_start[] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ PNG_CONST int FARDATA png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* start of interlace block in the y direction */
+ PNG_CONST int FARDATA png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* offset to next interlace block in the y direction */
+ PNG_CONST int FARDATA png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2};
+
+ /* Width of interlace block. This is not currently used - if you need
+ * it, uncomment it here and in png.h
+ PNG_CONST int FARDATA png_pass_width[] = {8, 4, 4, 2, 2, 1, 1};
+ */
+
+ /* Height of interlace block. This is not currently used - if you need
+ * it, uncomment it here and in png.h
+ PNG_CONST int FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
+ */
+#endif
+
+ png_ptr->row_number++;
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ png_memset_check(png_ptr, png_ptr->prev_row, 0,
+ png_ptr->rowbytes + 1);
+ do
+ {
+ png_ptr->pass++;
+ if ((png_ptr->pass == 1 && png_ptr->width < 5) ||
+ (png_ptr->pass == 3 && png_ptr->width < 3) ||
+ (png_ptr->pass == 5 && png_ptr->width < 2))
+ png_ptr->pass++;
+
+ if (png_ptr->pass > 7)
+ png_ptr->pass--;
+ if (png_ptr->pass >= 7)
+ break;
+
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+
+ png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,
+ png_ptr->iwidth) + 1;
+
+ if (png_ptr->transformations & PNG_INTERLACE)
+ break;
+
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+
+ } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0);
+ }
+}
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+void /* PRIVATE */
+png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
+ length)
+{
+ if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
+ {
+ png_error(png_ptr, "Out of place tEXt");
+ info_ptr = info_ptr; /* to quiet some compiler warnings */
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ png_ptr->skip_length = 0; /* This may not be necessary */
+
+ if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */
+ {
+ png_warning(png_ptr, "tEXt chunk too large to fit in memory");
+ png_ptr->skip_length = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ png_ptr->current_text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(length+1));
+ png_ptr->current_text[length] = '\0';
+ png_ptr->current_text_ptr = png_ptr->current_text;
+ png_ptr->current_text_size = (png_size_t)length;
+ png_ptr->current_text_left = (png_size_t)length;
+ png_ptr->process_mode = PNG_READ_tEXt_MODE;
+}
+
+void /* PRIVATE */
+png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->buffer_size && png_ptr->current_text_left)
+ {
+ png_size_t text_size;
+
+ if (png_ptr->buffer_size < png_ptr->current_text_left)
+ text_size = png_ptr->buffer_size;
+ else
+ text_size = png_ptr->current_text_left;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
+ png_ptr->current_text_left -= text_size;
+ png_ptr->current_text_ptr += text_size;
+ }
+ if (!(png_ptr->current_text_left))
+ {
+ png_textp text_ptr;
+ png_charp text;
+ png_charp key;
+ int ret;
+
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_crc_finish(png_ptr);
+
+#if defined(PNG_MAX_MALLOC_64K)
+ if (png_ptr->skip_length)
+ return;
+#endif
+
+ key = png_ptr->current_text;
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ if (text != key + png_ptr->current_text_size)
+ text++;
+
+ text_ptr = (png_textp)png_malloc(png_ptr,
+ (png_uint_32)png_sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr->key = key;
+#ifdef PNG_iTXt_SUPPORTED
+ text_ptr->lang = NULL;
+ text_ptr->lang_key = NULL;
+#endif
+ text_ptr->text = text;
+
+ ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, key);
+ png_free(png_ptr, text_ptr);
+ png_ptr->current_text = NULL;
+
+ if (ret)
+ png_warning(png_ptr, "Insufficient memory to store text chunk.");
+ }
+}
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+void /* PRIVATE */
+png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
+ length)
+{
+ if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
+ {
+ png_error(png_ptr, "Out of place zTXt");
+ info_ptr = info_ptr; /* to quiet some compiler warnings */
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ /* We can't handle zTXt chunks > 64K, since we don't have enough space
+ * to be able to store the uncompressed data. Actually, the threshold
+ * is probably around 32K, but it isn't as definite as 64K is.
+ */
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "zTXt chunk too large to fit in memory");
+ png_push_crc_skip(png_ptr, length);
+ return;
+ }
+#endif
+
+ png_ptr->current_text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(length+1));
+ png_ptr->current_text[length] = '\0';
+ png_ptr->current_text_ptr = png_ptr->current_text;
+ png_ptr->current_text_size = (png_size_t)length;
+ png_ptr->current_text_left = (png_size_t)length;
+ png_ptr->process_mode = PNG_READ_zTXt_MODE;
+}
+
+void /* PRIVATE */
+png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->buffer_size && png_ptr->current_text_left)
+ {
+ png_size_t text_size;
+
+ if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left)
+ text_size = png_ptr->buffer_size;
+ else
+ text_size = png_ptr->current_text_left;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
+ png_ptr->current_text_left -= text_size;
+ png_ptr->current_text_ptr += text_size;
+ }
+ if (!(png_ptr->current_text_left))
+ {
+ png_textp text_ptr;
+ png_charp text;
+ png_charp key;
+ int ret;
+ png_size_t text_size, key_size;
+
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_crc_finish(png_ptr);
+
+ key = png_ptr->current_text;
+
+ for (text = key; *text; text++)
+ /* empty loop */ ;
+
+ /* zTXt can't have zero text */
+ if (text == key + png_ptr->current_text_size)
+ {
+ png_ptr->current_text = NULL;
+ png_free(png_ptr, key);
+ return;
+ }
+
+ text++;
+
+ if (*text != PNG_TEXT_COMPRESSION_zTXt) /* check compression byte */
+ {
+ png_ptr->current_text = NULL;
+ png_free(png_ptr, key);
+ return;
+ }
+
+ text++;
+
+ png_ptr->zstream.next_in = (png_bytep )text;
+ png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size -
+ (text - key));
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ key_size = text - key;
+ text_size = 0;
+ text = NULL;
+ ret = Z_STREAM_END;
+
+ while (png_ptr->zstream.avail_in)
+ {
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+ png_ptr->current_text = NULL;
+ png_free(png_ptr, key);
+ png_free(png_ptr, text);
+ return;
+ }
+ if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END)
+ {
+ if (text == NULL)
+ {
+ text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out
+ + key_size + 1));
+ png_memcpy(text + key_size, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ png_memcpy(text, key, key_size);
+ text_size = key_size + png_ptr->zbuf_size -
+ png_ptr->zstream.avail_out;
+ *(text + text_size) = '\0';
+ }
+ else
+ {
+ png_charp tmp;
+
+ tmp = text;
+ text = (png_charp)png_malloc(png_ptr, text_size +
+ (png_uint_32)(png_ptr->zbuf_size - png_ptr->zstream.avail_out
+ + 1));
+ png_memcpy(text, tmp, text_size);
+ png_free(png_ptr, tmp);
+ png_memcpy(text + text_size, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ *(text + text_size) = '\0';
+ }
+ if (ret != Z_STREAM_END)
+ {
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ }
+ else
+ {
+ break;
+ }
+
+ if (ret == Z_STREAM_END)
+ break;
+ }
+
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ if (ret != Z_STREAM_END)
+ {
+ png_ptr->current_text = NULL;
+ png_free(png_ptr, key);
+ png_free(png_ptr, text);
+ return;
+ }
+
+ png_ptr->current_text = NULL;
+ png_free(png_ptr, key);
+ key = text;
+ text += key_size;
+
+ text_ptr = (png_textp)png_malloc(png_ptr,
+ (png_uint_32)png_sizeof(png_text));
+ text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt;
+ text_ptr->key = key;
+#ifdef PNG_iTXt_SUPPORTED
+ text_ptr->lang = NULL;
+ text_ptr->lang_key = NULL;
+#endif
+ text_ptr->text = text;
+
+ ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, key);
+ png_free(png_ptr, text_ptr);
+
+ if (ret)
+ png_warning(png_ptr, "Insufficient memory to store text chunk.");
+ }
+}
+#endif
+
+#if defined(PNG_READ_iTXt_SUPPORTED)
+void /* PRIVATE */
+png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
+ length)
+{
+ if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
+ {
+ png_error(png_ptr, "Out of place iTXt");
+ info_ptr = info_ptr; /* to quiet some compiler warnings */
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ png_ptr->skip_length = 0; /* This may not be necessary */
+
+ if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */
+ {
+ png_warning(png_ptr, "iTXt chunk too large to fit in memory");
+ png_ptr->skip_length = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ png_ptr->current_text = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)(length+1));
+ png_ptr->current_text[length] = '\0';
+ png_ptr->current_text_ptr = png_ptr->current_text;
+ png_ptr->current_text_size = (png_size_t)length;
+ png_ptr->current_text_left = (png_size_t)length;
+ png_ptr->process_mode = PNG_READ_iTXt_MODE;
+}
+
+void /* PRIVATE */
+png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr)
+{
+
+ if (png_ptr->buffer_size && png_ptr->current_text_left)
+ {
+ png_size_t text_size;
+
+ if (png_ptr->buffer_size < png_ptr->current_text_left)
+ text_size = png_ptr->buffer_size;
+ else
+ text_size = png_ptr->current_text_left;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
+ png_ptr->current_text_left -= text_size;
+ png_ptr->current_text_ptr += text_size;
+ }
+ if (!(png_ptr->current_text_left))
+ {
+ png_textp text_ptr;
+ png_charp key;
+ int comp_flag;
+ png_charp lang;
+ png_charp lang_key;
+ png_charp text;
+ int ret;
+
+ if (png_ptr->buffer_size < 4)
+ {
+ png_push_save_buffer(png_ptr);
+ return;
+ }
+
+ png_push_crc_finish(png_ptr);
+
+#if defined(PNG_MAX_MALLOC_64K)
+ if (png_ptr->skip_length)
+ return;
+#endif
+
+ key = png_ptr->current_text;
+
+ for (lang = key; *lang; lang++)
+ /* empty loop */ ;
+
+ if (lang != key + png_ptr->current_text_size)
+ lang++;
+
+ comp_flag = *lang++;
+ lang++; /* skip comp_type, always zero */
+
+ for (lang_key = lang; *lang_key; lang_key++)
+ /* empty loop */ ;
+ lang_key++; /* skip NUL separator */
+
+ for (text = lang_key; *text; text++)
+ /* empty loop */ ;
+
+ if (text != key + png_ptr->current_text_size)
+ text++;
+
+ text_ptr = (png_textp)png_malloc(png_ptr,
+ (png_uint_32)png_sizeof(png_text));
+ text_ptr->compression = comp_flag + 2;
+ text_ptr->key = key;
+ text_ptr->lang = lang;
+ text_ptr->lang_key = lang_key;
+ text_ptr->text = text;
+ text_ptr->text_length = 0;
+ text_ptr->itxt_length = png_strlen(text);
+
+ ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
+
+ png_ptr->current_text = NULL;
+
+ png_free(png_ptr, text_ptr);
+ if (ret)
+ png_warning(png_ptr, "Insufficient memory to store iTXt chunk.");
+ }
+}
+#endif
+
+/* This function is called when we haven't found a handler for this
+ * chunk. If there isn't a problem with the chunk itself (ie a bad chunk
+ * name or a critical chunk), the chunk is (currently) silently ignored.
+ */
+void /* PRIVATE */
+png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32
+ length)
+{
+ png_uint_32 skip=0;
+ png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ {
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
+ PNG_HANDLE_CHUNK_ALWAYS
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+ && png_ptr->read_user_chunk_fn == NULL
+#endif
+ )
+#endif
+ png_chunk_error(png_ptr, "unknown critical chunk");
+
+ info_ptr = info_ptr; /* to quiet some compiler warnings */
+ }
+
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
+ {
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "unknown chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+ png_strncpy((png_charp)png_ptr->unknown_chunk.name,
+ (png_charp)png_ptr->chunk_name,
+ png_sizeof((png_charp)png_ptr->chunk_name));
+ png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
+ png_ptr->unknown_chunk.size = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+ if(png_ptr->read_user_chunk_fn != NULL)
+ {
+ /* callback to user unknown chunk handler */
+ int ret;
+ ret = (*(png_ptr->read_user_chunk_fn))
+ (png_ptr, &png_ptr->unknown_chunk);
+ if (ret < 0)
+ png_chunk_error(png_ptr, "error in user chunk");
+ if (ret == 0)
+ {
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
+ PNG_HANDLE_CHUNK_ALWAYS)
+ png_chunk_error(png_ptr, "unknown critical chunk");
+ png_set_unknown_chunks(png_ptr, info_ptr,
+ &png_ptr->unknown_chunk, 1);
+ }
+ }
+#else
+ png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
+#endif
+ png_free(png_ptr, png_ptr->unknown_chunk.data);
+ png_ptr->unknown_chunk.data = NULL;
+ }
+ else
+#endif
+ skip=length;
+ png_push_crc_skip(png_ptr, skip);
+}
+
+void /* PRIVATE */
+png_push_have_info(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->info_fn != NULL)
+ (*(png_ptr->info_fn))(png_ptr, info_ptr);
+}
+
+void /* PRIVATE */
+png_push_have_end(png_structp png_ptr, png_infop info_ptr)
+{
+ if (png_ptr->end_fn != NULL)
+ (*(png_ptr->end_fn))(png_ptr, info_ptr);
+}
+
+void /* PRIVATE */
+png_push_have_row(png_structp png_ptr, png_bytep row)
+{
+ if (png_ptr->row_fn != NULL)
+ (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number,
+ (int)png_ptr->pass);
+}
+
+void PNGAPI
+png_progressive_combine_row (png_structp png_ptr,
+ png_bytep old_row, png_bytep new_row)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_CONST int FARDATA png_pass_dsp_mask[7] =
+ {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55, 0xff};
+#endif
+ if(png_ptr == NULL) return;
+ if (new_row != NULL) /* new_row must == png_ptr->row_buf here. */
+ png_combine_row(png_ptr, old_row, png_pass_dsp_mask[png_ptr->pass]);
+}
+
+void PNGAPI
+png_set_progressive_read_fn(png_structp png_ptr, png_voidp progressive_ptr,
+ png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn,
+ png_progressive_end_ptr end_fn)
+{
+ if(png_ptr == NULL) return;
+ png_ptr->info_fn = info_fn;
+ png_ptr->row_fn = row_fn;
+ png_ptr->end_fn = end_fn;
+
+ png_set_read_fn(png_ptr, progressive_ptr, png_push_fill_buffer);
+}
+
+png_voidp PNGAPI
+png_get_progressive_ptr(png_structp png_ptr)
+{
+ if(png_ptr == NULL) return (NULL);
+ return png_ptr->io_ptr;
+}
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngread.c b/distrib/libpng-1.2.19/pngread.c
new file mode 100644
index 0000000..2e561e8
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngread.c
@@ -0,0 +1,1478 @@
+
+/* pngread.c - read a PNG file
+ *
+ * Last changed in libpng 1.2.19 August 18, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file contains routines that an application calls directly to
+ * read a PNG file or stream.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_SUPPORTED)
+
+/* Create a PNG structure for reading, and allocate any memory needed. */
+png_structp PNGAPI
+png_create_read_struct(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn)
+{
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_read_struct_2(user_png_ver, error_ptr, error_fn,
+ warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL));
+}
+
+/* Alternate create PNG structure for reading, and allocate any memory needed. */
+png_structp PNGAPI
+png_create_read_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+
+ png_structp png_ptr;
+
+#ifdef PNG_SETJMP_SUPPORTED
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+#endif
+
+ int i;
+
+ png_debug(1, "in png_create_read_struct\n");
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
+ (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
+#else
+ png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
+#endif
+ if (png_ptr == NULL)
+ return (NULL);
+
+#if !defined(PNG_1_0_X)
+#ifdef PNG_MMX_CODE_SUPPORTED
+ png_init_mmx_flags(png_ptr); /* 1.2.0 addition */
+#endif
+#endif /* PNG_1_0_X */
+
+ /* added at libpng-1.2.6 */
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
+ png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(png_ptr->jmpbuf))
+#endif
+ {
+ png_free(png_ptr, png_ptr->zbuf);
+ png_ptr->zbuf=NULL;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)png_ptr,
+ (png_free_ptr)free_fn, (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)png_ptr);
+#endif
+ return (NULL);
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
+#endif
+#endif
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
+#endif
+
+ png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
+
+ i=0;
+ do
+ {
+ if(user_png_ver[i] != png_libpng_ver[i])
+ png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+ } while (png_libpng_ver[i++]);
+
+ if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
+ {
+ /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+ * we must recompile any applications that use any older library version.
+ * For versions after libpng 1.0, we will be compatible, so we need
+ * only check the first digit.
+ */
+ if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+ (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
+ (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char msg[80];
+ if (user_png_ver)
+ {
+ png_snprintf(msg, 80,
+ "Application was compiled with png.h from libpng-%.20s",
+ user_png_ver);
+ png_warning(png_ptr, msg);
+ }
+ png_snprintf(msg, 80,
+ "Application is running with png.c from libpng-%.20s",
+ png_libpng_ver);
+ png_warning(png_ptr, msg);
+#endif
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "Incompatible libpng version in application and library");
+ }
+ }
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+
+ switch (inflateInit(&png_ptr->zstream))
+ {
+ case Z_OK: /* Do nothing */ break;
+ case Z_MEM_ERROR:
+ case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory error"); break;
+ case Z_VERSION_ERROR: png_error(png_ptr, "zlib version error"); break;
+ default: png_error(png_ptr, "Unknown zlib error");
+ }
+
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL);
+
+#ifdef PNG_SETJMP_SUPPORTED
+/* Applications that neglect to set up their own setjmp() and then encounter
+ a png_error() will longjmp here. Since the jmpbuf is then meaningless we
+ abort instead of returning. */
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+ PNG_ABORT();
+ png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
+#else
+ if (setjmp(png_ptr->jmpbuf))
+ PNG_ABORT();
+#endif
+#endif
+ return (png_ptr);
+}
+
+#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
+/* Initialize PNG structure for reading, and allocate any memory needed.
+ This interface is deprecated in favour of the png_create_read_struct(),
+ and it will disappear as of libpng-1.3.0. */
+#undef png_read_init
+void PNGAPI
+png_read_init(png_structp png_ptr)
+{
+ /* We only come here via pre-1.0.7-compiled applications */
+ png_read_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
+}
+
+void PNGAPI
+png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver,
+ png_size_t png_struct_size, png_size_t png_info_size)
+{
+ /* We only come here via pre-1.0.12-compiled applications */
+ if(png_ptr == NULL) return;
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ if(png_sizeof(png_struct) > png_struct_size ||
+ png_sizeof(png_info) > png_info_size)
+ {
+ char msg[80];
+ png_ptr->warning_fn=NULL;
+ if (user_png_ver)
+ {
+ png_snprintf(msg, 80,
+ "Application was compiled with png.h from libpng-%.20s",
+ user_png_ver);
+ png_warning(png_ptr, msg);
+ }
+ png_snprintf(msg, 80,
+ "Application is running with png.c from libpng-%.20s",
+ png_libpng_ver);
+ png_warning(png_ptr, msg);
+ }
+#endif
+ if(png_sizeof(png_struct) > png_struct_size)
+ {
+ png_ptr->error_fn=NULL;
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "The png struct allocated by the application for reading is too small.");
+ }
+ if(png_sizeof(png_info) > png_info_size)
+ {
+ png_ptr->error_fn=NULL;
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "The info struct allocated by application for reading is too small.");
+ }
+ png_read_init_3(&png_ptr, user_png_ver, png_struct_size);
+}
+#endif /* PNG_1_0_X || PNG_1_2_X */
+
+void PNGAPI
+png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
+ png_size_t png_struct_size)
+{
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf tmp_jmp; /* to save current jump buffer */
+#endif
+
+ int i=0;
+
+ png_structp png_ptr=*ptr_ptr;
+
+ if(png_ptr == NULL) return;
+
+ do
+ {
+ if(user_png_ver[i] != png_libpng_ver[i])
+ {
+#ifdef PNG_LEGACY_SUPPORTED
+ png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+#else
+ png_ptr->warning_fn=NULL;
+ png_warning(png_ptr,
+ "Application uses deprecated png_read_init() and should be recompiled.");
+ break;
+#endif
+ }
+ } while (png_libpng_ver[i++]);
+
+ png_debug(1, "in png_read_init_3\n");
+
+#ifdef PNG_SETJMP_SUPPORTED
+ /* save jump buffer and error functions */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
+#endif
+
+ if(png_sizeof(png_struct) > png_struct_size)
+ {
+ png_destroy_struct(png_ptr);
+ *ptr_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
+ png_ptr = *ptr_ptr;
+ }
+
+ /* reset all variables to 0 */
+ png_memset(png_ptr, 0, png_sizeof (png_struct));
+
+#ifdef PNG_SETJMP_SUPPORTED
+ /* restore jump buffer */
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
+#endif
+
+ /* added at libpng-1.2.6 */
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
+ png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
+#endif
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+
+ switch (inflateInit(&png_ptr->zstream))
+ {
+ case Z_OK: /* Do nothing */ break;
+ case Z_MEM_ERROR:
+ case Z_STREAM_ERROR: png_error(png_ptr, "zlib memory"); break;
+ case Z_VERSION_ERROR: png_error(png_ptr, "zlib version"); break;
+ default: png_error(png_ptr, "Unknown zlib error");
+ }
+
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ png_set_read_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL);
+}
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+/* Read the information before the actual image data. This has been
+ * changed in v0.90 to allow reading a file that already has the magic
+ * bytes read from the stream. You can tell libpng how many bytes have
+ * been read from the beginning of the stream (up to the maximum of 8)
+ * via png_set_sig_bytes(), and we will only check the remaining bytes
+ * here. The application can then have access to the signature bytes we
+ * read if it is determined that this isn't a valid PNG file.
+ */
+void PNGAPI
+png_read_info(png_structp png_ptr, png_infop info_ptr)
+{
+ if(png_ptr == NULL) return;
+ png_debug(1, "in png_read_info\n");
+ /* If we haven't checked all of the PNG signature bytes, do so now. */
+ if (png_ptr->sig_bytes < 8)
+ {
+ png_size_t num_checked = png_ptr->sig_bytes,
+ num_to_check = 8 - num_checked;
+
+ png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check);
+ png_ptr->sig_bytes = 8;
+
+ if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check))
+ {
+ if (num_checked < 4 &&
+ png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4))
+ png_error(png_ptr, "Not a PNG file");
+ else
+ png_error(png_ptr, "PNG file corrupted by ASCII conversion");
+ }
+ if (num_checked < 3)
+ png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
+ }
+
+ for(;;)
+ {
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_CONST PNG_IHDR;
+ PNG_CONST PNG_IDAT;
+ PNG_CONST PNG_IEND;
+ PNG_CONST PNG_PLTE;
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ PNG_CONST PNG_bKGD;
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ PNG_CONST PNG_cHRM;
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ PNG_CONST PNG_gAMA;
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ PNG_CONST PNG_hIST;
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ PNG_CONST PNG_iCCP;
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ PNG_CONST PNG_iTXt;
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ PNG_CONST PNG_oFFs;
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ PNG_CONST PNG_pCAL;
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ PNG_CONST PNG_pHYs;
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ PNG_CONST PNG_sBIT;
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ PNG_CONST PNG_sCAL;
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ PNG_CONST PNG_sPLT;
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ PNG_CONST PNG_sRGB;
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ PNG_CONST PNG_tEXt;
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ PNG_CONST PNG_tIME;
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ PNG_CONST PNG_tRNS;
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ PNG_CONST PNG_zTXt;
+#endif
+#endif /* PNG_USE_LOCAL_ARRAYS */
+ png_byte chunk_length[4];
+ png_uint_32 length;
+
+ png_read_data(png_ptr, chunk_length, 4);
+ length = png_get_uint_31(png_ptr,chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+
+ png_debug2(0, "Reading %s chunk, length=%lu.\n", png_ptr->chunk_name,
+ length);
+
+ /* This should be a binary subdivision search or a hash for
+ * matching the chunk name rather than a linear search.
+ */
+ if (!png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
+ if(png_ptr->mode & PNG_AFTER_IDAT)
+ png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT;
+
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ png_handle_IHDR(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ png_handle_IEND(png_ptr, info_ptr, length);
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name))
+ {
+ if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ png_handle_unknown(png_ptr, info_ptr, length);
+ if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_ptr->mode |= PNG_HAVE_PLTE;
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before IDAT");
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ png_error(png_ptr, "Missing PLTE before IDAT");
+ break;
+ }
+ }
+#endif
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_handle_PLTE(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before IDAT");
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ png_error(png_ptr, "Missing PLTE before IDAT");
+
+ png_ptr->idat_size = length;
+ png_ptr->mode |= PNG_HAVE_IDAT;
+ break;
+ }
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ png_handle_bKGD(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ png_handle_cHRM(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ png_handle_gAMA(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ png_handle_hIST(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ png_handle_oFFs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ png_handle_pCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4))
+ png_handle_sCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ png_handle_pHYs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ png_handle_sBIT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+ png_handle_sRGB(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4))
+ png_handle_iCCP(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4))
+ png_handle_sPLT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ png_handle_tEXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ png_handle_tIME(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ png_handle_tRNS(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ png_handle_zTXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
+ png_handle_iTXt(png_ptr, info_ptr, length);
+#endif
+ else
+ png_handle_unknown(png_ptr, info_ptr, length);
+ }
+}
+#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+
+/* optional call to update the users info_ptr structure */
+void PNGAPI
+png_read_update_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_update_info\n");
+ if(png_ptr == NULL) return;
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+ else
+ png_warning(png_ptr,
+ "Ignoring extra png_read_update_info() call; row buffer not reallocated");
+ png_read_transform_info(png_ptr, info_ptr);
+}
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+/* Initialize palette, background, etc, after transformations
+ * are set, but before any reading takes place. This allows
+ * the user to obtain a gamma-corrected palette, for example.
+ * If the user doesn't call this, we will do it ourselves.
+ */
+void PNGAPI
+png_start_read_image(png_structp png_ptr)
+{
+ png_debug(1, "in png_start_read_image\n");
+ if(png_ptr == NULL) return;
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+}
+#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+void PNGAPI
+png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_CONST PNG_IDAT;
+ PNG_CONST int png_pass_dsp_mask[7] = {0xff, 0x0f, 0xff, 0x33, 0xff, 0x55,
+ 0xff};
+ PNG_CONST int png_pass_mask[7] = {0x80, 0x08, 0x88, 0x22, 0xaa, 0x55, 0xff};
+#endif
+ int ret;
+ if(png_ptr == NULL) return;
+ png_debug2(1, "in png_read_row (row %lu, pass %d)\n",
+ png_ptr->row_number, png_ptr->pass);
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ png_read_start_row(png_ptr);
+ if (png_ptr->row_number == 0 && png_ptr->pass == 0)
+ {
+ /* check for transforms that have been set but were defined out */
+#if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && !defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined.");
+#endif
+#if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined.");
+#endif
+ }
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* if interlaced and we do not need a new row, combine row and return */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ switch (png_ptr->pass)
+ {
+ case 0:
+ if (png_ptr->row_number & 0x07)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 1:
+ if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 2:
+ if ((png_ptr->row_number & 0x07) != 4)
+ {
+ if (dsp_row != NULL && (png_ptr->row_number & 4))
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 3:
+ if ((png_ptr->row_number & 3) || png_ptr->width < 3)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 4:
+ if ((png_ptr->row_number & 3) != 2)
+ {
+ if (dsp_row != NULL && (png_ptr->row_number & 2))
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 5:
+ if ((png_ptr->row_number & 1) || png_ptr->width < 2)
+ {
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 6:
+ if (!(png_ptr->row_number & 1))
+ {
+ png_read_finish_row(png_ptr);
+ return;
+ }
+ break;
+ }
+ }
+#endif
+
+ if (!(png_ptr->mode & PNG_HAVE_IDAT))
+ png_error(png_ptr, "Invalid attempt to read row data");
+
+ png_ptr->zstream.next_out = png_ptr->row_buf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->irowbytes;
+ do
+ {
+ if (!(png_ptr->zstream.avail_in))
+ {
+ while (!png_ptr->idat_size)
+ {
+ png_byte chunk_length[4];
+
+ png_crc_finish(png_ptr, 0);
+
+ png_read_data(png_ptr, chunk_length, 4);
+ png_ptr->idat_size = png_get_uint_31(png_ptr,chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ png_error(png_ptr, "Not enough image data");
+ }
+ png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_in = png_ptr->zbuf;
+ if (png_ptr->zbuf_size > png_ptr->idat_size)
+ png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
+ png_crc_read(png_ptr, png_ptr->zbuf,
+ (png_size_t)png_ptr->zstream.avail_in);
+ png_ptr->idat_size -= png_ptr->zstream.avail_in;
+ }
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret == Z_STREAM_END)
+ {
+ if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in ||
+ png_ptr->idat_size)
+ png_error(png_ptr, "Extra compressed data");
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ if (ret != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
+ "Decompression error");
+
+ } while (png_ptr->zstream.avail_out);
+
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->iwidth;
+ png_ptr->row_info.channels = png_ptr->channels;
+ png_ptr->row_info.bit_depth = png_ptr->bit_depth;
+ png_ptr->row_info.pixel_depth = png_ptr->pixel_depth;
+ png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
+ png_ptr->row_info.width);
+
+ if(png_ptr->row_buf[0])
+ png_read_filter_row(png_ptr, &(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->prev_row + 1,
+ (int)(png_ptr->row_buf[0]));
+
+ png_memcpy_check(png_ptr, png_ptr->prev_row, png_ptr->row_buf,
+ png_ptr->rowbytes + 1);
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
+ (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
+ {
+ /* Intrapixel differencing */
+ png_do_read_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ }
+#endif
+
+
+ if (png_ptr->transformations || (png_ptr->flags&PNG_FLAG_STRIP_ALPHA))
+ png_do_read_transformations(png_ptr);
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+ /* blow up interlaced rows to full size */
+ if (png_ptr->interlaced &&
+ (png_ptr->transformations & PNG_INTERLACE))
+ {
+ if (png_ptr->pass < 6)
+/* old interface (pre-1.0.9):
+ png_do_read_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass, png_ptr->transformations);
+ */
+ png_do_read_interlace(png_ptr);
+
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row,
+ png_pass_dsp_mask[png_ptr->pass]);
+ if (row != NULL)
+ png_combine_row(png_ptr, row,
+ png_pass_mask[png_ptr->pass]);
+ }
+ else
+#endif
+ {
+ if (row != NULL)
+ png_combine_row(png_ptr, row, 0xff);
+ if (dsp_row != NULL)
+ png_combine_row(png_ptr, dsp_row, 0xff);
+ }
+ png_read_finish_row(png_ptr);
+
+ if (png_ptr->read_row_fn != NULL)
+ (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
+}
+#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+/* Read one or more rows of image data. If the image is interlaced,
+ * and png_set_interlace_handling() has been called, the rows need to
+ * contain the contents of the rows from the previous pass. If the
+ * image has alpha or transparency, and png_handle_alpha()[*] has been
+ * called, the rows contents must be initialized to the contents of the
+ * screen.
+ *
+ * "row" holds the actual image, and pixels are placed in it
+ * as they arrive. If the image is displayed after each pass, it will
+ * appear to "sparkle" in. "display_row" can be used to display a
+ * "chunky" progressive image, with finer detail added as it becomes
+ * available. If you do not want this "chunky" display, you may pass
+ * NULL for display_row. If you do not want the sparkle display, and
+ * you have not called png_handle_alpha(), you may pass NULL for rows.
+ * If you have called png_handle_alpha(), and the image has either an
+ * alpha channel or a transparency chunk, you must provide a buffer for
+ * rows. In this case, you do not have to provide a display_row buffer
+ * also, but you may. If the image is not interlaced, or if you have
+ * not called png_set_interlace_handling(), the display_row buffer will
+ * be ignored, so pass NULL to it.
+ *
+ * [*] png_handle_alpha() does not exist yet, as of this version of libpng
+ */
+
+void PNGAPI
+png_read_rows(png_structp png_ptr, png_bytepp row,
+ png_bytepp display_row, png_uint_32 num_rows)
+{
+ png_uint_32 i;
+ png_bytepp rp;
+ png_bytepp dp;
+
+ png_debug(1, "in png_read_rows\n");
+ if(png_ptr == NULL) return;
+ rp = row;
+ dp = display_row;
+ if (rp != NULL && dp != NULL)
+ for (i = 0; i < num_rows; i++)
+ {
+ png_bytep rptr = *rp++;
+ png_bytep dptr = *dp++;
+
+ png_read_row(png_ptr, rptr, dptr);
+ }
+ else if(rp != NULL)
+ for (i = 0; i < num_rows; i++)
+ {
+ png_bytep rptr = *rp;
+ png_read_row(png_ptr, rptr, png_bytep_NULL);
+ rp++;
+ }
+ else if(dp != NULL)
+ for (i = 0; i < num_rows; i++)
+ {
+ png_bytep dptr = *dp;
+ png_read_row(png_ptr, png_bytep_NULL, dptr);
+ dp++;
+ }
+}
+#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+/* Read the entire image. If the image has an alpha channel or a tRNS
+ * chunk, and you have called png_handle_alpha()[*], you will need to
+ * initialize the image to the current image that PNG will be overlaying.
+ * We set the num_rows again here, in case it was incorrectly set in
+ * png_read_start_row() by a call to png_read_update_info() or
+ * png_start_read_image() if png_set_interlace_handling() wasn't called
+ * prior to either of these functions like it should have been. You can
+ * only call this function once. If you desire to have an image for
+ * each pass of a interlaced image, use png_read_rows() instead.
+ *
+ * [*] png_handle_alpha() does not exist yet, as of this version of libpng
+ */
+void PNGAPI
+png_read_image(png_structp png_ptr, png_bytepp image)
+{
+ png_uint_32 i,image_height;
+ int pass, j;
+ png_bytepp rp;
+
+ png_debug(1, "in png_read_image\n");
+ if(png_ptr == NULL) return;
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+ pass = png_set_interlace_handling(png_ptr);
+#else
+ if (png_ptr->interlaced)
+ png_error(png_ptr,
+ "Cannot read interlaced image -- interlace handler disabled.");
+ pass = 1;
+#endif
+
+
+ image_height=png_ptr->height;
+ png_ptr->num_rows = image_height; /* Make sure this is set correctly */
+
+ for (j = 0; j < pass; j++)
+ {
+ rp = image;
+ for (i = 0; i < image_height; i++)
+ {
+ png_read_row(png_ptr, *rp, png_bytep_NULL);
+ rp++;
+ }
+ }
+}
+#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+/* Read the end of the PNG file. Will not read past the end of the
+ * file, will verify the end is accurate, and will read any comments
+ * or time information at the end of the file, if info is not NULL.
+ */
+void PNGAPI
+png_read_end(png_structp png_ptr, png_infop info_ptr)
+{
+ png_byte chunk_length[4];
+ png_uint_32 length;
+
+ png_debug(1, "in png_read_end\n");
+ if(png_ptr == NULL) return;
+ png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
+
+ do
+ {
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_CONST PNG_IHDR;
+ PNG_CONST PNG_IDAT;
+ PNG_CONST PNG_IEND;
+ PNG_CONST PNG_PLTE;
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ PNG_CONST PNG_bKGD;
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ PNG_CONST PNG_cHRM;
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ PNG_CONST PNG_gAMA;
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ PNG_CONST PNG_hIST;
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ PNG_CONST PNG_iCCP;
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ PNG_CONST PNG_iTXt;
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ PNG_CONST PNG_oFFs;
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ PNG_CONST PNG_pCAL;
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ PNG_CONST PNG_pHYs;
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ PNG_CONST PNG_sBIT;
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ PNG_CONST PNG_sCAL;
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ PNG_CONST PNG_sPLT;
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ PNG_CONST PNG_sRGB;
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ PNG_CONST PNG_tEXt;
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ PNG_CONST PNG_tIME;
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ PNG_CONST PNG_tRNS;
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ PNG_CONST PNG_zTXt;
+#endif
+#endif /* PNG_USE_LOCAL_ARRAYS */
+
+ png_read_data(png_ptr, chunk_length, 4);
+ length = png_get_uint_31(png_ptr,chunk_length);
+
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+
+ png_debug1(0, "Reading %s chunk.\n", png_ptr->chunk_name);
+
+ if (!png_memcmp(png_ptr->chunk_name, png_IHDR, 4))
+ png_handle_IHDR(png_ptr, info_ptr, length);
+ else if (!png_memcmp(png_ptr->chunk_name, png_IEND, 4))
+ png_handle_IEND(png_ptr, info_ptr, length);
+#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
+ else if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name))
+ {
+ if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))
+ png_error(png_ptr, "Too many IDAT's found");
+ }
+ png_handle_unknown(png_ptr, info_ptr, length);
+ if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_ptr->mode |= PNG_HAVE_PLTE;
+ }
+#endif
+ else if (!png_memcmp(png_ptr->chunk_name, png_IDAT, 4))
+ {
+ /* Zero length IDATs are legal after the last IDAT has been
+ * read, but not after other chunks have been read.
+ */
+ if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT))
+ png_error(png_ptr, "Too many IDAT's found");
+ png_crc_finish(png_ptr, length);
+ }
+ else if (!png_memcmp(png_ptr->chunk_name, png_PLTE, 4))
+ png_handle_PLTE(png_ptr, info_ptr, length);
+#if defined(PNG_READ_bKGD_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_bKGD, 4))
+ png_handle_bKGD(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_cHRM_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_cHRM, 4))
+ png_handle_cHRM(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_gAMA_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_gAMA, 4))
+ png_handle_gAMA(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_hIST, 4))
+ png_handle_hIST(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_oFFs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_oFFs, 4))
+ png_handle_oFFs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pCAL, 4))
+ png_handle_pCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sCAL_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sCAL, 4))
+ png_handle_sCAL(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_pHYs_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_pHYs, 4))
+ png_handle_pHYs(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sBIT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sBIT, 4))
+ png_handle_sBIT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sRGB, 4))
+ png_handle_sRGB(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_iCCP_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iCCP, 4))
+ png_handle_iCCP(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_sPLT_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_sPLT, 4))
+ png_handle_sPLT(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tEXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tEXt, 4))
+ png_handle_tEXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tIME_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tIME, 4))
+ png_handle_tIME(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_tRNS, 4))
+ png_handle_tRNS(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_zTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_zTXt, 4))
+ png_handle_zTXt(png_ptr, info_ptr, length);
+#endif
+#if defined(PNG_READ_iTXt_SUPPORTED)
+ else if (!png_memcmp(png_ptr->chunk_name, png_iTXt, 4))
+ png_handle_iTXt(png_ptr, info_ptr, length);
+#endif
+ else
+ png_handle_unknown(png_ptr, info_ptr, length);
+ } while (!(png_ptr->mode & PNG_HAVE_IEND));
+}
+#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+
+/* free all memory used by the read */
+void PNGAPI
+png_destroy_read_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr,
+ png_infopp end_info_ptr_ptr)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL, end_info_ptr = NULL;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn;
+ png_voidp mem_ptr;
+#endif
+
+ png_debug(1, "in png_destroy_read_struct\n");
+ if (png_ptr_ptr != NULL)
+ png_ptr = *png_ptr_ptr;
+
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (end_info_ptr_ptr != NULL)
+ end_info_ptr = *end_info_ptr_ptr;
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+ mem_ptr = png_ptr->mem_ptr;
+#endif
+
+ png_read_destroy(png_ptr, info_ptr, end_info_ptr);
+
+ if (info_ptr != NULL)
+ {
+#if defined(PNG_TEXT_SUPPORTED)
+ png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, -1);
+#endif
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
+ (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)info_ptr);
+#endif
+ *info_ptr_ptr = NULL;
+ }
+
+ if (end_info_ptr != NULL)
+ {
+#if defined(PNG_READ_TEXT_SUPPORTED)
+ png_free_data(png_ptr, end_info_ptr, PNG_FREE_TEXT, -1);
+#endif
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)end_info_ptr, (png_free_ptr)free_fn,
+ (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)end_info_ptr);
+#endif
+ *end_info_ptr_ptr = NULL;
+ }
+
+ if (png_ptr != NULL)
+ {
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
+ (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)png_ptr);
+#endif
+ *png_ptr_ptr = NULL;
+ }
+}
+
+/* free all memory used by the read (old method) */
+void /* PRIVATE */
+png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_infop end_info_ptr)
+{
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf tmp_jmp;
+#endif
+ png_error_ptr error_fn;
+ png_error_ptr warning_fn;
+ png_voidp error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn;
+#endif
+
+ png_debug(1, "in png_read_destroy\n");
+ if (info_ptr != NULL)
+ png_info_destroy(png_ptr, info_ptr);
+
+ if (end_info_ptr != NULL)
+ png_info_destroy(png_ptr, end_info_ptr);
+
+ png_free(png_ptr, png_ptr->zbuf);
+ png_free(png_ptr, png_ptr->big_row_buf);
+ png_free(png_ptr, png_ptr->prev_row);
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ png_free(png_ptr, png_ptr->palette_lookup);
+ png_free(png_ptr, png_ptr->dither_index);
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ png_free(png_ptr, png_ptr->gamma_table);
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ png_free(png_ptr, png_ptr->gamma_from_1);
+ png_free(png_ptr, png_ptr->gamma_to_1);
+#endif
+#ifdef PNG_FREE_ME_SUPPORTED
+ if (png_ptr->free_me & PNG_FREE_PLTE)
+ png_zfree(png_ptr, png_ptr->palette);
+ png_ptr->free_me &= ~PNG_FREE_PLTE;
+#else
+ if (png_ptr->flags & PNG_FLAG_FREE_PLTE)
+ png_zfree(png_ptr, png_ptr->palette);
+ png_ptr->flags &= ~PNG_FLAG_FREE_PLTE;
+#endif
+#if defined(PNG_tRNS_SUPPORTED) || \
+ defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+#ifdef PNG_FREE_ME_SUPPORTED
+ if (png_ptr->free_me & PNG_FREE_TRNS)
+ png_free(png_ptr, png_ptr->trans);
+ png_ptr->free_me &= ~PNG_FREE_TRNS;
+#else
+ if (png_ptr->flags & PNG_FLAG_FREE_TRNS)
+ png_free(png_ptr, png_ptr->trans);
+ png_ptr->flags &= ~PNG_FLAG_FREE_TRNS;
+#endif
+#endif
+#if defined(PNG_READ_hIST_SUPPORTED)
+#ifdef PNG_FREE_ME_SUPPORTED
+ if (png_ptr->free_me & PNG_FREE_HIST)
+ png_free(png_ptr, png_ptr->hist);
+ png_ptr->free_me &= ~PNG_FREE_HIST;
+#else
+ if (png_ptr->flags & PNG_FLAG_FREE_HIST)
+ png_free(png_ptr, png_ptr->hist);
+ png_ptr->flags &= ~PNG_FLAG_FREE_HIST;
+#endif
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->gamma_16_table != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_table[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_table);
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_16_from_1 != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_from_1[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_from_1);
+ }
+ if (png_ptr->gamma_16_to_1 != NULL)
+ {
+ int i;
+ int istop = (1 << (8 - png_ptr->gamma_shift));
+ for (i = 0; i < istop; i++)
+ {
+ png_free(png_ptr, png_ptr->gamma_16_to_1[i]);
+ }
+ png_free(png_ptr, png_ptr->gamma_16_to_1);
+ }
+#endif
+#endif
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ png_free(png_ptr, png_ptr->time_buffer);
+#endif
+
+ inflateEnd(&png_ptr->zstream);
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+ png_free(png_ptr, png_ptr->save_buffer);
+#endif
+
+#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
+#ifdef PNG_TEXT_SUPPORTED
+ png_free(png_ptr, png_ptr->current_text);
+#endif /* PNG_TEXT_SUPPORTED */
+#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
+
+ /* Save the important info out of the png_struct, in case it is
+ * being used again.
+ */
+#ifdef PNG_SETJMP_SUPPORTED
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
+#endif
+
+ error_fn = png_ptr->error_fn;
+ warning_fn = png_ptr->warning_fn;
+ error_ptr = png_ptr->error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+#endif
+
+ png_memset(png_ptr, 0, png_sizeof (png_struct));
+
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+ png_ptr->error_ptr = error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_ptr->free_fn = free_fn;
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
+#endif
+
+}
+
+void PNGAPI
+png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn)
+{
+ if(png_ptr == NULL) return;
+ png_ptr->read_row_fn = read_row_fn;
+}
+
+
+#ifndef PNG_NO_SEQUENTIAL_READ_SUPPORTED
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+void PNGAPI
+png_read_png(png_structp png_ptr, png_infop info_ptr,
+ int transforms,
+ voidp params)
+{
+ int row;
+
+ if(png_ptr == NULL) return;
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+ /* invert the alpha channel from opacity to transparency
+ */
+ if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
+ png_set_invert_alpha(png_ptr);
+#endif
+
+ /* png_read_info() gives us all of the information from the
+ * PNG file before the first IDAT (image data chunk).
+ */
+ png_read_info(png_ptr, info_ptr);
+ if (info_ptr->height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
+ png_error(png_ptr,"Image is too high to process with png_read_png()");
+
+ /* -------------- image transformations start here ------------------- */
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+ /* tell libpng to strip 16 bit/color files down to 8 bits per color
+ */
+ if (transforms & PNG_TRANSFORM_STRIP_16)
+ png_set_strip_16(png_ptr);
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+ /* Strip alpha bytes from the input data without combining with
+ * the background (not recommended).
+ */
+ if (transforms & PNG_TRANSFORM_STRIP_ALPHA)
+ png_set_strip_alpha(png_ptr);
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED)
+ /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single
+ * byte into separate bytes (useful for paletted and grayscale images).
+ */
+ if (transforms & PNG_TRANSFORM_PACKING)
+ png_set_packing(png_ptr);
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ /* Change the order of packed pixels to least significant bit first
+ * (not useful if you are using png_set_packing).
+ */
+ if (transforms & PNG_TRANSFORM_PACKSWAP)
+ png_set_packswap(png_ptr);
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ /* Expand paletted colors into true RGB triplets
+ * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel
+ * Expand paletted or RGB images with transparency to full alpha
+ * channels so the data will be available as RGBA quartets.
+ */
+ if (transforms & PNG_TRANSFORM_EXPAND)
+ if ((png_ptr->bit_depth < 8) ||
+ (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
+ (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
+ png_set_expand(png_ptr);
+#endif
+
+ /* We don't handle background color or gamma transformation or dithering.
+ */
+
+#if defined(PNG_READ_INVERT_SUPPORTED)
+ /* invert monochrome files to have 0 as white and 1 as black
+ */
+ if (transforms & PNG_TRANSFORM_INVERT_MONO)
+ png_set_invert_mono(png_ptr);
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+ /* If you want to shift the pixel values from the range [0,255] or
+ * [0,65535] to the original [0,7] or [0,31], or whatever range the
+ * colors were originally in:
+ */
+ if ((transforms & PNG_TRANSFORM_SHIFT)
+ && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
+ {
+ png_color_8p sig_bit;
+
+ png_get_sBIT(png_ptr, info_ptr, &sig_bit);
+ png_set_shift(png_ptr, sig_bit);
+ }
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED)
+ /* flip the RGB pixels to BGR (or RGBA to BGRA)
+ */
+ if (transforms & PNG_TRANSFORM_BGR)
+ png_set_bgr(png_ptr);
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+ /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR)
+ */
+ if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
+ png_set_swap_alpha(png_ptr);
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED)
+ /* swap bytes of 16 bit files to least significant byte first
+ */
+ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
+ png_set_swap(png_ptr);
+#endif
+
+ /* We don't handle adding filler bytes */
+
+ /* Optional call to gamma correct and add the background to the palette
+ * and update info structure. REQUIRED if you are expecting libpng to
+ * update the palette for you (i.e., you selected such a transform above).
+ */
+ png_read_update_info(png_ptr, info_ptr);
+
+ /* -------------- image transformations end here ------------------- */
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
+#endif
+ if(info_ptr->row_pointers == NULL)
+ {
+ info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr,
+ info_ptr->height * png_sizeof(png_bytep));
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_ROWS;
+#endif
+ for (row = 0; row < (int)info_ptr->height; row++)
+ {
+ info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,
+ png_get_rowbytes(png_ptr, info_ptr));
+ }
+ }
+
+ png_read_image(png_ptr, info_ptr->row_pointers);
+ info_ptr->valid |= PNG_INFO_IDAT;
+
+ /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
+ png_read_end(png_ptr, info_ptr);
+
+ transforms = transforms; /* quiet compiler warnings */
+ params = params;
+
+}
+#endif /* PNG_INFO_IMAGE_SUPPORTED */
+#endif /* PNG_NO_SEQUENTIAL_READ_SUPPORTED */
+#endif /* PNG_READ_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngrio.c b/distrib/libpng-1.2.19/pngrio.c
new file mode 100644
index 0000000..7d2522f
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngrio.c
@@ -0,0 +1,167 @@
+
+/* pngrio.c - functions for data input
+ *
+ * Last changed in libpng 1.2.13 November 13, 2006
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2006 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file provides a location for all input. Users who need
+ * special handling are expected to write a function that has the same
+ * arguments as this and performs a similar function, but that possibly
+ * has a different input method. Note that you shouldn't change this
+ * function, but rather write a replacement function and then make
+ * libpng use it at run time with png_set_read_fn(...).
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_SUPPORTED)
+
+/* Read the data from whatever input you are using. The default routine
+ reads from a file pointer. Note that this routine sometimes gets called
+ with very small lengths, so you should implement some kind of simple
+ buffering if you are using unbuffered reads. This should never be asked
+ to read more then 64K on a 16 bit machine. */
+void /* PRIVATE */
+png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_debug1(4,"reading %d bytes\n", (int)length);
+ if (png_ptr->read_data_fn != NULL)
+ (*(png_ptr->read_data_fn))(png_ptr, data, length);
+ else
+ png_error(png_ptr, "Call to NULL read function");
+}
+
+#if !defined(PNG_NO_STDIO)
+/* This is the function that does the actual reading of data. If you are
+ not reading from a standard C stream, you should create a replacement
+ read_data function and use it at run time with png_set_read_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+void PNGAPI
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_size_t check;
+
+ if(png_ptr == NULL) return;
+ /* fread() returns 0 on error, so it is OK to store this in a png_size_t
+ * instead of an int, which is what fread() actually returns.
+ */
+#if defined(_WIN32_WCE)
+ if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
+ check = 0;
+#else
+ check = (png_size_t)fread(data, (png_size_t)1, length,
+ (png_FILE_p)png_ptr->io_ptr);
+#endif
+
+ if (check != length)
+ png_error(png_ptr, "Read Error");
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void PNGAPI
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ int check;
+ png_byte *n_data;
+ png_FILE_p io_ptr;
+
+ if(png_ptr == NULL) return;
+ /* Check if data really is near. If so, use usual code. */
+ n_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)n_data == data)
+ {
+#if defined(_WIN32_WCE)
+ if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
+ check = 0;
+#else
+ check = fread(n_data, 1, length, io_ptr);
+#endif
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t read, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ read = MIN(NEAR_BUF_SIZE, remaining);
+#if defined(_WIN32_WCE)
+ if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) )
+ err = 0;
+#else
+ err = fread(buf, (png_size_t)1, read, io_ptr);
+#endif
+ png_memcpy(data, buf, read); /* copy far buffer to near buffer */
+ if(err != read)
+ break;
+ else
+ check += err;
+ data += read;
+ remaining -= read;
+ }
+ while (remaining != 0);
+ }
+ if ((png_uint_32)check != (png_uint_32)length)
+ png_error(png_ptr, "read Error");
+}
+#endif
+#endif
+
+/* This function allows the application to supply a new input function
+ for libpng if standard C streams aren't being used.
+
+ This function takes as its arguments:
+ png_ptr - pointer to a png input data structure
+ io_ptr - pointer to user supplied structure containing info about
+ the input functions. May be NULL.
+ read_data_fn - pointer to a new input function that takes as its
+ arguments a pointer to a png_struct, a pointer to
+ a location where input data can be stored, and a 32-bit
+ unsigned int that is the number of bytes to be read.
+ To exit and output any fatal error messages the new write
+ function should call png_error(png_ptr, "Error msg"). */
+void PNGAPI
+png_set_read_fn(png_structp png_ptr, png_voidp io_ptr,
+ png_rw_ptr read_data_fn)
+{
+ if(png_ptr == NULL) return;
+ png_ptr->io_ptr = io_ptr;
+
+#if !defined(PNG_NO_STDIO)
+ if (read_data_fn != NULL)
+ png_ptr->read_data_fn = read_data_fn;
+ else
+ png_ptr->read_data_fn = png_default_read_data;
+#else
+ png_ptr->read_data_fn = read_data_fn;
+#endif
+
+ /* It is an error to write to a read device */
+ if (png_ptr->write_data_fn != NULL)
+ {
+ png_ptr->write_data_fn = NULL;
+ png_warning(png_ptr,
+ "It's an error to set both read_data_fn and write_data_fn in the ");
+ png_warning(png_ptr,
+ "same structure. Resetting write_data_fn to NULL.");
+ }
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_ptr->output_flush_fn = NULL;
+#endif
+}
+#endif /* PNG_READ_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngrtran.c b/distrib/libpng-1.2.19/pngrtran.c
new file mode 100644
index 0000000..3f04051
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngrtran.c
@@ -0,0 +1,4284 @@
+
+/* pngrtran.c - transforms the data in a row for PNG readers
+ *
+ * Last changed in libpng 1.2.19 August 18, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file contains functions optionally called by an application
+ * in order to tell libpng how to handle data when reading a PNG.
+ * Transformations that are used in both reading and writing are
+ * in pngtrans.c.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_SUPPORTED)
+
+/* Set the action on getting a CRC error for an ancillary or critical chunk. */
+void PNGAPI
+png_set_crc_action(png_structp png_ptr, int crit_action, int ancil_action)
+{
+ png_debug(1, "in png_set_crc_action\n");
+ /* Tell libpng how we react to CRC errors in critical chunks */
+ if(png_ptr == NULL) return;
+ switch (crit_action)
+ {
+ case PNG_CRC_NO_CHANGE: /* leave setting as is */
+ break;
+ case PNG_CRC_WARN_USE: /* warn/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE;
+ break;
+ case PNG_CRC_QUIET_USE: /* quiet/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE |
+ PNG_FLAG_CRC_CRITICAL_IGNORE;
+ break;
+ case PNG_CRC_WARN_DISCARD: /* not a valid action for critical data */
+ png_warning(png_ptr, "Can't discard critical data on CRC error.");
+ case PNG_CRC_ERROR_QUIT: /* error/quit */
+ case PNG_CRC_DEFAULT:
+ default:
+ png_ptr->flags &= ~PNG_FLAG_CRC_CRITICAL_MASK;
+ break;
+ }
+
+ switch (ancil_action)
+ {
+ case PNG_CRC_NO_CHANGE: /* leave setting as is */
+ break;
+ case PNG_CRC_WARN_USE: /* warn/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE;
+ break;
+ case PNG_CRC_QUIET_USE: /* quiet/use data */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE |
+ PNG_FLAG_CRC_ANCILLARY_NOWARN;
+ break;
+ case PNG_CRC_ERROR_QUIT: /* error/quit */
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN;
+ break;
+ case PNG_CRC_WARN_DISCARD: /* warn/discard data */
+ case PNG_CRC_DEFAULT:
+ default:
+ png_ptr->flags &= ~PNG_FLAG_CRC_ANCILLARY_MASK;
+ break;
+ }
+}
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
+ defined(PNG_FLOATING_POINT_SUPPORTED)
+/* handle alpha and tRNS via a background color */
+void PNGAPI
+png_set_background(png_structp png_ptr,
+ png_color_16p background_color, int background_gamma_code,
+ int need_expand, double background_gamma)
+{
+ png_debug(1, "in png_set_background\n");
+ if(png_ptr == NULL) return;
+ if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN)
+ {
+ png_warning(png_ptr, "Application must supply a known background gamma");
+ return;
+ }
+
+ png_ptr->transformations |= PNG_BACKGROUND;
+ png_memcpy(&(png_ptr->background), background_color,
+ png_sizeof(png_color_16));
+ png_ptr->background_gamma = (float)background_gamma;
+ png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
+ png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0);
+}
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* strip 16 bit depth files to 8 bit depth */
+void PNGAPI
+png_set_strip_16(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_strip_16\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= PNG_16_TO_8;
+}
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+void PNGAPI
+png_set_strip_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_strip_alpha\n");
+ if(png_ptr == NULL) return;
+ png_ptr->flags |= PNG_FLAG_STRIP_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+/* Dither file to 8 bit. Supply a palette, the current number
+ * of elements in the palette, the maximum number of elements
+ * allowed, and a histogram if possible. If the current number
+ * of colors is greater then the maximum number, the palette will be
+ * modified to fit in the maximum number. "full_dither" indicates
+ * whether we need a dithering cube set up for RGB images, or if we
+ * simply are reducing the number of colors in a paletted image.
+ */
+
+typedef struct png_dsort_struct
+{
+ struct png_dsort_struct FAR * next;
+ png_byte left;
+ png_byte right;
+} png_dsort;
+typedef png_dsort FAR * png_dsortp;
+typedef png_dsort FAR * FAR * png_dsortpp;
+
+void PNGAPI
+png_set_dither(png_structp png_ptr, png_colorp palette,
+ int num_palette, int maximum_colors, png_uint_16p histogram,
+ int full_dither)
+{
+ png_debug(1, "in png_set_dither\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= PNG_DITHER;
+
+ if (!full_dither)
+ {
+ int i;
+
+ png_ptr->dither_index = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(num_palette * png_sizeof (png_byte)));
+ for (i = 0; i < num_palette; i++)
+ png_ptr->dither_index[i] = (png_byte)i;
+ }
+
+ if (num_palette > maximum_colors)
+ {
+ if (histogram != NULL)
+ {
+ /* This is easy enough, just throw out the least used colors.
+ Perhaps not the best solution, but good enough. */
+
+ int i;
+
+ /* initialize an array to sort colors */
+ png_ptr->dither_sort = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(num_palette * png_sizeof (png_byte)));
+
+ /* initialize the dither_sort array */
+ for (i = 0; i < num_palette; i++)
+ png_ptr->dither_sort[i] = (png_byte)i;
+
+ /* Find the least used palette entries by starting a
+ bubble sort, and running it until we have sorted
+ out enough colors. Note that we don't care about
+ sorting all the colors, just finding which are
+ least used. */
+
+ for (i = num_palette - 1; i >= maximum_colors; i--)
+ {
+ int done; /* to stop early if the list is pre-sorted */
+ int j;
+
+ done = 1;
+ for (j = 0; j < i; j++)
+ {
+ if (histogram[png_ptr->dither_sort[j]]
+ < histogram[png_ptr->dither_sort[j + 1]])
+ {
+ png_byte t;
+
+ t = png_ptr->dither_sort[j];
+ png_ptr->dither_sort[j] = png_ptr->dither_sort[j + 1];
+ png_ptr->dither_sort[j + 1] = t;
+ done = 0;
+ }
+ }
+ if (done)
+ break;
+ }
+
+ /* swap the palette around, and set up a table, if necessary */
+ if (full_dither)
+ {
+ int j = num_palette;
+
+ /* put all the useful colors within the max, but don't
+ move the others */
+ for (i = 0; i < maximum_colors; i++)
+ {
+ if ((int)png_ptr->dither_sort[i] >= maximum_colors)
+ {
+ do
+ j--;
+ while ((int)png_ptr->dither_sort[j] >= maximum_colors);
+ palette[i] = palette[j];
+ }
+ }
+ }
+ else
+ {
+ int j = num_palette;
+
+ /* move all the used colors inside the max limit, and
+ develop a translation table */
+ for (i = 0; i < maximum_colors; i++)
+ {
+ /* only move the colors we need to */
+ if ((int)png_ptr->dither_sort[i] >= maximum_colors)
+ {
+ png_color tmp_color;
+
+ do
+ j--;
+ while ((int)png_ptr->dither_sort[j] >= maximum_colors);
+
+ tmp_color = palette[j];
+ palette[j] = palette[i];
+ palette[i] = tmp_color;
+ /* indicate where the color went */
+ png_ptr->dither_index[j] = (png_byte)i;
+ png_ptr->dither_index[i] = (png_byte)j;
+ }
+ }
+
+ /* find closest color for those colors we are not using */
+ for (i = 0; i < num_palette; i++)
+ {
+ if ((int)png_ptr->dither_index[i] >= maximum_colors)
+ {
+ int min_d, k, min_k, d_index;
+
+ /* find the closest color to one we threw out */
+ d_index = png_ptr->dither_index[i];
+ min_d = PNG_COLOR_DIST(palette[d_index], palette[0]);
+ for (k = 1, min_k = 0; k < maximum_colors; k++)
+ {
+ int d;
+
+ d = PNG_COLOR_DIST(palette[d_index], palette[k]);
+
+ if (d < min_d)
+ {
+ min_d = d;
+ min_k = k;
+ }
+ }
+ /* point to closest color */
+ png_ptr->dither_index[i] = (png_byte)min_k;
+ }
+ }
+ }
+ png_free(png_ptr, png_ptr->dither_sort);
+ png_ptr->dither_sort=NULL;
+ }
+ else
+ {
+ /* This is much harder to do simply (and quickly). Perhaps
+ we need to go through a median cut routine, but those
+ don't always behave themselves with only a few colors
+ as input. So we will just find the closest two colors,
+ and throw out one of them (chosen somewhat randomly).
+ [We don't understand this at all, so if someone wants to
+ work on improving it, be our guest - AED, GRP]
+ */
+ int i;
+ int max_d;
+ int num_new_palette;
+ png_dsortp t;
+ png_dsortpp hash;
+
+ t=NULL;
+
+ /* initialize palette index arrays */
+ png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(num_palette * png_sizeof (png_byte)));
+ png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(num_palette * png_sizeof (png_byte)));
+
+ /* initialize the sort array */
+ for (i = 0; i < num_palette; i++)
+ {
+ png_ptr->index_to_palette[i] = (png_byte)i;
+ png_ptr->palette_to_index[i] = (png_byte)i;
+ }
+
+ hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 *
+ png_sizeof (png_dsortp)));
+ for (i = 0; i < 769; i++)
+ hash[i] = NULL;
+/* png_memset(hash, 0, 769 * png_sizeof (png_dsortp)); */
+
+ num_new_palette = num_palette;
+
+ /* initial wild guess at how far apart the farthest pixel
+ pair we will be eliminating will be. Larger
+ numbers mean more areas will be allocated, Smaller
+ numbers run the risk of not saving enough data, and
+ having to do this all over again.
+
+ I have not done extensive checking on this number.
+ */
+ max_d = 96;
+
+ while (num_new_palette > maximum_colors)
+ {
+ for (i = 0; i < num_new_palette - 1; i++)
+ {
+ int j;
+
+ for (j = i + 1; j < num_new_palette; j++)
+ {
+ int d;
+
+ d = PNG_COLOR_DIST(palette[i], palette[j]);
+
+ if (d <= max_d)
+ {
+
+ t = (png_dsortp)png_malloc_warn(png_ptr,
+ (png_uint_32)(png_sizeof(png_dsort)));
+ if (t == NULL)
+ break;
+ t->next = hash[d];
+ t->left = (png_byte)i;
+ t->right = (png_byte)j;
+ hash[d] = t;
+ }
+ }
+ if (t == NULL)
+ break;
+ }
+
+ if (t != NULL)
+ for (i = 0; i <= max_d; i++)
+ {
+ if (hash[i] != NULL)
+ {
+ png_dsortp p;
+
+ for (p = hash[i]; p; p = p->next)
+ {
+ if ((int)png_ptr->index_to_palette[p->left]
+ < num_new_palette &&
+ (int)png_ptr->index_to_palette[p->right]
+ < num_new_palette)
+ {
+ int j, next_j;
+
+ if (num_new_palette & 0x01)
+ {
+ j = p->left;
+ next_j = p->right;
+ }
+ else
+ {
+ j = p->right;
+ next_j = p->left;
+ }
+
+ num_new_palette--;
+ palette[png_ptr->index_to_palette[j]]
+ = palette[num_new_palette];
+ if (!full_dither)
+ {
+ int k;
+
+ for (k = 0; k < num_palette; k++)
+ {
+ if (png_ptr->dither_index[k] ==
+ png_ptr->index_to_palette[j])
+ png_ptr->dither_index[k] =
+ png_ptr->index_to_palette[next_j];
+ if ((int)png_ptr->dither_index[k] ==
+ num_new_palette)
+ png_ptr->dither_index[k] =
+ png_ptr->index_to_palette[j];
+ }
+ }
+
+ png_ptr->index_to_palette[png_ptr->palette_to_index
+ [num_new_palette]] = png_ptr->index_to_palette[j];
+ png_ptr->palette_to_index[png_ptr->index_to_palette[j]]
+ = png_ptr->palette_to_index[num_new_palette];
+
+ png_ptr->index_to_palette[j] = (png_byte)num_new_palette;
+ png_ptr->palette_to_index[num_new_palette] = (png_byte)j;
+ }
+ if (num_new_palette <= maximum_colors)
+ break;
+ }
+ if (num_new_palette <= maximum_colors)
+ break;
+ }
+ }
+
+ for (i = 0; i < 769; i++)
+ {
+ if (hash[i] != NULL)
+ {
+ png_dsortp p = hash[i];
+ while (p)
+ {
+ t = p->next;
+ png_free(png_ptr, p);
+ p = t;
+ }
+ }
+ hash[i] = 0;
+ }
+ max_d += 96;
+ }
+ png_free(png_ptr, hash);
+ png_free(png_ptr, png_ptr->palette_to_index);
+ png_free(png_ptr, png_ptr->index_to_palette);
+ png_ptr->palette_to_index=NULL;
+ png_ptr->index_to_palette=NULL;
+ }
+ num_palette = maximum_colors;
+ }
+ if (png_ptr->palette == NULL)
+ {
+ png_ptr->palette = palette;
+ }
+ png_ptr->num_palette = (png_uint_16)num_palette;
+
+ if (full_dither)
+ {
+ int i;
+ png_bytep distance;
+ int total_bits = PNG_DITHER_RED_BITS + PNG_DITHER_GREEN_BITS +
+ PNG_DITHER_BLUE_BITS;
+ int num_red = (1 << PNG_DITHER_RED_BITS);
+ int num_green = (1 << PNG_DITHER_GREEN_BITS);
+ int num_blue = (1 << PNG_DITHER_BLUE_BITS);
+ png_size_t num_entries = ((png_size_t)1 << total_bits);
+
+ png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr,
+ (png_uint_32)(num_entries * png_sizeof (png_byte)));
+
+ png_memset(png_ptr->palette_lookup, 0, num_entries *
+ png_sizeof (png_byte));
+
+ distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries *
+ png_sizeof(png_byte)));
+
+ png_memset(distance, 0xff, num_entries * png_sizeof(png_byte));
+
+ for (i = 0; i < num_palette; i++)
+ {
+ int ir, ig, ib;
+ int r = (palette[i].red >> (8 - PNG_DITHER_RED_BITS));
+ int g = (palette[i].green >> (8 - PNG_DITHER_GREEN_BITS));
+ int b = (palette[i].blue >> (8 - PNG_DITHER_BLUE_BITS));
+
+ for (ir = 0; ir < num_red; ir++)
+ {
+ /* int dr = abs(ir - r); */
+ int dr = ((ir > r) ? ir - r : r - ir);
+ int index_r = (ir << (PNG_DITHER_BLUE_BITS + PNG_DITHER_GREEN_BITS));
+
+ for (ig = 0; ig < num_green; ig++)
+ {
+ /* int dg = abs(ig - g); */
+ int dg = ((ig > g) ? ig - g : g - ig);
+ int dt = dr + dg;
+ int dm = ((dr > dg) ? dr : dg);
+ int index_g = index_r | (ig << PNG_DITHER_BLUE_BITS);
+
+ for (ib = 0; ib < num_blue; ib++)
+ {
+ int d_index = index_g | ib;
+ /* int db = abs(ib - b); */
+ int db = ((ib > b) ? ib - b : b - ib);
+ int dmax = ((dm > db) ? dm : db);
+ int d = dmax + dt + db;
+
+ if (d < (int)distance[d_index])
+ {
+ distance[d_index] = (png_byte)d;
+ png_ptr->palette_lookup[d_index] = (png_byte)i;
+ }
+ }
+ }
+ }
+ }
+
+ png_free(png_ptr, distance);
+ }
+}
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
+/* Transform the image from the file_gamma to the screen_gamma. We
+ * only do transformations on images where the file_gamma and screen_gamma
+ * are not close reciprocals, otherwise it slows things down slightly, and
+ * also needlessly introduces small errors.
+ *
+ * We will turn off gamma transformation later if no semitransparent entries
+ * are present in the tRNS array for palette images. We can't do it here
+ * because we don't necessarily have the tRNS chunk yet.
+ */
+void PNGAPI
+png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma)
+{
+ png_debug(1, "in png_set_gamma\n");
+ if(png_ptr == NULL) return;
+ if ((fabs(scrn_gamma * file_gamma - 1.0) > PNG_GAMMA_THRESHOLD) ||
+ (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) ||
+ (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
+ png_ptr->transformations |= PNG_GAMMA;
+ png_ptr->gamma = (float)file_gamma;
+ png_ptr->screen_gamma = (float)scrn_gamma;
+}
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expand paletted images to RGB, expand grayscale images of
+ * less than 8-bit depth to 8-bit depth, and expand tRNS chunks
+ * to alpha channels.
+ */
+void PNGAPI
+png_set_expand(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_expand\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
+#ifdef PNG_WARN_UNINITIALIZED_ROW
+ png_ptr->flags &= !(PNG_FLAG_ROW_INIT);
+#endif
+}
+
+/* GRR 19990627: the following three functions currently are identical
+ * to png_set_expand(). However, it is entirely reasonable that someone
+ * might wish to expand an indexed image to RGB but *not* expand a single,
+ * fully transparent palette entry to a full alpha channel--perhaps instead
+ * convert tRNS to the grayscale/RGB format (16-bit RGB value), or replace
+ * the transparent color with a particular RGB value, or drop tRNS entirely.
+ * IOW, a future version of the library may make the transformations flag
+ * a bit more fine-grained, with separate bits for each of these three
+ * functions.
+ *
+ * More to the point, these functions make it obvious what libpng will be
+ * doing, whereas "expand" can (and does) mean any number of things.
+ *
+ * GRP 20060307: In libpng-1.4.0, png_set_gray_1_2_4_to_8() was modified
+ * to expand only the sample depth but not to expand the tRNS to alpha.
+ */
+
+/* Expand paletted images to RGB. */
+void PNGAPI
+png_set_palette_to_rgb(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_palette_to_rgb\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
+#ifdef PNG_WARN_UNINITIALIZED_ROW
+ png_ptr->flags &= !(PNG_FLAG_ROW_INIT);
+#endif
+}
+
+#if !defined(PNG_1_0_X)
+/* Expand grayscale images of less than 8-bit depth to 8 bits. */
+void PNGAPI
+png_set_expand_gray_1_2_4_to_8(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_expand_gray_1_2_4_to_8\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= PNG_EXPAND;
+#ifdef PNG_WARN_UNINITIALIZED_ROW
+ png_ptr->flags &= !(PNG_FLAG_ROW_INIT);
+#endif
+}
+#endif
+
+#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
+/* Expand grayscale images of less than 8-bit depth to 8 bits. */
+/* Deprecated as of libpng-1.2.9 */
+void PNGAPI
+png_set_gray_1_2_4_to_8(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_gray_1_2_4_to_8\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
+}
+#endif
+
+
+/* Expand tRNS chunks to alpha channels. */
+void PNGAPI
+png_set_tRNS_to_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_tRNS_to_alpha\n");
+ png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS);
+#ifdef PNG_WARN_UNINITIALIZED_ROW
+ png_ptr->flags &= !(PNG_FLAG_ROW_INIT);
+#endif
+}
+#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+void PNGAPI
+png_set_gray_to_rgb(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_gray_to_rgb\n");
+ png_ptr->transformations |= PNG_GRAY_TO_RGB;
+#ifdef PNG_WARN_UNINITIALIZED_ROW
+ png_ptr->flags &= !(PNG_FLAG_ROW_INIT);
+#endif
+}
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+#if defined(PNG_FLOATING_POINT_SUPPORTED)
+/* Convert a RGB image to a grayscale of the same width. This allows us,
+ * for example, to convert a 24 bpp RGB image into an 8 bpp grayscale image.
+ */
+
+void PNGAPI
+png_set_rgb_to_gray(png_structp png_ptr, int error_action, double red,
+ double green)
+{
+ int red_fixed = (int)((float)red*100000.0 + 0.5);
+ int green_fixed = (int)((float)green*100000.0 + 0.5);
+ if(png_ptr == NULL) return;
+ png_set_rgb_to_gray_fixed(png_ptr, error_action, red_fixed, green_fixed);
+}
+#endif
+
+void PNGAPI
+png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
+ png_fixed_point red, png_fixed_point green)
+{
+ png_debug(1, "in png_set_rgb_to_gray\n");
+ if(png_ptr == NULL) return;
+ switch(error_action)
+ {
+ case 1: png_ptr->transformations |= PNG_RGB_TO_GRAY;
+ break;
+ case 2: png_ptr->transformations |= PNG_RGB_TO_GRAY_WARN;
+ break;
+ case 3: png_ptr->transformations |= PNG_RGB_TO_GRAY_ERR;
+ }
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ png_ptr->transformations |= PNG_EXPAND;
+#else
+ {
+ png_warning(png_ptr, "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED.");
+ png_ptr->transformations &= ~PNG_RGB_TO_GRAY;
+ }
+#endif
+ {
+ png_uint_16 red_int, green_int;
+ if(red < 0 || green < 0)
+ {
+ red_int = 6968; /* .212671 * 32768 + .5 */
+ green_int = 23434; /* .715160 * 32768 + .5 */
+ }
+ else if(red + green < 100000L)
+ {
+ red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L);
+ green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L);
+ }
+ else
+ {
+ png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients");
+ red_int = 6968;
+ green_int = 23434;
+ }
+ png_ptr->rgb_to_gray_red_coeff = red_int;
+ png_ptr->rgb_to_gray_green_coeff = green_int;
+ png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(32768-red_int-green_int);
+ }
+}
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+void PNGAPI
+png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
+ read_user_transform_fn)
+{
+ png_debug(1, "in png_set_read_user_transform_fn\n");
+ if(png_ptr == NULL) return;
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ png_ptr->transformations |= PNG_USER_TRANSFORM;
+ png_ptr->read_user_transform_fn = read_user_transform_fn;
+#endif
+#ifdef PNG_LEGACY_SUPPORTED
+ if(read_user_transform_fn)
+ png_warning(png_ptr,
+ "This version of libpng does not support user transforms");
+#endif
+}
+#endif
+
+/* Initialize everything needed for the read. This includes modifying
+ * the palette.
+ */
+void /* PRIVATE */
+png_init_read_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_init_read_transformations\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if(png_ptr != NULL)
+#endif
+ {
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || defined(PNG_READ_SHIFT_SUPPORTED) \
+ || defined(PNG_READ_GAMMA_SUPPORTED)
+ int color_type = png_ptr->color_type;
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED)
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ /* Detect gray background and attempt to enable optimization
+ * for gray --> RGB case */
+ /* Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or
+ * RGB_ALPHA (in which case need_expand is superfluous anyway), the
+ * background color might actually be gray yet not be flagged as such.
+ * This is not a problem for the current code, which uses
+ * PNG_BACKGROUND_IS_GRAY only to decide when to do the
+ * png_do_gray_to_rgb() transformation.
+ */
+ if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
+ !(color_type & PNG_COLOR_MASK_COLOR))
+ {
+ png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
+ } else if ((png_ptr->transformations & PNG_BACKGROUND) &&
+ !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
+ (png_ptr->transformations & PNG_GRAY_TO_RGB) &&
+ png_ptr->background.red == png_ptr->background.green &&
+ png_ptr->background.red == png_ptr->background.blue)
+ {
+ png_ptr->mode |= PNG_BACKGROUND_IS_GRAY;
+ png_ptr->background.gray = png_ptr->background.red;
+ }
+#endif
+
+ if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) &&
+ (png_ptr->transformations & PNG_EXPAND))
+ {
+ if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */
+ {
+ /* expand background and tRNS chunks */
+ switch (png_ptr->bit_depth)
+ {
+ case 1:
+ png_ptr->background.gray *= (png_uint_16)0xff;
+ png_ptr->background.red = png_ptr->background.green
+ = png_ptr->background.blue = png_ptr->background.gray;
+ if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
+ {
+ png_ptr->trans_values.gray *= (png_uint_16)0xff;
+ png_ptr->trans_values.red = png_ptr->trans_values.green
+ = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
+ }
+ break;
+ case 2:
+ png_ptr->background.gray *= (png_uint_16)0x55;
+ png_ptr->background.red = png_ptr->background.green
+ = png_ptr->background.blue = png_ptr->background.gray;
+ if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
+ {
+ png_ptr->trans_values.gray *= (png_uint_16)0x55;
+ png_ptr->trans_values.red = png_ptr->trans_values.green
+ = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
+ }
+ break;
+ case 4:
+ png_ptr->background.gray *= (png_uint_16)0x11;
+ png_ptr->background.red = png_ptr->background.green
+ = png_ptr->background.blue = png_ptr->background.gray;
+ if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
+ {
+ png_ptr->trans_values.gray *= (png_uint_16)0x11;
+ png_ptr->trans_values.red = png_ptr->trans_values.green
+ = png_ptr->trans_values.blue = png_ptr->trans_values.gray;
+ }
+ break;
+ case 8:
+ case 16:
+ png_ptr->background.red = png_ptr->background.green
+ = png_ptr->background.blue = png_ptr->background.gray;
+ break;
+ }
+ }
+ else if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_ptr->background.red =
+ png_ptr->palette[png_ptr->background.index].red;
+ png_ptr->background.green =
+ png_ptr->palette[png_ptr->background.index].green;
+ png_ptr->background.blue =
+ png_ptr->palette[png_ptr->background.index].blue;
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_ALPHA)
+ {
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (!(png_ptr->transformations & PNG_EXPAND_tRNS))
+#endif
+ {
+ /* invert the alpha channel (in tRNS) unless the pixels are
+ going to be expanded, in which case leave it for later */
+ int i,istop;
+ istop=(int)png_ptr->num_trans;
+ for (i=0; i<istop; i++)
+ png_ptr->trans[i] = (png_byte)(255 - png_ptr->trans[i]);
+ }
+ }
+#endif
+
+ }
+ }
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
+ png_ptr->background_1 = png_ptr->background;
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
+
+ if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0)
+ && (fabs(png_ptr->screen_gamma * png_ptr->gamma - 1.0)
+ < PNG_GAMMA_THRESHOLD))
+ {
+ int i,k;
+ k=0;
+ for (i=0; i<png_ptr->num_trans; i++)
+ {
+ if (png_ptr->trans[i] != 0 && png_ptr->trans[i] != 0xff)
+ k=1; /* partial transparency is present */
+ }
+ if (k == 0)
+ png_ptr->transformations &= (~PNG_GAMMA);
+ }
+
+ if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) &&
+ png_ptr->gamma != 0.0)
+ {
+ png_build_gamma_table(png_ptr);
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ /* could skip if no transparency and
+ */
+ png_color back, back_1;
+ png_colorp palette = png_ptr->palette;
+ int num_palette = png_ptr->num_palette;
+ int i;
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
+ {
+ back.red = png_ptr->gamma_table[png_ptr->background.red];
+ back.green = png_ptr->gamma_table[png_ptr->background.green];
+ back.blue = png_ptr->gamma_table[png_ptr->background.blue];
+
+ back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
+ back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
+ back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+ }
+ else
+ {
+ double g, gs;
+
+ switch (png_ptr->background_gamma_type)
+ {
+ case PNG_BACKGROUND_GAMMA_SCREEN:
+ g = (png_ptr->screen_gamma);
+ gs = 1.0;
+ break;
+ case PNG_BACKGROUND_GAMMA_FILE:
+ g = 1.0 / (png_ptr->gamma);
+ gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ break;
+ case PNG_BACKGROUND_GAMMA_UNIQUE:
+ g = 1.0 / (png_ptr->background_gamma);
+ gs = 1.0 / (png_ptr->background_gamma *
+ png_ptr->screen_gamma);
+ break;
+ default:
+ g = 1.0; /* back_1 */
+ gs = 1.0; /* back */
+ }
+
+ if ( fabs(gs - 1.0) < PNG_GAMMA_THRESHOLD)
+ {
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+ }
+ else
+ {
+ back.red = (png_byte)(pow(
+ (double)png_ptr->background.red/255, gs) * 255.0 + .5);
+ back.green = (png_byte)(pow(
+ (double)png_ptr->background.green/255, gs) * 255.0 + .5);
+ back.blue = (png_byte)(pow(
+ (double)png_ptr->background.blue/255, gs) * 255.0 + .5);
+ }
+
+ back_1.red = (png_byte)(pow(
+ (double)png_ptr->background.red/255, g) * 255.0 + .5);
+ back_1.green = (png_byte)(pow(
+ (double)png_ptr->background.green/255, g) * 255.0 + .5);
+ back_1.blue = (png_byte)(pow(
+ (double)png_ptr->background.blue/255, g) * 255.0 + .5);
+ }
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i < (int)png_ptr->num_trans && png_ptr->trans[i] != 0xff)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else /* if (png_ptr->trans[i] != 0xff) */
+ {
+ png_byte v, w;
+
+ v = png_ptr->gamma_to_1[palette[i].red];
+ png_composite(w, v, png_ptr->trans[i], back_1.red);
+ palette[i].red = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[palette[i].green];
+ png_composite(w, v, png_ptr->trans[i], back_1.green);
+ palette[i].green = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[palette[i].blue];
+ png_composite(w, v, png_ptr->trans[i], back_1.blue);
+ palette[i].blue = png_ptr->gamma_from_1[w];
+ }
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */
+ else
+ /* color_type != PNG_COLOR_TYPE_PALETTE */
+ {
+ double m = (double)(((png_uint_32)1 << png_ptr->bit_depth) - 1);
+ double g = 1.0;
+ double gs = 1.0;
+
+ switch (png_ptr->background_gamma_type)
+ {
+ case PNG_BACKGROUND_GAMMA_SCREEN:
+ g = (png_ptr->screen_gamma);
+ gs = 1.0;
+ break;
+ case PNG_BACKGROUND_GAMMA_FILE:
+ g = 1.0 / (png_ptr->gamma);
+ gs = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ break;
+ case PNG_BACKGROUND_GAMMA_UNIQUE:
+ g = 1.0 / (png_ptr->background_gamma);
+ gs = 1.0 / (png_ptr->background_gamma *
+ png_ptr->screen_gamma);
+ break;
+ }
+
+ png_ptr->background_1.gray = (png_uint_16)(pow(
+ (double)png_ptr->background.gray / m, g) * m + .5);
+ png_ptr->background.gray = (png_uint_16)(pow(
+ (double)png_ptr->background.gray / m, gs) * m + .5);
+
+ if ((png_ptr->background.red != png_ptr->background.green) ||
+ (png_ptr->background.red != png_ptr->background.blue) ||
+ (png_ptr->background.red != png_ptr->background.gray))
+ {
+ /* RGB or RGBA with color background */
+ png_ptr->background_1.red = (png_uint_16)(pow(
+ (double)png_ptr->background.red / m, g) * m + .5);
+ png_ptr->background_1.green = (png_uint_16)(pow(
+ (double)png_ptr->background.green / m, g) * m + .5);
+ png_ptr->background_1.blue = (png_uint_16)(pow(
+ (double)png_ptr->background.blue / m, g) * m + .5);
+ png_ptr->background.red = (png_uint_16)(pow(
+ (double)png_ptr->background.red / m, gs) * m + .5);
+ png_ptr->background.green = (png_uint_16)(pow(
+ (double)png_ptr->background.green / m, gs) * m + .5);
+ png_ptr->background.blue = (png_uint_16)(pow(
+ (double)png_ptr->background.blue / m, gs) * m + .5);
+ }
+ else
+ {
+ /* GRAY, GRAY ALPHA, RGB, or RGBA with gray background */
+ png_ptr->background_1.red = png_ptr->background_1.green
+ = png_ptr->background_1.blue = png_ptr->background_1.gray;
+ png_ptr->background.red = png_ptr->background.green
+ = png_ptr->background.blue = png_ptr->background.gray;
+ }
+ }
+ }
+ else
+ /* transformation does not include PNG_BACKGROUND */
+#endif /* PNG_READ_BACKGROUND_SUPPORTED */
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_colorp palette = png_ptr->palette;
+ int num_palette = png_ptr->num_palette;
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ else
+#endif
+#endif /* PNG_READ_GAMMA_SUPPORTED && PNG_FLOATING_POINT_SUPPORTED */
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ /* No GAMMA transformation */
+ if ((png_ptr->transformations & PNG_BACKGROUND) &&
+ (color_type == PNG_COLOR_TYPE_PALETTE))
+ {
+ int i;
+ int istop = (int)png_ptr->num_trans;
+ png_color back;
+ png_colorp palette = png_ptr->palette;
+
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+
+ for (i = 0; i < istop; i++)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else if (png_ptr->trans[i] != 0xff)
+ {
+ /* The png_composite() macro is defined in png.h */
+ png_composite(palette[i].red, palette[i].red,
+ png_ptr->trans[i], back.red);
+ png_composite(palette[i].green, palette[i].green,
+ png_ptr->trans[i], back.green);
+ png_composite(palette[i].blue, palette[i].blue,
+ png_ptr->trans[i], back.blue);
+ }
+ }
+ }
+#endif /* PNG_READ_BACKGROUND_SUPPORTED */
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+ if ((png_ptr->transformations & PNG_SHIFT) &&
+ (color_type == PNG_COLOR_TYPE_PALETTE))
+ {
+ png_uint_16 i;
+ png_uint_16 istop = png_ptr->num_palette;
+ int sr = 8 - png_ptr->sig_bit.red;
+ int sg = 8 - png_ptr->sig_bit.green;
+ int sb = 8 - png_ptr->sig_bit.blue;
+
+ if (sr < 0 || sr > 8)
+ sr = 0;
+ if (sg < 0 || sg > 8)
+ sg = 0;
+ if (sb < 0 || sb > 8)
+ sb = 0;
+ for (i = 0; i < istop; i++)
+ {
+ png_ptr->palette[i].red >>= sr;
+ png_ptr->palette[i].green >>= sg;
+ png_ptr->palette[i].blue >>= sb;
+ }
+ }
+#endif /* PNG_READ_SHIFT_SUPPORTED */
+ }
+#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \
+ && !defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if(png_ptr)
+ return;
+#endif
+}
+
+/* Modify the info structure to reflect the transformations. The
+ * info should be updated so a PNG file could be written with it,
+ * assuming the transformations result in valid PNG data.
+ */
+void /* PRIVATE */
+png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_read_transform_info\n");
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND_tRNS))
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ else
+ info_ptr->color_type = PNG_COLOR_TYPE_RGB;
+ info_ptr->bit_depth = 8;
+ info_ptr->num_trans = 0;
+ }
+ else
+ {
+ if (png_ptr->num_trans)
+ {
+ if (png_ptr->transformations & PNG_EXPAND_tRNS)
+ info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
+ else
+ info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
+ }
+ if (info_ptr->bit_depth < 8)
+ info_ptr->bit_depth = 8;
+ info_ptr->num_trans = 0;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ info_ptr->num_trans = 0;
+ info_ptr->background = png_ptr->background;
+ }
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->transformations & PNG_GAMMA)
+ {
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ info_ptr->gamma = png_ptr->gamma;
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ info_ptr->int_gamma = png_ptr->int_gamma;
+#endif
+ }
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+ if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
+ info_ptr->bit_depth = 8;
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & PNG_RGB_TO_GRAY)
+ info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ if (png_ptr->transformations & PNG_DITHER)
+ {
+ if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
+ (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
+ png_ptr->palette_lookup && info_ptr->bit_depth == 8)
+ {
+ info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
+ info_ptr->bit_depth = 8;
+#endif
+
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ info_ptr->channels = 1;
+ else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ info_ptr->channels = 3;
+ else
+ info_ptr->channels = 1;
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+ if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
+ info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+#endif
+
+ if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ info_ptr->channels++;
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */
+ if ((png_ptr->transformations & PNG_FILLER) &&
+ ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
+ (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
+ {
+ info_ptr->channels++;
+ /* if adding a true alpha channel not just filler */
+#if !defined(PNG_1_0_X)
+ if (png_ptr->transformations & PNG_ADD_ALPHA)
+ info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
+#endif
+ }
+#endif
+
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
+defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ if(png_ptr->transformations & PNG_USER_TRANSFORM)
+ {
+ if(info_ptr->bit_depth < png_ptr->user_transform_depth)
+ info_ptr->bit_depth = png_ptr->user_transform_depth;
+ if(info_ptr->channels < png_ptr->user_transform_channels)
+ info_ptr->channels = png_ptr->user_transform_channels;
+ }
+#endif
+
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
+ info_ptr->bit_depth);
+
+ info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,info_ptr->width);
+
+#if !defined(PNG_READ_EXPAND_SUPPORTED)
+ if(png_ptr)
+ return;
+#endif
+}
+
+/* Transform the row. The order of transformations is significant,
+ * and is very touchy. If you add a transformation, take care to
+ * decide how it fits in with the other transformations here.
+ */
+void /* PRIVATE */
+png_do_read_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_do_read_transformations\n");
+ if (png_ptr->row_buf == NULL)
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char msg[50];
+
+ png_snprintf2(msg, 50,
+ "NULL row buffer for row %ld, pass %d", png_ptr->row_number,
+ png_ptr->pass);
+ png_error(png_ptr, msg);
+#else
+ png_error(png_ptr, "NULL row buffer");
+#endif
+ }
+#ifdef PNG_WARN_UNINITIALIZED_ROW
+ if (!(png_ptr->flags & PNG_FLAG_ROW_INIT))
+ /* Application has failed to call either png_read_start_image()
+ * or png_read_update_info() after setting transforms that expand
+ * pixels. This check added to libpng-1.2.19 */
+#if (PNG_WARN_UNINITIALIZED_ROW==1)
+ png_error(png_ptr, "Uninitialized row");
+#else
+ png_warning(png_ptr, "Uninitialized row");
+#endif
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->palette, png_ptr->trans, png_ptr->num_trans);
+ }
+ else
+ {
+ if (png_ptr->num_trans &&
+ (png_ptr->transformations & PNG_EXPAND_tRNS))
+ png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->trans_values));
+ else
+ png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ NULL);
+ }
+ }
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+ if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
+ png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ PNG_FLAG_FILLER_AFTER | (png_ptr->flags & PNG_FLAG_STRIP_ALPHA));
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & PNG_RGB_TO_GRAY)
+ {
+ int rgb_error =
+ png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), png_ptr->row_buf + 1);
+ if(rgb_error)
+ {
+ png_ptr->rgb_to_gray_status=1;
+ if((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
+ PNG_RGB_TO_GRAY_WARN)
+ png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel");
+ if((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
+ PNG_RGB_TO_GRAY_ERR)
+ png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel");
+ }
+ }
+#endif
+
+/*
+From Andreas Dilger e-mail to png-implement, 26 March 1998:
+
+ In most cases, the "simple transparency" should be done prior to doing
+ gray-to-RGB, or you will have to test 3x as many bytes to check if a
+ pixel is transparent. You would also need to make sure that the
+ transparency information is upgraded to RGB.
+
+ To summarize, the current flow is:
+ - Gray + simple transparency -> compare 1 or 2 gray bytes and composite
+ with background "in place" if transparent,
+ convert to RGB if necessary
+ - Gray + alpha -> composite with gray background and remove alpha bytes,
+ convert to RGB if necessary
+
+ To support RGB backgrounds for gray images we need:
+ - Gray + simple transparency -> convert to RGB + simple transparency, compare
+ 3 or 6 bytes and composite with background
+ "in place" if transparent (3x compare/pixel
+ compared to doing composite with gray bkgrnd)
+ - Gray + alpha -> convert to RGB + alpha, composite with background and
+ remove alpha bytes (3x float operations/pixel
+ compared with composite on gray background)
+
+ Greg's change will do this. The reason it wasn't done before is for
+ performance, as this increases the per-pixel operations. If we would check
+ in advance if the background was gray or RGB, and position the gray-to-RGB
+ transform appropriately, then it would save a lot of work/time.
+ */
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ /* if gray -> RGB, do so now only if background is non-gray; else do later
+ * for performance reasons */
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
+ !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
+ png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if ((png_ptr->transformations & PNG_BACKGROUND) &&
+ ((png_ptr->num_trans != 0 ) ||
+ (png_ptr->color_type & PNG_COLOR_MASK_ALPHA)))
+ png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->trans_values), &(png_ptr->background)
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ , &(png_ptr->background_1),
+ png_ptr->gamma_table, png_ptr->gamma_from_1,
+ png_ptr->gamma_to_1, png_ptr->gamma_16_table,
+ png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1,
+ png_ptr->gamma_shift
+#endif
+);
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if ((png_ptr->transformations & PNG_GAMMA) &&
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ !((png_ptr->transformations & PNG_BACKGROUND) &&
+ ((png_ptr->num_trans != 0) ||
+ (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) &&
+#endif
+ (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE))
+ png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->gamma_table, png_ptr->gamma_16_table,
+ png_ptr->gamma_shift);
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+ if (png_ptr->transformations & PNG_16_TO_8)
+ png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+ if (png_ptr->transformations & PNG_DITHER)
+ {
+ png_do_dither((png_row_infop)&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->palette_lookup, png_ptr->dither_index);
+ if(png_ptr->row_info.rowbytes == (png_uint_32)0)
+ png_error(png_ptr, "png_do_dither returned rowbytes=0");
+ }
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ /* if gray -> RGB, do so now only if we did not do so above */
+ if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
+ (png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
+ png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ (png_uint_32)png_ptr->filler, png_ptr->flags);
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_ALPHA)
+ png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_ALPHA)
+ png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+ if (png_ptr->transformations & PNG_USER_TRANSFORM)
+ {
+ if(png_ptr->read_user_transform_fn != NULL)
+ (*(png_ptr->read_user_transform_fn)) /* user read transform function */
+ (png_ptr, /* png_ptr */
+ &(png_ptr->row_info), /* row_info: */
+ /* png_uint_32 width; width of row */
+ /* png_uint_32 rowbytes; number of bytes in row */
+ /* png_byte color_type; color type of pixels */
+ /* png_byte bit_depth; bit depth of samples */
+ /* png_byte channels; number of channels (1-4) */
+ /* png_byte pixel_depth; bits per pixel (depth*channels) */
+ png_ptr->row_buf + 1); /* start of pixel data for row */
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+ if(png_ptr->user_transform_depth)
+ png_ptr->row_info.bit_depth = png_ptr->user_transform_depth;
+ if(png_ptr->user_transform_channels)
+ png_ptr->row_info.channels = png_ptr->user_transform_channels;
+#endif
+ png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
+ png_ptr->row_info.channels);
+ png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
+ png_ptr->row_info.width);
+ }
+#endif
+
+}
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+/* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel,
+ * without changing the actual values. Thus, if you had a row with
+ * a bit depth of 1, you would end up with bytes that only contained
+ * the numbers 0 or 1. If you would rather they contain 0 and 255, use
+ * png_do_shift() after this.
+ */
+void /* PRIVATE */
+png_do_unpack(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_unpack\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && row_info->bit_depth < 8)
+#else
+ if (row_info->bit_depth < 8)
+#endif
+ {
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ png_bytep sp = row + (png_size_t)((row_width - 1) >> 3);
+ png_bytep dp = row + (png_size_t)row_width - 1;
+ png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07);
+ for (i = 0; i < row_width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0x01);
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+
+ png_bytep sp = row + (png_size_t)((row_width - 1) >> 2);
+ png_bytep dp = row + (png_size_t)row_width - 1;
+ png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
+ for (i = 0; i < row_width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0x03);
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp = row + (png_size_t)((row_width - 1) >> 1);
+ png_bytep dp = row + (png_size_t)row_width - 1;
+ png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
+ for (i = 0; i < row_width; i++)
+ {
+ *dp = (png_byte)((*sp >> shift) & 0x0f);
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift = 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = (png_byte)(8 * row_info->channels);
+ row_info->rowbytes = row_width * row_info->channels;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED)
+/* Reverse the effects of png_do_shift. This routine merely shifts the
+ * pixels back to their significant bits values. Thus, if you have
+ * a row of bit depth 8, but only 5 are significant, this will shift
+ * the values back to 0 through 31.
+ */
+void /* PRIVATE */
+png_do_unshift(png_row_infop row_info, png_bytep row, png_color_8p sig_bits)
+{
+ png_debug(1, "in png_do_unshift\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL && sig_bits != NULL &&
+#endif
+ row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ int shift[4];
+ int channels = 0;
+ int c;
+ png_uint_16 value = 0;
+ png_uint_32 row_width = row_info->width;
+
+ if (row_info->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->red;
+ shift[channels++] = row_info->bit_depth - sig_bits->green;
+ shift[channels++] = row_info->bit_depth - sig_bits->blue;
+ }
+ else
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->gray;
+ }
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ shift[channels++] = row_info->bit_depth - sig_bits->alpha;
+ }
+
+ for (c = 0; c < channels; c++)
+ {
+ if (shift[c] <= 0)
+ shift[c] = 0;
+ else
+ value = 1;
+ }
+
+ if (!value)
+ return;
+
+ switch (row_info->bit_depth)
+ {
+ case 2:
+ {
+ png_bytep bp;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+
+ for (bp = row, i = 0; i < istop; i++)
+ {
+ *bp >>= 1;
+ *bp++ &= 0x55;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) |
+ (png_byte)((int)0xf >> shift[0]));
+
+ for (i = 0; i < istop; i++)
+ {
+ *bp >>= shift[0];
+ *bp++ &= mask;
+ }
+ break;
+ }
+ case 8:
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_width * channels;
+
+ for (i = 0; i < istop; i++)
+ {
+ *bp++ >>= shift[i%channels];
+ }
+ break;
+ }
+ case 16:
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = channels * row_width;
+
+ for (i = 0; i < istop; i++)
+ {
+ value = (png_uint_16)((*bp << 8) + *(bp + 1));
+ value >>= shift[i%channels];
+ *bp++ = (png_byte)(value >> 8);
+ *bp++ = (png_byte)(value & 0xff);
+ }
+ break;
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+/* chop rows of bit depth 16 down to 8 */
+void /* PRIVATE */
+png_do_chop(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_chop\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && row_info->bit_depth == 16)
+#else
+ if (row_info->bit_depth == 16)
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->width * row_info->channels;
+
+ for (i = 0; i<istop; i++, sp += 2, dp++)
+ {
+#if defined(PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED)
+ /* This does a more accurate scaling of the 16-bit color
+ * value, rather than a simple low-byte truncation.
+ *
+ * What the ideal calculation should be:
+ * *dp = (((((png_uint_32)(*sp) << 8) |
+ * (png_uint_32)(*(sp + 1))) * 255 + 127) / (png_uint_32)65535L;
+ *
+ * GRR: no, I think this is what it really should be:
+ * *dp = (((((png_uint_32)(*sp) << 8) |
+ * (png_uint_32)(*(sp + 1))) + 128L) / (png_uint_32)257L;
+ *
+ * GRR: here's the exact calculation with shifts:
+ * temp = (((png_uint_32)(*sp) << 8) | (png_uint_32)(*(sp + 1))) + 128L;
+ * *dp = (temp - (temp >> 8)) >> 8;
+ *
+ * Approximate calculation with shift/add instead of multiply/divide:
+ * *dp = ((((png_uint_32)(*sp) << 8) |
+ * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8;
+ *
+ * What we actually do to avoid extra shifting and conversion:
+ */
+
+ *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0);
+#else
+ /* Simply discard the low order byte */
+ *dp = *sp;
+#endif
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = (png_byte)(8 * row_info->channels);
+ row_info->rowbytes = row_info->width * row_info->channels;
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED)
+void /* PRIVATE */
+png_do_read_swap_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_read_swap_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ png_uint_32 row_width = row_info->width;
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This converts from RGBA to ARGB */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+ /* This converts from RRGGBBAA to AARRGGBB */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This converts from GA to AG */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save;
+ }
+ }
+ /* This converts from GGAA to AAGG */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_byte save[2];
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ save[0] = *(--sp);
+ save[1] = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = save[0];
+ *(--dp) = save[1];
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED)
+void /* PRIVATE */
+png_do_read_invert_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_read_invert_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ png_uint_32 row_width = row_info->width;
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This inverts the alpha channel in RGBA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = (png_byte)(255 - *(--sp));
+
+/* This does nothing:
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ We can replace it with:
+*/
+ sp-=3;
+ dp=sp;
+ }
+ }
+ /* This inverts the alpha channel in RRGGBBAA */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = (png_byte)(255 - *(--sp));
+ *(--dp) = (png_byte)(255 - *(--sp));
+
+/* This does nothing:
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ We can replace it with:
+*/
+ sp-=6;
+ dp=sp;
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This inverts the alpha channel in GA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = (png_byte)(255 - *(--sp));
+ *(--dp) = *(--sp);
+ }
+ }
+ /* This inverts the alpha channel in GGAA */
+ else
+ {
+ png_bytep sp = row + row_info->rowbytes;
+ png_bytep dp = sp;
+ png_uint_32 i;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = (png_byte)(255 - *(--sp));
+ *(--dp) = (png_byte)(255 - *(--sp));
+/*
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+*/
+ sp-=2;
+ dp=sp;
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+/* Add filler channel if we have RGB color */
+void /* PRIVATE */
+png_do_read_filler(png_row_infop row_info, png_bytep row,
+ png_uint_32 filler, png_uint_32 flags)
+{
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ png_byte hi_filler = (png_byte)((filler>>8) & 0xff);
+ png_byte lo_filler = (png_byte)(filler & 0xff);
+
+ png_debug(1, "in png_do_read_filler\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if(row_info->bit_depth == 8)
+ {
+ /* This changes the data from G to GX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = lo_filler;
+ row_info->channels = 2;
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_width * 2;
+ }
+ /* This changes the data from G to XG */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 2;
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_width * 2;
+ }
+ }
+ else if(row_info->bit_depth == 16)
+ {
+ /* This changes the data from GG to GGXX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width * 2;
+ png_bytep dp = sp + (png_size_t)row_width * 2;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ row_info->channels = 2;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ }
+ /* This changes the data from GG to XXGG */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 2;
+ png_bytep dp = sp + (png_size_t)row_width * 2;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 2;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ }
+ }
+ } /* COLOR_TYPE == GRAY */
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if(row_info->bit_depth == 8)
+ {
+ /* This changes the data from RGB to RGBX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width * 3;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = lo_filler;
+ row_info->channels = 4;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ }
+ /* This changes the data from RGB to XRGB */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 3;
+ png_bytep dp = sp + (png_size_t)row_width;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 4;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ }
+ }
+ else if(row_info->bit_depth == 16)
+ {
+ /* This changes the data from RRGGBB to RRGGBBXX */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ png_bytep sp = row + (png_size_t)row_width * 6;
+ png_bytep dp = sp + (png_size_t)row_width * 2;
+ for (i = 1; i < row_width; i++)
+ {
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ }
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ row_info->channels = 4;
+ row_info->pixel_depth = 64;
+ row_info->rowbytes = row_width * 8;
+ }
+ /* This changes the data from RRGGBB to XXRRGGBB */
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 6;
+ png_bytep dp = sp + (png_size_t)row_width * 2;
+ for (i = 0; i < row_width; i++)
+ {
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = *(--sp);
+ *(--dp) = hi_filler;
+ *(--dp) = lo_filler;
+ }
+ row_info->channels = 4;
+ row_info->pixel_depth = 64;
+ row_info->rowbytes = row_width * 8;
+ }
+ }
+ } /* COLOR_TYPE == RGB */
+}
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+/* expand grayscale files to RGB, with or without alpha */
+void /* PRIVATE */
+png_do_gray_to_rgb(png_row_infop row_info, png_bytep row)
+{
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ png_debug(1, "in png_do_gray_to_rgb\n");
+ if (row_info->bit_depth >= 8 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ !(row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + (png_size_t)row_width - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 2;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ *(dp--) = *(sp--);
+ }
+ }
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 2 - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 4;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *(sp--);
+ *(dp--) = *(sp--);
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp = row + (png_size_t)row_width * 2 - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 2;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *(sp--);
+ *(dp--) = *sp;
+ *(dp--) = *sp;
+ *(dp--) = *(sp--);
+ }
+ }
+ else
+ {
+ png_bytep sp = row + (png_size_t)row_width * 4 - 1;
+ png_bytep dp = sp + (png_size_t)row_width * 4;
+ for (i = 0; i < row_width; i++)
+ {
+ *(dp--) = *(sp--);
+ *(dp--) = *(sp--);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *sp;
+ *(dp--) = *(sp - 1);
+ *(dp--) = *(sp--);
+ *(dp--) = *(sp--);
+ }
+ }
+ }
+ row_info->channels += (png_byte)2;
+ row_info->color_type |= PNG_COLOR_MASK_COLOR;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ }
+}
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+/* reduce RGB files to grayscale, with or without alpha
+ * using the equation given in Poynton's ColorFAQ at
+ * <http://www.inforamp.net/~poynton/>
+ * Copyright (c) 1998-01-04 Charles Poynton poynton at inforamp.net
+ *
+ * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B
+ *
+ * We approximate this with
+ *
+ * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B
+ *
+ * which can be expressed with integers as
+ *
+ * Y = (6969 * R + 23434 * G + 2365 * B)/32768
+ *
+ * The calculation is to be done in a linear colorspace.
+ *
+ * Other integer coefficents can be used via png_set_rgb_to_gray().
+ */
+int /* PRIVATE */
+png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
+
+{
+ png_uint_32 i;
+
+ png_uint_32 row_width = row_info->width;
+ int rgb_error = 0;
+
+ png_debug(1, "in png_do_rgb_to_gray\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff;
+ png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff;
+ png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = png_ptr->gamma_to_1[*(sp++)];
+ png_byte green = png_ptr->gamma_to_1[*(sp++)];
+ png_byte blue = png_ptr->gamma_to_1[*(sp++)];
+ if(red != green || red != blue)
+ {
+ rgb_error |= 1;
+ *(dp++) = png_ptr->gamma_from_1[
+ (rc*red+gc*green+bc*blue)>>15];
+ }
+ else
+ *(dp++) = *(sp-1);
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = *(sp++);
+ png_byte green = *(sp++);
+ png_byte blue = *(sp++);
+ if(red != green || red != blue)
+ {
+ rgb_error |= 1;
+ *(dp++) = (png_byte)((rc*red+gc*green+bc*blue)>>15);
+ }
+ else
+ *(dp++) = *(sp-1);
+ }
+ }
+ }
+
+ else /* RGB bit_depth == 16 */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_16_to_1 != NULL &&
+ png_ptr->gamma_16_from_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, w;
+
+ red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+
+ if(red == green && red == blue)
+ w = red;
+ else
+ {
+ png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
+ png_ptr->gamma_shift][red>>8];
+ png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
+ png_ptr->gamma_shift][green>>8];
+ png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
+ png_ptr->gamma_shift][blue>>8];
+ png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1
+ + bc*blue_1)>>15);
+ w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
+ png_ptr->gamma_shift][gray16 >> 8];
+ rgb_error |= 1;
+ }
+
+ *(dp++) = (png_byte)((w>>8) & 0xff);
+ *(dp++) = (png_byte)(w & 0xff);
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, gray16;
+
+ red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
+ *(dp++) = (png_byte)((gray16>>8) & 0xff);
+ *(dp++) = (png_byte)(gray16 & 0xff);
+ }
+ }
+ }
+ }
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = png_ptr->gamma_to_1[*(sp++)];
+ png_byte green = png_ptr->gamma_to_1[*(sp++)];
+ png_byte blue = png_ptr->gamma_to_1[*(sp++)];
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ *(dp++) = png_ptr->gamma_from_1
+ [(rc*red + gc*green + bc*blue)>>15];
+ *(dp++) = *(sp++); /* alpha */
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte red = *(sp++);
+ png_byte green = *(sp++);
+ png_byte blue = *(sp++);
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
+ *(dp++) = *(sp++); /* alpha */
+ }
+ }
+ }
+ else /* RGBA bit_depth == 16 */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->gamma_16_to_1 != NULL &&
+ png_ptr->gamma_16_from_1 != NULL)
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, w;
+
+ red = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ green = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+ blue = (png_uint_16)(((*(sp))<<8) | *(sp+1)); sp+=2;
+
+ if(red == green && red == blue)
+ w = red;
+ else
+ {
+ png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >>
+ png_ptr->gamma_shift][red>>8];
+ png_uint_16 green_1 = png_ptr->gamma_16_to_1[(green&0xff) >>
+ png_ptr->gamma_shift][green>>8];
+ png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >>
+ png_ptr->gamma_shift][blue>>8];
+ png_uint_16 gray16 = (png_uint_16)((rc * red_1
+ + gc * green_1 + bc * blue_1)>>15);
+ w = png_ptr->gamma_16_from_1[(gray16&0xff) >>
+ png_ptr->gamma_shift][gray16 >> 8];
+ rgb_error |= 1;
+ }
+
+ *(dp++) = (png_byte)((w>>8) & 0xff);
+ *(dp++) = (png_byte)(w & 0xff);
+ *(dp++) = *(sp++); /* alpha */
+ *(dp++) = *(sp++);
+ }
+ }
+ else
+#endif
+ {
+ png_bytep sp = row;
+ png_bytep dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 red, green, blue, gray16;
+ red = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
+ green = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
+ blue = (png_uint_16)((*(sp)<<8) | *(sp+1)); sp+=2;
+ if(red != green || red != blue)
+ rgb_error |= 1;
+ gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15);
+ *(dp++) = (png_byte)((gray16>>8) & 0xff);
+ *(dp++) = (png_byte)(gray16 & 0xff);
+ *(dp++) = *(sp++); /* alpha */
+ *(dp++) = *(sp++);
+ }
+ }
+ }
+ }
+ row_info->channels -= (png_byte)2;
+ row_info->color_type &= ~PNG_COLOR_MASK_COLOR;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ }
+ return rgb_error;
+}
+#endif
+
+/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth
+ * large of png_color. This lets grayscale images be treated as
+ * paletted. Most useful for gamma correction and simplification
+ * of code.
+ */
+void PNGAPI
+png_build_grayscale_palette(int bit_depth, png_colorp palette)
+{
+ int num_palette;
+ int color_inc;
+ int i;
+ int v;
+
+ png_debug(1, "in png_do_build_grayscale_palette\n");
+ if (palette == NULL)
+ return;
+
+ switch (bit_depth)
+ {
+ case 1:
+ num_palette = 2;
+ color_inc = 0xff;
+ break;
+ case 2:
+ num_palette = 4;
+ color_inc = 0x55;
+ break;
+ case 4:
+ num_palette = 16;
+ color_inc = 0x11;
+ break;
+ case 8:
+ num_palette = 256;
+ color_inc = 1;
+ break;
+ default:
+ num_palette = 0;
+ color_inc = 0;
+ break;
+ }
+
+ for (i = 0, v = 0; i < num_palette; i++, v += color_inc)
+ {
+ palette[i].red = (png_byte)v;
+ palette[i].green = (png_byte)v;
+ palette[i].blue = (png_byte)v;
+ }
+}
+
+/* This function is currently unused. Do we really need it? */
+#if defined(PNG_READ_DITHER_SUPPORTED) && defined(PNG_CORRECT_PALETTE_SUPPORTED)
+void /* PRIVATE */
+png_correct_palette(png_structp png_ptr, png_colorp palette,
+ int num_palette)
+{
+ png_debug(1, "in png_correct_palette\n");
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \
+ defined(PNG_READ_GAMMA_SUPPORTED) && defined(PNG_FLOATING_POINT_SUPPORTED)
+ if (png_ptr->transformations & (PNG_GAMMA | PNG_BACKGROUND))
+ {
+ png_color back, back_1;
+
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_FILE)
+ {
+ back.red = png_ptr->gamma_table[png_ptr->background.red];
+ back.green = png_ptr->gamma_table[png_ptr->background.green];
+ back.blue = png_ptr->gamma_table[png_ptr->background.blue];
+
+ back_1.red = png_ptr->gamma_to_1[png_ptr->background.red];
+ back_1.green = png_ptr->gamma_to_1[png_ptr->background.green];
+ back_1.blue = png_ptr->gamma_to_1[png_ptr->background.blue];
+ }
+ else
+ {
+ double g;
+
+ g = 1.0 / (png_ptr->background_gamma * png_ptr->screen_gamma);
+
+ if (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_SCREEN ||
+ fabs(g - 1.0) < PNG_GAMMA_THRESHOLD)
+ {
+ back.red = png_ptr->background.red;
+ back.green = png_ptr->background.green;
+ back.blue = png_ptr->background.blue;
+ }
+ else
+ {
+ back.red =
+ (png_byte)(pow((double)png_ptr->background.red/255, g) *
+ 255.0 + 0.5);
+ back.green =
+ (png_byte)(pow((double)png_ptr->background.green/255, g) *
+ 255.0 + 0.5);
+ back.blue =
+ (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+ 255.0 + 0.5);
+ }
+
+ g = 1.0 / png_ptr->background_gamma;
+
+ back_1.red =
+ (png_byte)(pow((double)png_ptr->background.red/255, g) *
+ 255.0 + 0.5);
+ back_1.green =
+ (png_byte)(pow((double)png_ptr->background.green/255, g) *
+ 255.0 + 0.5);
+ back_1.blue =
+ (png_byte)(pow((double)png_ptr->background.blue/255, g) *
+ 255.0 + 0.5);
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_uint_32 i;
+
+ for (i = 0; i < (png_uint_32)num_palette; i++)
+ {
+ if (i < png_ptr->num_trans && png_ptr->trans[i] == 0)
+ {
+ palette[i] = back;
+ }
+ else if (i < png_ptr->num_trans && png_ptr->trans[i] != 0xff)
+ {
+ png_byte v, w;
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].red];
+ png_composite(w, v, png_ptr->trans[i], back_1.red);
+ palette[i].red = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].green];
+ png_composite(w, v, png_ptr->trans[i], back_1.green);
+ palette[i].green = png_ptr->gamma_from_1[w];
+
+ v = png_ptr->gamma_to_1[png_ptr->palette[i].blue];
+ png_composite(w, v, png_ptr->trans[i], back_1.blue);
+ palette[i].blue = png_ptr->gamma_from_1[w];
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ else
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (palette[i].red == (png_byte)png_ptr->trans_values.gray)
+ {
+ palette[i] = back;
+ }
+ else
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+ }
+ }
+ else
+#endif
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (png_ptr->transformations & PNG_GAMMA)
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ palette[i].red = png_ptr->gamma_table[palette[i].red];
+ palette[i].green = png_ptr->gamma_table[palette[i].green];
+ palette[i].blue = png_ptr->gamma_table[palette[i].blue];
+ }
+ }
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ else
+#endif
+#endif
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+ if (png_ptr->transformations & PNG_BACKGROUND)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_color back;
+
+ back.red = (png_byte)png_ptr->background.red;
+ back.green = (png_byte)png_ptr->background.green;
+ back.blue = (png_byte)png_ptr->background.blue;
+
+ for (i = 0; i < (int)png_ptr->num_trans; i++)
+ {
+ if (png_ptr->trans[i] == 0)
+ {
+ palette[i].red = back.red;
+ palette[i].green = back.green;
+ palette[i].blue = back.blue;
+ }
+ else if (png_ptr->trans[i] != 0xff)
+ {
+ png_composite(palette[i].red, png_ptr->palette[i].red,
+ png_ptr->trans[i], back.red);
+ png_composite(palette[i].green, png_ptr->palette[i].green,
+ png_ptr->trans[i], back.green);
+ png_composite(palette[i].blue, png_ptr->palette[i].blue,
+ png_ptr->trans[i], back.blue);
+ }
+ }
+ }
+ else /* assume grayscale palette (what else could it be?) */
+ {
+ int i;
+
+ for (i = 0; i < num_palette; i++)
+ {
+ if (i == (png_byte)png_ptr->trans_values.gray)
+ {
+ palette[i].red = (png_byte)png_ptr->background.red;
+ palette[i].green = (png_byte)png_ptr->background.green;
+ palette[i].blue = (png_byte)png_ptr->background.blue;
+ }
+ }
+ }
+ }
+#endif
+}
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+/* Replace any alpha or transparency with the supplied background color.
+ * "background" is already in the screen gamma, while "background_1" is
+ * at a gamma of 1.0. Paletted files have already been taken care of.
+ */
+void /* PRIVATE */
+png_do_background(png_row_infop row_info, png_bytep row,
+ png_color_16p trans_values, png_color_16p background
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ , png_color_16p background_1,
+ png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1,
+ png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1,
+ png_uint_16pp gamma_16_to_1, int gamma_shift
+#endif
+ )
+{
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+ int shift;
+
+ png_debug(1, "in png_do_background\n");
+ if (background != NULL &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) ||
+ (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_values)))
+ {
+ switch (row_info->color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ sp = row;
+ shift = 7;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x01)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 7;
+ sp++;
+ }
+ else
+ shift--;
+ }
+ break;
+ }
+ case 2:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ shift = 6;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x03)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ else
+ {
+ png_byte p = (png_byte)((*sp >> shift) & 0x03);
+ png_byte g = (png_byte)((gamma_table [p | (p << 2) |
+ (p << 4) | (p << 6)] >> 6) & 0x03);
+ *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (png_byte)(g << shift);
+ }
+ if (!shift)
+ {
+ shift = 6;
+ sp++;
+ }
+ else
+ shift -= 2;
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ shift = 6;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x03)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 6;
+ sp++;
+ }
+ else
+ shift -= 2;
+ }
+ }
+ break;
+ }
+ case 4:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ shift = 4;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x0f)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ else
+ {
+ png_byte p = (png_byte)((*sp >> shift) & 0x0f);
+ png_byte g = (png_byte)((gamma_table[p |
+ (p << 4)] >> 4) & 0x0f);
+ *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (png_byte)(g << shift);
+ }
+ if (!shift)
+ {
+ shift = 4;
+ sp++;
+ }
+ else
+ shift -= 4;
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ shift = 4;
+ for (i = 0; i < row_width; i++)
+ {
+ if ((png_uint_16)((*sp >> shift) & 0x0f)
+ == trans_values->gray)
+ {
+ *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *sp |= (png_byte)(background->gray << shift);
+ }
+ if (!shift)
+ {
+ shift = 4;
+ sp++;
+ }
+ else
+ shift -= 4;
+ }
+ }
+ break;
+ }
+ case 8:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp++)
+ {
+ if (*sp == trans_values->gray)
+ {
+ *sp = (png_byte)background->gray;
+ }
+ else
+ {
+ *sp = gamma_table[*sp];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp++)
+ {
+ if (*sp == trans_values->gray)
+ {
+ *sp = (png_byte)background->gray;
+ }
+ }
+ }
+ break;
+ }
+ case 16:
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 2)
+ {
+ png_uint_16 v;
+
+ v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ if (v == trans_values->gray)
+ {
+ /* background is already in screen gamma */
+ *sp = (png_byte)((background->gray >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ else
+ {
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 2)
+ {
+ png_uint_16 v;
+
+ v = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ if (v == trans_values->gray)
+ {
+ *sp = (png_byte)((background->gray >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->gray & 0xff);
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_table != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 3)
+ {
+ if (*sp == trans_values->red &&
+ *(sp + 1) == trans_values->green &&
+ *(sp + 2) == trans_values->blue)
+ {
+ *sp = (png_byte)background->red;
+ *(sp + 1) = (png_byte)background->green;
+ *(sp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ *sp = gamma_table[*sp];
+ *(sp + 1) = gamma_table[*(sp + 1)];
+ *(sp + 2) = gamma_table[*(sp + 2)];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 3)
+ {
+ if (*sp == trans_values->red &&
+ *(sp + 1) == trans_values->green &&
+ *(sp + 2) == trans_values->blue)
+ {
+ *sp = (png_byte)background->red;
+ *(sp + 1) = (png_byte)background->green;
+ *(sp + 2) = (png_byte)background->blue;
+ }
+ }
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 6)
+ {
+ png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
+ png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
+ if (r == trans_values->red && g == trans_values->green &&
+ b == trans_values->blue)
+ {
+ /* background is already in screen gamma */
+ *sp = (png_byte)((background->red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->red & 0xff);
+ *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(background->green & 0xff);
+ *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(sp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(sp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp += 6)
+ {
+ png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp+1));
+ png_uint_16 g = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
+ png_uint_16 b = (png_uint_16)(((*(sp+4)) << 8) + *(sp+5));
+
+ if (r == trans_values->red && g == trans_values->green &&
+ b == trans_values->blue)
+ {
+ *sp = (png_byte)((background->red >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(background->red & 0xff);
+ *(sp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(sp + 3) = (png_byte)(background->green & 0xff);
+ *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(sp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+ gamma_table != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 2, dp++)
+ {
+ png_uint_16 a = *(sp + 1);
+
+ if (a == 0xff)
+ {
+ *dp = gamma_table[*sp];
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)background->gray;
+ }
+ else
+ {
+ png_byte v, w;
+
+ v = gamma_to_1[*sp];
+ png_composite(w, v, a, background_1->gray);
+ *dp = gamma_from_1[w];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 2, dp++)
+ {
+ png_byte a = *(sp + 1);
+
+ if (a == 0xff)
+ {
+ *dp = *sp;
+ }
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ else if (a == 0)
+ {
+ *dp = (png_byte)background->gray;
+ }
+ else
+ {
+ png_composite(*dp, *sp, a, background_1->gray);
+ }
+#else
+ *dp = (png_byte)background->gray;
+#endif
+ }
+ }
+ }
+ else /* if (png_ptr->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+ gamma_16_to_1 != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 2)
+ {
+ png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
+
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_16 v;
+
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ }
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ else if (a == 0)
+#else
+ else
+#endif
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)((background->gray >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->gray & 0xff);
+ }
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ else
+ {
+ png_uint_16 g, v, w;
+
+ g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+ png_composite_16(v, g, a, background_1->gray);
+ w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
+ *dp = (png_byte)((w >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(w & 0xff);
+ }
+#endif
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 2)
+ {
+ png_uint_16 a = (png_uint_16)(((*(sp+2)) << 8) + *(sp+3));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_memcpy(dp, sp, 2);
+ }
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ else if (a == 0)
+#else
+ else
+#endif
+ {
+ *dp = (png_byte)((background->gray >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->gray & 0xff);
+ }
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ else
+ {
+ png_uint_16 g, v;
+
+ g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ png_composite_16(v, g, a, background_1->gray);
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ }
+#endif
+ }
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_to_1 != NULL && gamma_from_1 != NULL &&
+ gamma_table != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 3)
+ {
+ png_byte a = *(sp + 3);
+
+ if (a == 0xff)
+ {
+ *dp = gamma_table[*sp];
+ *(dp + 1) = gamma_table[*(sp + 1)];
+ *(dp + 2) = gamma_table[*(sp + 2)];
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)background->red;
+ *(dp + 1) = (png_byte)background->green;
+ *(dp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ png_byte v, w;
+
+ v = gamma_to_1[*sp];
+ png_composite(w, v, a, background_1->red);
+ *dp = gamma_from_1[w];
+ v = gamma_to_1[*(sp + 1)];
+ png_composite(w, v, a, background_1->green);
+ *(dp + 1) = gamma_from_1[w];
+ v = gamma_to_1[*(sp + 2)];
+ png_composite(w, v, a, background_1->blue);
+ *(dp + 2) = gamma_from_1[w];
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 4, dp += 3)
+ {
+ png_byte a = *(sp + 3);
+
+ if (a == 0xff)
+ {
+ *dp = *sp;
+ *(dp + 1) = *(sp + 1);
+ *(dp + 2) = *(sp + 2);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)background->red;
+ *(dp + 1) = (png_byte)background->green;
+ *(dp + 2) = (png_byte)background->blue;
+ }
+ else
+ {
+ png_composite(*dp, *sp, a, background->red);
+ png_composite(*(dp + 1), *(sp + 1), a,
+ background->green);
+ png_composite(*(dp + 2), *(sp + 2), a,
+ background->blue);
+ }
+ }
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+ if (gamma_16 != NULL && gamma_16_from_1 != NULL &&
+ gamma_16_to_1 != NULL)
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 8, dp += 6)
+ {
+ png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
+ << 8) + (png_uint_16)(*(sp + 7)));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_uint_16 v;
+
+ v = gamma_16[*(sp + 1) >> gamma_shift][*sp];
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ *(dp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(v & 0xff);
+ v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ *(dp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(v & 0xff);
+ }
+ else if (a == 0)
+ {
+ /* background is already in screen gamma */
+ *dp = (png_byte)((background->red >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->red & 0xff);
+ *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(background->green & 0xff);
+ *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v, w, x;
+
+ v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
+ png_composite_16(w, v, a, background_1->red);
+ x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ *dp = (png_byte)((x >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(x & 0xff);
+ v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
+ png_composite_16(w, v, a, background_1->green);
+ x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ *(dp + 2) = (png_byte)((x >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(x & 0xff);
+ v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
+ png_composite_16(w, v, a, background_1->blue);
+ x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8];
+ *(dp + 4) = (png_byte)((x >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(x & 0xff);
+ }
+ }
+ }
+ else
+#endif
+ {
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++, sp += 8, dp += 6)
+ {
+ png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6))
+ << 8) + (png_uint_16)(*(sp + 7)));
+ if (a == (png_uint_16)0xffff)
+ {
+ png_memcpy(dp, sp, 6);
+ }
+ else if (a == 0)
+ {
+ *dp = (png_byte)((background->red >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(background->red & 0xff);
+ *(dp + 2) = (png_byte)((background->green >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(background->green & 0xff);
+ *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(background->blue & 0xff);
+ }
+ else
+ {
+ png_uint_16 v;
+
+ png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1));
+ png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8)
+ + *(sp + 3));
+ png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8)
+ + *(sp + 5));
+
+ png_composite_16(v, r, a, background->red);
+ *dp = (png_byte)((v >> 8) & 0xff);
+ *(dp + 1) = (png_byte)(v & 0xff);
+ png_composite_16(v, g, a, background->green);
+ *(dp + 2) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 3) = (png_byte)(v & 0xff);
+ png_composite_16(v, b, a, background->blue);
+ *(dp + 4) = (png_byte)((v >> 8) & 0xff);
+ *(dp + 5) = (png_byte)(v & 0xff);
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ row_info->channels--;
+ row_info->pixel_depth = (png_byte)(row_info->channels *
+ row_info->bit_depth);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+/* Gamma correct the image, avoiding the alpha channel. Make sure
+ * you do this after you deal with the transparency issue on grayscale
+ * or RGB images. If your bit depth is 8, use gamma_table, if it
+ * is 16, use gamma_16_table and gamma_shift. Build these with
+ * build_gamma_table().
+ */
+void /* PRIVATE */
+png_do_gamma(png_row_infop row_info, png_bytep row,
+ png_bytep gamma_table, png_uint_16pp gamma_16_table,
+ int gamma_shift)
+{
+ png_bytep sp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_gamma\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ ((row_info->bit_depth <= 8 && gamma_table != NULL) ||
+ (row_info->bit_depth == 16 && gamma_16_table != NULL)))
+ {
+ switch (row_info->color_type)
+ {
+ case PNG_COLOR_TYPE_RGB:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v;
+
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ *sp = gamma_table[*sp];
+ sp++;
+ sp++;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 4;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ {
+ if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp += 2;
+ }
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 4;
+ }
+ }
+ break;
+ }
+ case PNG_COLOR_TYPE_GRAY:
+ {
+ if (row_info->bit_depth == 2)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i += 4)
+ {
+ int a = *sp & 0xc0;
+ int b = *sp & 0x30;
+ int c = *sp & 0x0c;
+ int d = *sp & 0x03;
+
+ *sp = (png_byte)(
+ ((((int)gamma_table[a|(a>>2)|(a>>4)|(a>>6)]) ) & 0xc0)|
+ ((((int)gamma_table[(b<<2)|b|(b>>2)|(b>>4)])>>2) & 0x30)|
+ ((((int)gamma_table[(c<<4)|(c<<2)|c|(c>>2)])>>4) & 0x0c)|
+ ((((int)gamma_table[(d<<6)|(d<<4)|(d<<2)|d])>>6) ));
+ sp++;
+ }
+ }
+ if (row_info->bit_depth == 4)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i += 2)
+ {
+ int msb = *sp & 0xf0;
+ int lsb = *sp & 0x0f;
+
+ *sp = (png_byte)((((int)gamma_table[msb | (msb >> 4)]) & 0xf0)
+ | (((int)gamma_table[(lsb << 4) | lsb]) >> 4));
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ *sp = gamma_table[*sp];
+ sp++;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ png_uint_16 v = gamma_16_table[*(sp + 1) >> gamma_shift][*sp];
+ *sp = (png_byte)((v >> 8) & 0xff);
+ *(sp + 1) = (png_byte)(v & 0xff);
+ sp += 2;
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+/* Expands a palette row to an RGB or RGBA row depending
+ * upon whether you supply trans and num_trans.
+ */
+void /* PRIVATE */
+png_do_expand_palette(png_row_infop row_info, png_bytep row,
+ png_colorp palette, png_bytep trans, int num_trans)
+{
+ int shift, value;
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_expand_palette\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ sp = row + (png_size_t)((row_width - 1) >> 3);
+ dp = row + (png_size_t)row_width - 1;
+ shift = 7 - (int)((row_width + 7) & 0x07);
+ for (i = 0; i < row_width; i++)
+ {
+ if ((*sp >> shift) & 0x01)
+ *dp = 1;
+ else
+ *dp = 0;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ sp = row + (png_size_t)((row_width - 1) >> 2);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x03;
+ *dp = (png_byte)value;
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ sp = row + (png_size_t)((row_width - 1) >> 1);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((row_width & 0x01) << 2);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x0f;
+ *dp = (png_byte)value;
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_width;
+ }
+ switch (row_info->bit_depth)
+ {
+ case 8:
+ {
+ if (trans != NULL)
+ {
+ sp = row + (png_size_t)row_width - 1;
+ dp = row + (png_size_t)(row_width << 2) - 1;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if ((int)(*sp) >= num_trans)
+ *dp-- = 0xff;
+ else
+ *dp-- = trans[*sp];
+ *dp-- = palette[*sp].blue;
+ *dp-- = palette[*sp].green;
+ *dp-- = palette[*sp].red;
+ sp--;
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 32;
+ row_info->rowbytes = row_width * 4;
+ row_info->color_type = 6;
+ row_info->channels = 4;
+ }
+ else
+ {
+ sp = row + (png_size_t)row_width - 1;
+ dp = row + (png_size_t)(row_width * 3) - 1;
+
+ for (i = 0; i < row_width; i++)
+ {
+ *dp-- = palette[*sp].blue;
+ *dp-- = palette[*sp].green;
+ *dp-- = palette[*sp].red;
+ sp--;
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 24;
+ row_info->rowbytes = row_width * 3;
+ row_info->color_type = 2;
+ row_info->channels = 3;
+ }
+ break;
+ }
+ }
+ }
+}
+
+/* If the bit depth < 8, it is expanded to 8. Also, if the already
+ * expanded transparency value is supplied, an alpha channel is built.
+ */
+void /* PRIVATE */
+png_do_expand(png_row_infop row_info, png_bytep row,
+ png_color_16p trans_value)
+{
+ int shift, value;
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_expand\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0);
+
+ if (row_info->bit_depth < 8)
+ {
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ gray = (png_uint_16)((gray&0x01)*0xff);
+ sp = row + (png_size_t)((row_width - 1) >> 3);
+ dp = row + (png_size_t)row_width - 1;
+ shift = 7 - (int)((row_width + 7) & 0x07);
+ for (i = 0; i < row_width; i++)
+ {
+ if ((*sp >> shift) & 0x01)
+ *dp = 0xff;
+ else
+ *dp = 0;
+ if (shift == 7)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift++;
+
+ dp--;
+ }
+ break;
+ }
+ case 2:
+ {
+ gray = (png_uint_16)((gray&0x03)*0x55);
+ sp = row + (png_size_t)((row_width - 1) >> 2);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((3 - ((row_width + 3) & 0x03)) << 1);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x03;
+ *dp = (png_byte)(value | (value << 2) | (value << 4) |
+ (value << 6));
+ if (shift == 6)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift += 2;
+
+ dp--;
+ }
+ break;
+ }
+ case 4:
+ {
+ gray = (png_uint_16)((gray&0x0f)*0x11);
+ sp = row + (png_size_t)((row_width - 1) >> 1);
+ dp = row + (png_size_t)row_width - 1;
+ shift = (int)((1 - ((row_width + 1) & 0x01)) << 2);
+ for (i = 0; i < row_width; i++)
+ {
+ value = (*sp >> shift) & 0x0f;
+ *dp = (png_byte)(value | (value << 4));
+ if (shift == 4)
+ {
+ shift = 0;
+ sp--;
+ }
+ else
+ shift = 4;
+
+ dp--;
+ }
+ break;
+ }
+ }
+ row_info->bit_depth = 8;
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_width;
+ }
+
+ if (trans_value != NULL)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ gray = gray & 0xff;
+ sp = row + (png_size_t)row_width - 1;
+ dp = row + (png_size_t)(row_width << 1) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (*sp == gray)
+ *dp-- = 0;
+ else
+ *dp-- = 0xff;
+ *dp-- = *sp--;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_byte gray_high = (gray >> 8) & 0xff;
+ png_byte gray_low = gray & 0xff;
+ sp = row + row_info->rowbytes - 1;
+ dp = row + (row_info->rowbytes << 1) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (*(sp-1) == gray_high && *(sp) == gray_low)
+ {
+ *dp-- = 0;
+ *dp-- = 0;
+ }
+ else
+ {
+ *dp-- = 0xff;
+ *dp-- = 0xff;
+ }
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA;
+ row_info->channels = 2;
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
+ row_width);
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ png_byte red = trans_value->red & 0xff;
+ png_byte green = trans_value->green & 0xff;
+ png_byte blue = trans_value->blue & 0xff;
+ sp = row + (png_size_t)row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_width << 2) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue)
+ *dp-- = 0;
+ else
+ *dp-- = 0xff;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_byte red_high = (trans_value->red > 8) & 0xff;
+ png_byte green_high = (trans_value->green > 8) & 0xff;
+ png_byte blue_high = (trans_value->blue > 8) & 0xff;
+ png_byte red_low = trans_value->red & 0xff;
+ png_byte green_low = trans_value->green & 0xff;
+ png_byte blue_low = trans_value->blue & 0xff;
+ sp = row + row_info->rowbytes - 1;
+ dp = row + (png_size_t)(row_width << 3) - 1;
+ for (i = 0; i < row_width; i++)
+ {
+ if (*(sp - 5) == red_high &&
+ *(sp - 4) == red_low &&
+ *(sp - 3) == green_high &&
+ *(sp - 2) == green_low &&
+ *(sp - 1) == blue_high &&
+ *(sp ) == blue_low)
+ {
+ *dp-- = 0;
+ *dp-- = 0;
+ }
+ else
+ {
+ *dp-- = 0xff;
+ *dp-- = 0xff;
+ }
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ *dp-- = *sp--;
+ }
+ }
+ row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ row_info->channels = 4;
+ row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+void /* PRIVATE */
+png_do_dither(png_row_infop row_info, png_bytep row,
+ png_bytep palette_lookup, png_bytep dither_lookup)
+{
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width=row_info->width;
+
+ png_debug(1, "in png_do_dither\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB &&
+ palette_lookup && row_info->bit_depth == 8)
+ {
+ int r, g, b, p;
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ r = *sp++;
+ g = *sp++;
+ b = *sp++;
+
+ /* this looks real messy, but the compiler will reduce
+ it down to a reasonable formula. For example, with
+ 5 bits per color, we get:
+ p = (((r >> 3) & 0x1f) << 10) |
+ (((g >> 3) & 0x1f) << 5) |
+ ((b >> 3) & 0x1f);
+ */
+ p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
+ ((1 << PNG_DITHER_RED_BITS) - 1)) <<
+ (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
+ (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
+ ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
+ (PNG_DITHER_BLUE_BITS)) |
+ ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
+ ((1 << PNG_DITHER_BLUE_BITS) - 1));
+
+ *dp++ = palette_lookup[p];
+ }
+ row_info->color_type = PNG_COLOR_TYPE_PALETTE;
+ row_info->channels = 1;
+ row_info->pixel_depth = row_info->bit_depth;
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
+ palette_lookup != NULL && row_info->bit_depth == 8)
+ {
+ int r, g, b, p;
+ sp = row;
+ dp = row;
+ for (i = 0; i < row_width; i++)
+ {
+ r = *sp++;
+ g = *sp++;
+ b = *sp++;
+ sp++;
+
+ p = (((r >> (8 - PNG_DITHER_RED_BITS)) &
+ ((1 << PNG_DITHER_RED_BITS) - 1)) <<
+ (PNG_DITHER_GREEN_BITS + PNG_DITHER_BLUE_BITS)) |
+ (((g >> (8 - PNG_DITHER_GREEN_BITS)) &
+ ((1 << PNG_DITHER_GREEN_BITS) - 1)) <<
+ (PNG_DITHER_BLUE_BITS)) |
+ ((b >> (8 - PNG_DITHER_BLUE_BITS)) &
+ ((1 << PNG_DITHER_BLUE_BITS) - 1));
+
+ *dp++ = palette_lookup[p];
+ }
+ row_info->color_type = PNG_COLOR_TYPE_PALETTE;
+ row_info->channels = 1;
+ row_info->pixel_depth = row_info->bit_depth;
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,row_width);
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
+ dither_lookup && row_info->bit_depth == 8)
+ {
+ sp = row;
+ for (i = 0; i < row_width; i++, sp++)
+ {
+ *sp = dither_lookup[*sp];
+ }
+ }
+ }
+}
+#endif
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+static PNG_CONST int png_gamma_shift[] =
+ {0x10, 0x21, 0x42, 0x84, 0x110, 0x248, 0x550, 0xff0, 0x00};
+
+/* We build the 8- or 16-bit gamma tables here. Note that for 16-bit
+ * tables, we don't make a full table if we are reducing to 8-bit in
+ * the future. Note also how the gamma_16 tables are segmented so that
+ * we don't need to allocate > 64K chunks for a full 16-bit table.
+ */
+void /* PRIVATE */
+png_build_gamma_table(png_structp png_ptr)
+{
+ png_debug(1, "in png_build_gamma_table\n");
+
+ if (png_ptr->bit_depth <= 8)
+ {
+ int i;
+ double g;
+
+ if (png_ptr->screen_gamma > .000001)
+ g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ else
+ g = 1.0;
+
+ png_ptr->gamma_table = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_table[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+ }
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY))
+ {
+
+ g = 1.0 / (png_ptr->gamma);
+
+ png_ptr->gamma_to_1 = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_to_1[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+ }
+
+
+ png_ptr->gamma_from_1 = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)256);
+
+ if(png_ptr->screen_gamma > 0.000001)
+ g = 1.0 / png_ptr->screen_gamma;
+ else
+ g = png_ptr->gamma; /* probably doing rgb_to_gray */
+
+ for (i = 0; i < 256; i++)
+ {
+ png_ptr->gamma_from_1[i] = (png_byte)(pow((double)i / 255.0,
+ g) * 255.0 + .5);
+
+ }
+ }
+#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
+ }
+ else
+ {
+ double g;
+ int i, j, shift, num;
+ int sig_bit;
+ png_uint_32 ig;
+
+ if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ sig_bit = (int)png_ptr->sig_bit.red;
+ if ((int)png_ptr->sig_bit.green > sig_bit)
+ sig_bit = png_ptr->sig_bit.green;
+ if ((int)png_ptr->sig_bit.blue > sig_bit)
+ sig_bit = png_ptr->sig_bit.blue;
+ }
+ else
+ {
+ sig_bit = (int)png_ptr->sig_bit.gray;
+ }
+
+ if (sig_bit > 0)
+ shift = 16 - sig_bit;
+ else
+ shift = 0;
+
+ if (png_ptr->transformations & PNG_16_TO_8)
+ {
+ if (shift < (16 - PNG_MAX_GAMMA_8))
+ shift = (16 - PNG_MAX_GAMMA_8);
+ }
+
+ if (shift > 8)
+ shift = 8;
+ if (shift < 0)
+ shift = 0;
+
+ png_ptr->gamma_shift = (png_byte)shift;
+
+ num = (1 << (8 - shift));
+
+ if (png_ptr->screen_gamma > .000001)
+ g = 1.0 / (png_ptr->gamma * png_ptr->screen_gamma);
+ else
+ g = 1.0;
+
+ png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr,
+ (png_uint_32)(num * png_sizeof (png_uint_16p)));
+
+ if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND))
+ {
+ double fin, fout;
+ png_uint_32 last, max;
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * png_sizeof (png_uint_16)));
+ }
+
+ g = 1.0 / g;
+ last = 0;
+ for (i = 0; i < 256; i++)
+ {
+ fout = ((double)i + 0.5) / 256.0;
+ fin = pow(fout, g);
+ max = (png_uint_32)(fin * (double)((png_uint_32)num << 8));
+ while (last <= max)
+ {
+ png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
+ [(int)(last >> (8 - shift))] = (png_uint_16)(
+ (png_uint_16)i | ((png_uint_16)i << 8));
+ last++;
+ }
+ }
+ while (last < ((png_uint_32)num << 8))
+ {
+ png_ptr->gamma_16_table[(int)(last & (0xff >> shift))]
+ [(int)(last >> (8 - shift))] = (png_uint_16)65535L;
+ last++;
+ }
+ }
+ else
+ {
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_table[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * png_sizeof (png_uint_16)));
+
+ ig = (((png_uint_32)i * (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_table[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+ }
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \
+ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+ if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY))
+ {
+
+ g = 1.0 / (png_ptr->gamma);
+
+ png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr,
+ (png_uint_32)(num * png_sizeof (png_uint_16p )));
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_to_1[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * png_sizeof (png_uint_16)));
+
+ ig = (((png_uint_32)i *
+ (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_to_1[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+
+ if(png_ptr->screen_gamma > 0.000001)
+ g = 1.0 / png_ptr->screen_gamma;
+ else
+ g = png_ptr->gamma; /* probably doing rgb_to_gray */
+
+ png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr,
+ (png_uint_32)(num * png_sizeof (png_uint_16p)));
+
+ for (i = 0; i < num; i++)
+ {
+ png_ptr->gamma_16_from_1[i] = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(256 * png_sizeof (png_uint_16)));
+
+ ig = (((png_uint_32)i *
+ (png_uint_32)png_gamma_shift[shift]) >> 4);
+ for (j = 0; j < 256; j++)
+ {
+ png_ptr->gamma_16_from_1[i][j] =
+ (png_uint_16)(pow((double)(ig + ((png_uint_32)j << 8)) /
+ 65535.0, g) * 65535.0 + .5);
+ }
+ }
+ }
+#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */
+ }
+}
+#endif
+/* To do: install integer version of png_build_gamma_table here */
+#endif
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+/* undoes intrapixel differencing */
+void /* PRIVATE */
+png_do_read_intrapixel(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_read_intrapixel\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ int bytes_per_pixel;
+ png_uint_32 row_width = row_info->width;
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 3;
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 4;
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ *(rp) = (png_byte)((256 + *rp + *(rp+1))&0xff);
+ *(rp+2) = (png_byte)((256 + *(rp+2) + *(rp+1))&0xff);
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 6;
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 8;
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ png_uint_32 s0 = (*(rp ) << 8) | *(rp+1);
+ png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3);
+ png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5);
+ png_uint_32 red = (png_uint_32)((s0+s1+65536L) & 0xffffL);
+ png_uint_32 blue = (png_uint_32)((s2+s1+65536L) & 0xffffL);
+ *(rp ) = (png_byte)((red >> 8) & 0xff);
+ *(rp+1) = (png_byte)(red & 0xff);
+ *(rp+4) = (png_byte)((blue >> 8) & 0xff);
+ *(rp+5) = (png_byte)(blue & 0xff);
+ }
+ }
+ }
+}
+#endif /* PNG_MNG_FEATURES_SUPPORTED */
+#endif /* PNG_READ_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngrutil.c b/distrib/libpng-1.2.19/pngrutil.c
new file mode 100644
index 0000000..86e924c
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngrutil.c
@@ -0,0 +1,4189 @@
+
+/* pngrutil.c - utilities to read a PNG file
+ *
+ * Last changed in libpng 1.2.19 August 18, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file contains routines that are only called from within
+ * libpng itself during the course of reading an image.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_SUPPORTED)
+
+#if defined(_WIN32_WCE) && (_WIN32_WCE<0x500)
+# define WIN32_WCE_OLD
+#endif
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+# if defined(WIN32_WCE_OLD)
+/* strtod() function is not supported on WindowsCE */
+__inline double png_strtod(png_structp png_ptr, PNG_CONST char *nptr, char **endptr)
+{
+ double result = 0;
+ int len;
+ wchar_t *str, *end;
+
+ len = MultiByteToWideChar(CP_ACP, 0, nptr, -1, NULL, 0);
+ str = (wchar_t *)png_malloc(png_ptr, len * sizeof(wchar_t));
+ if ( NULL != str )
+ {
+ MultiByteToWideChar(CP_ACP, 0, nptr, -1, str, len);
+ result = wcstod(str, &end);
+ len = WideCharToMultiByte(CP_ACP, 0, end, -1, NULL, 0, NULL, NULL);
+ *endptr = (char *)nptr + (png_strlen(nptr) - len + 1);
+ png_free(png_ptr, str);
+ }
+ return result;
+}
+# else
+# define png_strtod(p,a,b) strtod(a,b)
+# endif
+#endif
+
+png_uint_32 PNGAPI
+png_get_uint_31(png_structp png_ptr, png_bytep buf)
+{
+ png_uint_32 i = png_get_uint_32(buf);
+ if (i > PNG_UINT_31_MAX)
+ png_error(png_ptr, "PNG unsigned integer out of range.");
+ return (i);
+}
+#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
+/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
+png_uint_32 PNGAPI
+png_get_uint_32(png_bytep buf)
+{
+ png_uint_32 i = ((png_uint_32)(*buf) << 24) +
+ ((png_uint_32)(*(buf + 1)) << 16) +
+ ((png_uint_32)(*(buf + 2)) << 8) +
+ (png_uint_32)(*(buf + 3));
+
+ return (i);
+}
+
+/* Grab a signed 32-bit integer from a buffer in big-endian format. The
+ * data is stored in the PNG file in two's complement format, and it is
+ * assumed that the machine format for signed integers is the same. */
+png_int_32 PNGAPI
+png_get_int_32(png_bytep buf)
+{
+ png_int_32 i = ((png_int_32)(*buf) << 24) +
+ ((png_int_32)(*(buf + 1)) << 16) +
+ ((png_int_32)(*(buf + 2)) << 8) +
+ (png_int_32)(*(buf + 3));
+
+ return (i);
+}
+
+/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
+png_uint_16 PNGAPI
+png_get_uint_16(png_bytep buf)
+{
+ png_uint_16 i = (png_uint_16)(((png_uint_16)(*buf) << 8) +
+ (png_uint_16)(*(buf + 1)));
+
+ return (i);
+}
+#endif /* PNG_READ_BIG_ENDIAN_SUPPORTED */
+
+/* Read data, and (optionally) run it through the CRC. */
+void /* PRIVATE */
+png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
+{
+ if(png_ptr == NULL) return;
+ png_read_data(png_ptr, buf, length);
+ png_calculate_crc(png_ptr, buf, length);
+}
+
+/* Optionally skip data and then check the CRC. Depending on whether we
+ are reading a ancillary or critical chunk, and how the program has set
+ things up, we may calculate the CRC on the data and print a message.
+ Returns '1' if there was a CRC error, '0' otherwise. */
+int /* PRIVATE */
+png_crc_finish(png_structp png_ptr, png_uint_32 skip)
+{
+ png_size_t i;
+ png_size_t istop = png_ptr->zbuf_size;
+
+ for (i = (png_size_t)skip; i > istop; i -= istop)
+ {
+ png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ }
+ if (i)
+ {
+ png_crc_read(png_ptr, png_ptr->zbuf, i);
+ }
+
+ if (png_crc_error(png_ptr))
+ {
+ if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */
+ !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
+ (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */
+ (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
+ {
+ png_chunk_warning(png_ptr, "CRC error");
+ }
+ else
+ {
+ png_chunk_error(png_ptr, "CRC error");
+ }
+ return (1);
+ }
+
+ return (0);
+}
+
+/* Compare the CRC stored in the PNG file with that calculated by libpng from
+ the data it has read thus far. */
+int /* PRIVATE */
+png_crc_error(png_structp png_ptr)
+{
+ png_byte crc_bytes[4];
+ png_uint_32 crc;
+ int need_crc = 1;
+
+ if (png_ptr->chunk_name[0] & 0x20) /* ancillary */
+ {
+ if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+ (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ need_crc = 0;
+ }
+ else /* critical */
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+ need_crc = 0;
+ }
+
+ png_read_data(png_ptr, crc_bytes, 4);
+
+ if (need_crc)
+ {
+ crc = png_get_uint_32(crc_bytes);
+ return ((int)(crc != png_ptr->crc));
+ }
+ else
+ return (0);
+}
+
+#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \
+ defined(PNG_READ_iCCP_SUPPORTED)
+/*
+ * Decompress trailing data in a chunk. The assumption is that chunkdata
+ * points at an allocated area holding the contents of a chunk with a
+ * trailing compressed part. What we get back is an allocated area
+ * holding the original prefix part and an uncompressed version of the
+ * trailing part (the malloc area passed in is freed).
+ */
+png_charp /* PRIVATE */
+png_decompress_chunk(png_structp png_ptr, int comp_type,
+ png_charp chunkdata, png_size_t chunklength,
+ png_size_t prefix_size, png_size_t *newlength)
+{
+ static PNG_CONST char msg[] = "Error decoding compressed text";
+ png_charp text;
+ png_size_t text_size;
+
+ if (comp_type == PNG_COMPRESSION_TYPE_BASE)
+ {
+ int ret = Z_OK;
+ png_ptr->zstream.next_in = (png_bytep)(chunkdata + prefix_size);
+ png_ptr->zstream.avail_in = (uInt)(chunklength - prefix_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+
+ text_size = 0;
+ text = NULL;
+
+ while (png_ptr->zstream.avail_in)
+ {
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret != Z_OK && ret != Z_STREAM_END)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_warning(png_ptr, png_ptr->zstream.msg);
+ else
+ png_warning(png_ptr, msg);
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ if (text == NULL)
+ {
+ text_size = prefix_size + png_sizeof(msg) + 1;
+ text = (png_charp)png_malloc_warn(png_ptr, text_size);
+ if (text == NULL)
+ {
+ png_free(png_ptr,chunkdata);
+ png_error(png_ptr,"Not enough memory to decompress chunk");
+ }
+ png_memcpy(text, chunkdata, prefix_size);
+ }
+
+ text[text_size - 1] = 0x00;
+
+ /* Copy what we can of the error message into the text chunk */
+ text_size = (png_size_t)(chunklength - (text - chunkdata) - 1);
+ text_size = png_sizeof(msg) > text_size ? text_size :
+ png_sizeof(msg);
+ png_memcpy(text + prefix_size, msg, text_size + 1);
+ break;
+ }
+ if (!png_ptr->zstream.avail_out || ret == Z_STREAM_END)
+ {
+ if (text == NULL)
+ {
+ text_size = prefix_size +
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ text = (png_charp)png_malloc_warn(png_ptr, text_size + 1);
+ if (text == NULL)
+ {
+ png_free(png_ptr,chunkdata);
+ png_error(png_ptr,"Not enough memory to decompress chunk.");
+ }
+ png_memcpy(text + prefix_size, png_ptr->zbuf,
+ text_size - prefix_size);
+ png_memcpy(text, chunkdata, prefix_size);
+ *(text + text_size) = 0x00;
+ }
+ else
+ {
+ png_charp tmp;
+
+ tmp = text;
+ text = (png_charp)png_malloc_warn(png_ptr,
+ (png_uint_32)(text_size +
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out + 1));
+ if (text == NULL)
+ {
+ png_free(png_ptr, tmp);
+ png_free(png_ptr, chunkdata);
+ png_error(png_ptr,"Not enough memory to decompress chunk..");
+ }
+ png_memcpy(text, tmp, text_size);
+ png_free(png_ptr, tmp);
+ png_memcpy(text + text_size, png_ptr->zbuf,
+ (png_ptr->zbuf_size - png_ptr->zstream.avail_out));
+ text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
+ *(text + text_size) = 0x00;
+ }
+ if (ret == Z_STREAM_END)
+ break;
+ else
+ {
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ }
+ }
+ if (ret != Z_STREAM_END)
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char umsg[52];
+
+ if (ret == Z_BUF_ERROR)
+ png_snprintf(umsg, 52,
+ "Buffer error in compressed datastream in %s chunk",
+ png_ptr->chunk_name);
+ else if (ret == Z_DATA_ERROR)
+ png_snprintf(umsg, 52,
+ "Data error in compressed datastream in %s chunk",
+ png_ptr->chunk_name);
+ else
+ png_snprintf(umsg, 52,
+ "Incomplete compressed datastream in %s chunk",
+ png_ptr->chunk_name);
+ png_warning(png_ptr, umsg);
+#else
+ png_warning(png_ptr,
+ "Incomplete compressed datastream in chunk other than IDAT");
+#endif
+ text_size=prefix_size;
+ if (text == NULL)
+ {
+ text = (png_charp)png_malloc_warn(png_ptr, text_size+1);
+ if (text == NULL)
+ {
+ png_free(png_ptr, chunkdata);
+ png_error(png_ptr,"Not enough memory for text.");
+ }
+ png_memcpy(text, chunkdata, prefix_size);
+ }
+ *(text + text_size) = 0x00;
+ }
+
+ inflateReset(&png_ptr->zstream);
+ png_ptr->zstream.avail_in = 0;
+
+ png_free(png_ptr, chunkdata);
+ chunkdata = text;
+ *newlength=text_size;
+ }
+ else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char umsg[50];
+
+ png_snprintf(umsg, 50,
+ "Unknown zTXt compression type %d", comp_type);
+ png_warning(png_ptr, umsg);
+#else
+ png_warning(png_ptr, "Unknown zTXt compression type");
+#endif
+
+ *(chunkdata + prefix_size) = 0x00;
+ *newlength=prefix_size;
+ }
+
+ return chunkdata;
+}
+#endif
+
+/* read and check the IDHR chunk */
+void /* PRIVATE */
+png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[13];
+ png_uint_32 width, height;
+ int bit_depth, color_type, compression_type, filter_type;
+ int interlace_type;
+
+ png_debug(1, "in png_handle_IHDR\n");
+
+ if (png_ptr->mode & PNG_HAVE_IHDR)
+ png_error(png_ptr, "Out of place IHDR");
+
+ /* check the length */
+ if (length != 13)
+ png_error(png_ptr, "Invalid IHDR chunk");
+
+ png_ptr->mode |= PNG_HAVE_IHDR;
+
+ png_crc_read(png_ptr, buf, 13);
+ png_crc_finish(png_ptr, 0);
+
+ width = png_get_uint_31(png_ptr, buf);
+ height = png_get_uint_31(png_ptr, buf + 4);
+ bit_depth = buf[8];
+ color_type = buf[9];
+ compression_type = buf[10];
+ filter_type = buf[11];
+ interlace_type = buf[12];
+
+ /* set internal variables */
+ png_ptr->width = width;
+ png_ptr->height = height;
+ png_ptr->bit_depth = (png_byte)bit_depth;
+ png_ptr->interlaced = (png_byte)interlace_type;
+ png_ptr->color_type = (png_byte)color_type;
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ png_ptr->filter_type = (png_byte)filter_type;
+#endif
+ png_ptr->compression_type = (png_byte)compression_type;
+
+ /* find number of channels */
+ switch (png_ptr->color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ case PNG_COLOR_TYPE_PALETTE:
+ png_ptr->channels = 1;
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ png_ptr->channels = 3;
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ png_ptr->channels = 2;
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ png_ptr->channels = 4;
+ break;
+ }
+
+ /* set up other useful info */
+ png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth *
+ png_ptr->channels);
+ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->width);
+ png_debug1(3,"bit_depth = %d\n", png_ptr->bit_depth);
+ png_debug1(3,"channels = %d\n", png_ptr->channels);
+ png_debug1(3,"rowbytes = %lu\n", png_ptr->rowbytes);
+ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth,
+ color_type, interlace_type, compression_type, filter_type);
+}
+
+/* read and check the palette */
+void /* PRIVATE */
+png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_color palette[PNG_MAX_PALETTE_LENGTH];
+ int num, i;
+#ifndef PNG_NO_POINTER_INDEXING
+ png_colorp pal_ptr;
+#endif
+
+ png_debug(1, "in png_handle_PLTE\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before PLTE");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid PLTE after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ png_error(png_ptr, "Duplicate PLTE chunk");
+
+ png_ptr->mode |= PNG_HAVE_PLTE;
+
+ if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
+ {
+ png_warning(png_ptr,
+ "Ignoring PLTE chunk in grayscale PNG");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#endif
+
+ if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3)
+ {
+ if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ png_warning(png_ptr, "Invalid palette chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else
+ {
+ png_error(png_ptr, "Invalid palette chunk");
+ }
+ }
+
+ num = (int)length / 3;
+
+#ifndef PNG_NO_POINTER_INDEXING
+ for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
+ {
+ png_byte buf[3];
+
+ png_crc_read(png_ptr, buf, 3);
+ pal_ptr->red = buf[0];
+ pal_ptr->green = buf[1];
+ pal_ptr->blue = buf[2];
+ }
+#else
+ for (i = 0; i < num; i++)
+ {
+ png_byte buf[3];
+
+ png_crc_read(png_ptr, buf, 3);
+ /* don't depend upon png_color being any order */
+ palette[i].red = buf[0];
+ palette[i].green = buf[1];
+ palette[i].blue = buf[2];
+ }
+#endif
+
+ /* If we actually NEED the PLTE chunk (ie for a paletted image), we do
+ whatever the normal CRC configuration tells us. However, if we
+ have an RGB image, the PLTE can be considered ancillary, so
+ we will act as though it is. */
+#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+#endif
+ {
+ png_crc_finish(png_ptr, 0);
+ }
+#if !defined(PNG_READ_OPT_PLTE_SUPPORTED)
+ else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */
+ {
+ /* If we don't want to use the data from an ancillary chunk,
+ we have two options: an error abort, or a warning and we
+ ignore the data in this chunk (which should be OK, since
+ it's considered ancillary for a RGB or RGBA image). */
+ if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE))
+ {
+ if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)
+ {
+ png_chunk_error(png_ptr, "CRC error");
+ }
+ else
+ {
+ png_chunk_warning(png_ptr, "CRC error");
+ return;
+ }
+ }
+ /* Otherwise, we (optionally) emit a warning and use the chunk. */
+ else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN))
+ {
+ png_chunk_warning(png_ptr, "CRC error");
+ }
+ }
+#endif
+
+ png_set_PLTE(png_ptr, info_ptr, palette, num);
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
+ {
+ if (png_ptr->num_trans > (png_uint_16)num)
+ {
+ png_warning(png_ptr, "Truncating incorrect tRNS chunk length");
+ png_ptr->num_trans = (png_uint_16)num;
+ }
+ if (info_ptr->num_trans > (png_uint_16)num)
+ {
+ png_warning(png_ptr, "Truncating incorrect info tRNS chunk length");
+ info_ptr->num_trans = (png_uint_16)num;
+ }
+ }
+ }
+#endif
+
+}
+
+void /* PRIVATE */
+png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_debug(1, "in png_handle_IEND\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT))
+ {
+ png_error(png_ptr, "No image in file");
+ }
+
+ png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND);
+
+ if (length != 0)
+ {
+ png_warning(png_ptr, "Incorrect IEND chunk length");
+ }
+ png_crc_finish(png_ptr, length);
+
+ info_ptr =info_ptr; /* quiet compiler warnings about unused info_ptr */
+}
+
+#if defined(PNG_READ_gAMA_SUPPORTED)
+void /* PRIVATE */
+png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_fixed_point igamma;
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float file_gamma;
+#endif
+ png_byte buf[4];
+
+ png_debug(1, "in png_handle_gAMA\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before gAMA");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid gAMA after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place gAMA chunk");
+
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ && !(info_ptr->valid & PNG_INFO_sRGB)
+#endif
+ )
+ {
+ png_warning(png_ptr, "Duplicate gAMA chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 4)
+ {
+ png_warning(png_ptr, "Incorrect gAMA chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ igamma = (png_fixed_point)png_get_uint_32(buf);
+ /* check for zero gamma */
+ if (igamma == 0)
+ {
+ png_warning(png_ptr,
+ "Ignoring gAMA chunk with gamma=0");
+ return;
+ }
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
+ if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
+ {
+ png_warning(png_ptr,
+ "Ignoring incorrect gAMA value when sRGB is also present");
+#ifndef PNG_NO_CONSOLE_IO
+ fprintf(stderr, "gamma = (%d/100000)\n", (int)igamma);
+#endif
+ return;
+ }
+#endif /* PNG_READ_sRGB_SUPPORTED */
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ file_gamma = (float)igamma / (float)100000.0;
+# ifdef PNG_READ_GAMMA_SUPPORTED
+ png_ptr->gamma = file_gamma;
+# endif
+ png_set_gAMA(png_ptr, info_ptr, file_gamma);
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_set_gAMA_fixed(png_ptr, info_ptr, igamma);
+#endif
+}
+#endif
+
+#if defined(PNG_READ_sBIT_SUPPORTED)
+void /* PRIVATE */
+png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_size_t truelen;
+ png_byte buf[4];
+
+ png_debug(1, "in png_handle_sBIT\n");
+
+ buf[0] = buf[1] = buf[2] = buf[3] = 0;
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sBIT");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sBIT after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ {
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place sBIT chunk");
+ }
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT))
+ {
+ png_warning(png_ptr, "Duplicate sBIT chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ truelen = 3;
+ else
+ truelen = (png_size_t)png_ptr->channels;
+
+ if (length != truelen || length > 4)
+ {
+ png_warning(png_ptr, "Incorrect sBIT chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, truelen);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_ptr->sig_bit.red = buf[0];
+ png_ptr->sig_bit.green = buf[1];
+ png_ptr->sig_bit.blue = buf[2];
+ png_ptr->sig_bit.alpha = buf[3];
+ }
+ else
+ {
+ png_ptr->sig_bit.gray = buf[0];
+ png_ptr->sig_bit.red = buf[0];
+ png_ptr->sig_bit.green = buf[0];
+ png_ptr->sig_bit.blue = buf[0];
+ png_ptr->sig_bit.alpha = buf[1];
+ }
+ png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit));
+}
+#endif
+
+#if defined(PNG_READ_cHRM_SUPPORTED)
+void /* PRIVATE */
+png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[4];
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+#endif
+ png_fixed_point int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
+ int_y_green, int_x_blue, int_y_blue;
+
+ png_uint_32 uint_x, uint_y;
+
+ png_debug(1, "in png_handle_cHRM\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before cHRM");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid cHRM after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Missing PLTE before cHRM");
+
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ && !(info_ptr->valid & PNG_INFO_sRGB)
+#endif
+ )
+ {
+ png_warning(png_ptr, "Duplicate cHRM chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 32)
+ {
+ png_warning(png_ptr, "Incorrect cHRM chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 4);
+ uint_x = png_get_uint_32(buf);
+
+ png_crc_read(png_ptr, buf, 4);
+ uint_y = png_get_uint_32(buf);
+
+ if (uint_x > 80000L || uint_y > 80000L ||
+ uint_x + uint_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid cHRM white point");
+ png_crc_finish(png_ptr, 24);
+ return;
+ }
+ int_x_white = (png_fixed_point)uint_x;
+ int_y_white = (png_fixed_point)uint_y;
+
+ png_crc_read(png_ptr, buf, 4);
+ uint_x = png_get_uint_32(buf);
+
+ png_crc_read(png_ptr, buf, 4);
+ uint_y = png_get_uint_32(buf);
+
+ if (uint_x + uint_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid cHRM red point");
+ png_crc_finish(png_ptr, 16);
+ return;
+ }
+ int_x_red = (png_fixed_point)uint_x;
+ int_y_red = (png_fixed_point)uint_y;
+
+ png_crc_read(png_ptr, buf, 4);
+ uint_x = png_get_uint_32(buf);
+
+ png_crc_read(png_ptr, buf, 4);
+ uint_y = png_get_uint_32(buf);
+
+ if (uint_x + uint_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid cHRM green point");
+ png_crc_finish(png_ptr, 8);
+ return;
+ }
+ int_x_green = (png_fixed_point)uint_x;
+ int_y_green = (png_fixed_point)uint_y;
+
+ png_crc_read(png_ptr, buf, 4);
+ uint_x = png_get_uint_32(buf);
+
+ png_crc_read(png_ptr, buf, 4);
+ uint_y = png_get_uint_32(buf);
+
+ if (uint_x + uint_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid cHRM blue point");
+ png_crc_finish(png_ptr, 0);
+ return;
+ }
+ int_x_blue = (png_fixed_point)uint_x;
+ int_y_blue = (png_fixed_point)uint_y;
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ white_x = (float)int_x_white / (float)100000.0;
+ white_y = (float)int_y_white / (float)100000.0;
+ red_x = (float)int_x_red / (float)100000.0;
+ red_y = (float)int_y_red / (float)100000.0;
+ green_x = (float)int_x_green / (float)100000.0;
+ green_y = (float)int_y_green / (float)100000.0;
+ blue_x = (float)int_x_blue / (float)100000.0;
+ blue_y = (float)int_y_blue / (float)100000.0;
+#endif
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+ if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB))
+ {
+ if (PNG_OUT_OF_RANGE(int_x_white, 31270, 1000) ||
+ PNG_OUT_OF_RANGE(int_y_white, 32900, 1000) ||
+ PNG_OUT_OF_RANGE(int_x_red, 64000L, 1000) ||
+ PNG_OUT_OF_RANGE(int_y_red, 33000, 1000) ||
+ PNG_OUT_OF_RANGE(int_x_green, 30000, 1000) ||
+ PNG_OUT_OF_RANGE(int_y_green, 60000L, 1000) ||
+ PNG_OUT_OF_RANGE(int_x_blue, 15000, 1000) ||
+ PNG_OUT_OF_RANGE(int_y_blue, 6000, 1000))
+ {
+ png_warning(png_ptr,
+ "Ignoring incorrect cHRM value when sRGB is also present");
+#ifndef PNG_NO_CONSOLE_IO
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ fprintf(stderr,"wx=%f, wy=%f, rx=%f, ry=%f\n",
+ white_x, white_y, red_x, red_y);
+ fprintf(stderr,"gx=%f, gy=%f, bx=%f, by=%f\n",
+ green_x, green_y, blue_x, blue_y);
+#else
+ fprintf(stderr,"wx=%ld, wy=%ld, rx=%ld, ry=%ld\n",
+ int_x_white, int_y_white, int_x_red, int_y_red);
+ fprintf(stderr,"gx=%ld, gy=%ld, bx=%ld, by=%ld\n",
+ int_x_green, int_y_green, int_x_blue, int_y_blue);
+#endif
+#endif /* PNG_NO_CONSOLE_IO */
+ }
+ png_crc_finish(png_ptr, 0);
+ return;
+ }
+#endif /* PNG_READ_sRGB_SUPPORTED */
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ png_set_cHRM(png_ptr, info_ptr,
+ white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_set_cHRM_fixed(png_ptr, info_ptr,
+ int_x_white, int_y_white, int_x_red, int_y_red, int_x_green,
+ int_y_green, int_x_blue, int_y_blue);
+#endif
+ if (png_crc_finish(png_ptr, 0))
+ return;
+}
+#endif
+
+#if defined(PNG_READ_sRGB_SUPPORTED)
+void /* PRIVATE */
+png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ int intent;
+ png_byte buf[1];
+
+ png_debug(1, "in png_handle_sRGB\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sRGB");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sRGB after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place sRGB chunk");
+
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB))
+ {
+ png_warning(png_ptr, "Duplicate sRGB chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 1)
+ {
+ png_warning(png_ptr, "Incorrect sRGB chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 1);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ intent = buf[0];
+ /* check for bad intent */
+ if (intent >= PNG_sRGB_INTENT_LAST)
+ {
+ png_warning(png_ptr, "Unknown sRGB intent");
+ return;
+ }
+
+#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED)
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA))
+ {
+ png_fixed_point igamma;
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ igamma=info_ptr->int_gamma;
+#else
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+ igamma=(png_fixed_point)(info_ptr->gamma * 100000.);
+# endif
+#endif
+ if (PNG_OUT_OF_RANGE(igamma, 45500L, 500))
+ {
+ png_warning(png_ptr,
+ "Ignoring incorrect gAMA value when sRGB is also present");
+#ifndef PNG_NO_CONSOLE_IO
+# ifdef PNG_FIXED_POINT_SUPPORTED
+ fprintf(stderr,"incorrect gamma=(%d/100000)\n",(int)png_ptr->int_gamma);
+# else
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+ fprintf(stderr,"incorrect gamma=%f\n",png_ptr->gamma);
+# endif
+# endif
+#endif
+ }
+ }
+#endif /* PNG_READ_gAMA_SUPPORTED */
+
+#ifdef PNG_READ_cHRM_SUPPORTED
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM))
+ if (PNG_OUT_OF_RANGE(info_ptr->int_x_white, 31270, 1000) ||
+ PNG_OUT_OF_RANGE(info_ptr->int_y_white, 32900, 1000) ||
+ PNG_OUT_OF_RANGE(info_ptr->int_x_red, 64000L, 1000) ||
+ PNG_OUT_OF_RANGE(info_ptr->int_y_red, 33000, 1000) ||
+ PNG_OUT_OF_RANGE(info_ptr->int_x_green, 30000, 1000) ||
+ PNG_OUT_OF_RANGE(info_ptr->int_y_green, 60000L, 1000) ||
+ PNG_OUT_OF_RANGE(info_ptr->int_x_blue, 15000, 1000) ||
+ PNG_OUT_OF_RANGE(info_ptr->int_y_blue, 6000, 1000))
+ {
+ png_warning(png_ptr,
+ "Ignoring incorrect cHRM value when sRGB is also present");
+ }
+#endif /* PNG_FIXED_POINT_SUPPORTED */
+#endif /* PNG_READ_cHRM_SUPPORTED */
+
+ png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent);
+}
+#endif /* PNG_READ_sRGB_SUPPORTED */
+
+#if defined(PNG_READ_iCCP_SUPPORTED)
+void /* PRIVATE */
+png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+/* Note: this does not properly handle chunks that are > 64K under DOS */
+{
+ png_charp chunkdata;
+ png_byte compression_type;
+ png_bytep pC;
+ png_charp profile;
+ png_uint_32 skip = 0;
+ png_uint_32 profile_size, profile_length;
+ png_size_t slength, prefix_length, data_length;
+
+ png_debug(1, "in png_handle_iCCP\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before iCCP");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid iCCP after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->mode & PNG_HAVE_PLTE)
+ /* Should be an error, but we can cope with it */
+ png_warning(png_ptr, "Out of place iCCP chunk");
+
+ if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
+ {
+ png_warning(png_ptr, "Duplicate iCCP chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "iCCP chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
+
+ if (png_crc_finish(png_ptr, skip))
+ {
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+
+ chunkdata[slength] = 0x00;
+
+ for (profile = chunkdata; *profile; profile++)
+ /* empty loop to find end of name */ ;
+
+ ++profile;
+
+ /* there should be at least one zero (the compression type byte)
+ following the separator, and we should be on it */
+ if ( profile >= chunkdata + slength - 1)
+ {
+ png_free(png_ptr, chunkdata);
+ png_warning(png_ptr, "Malformed iCCP chunk");
+ return;
+ }
+
+ /* compression_type should always be zero */
+ compression_type = *profile++;
+ if (compression_type)
+ {
+ png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
+ compression_type=0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
+ wrote nonzero) */
+ }
+
+ prefix_length = profile - chunkdata;
+ chunkdata = png_decompress_chunk(png_ptr, compression_type, chunkdata,
+ slength, prefix_length, &data_length);
+
+ profile_length = data_length - prefix_length;
+
+ if ( prefix_length > data_length || profile_length < 4)
+ {
+ png_free(png_ptr, chunkdata);
+ png_warning(png_ptr, "Profile size field missing from iCCP chunk");
+ return;
+ }
+
+ /* Check the profile_size recorded in the first 32 bits of the ICC profile */
+ pC = (png_bytep)(chunkdata+prefix_length);
+ profile_size = ((*(pC ))<<24) |
+ ((*(pC+1))<<16) |
+ ((*(pC+2))<< 8) |
+ ((*(pC+3)) );
+
+ if(profile_size < profile_length)
+ profile_length = profile_size;
+
+ if(profile_size > profile_length)
+ {
+ png_free(png_ptr, chunkdata);
+ png_warning(png_ptr, "Ignoring truncated iCCP profile.");
+ return;
+ }
+
+ png_set_iCCP(png_ptr, info_ptr, chunkdata, compression_type,
+ chunkdata + prefix_length, profile_length);
+ png_free(png_ptr, chunkdata);
+}
+#endif /* PNG_READ_iCCP_SUPPORTED */
+
+#if defined(PNG_READ_sPLT_SUPPORTED)
+void /* PRIVATE */
+png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+/* Note: this does not properly handle chunks that are > 64K under DOS */
+{
+ png_bytep chunkdata;
+ png_bytep entry_start;
+ png_sPLT_t new_palette;
+#ifdef PNG_NO_POINTER_INDEXING
+ png_sPLT_entryp pp;
+#endif
+ int data_length, entry_size, i;
+ png_uint_32 skip = 0;
+ png_size_t slength;
+
+ png_debug(1, "in png_handle_sPLT\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sPLT");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sPLT after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "sPLT chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ chunkdata = (png_bytep)png_malloc(png_ptr, length + 1);
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
+
+ if (png_crc_finish(png_ptr, skip))
+ {
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+
+ chunkdata[slength] = 0x00;
+
+ for (entry_start = chunkdata; *entry_start; entry_start++)
+ /* empty loop to find end of name */ ;
+ ++entry_start;
+
+ /* a sample depth should follow the separator, and we should be on it */
+ if (entry_start > chunkdata + slength - 2)
+ {
+ png_free(png_ptr, chunkdata);
+ png_warning(png_ptr, "malformed sPLT chunk");
+ return;
+ }
+
+ new_palette.depth = *entry_start++;
+ entry_size = (new_palette.depth == 8 ? 6 : 10);
+ data_length = (slength - (entry_start - chunkdata));
+
+ /* integrity-check the data length */
+ if (data_length % entry_size)
+ {
+ png_free(png_ptr, chunkdata);
+ png_warning(png_ptr, "sPLT chunk has bad length");
+ return;
+ }
+
+ new_palette.nentries = (png_int_32) ( data_length / entry_size);
+ if ((png_uint_32) new_palette.nentries > (png_uint_32) (PNG_SIZE_MAX /
+ png_sizeof(png_sPLT_entry)))
+ {
+ png_warning(png_ptr, "sPLT chunk too long");
+ return;
+ }
+ new_palette.entries = (png_sPLT_entryp)png_malloc_warn(
+ png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry));
+ if (new_palette.entries == NULL)
+ {
+ png_warning(png_ptr, "sPLT chunk requires too much memory");
+ return;
+ }
+
+#ifndef PNG_NO_POINTER_INDEXING
+ for (i = 0; i < new_palette.nentries; i++)
+ {
+ png_sPLT_entryp pp = new_palette.entries + i;
+
+ if (new_palette.depth == 8)
+ {
+ pp->red = *entry_start++;
+ pp->green = *entry_start++;
+ pp->blue = *entry_start++;
+ pp->alpha = *entry_start++;
+ }
+ else
+ {
+ pp->red = png_get_uint_16(entry_start); entry_start += 2;
+ pp->green = png_get_uint_16(entry_start); entry_start += 2;
+ pp->blue = png_get_uint_16(entry_start); entry_start += 2;
+ pp->alpha = png_get_uint_16(entry_start); entry_start += 2;
+ }
+ pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
+ }
+#else
+ pp = new_palette.entries;
+ for (i = 0; i < new_palette.nentries; i++)
+ {
+
+ if (new_palette.depth == 8)
+ {
+ pp[i].red = *entry_start++;
+ pp[i].green = *entry_start++;
+ pp[i].blue = *entry_start++;
+ pp[i].alpha = *entry_start++;
+ }
+ else
+ {
+ pp[i].red = png_get_uint_16(entry_start); entry_start += 2;
+ pp[i].green = png_get_uint_16(entry_start); entry_start += 2;
+ pp[i].blue = png_get_uint_16(entry_start); entry_start += 2;
+ pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2;
+ }
+ pp->frequency = png_get_uint_16(entry_start); entry_start += 2;
+ }
+#endif
+
+ /* discard all chunk data except the name and stash that */
+ new_palette.name = (png_charp)chunkdata;
+
+ png_set_sPLT(png_ptr, info_ptr, &new_palette, 1);
+
+ png_free(png_ptr, chunkdata);
+ png_free(png_ptr, new_palette.entries);
+}
+#endif /* PNG_READ_sPLT_SUPPORTED */
+
+#if defined(PNG_READ_tRNS_SUPPORTED)
+void /* PRIVATE */
+png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte readbuf[PNG_MAX_PALETTE_LENGTH];
+ int bit_mask;
+
+ png_debug(1, "in png_handle_tRNS\n");
+
+ /* For non-indexed color, mask off any bits in the tRNS value that
+ * exceed the bit depth. Some creators were writing extra bits there.
+ * This is not needed for indexed color. */
+ bit_mask = (1 << png_ptr->bit_depth) - 1;
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before tRNS");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid tRNS after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS))
+ {
+ png_warning(png_ptr, "Duplicate tRNS chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_byte buf[2];
+
+ if (length != 2)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 2);
+ png_ptr->num_trans = 1;
+ png_ptr->trans_values.gray = png_get_uint_16(buf) & bit_mask;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_byte buf[6];
+
+ if (length != 6)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ png_crc_read(png_ptr, buf, (png_size_t)length);
+ png_ptr->num_trans = 1;
+ png_ptr->trans_values.red = png_get_uint_16(buf) & bit_mask;
+ png_ptr->trans_values.green = png_get_uint_16(buf + 2) & bit_mask;
+ png_ptr->trans_values.blue = png_get_uint_16(buf + 4) & bit_mask;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (!(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ /* Should be an error, but we can cope with it. */
+ png_warning(png_ptr, "Missing PLTE before tRNS");
+ }
+ if (length > (png_uint_32)png_ptr->num_palette ||
+ length > PNG_MAX_PALETTE_LENGTH)
+ {
+ png_warning(png_ptr, "Incorrect tRNS chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ if (length == 0)
+ {
+ png_warning(png_ptr, "Zero length tRNS chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ png_crc_read(png_ptr, readbuf, (png_size_t)length);
+ png_ptr->num_trans = (png_uint_16)length;
+ }
+ else
+ {
+ png_warning(png_ptr, "tRNS chunk not allowed with alpha channel");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_ptr->num_trans = 0;
+ return;
+ }
+
+ png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans,
+ &(png_ptr->trans_values));
+}
+#endif
+
+#if defined(PNG_READ_bKGD_SUPPORTED)
+void /* PRIVATE */
+png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_size_t truelen;
+ png_byte buf[6];
+
+ png_debug(1, "in png_handle_bKGD\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before bKGD");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid bKGD after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ !(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ png_warning(png_ptr, "Missing PLTE before bKGD");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD))
+ {
+ png_warning(png_ptr, "Duplicate bKGD chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ truelen = 1;
+ else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ truelen = 6;
+ else
+ truelen = 2;
+
+ if (length != truelen)
+ {
+ png_warning(png_ptr, "Incorrect bKGD chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, truelen);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ /* We convert the index value into RGB components so that we can allow
+ * arbitrary RGB values for background when we have transparency, and
+ * so it is easy to determine the RGB values of the background color
+ * from the info_ptr struct. */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_ptr->background.index = buf[0];
+ if(info_ptr->num_palette)
+ {
+ if(buf[0] > info_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Incorrect bKGD chunk index value");
+ return;
+ }
+ png_ptr->background.red =
+ (png_uint_16)png_ptr->palette[buf[0]].red;
+ png_ptr->background.green =
+ (png_uint_16)png_ptr->palette[buf[0]].green;
+ png_ptr->background.blue =
+ (png_uint_16)png_ptr->palette[buf[0]].blue;
+ }
+ }
+ else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */
+ {
+ png_ptr->background.red =
+ png_ptr->background.green =
+ png_ptr->background.blue =
+ png_ptr->background.gray = png_get_uint_16(buf);
+ }
+ else
+ {
+ png_ptr->background.red = png_get_uint_16(buf);
+ png_ptr->background.green = png_get_uint_16(buf + 2);
+ png_ptr->background.blue = png_get_uint_16(buf + 4);
+ }
+
+ png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background));
+}
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED)
+void /* PRIVATE */
+png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ unsigned int num, i;
+ png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH];
+
+ png_debug(1, "in png_handle_hIST\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before hIST");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid hIST after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (!(png_ptr->mode & PNG_HAVE_PLTE))
+ {
+ png_warning(png_ptr, "Missing PLTE before hIST");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST))
+ {
+ png_warning(png_ptr, "Duplicate hIST chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ num = length / 2 ;
+ if (num != (unsigned int) png_ptr->num_palette || num >
+ (unsigned int) PNG_MAX_PALETTE_LENGTH)
+ {
+ png_warning(png_ptr, "Incorrect hIST chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ for (i = 0; i < num; i++)
+ {
+ png_byte buf[2];
+
+ png_crc_read(png_ptr, buf, 2);
+ readbuf[i] = png_get_uint_16(buf);
+ }
+
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ png_set_hIST(png_ptr, info_ptr, readbuf);
+}
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED)
+void /* PRIVATE */
+png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[9];
+ png_uint_32 res_x, res_y;
+ int unit_type;
+
+ png_debug(1, "in png_handle_pHYs\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before pHYs");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid pHYs after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs))
+ {
+ png_warning(png_ptr, "Duplicate pHYs chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 9)
+ {
+ png_warning(png_ptr, "Incorrect pHYs chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 9);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ res_x = png_get_uint_32(buf);
+ res_y = png_get_uint_32(buf + 4);
+ unit_type = buf[8];
+ png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type);
+}
+#endif
+
+#if defined(PNG_READ_oFFs_SUPPORTED)
+void /* PRIVATE */
+png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[9];
+ png_int_32 offset_x, offset_y;
+ int unit_type;
+
+ png_debug(1, "in png_handle_oFFs\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before oFFs");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid oFFs after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs))
+ {
+ png_warning(png_ptr, "Duplicate oFFs chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (length != 9)
+ {
+ png_warning(png_ptr, "Incorrect oFFs chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 9);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ offset_x = png_get_int_32(buf);
+ offset_y = png_get_int_32(buf + 4);
+ unit_type = buf[8];
+ png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type);
+}
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED)
+/* read the pCAL chunk (described in the PNG Extensions document) */
+void /* PRIVATE */
+png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_charp purpose;
+ png_int_32 X0, X1;
+ png_byte type, nparams;
+ png_charp buf, units, endptr;
+ png_charpp params;
+ png_size_t slength;
+ int i;
+
+ png_debug(1, "in png_handle_pCAL\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before pCAL");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid pCAL after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL))
+ {
+ png_warning(png_ptr, "Duplicate pCAL chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_debug1(2, "Allocating and reading pCAL chunk data (%lu bytes)\n",
+ length + 1);
+ purpose = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ if (purpose == NULL)
+ {
+ png_warning(png_ptr, "No memory for pCAL purpose.");
+ return;
+ }
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)purpose, slength);
+
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, purpose);
+ return;
+ }
+
+ purpose[slength] = 0x00; /* null terminate the last string */
+
+ png_debug(3, "Finding end of pCAL purpose string\n");
+ for (buf = purpose; *buf; buf++)
+ /* empty loop */ ;
+
+ endptr = purpose + slength;
+
+ /* We need to have at least 12 bytes after the purpose string
+ in order to get the parameter information. */
+ if (endptr <= buf + 12)
+ {
+ png_warning(png_ptr, "Invalid pCAL data");
+ png_free(png_ptr, purpose);
+ return;
+ }
+
+ png_debug(3, "Reading pCAL X0, X1, type, nparams, and units\n");
+ X0 = png_get_int_32((png_bytep)buf+1);
+ X1 = png_get_int_32((png_bytep)buf+5);
+ type = buf[9];
+ nparams = buf[10];
+ units = buf + 11;
+
+ png_debug(3, "Checking pCAL equation type and number of parameters\n");
+ /* Check that we have the right number of parameters for known
+ equation types. */
+ if ((type == PNG_EQUATION_LINEAR && nparams != 2) ||
+ (type == PNG_EQUATION_BASE_E && nparams != 3) ||
+ (type == PNG_EQUATION_ARBITRARY && nparams != 3) ||
+ (type == PNG_EQUATION_HYPERBOLIC && nparams != 4))
+ {
+ png_warning(png_ptr, "Invalid pCAL parameters for equation type");
+ png_free(png_ptr, purpose);
+ return;
+ }
+ else if (type >= PNG_EQUATION_LAST)
+ {
+ png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+ }
+
+ for (buf = units; *buf; buf++)
+ /* Empty loop to move past the units string. */ ;
+
+ png_debug(3, "Allocating pCAL parameters array\n");
+ params = (png_charpp)png_malloc_warn(png_ptr, (png_uint_32)(nparams
+ *png_sizeof(png_charp))) ;
+ if (params == NULL)
+ {
+ png_free(png_ptr, purpose);
+ png_warning(png_ptr, "No memory for pCAL params.");
+ return;
+ }
+
+ /* Get pointers to the start of each parameter string. */
+ for (i = 0; i < (int)nparams; i++)
+ {
+ buf++; /* Skip the null string terminator from previous parameter. */
+
+ png_debug1(3, "Reading pCAL parameter %d\n", i);
+ for (params[i] = buf; *buf != 0x00 && buf <= endptr; buf++)
+ /* Empty loop to move past each parameter string */ ;
+
+ /* Make sure we haven't run out of data yet */
+ if (buf > endptr)
+ {
+ png_warning(png_ptr, "Invalid pCAL data");
+ png_free(png_ptr, purpose);
+ png_free(png_ptr, params);
+ return;
+ }
+ }
+
+ png_set_pCAL(png_ptr, info_ptr, purpose, X0, X1, type, nparams,
+ units, params);
+
+ png_free(png_ptr, purpose);
+ png_free(png_ptr, params);
+}
+#endif
+
+#if defined(PNG_READ_sCAL_SUPPORTED)
+/* read the sCAL chunk */
+void /* PRIVATE */
+png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_charp buffer, ep;
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ double width, height;
+ png_charp vp;
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_charp swidth, sheight;
+#endif
+#endif
+ png_size_t slength;
+
+ png_debug(1, "in png_handle_sCAL\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before sCAL");
+ else if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+ png_warning(png_ptr, "Invalid sCAL after IDAT");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL))
+ {
+ png_warning(png_ptr, "Duplicate sCAL chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_debug1(2, "Allocating and reading sCAL chunk data (%lu bytes)\n",
+ length + 1);
+ buffer = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ if (buffer == NULL)
+ {
+ png_warning(png_ptr, "Out of memory while processing sCAL chunk");
+ return;
+ }
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)buffer, slength);
+
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, buffer);
+ return;
+ }
+
+ buffer[slength] = 0x00; /* null terminate the last string */
+
+ ep = buffer + 1; /* skip unit byte */
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ width = png_strtod(png_ptr, ep, &vp);
+ if (*vp)
+ {
+ png_warning(png_ptr, "malformed width string in sCAL chunk");
+ return;
+ }
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ swidth = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
+ if (swidth == NULL)
+ {
+ png_warning(png_ptr, "Out of memory while processing sCAL chunk width");
+ return;
+ }
+ png_memcpy(swidth, ep, (png_size_t)png_strlen(ep));
+#endif
+#endif
+
+ for (ep = buffer; *ep; ep++)
+ /* empty loop */ ;
+ ep++;
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ height = png_strtod(png_ptr, ep, &vp);
+ if (*vp)
+ {
+ png_warning(png_ptr, "malformed height string in sCAL chunk");
+ return;
+ }
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ sheight = (png_charp)png_malloc_warn(png_ptr, png_strlen(ep) + 1);
+ if (swidth == NULL)
+ {
+ png_warning(png_ptr, "Out of memory while processing sCAL chunk height");
+ return;
+ }
+ png_memcpy(sheight, ep, (png_size_t)png_strlen(ep));
+#endif
+#endif
+
+ if (buffer + slength < ep
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ || width <= 0. || height <= 0.
+#endif
+ )
+ {
+ png_warning(png_ptr, "Invalid sCAL data");
+ png_free(png_ptr, buffer);
+#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
+ png_free(png_ptr, swidth);
+ png_free(png_ptr, sheight);
+#endif
+ return;
+ }
+
+
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ png_set_sCAL(png_ptr, info_ptr, buffer[0], width, height);
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_set_sCAL_s(png_ptr, info_ptr, buffer[0], swidth, sheight);
+#endif
+#endif
+
+ png_free(png_ptr, buffer);
+#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED)
+ png_free(png_ptr, swidth);
+ png_free(png_ptr, sheight);
+#endif
+}
+#endif
+
+#if defined(PNG_READ_tIME_SUPPORTED)
+void /* PRIVATE */
+png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_byte buf[7];
+ png_time mod_time;
+
+ png_debug(1, "in png_handle_tIME\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Out of place tIME chunk");
+ else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME))
+ {
+ png_warning(png_ptr, "Duplicate tIME chunk");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+ if (length != 7)
+ {
+ png_warning(png_ptr, "Incorrect tIME chunk length");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+
+ png_crc_read(png_ptr, buf, 7);
+ if (png_crc_finish(png_ptr, 0))
+ return;
+
+ mod_time.second = buf[6];
+ mod_time.minute = buf[5];
+ mod_time.hour = buf[4];
+ mod_time.day = buf[3];
+ mod_time.month = buf[2];
+ mod_time.year = png_get_uint_16(buf);
+
+ png_set_tIME(png_ptr, info_ptr, &mod_time);
+}
+#endif
+
+#if defined(PNG_READ_tEXt_SUPPORTED)
+/* Note: this does not properly handle chunks that are > 64K under DOS */
+void /* PRIVATE */
+png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_textp text_ptr;
+ png_charp key;
+ png_charp text;
+ png_uint_32 skip = 0;
+ png_size_t slength;
+ int ret;
+
+ png_debug(1, "in png_handle_tEXt\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before tEXt");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "tEXt chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+
+ key = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ if (key == NULL)
+ {
+ png_warning(png_ptr, "No memory to process text chunk.");
+ return;
+ }
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)key, slength);
+
+ if (png_crc_finish(png_ptr, skip))
+ {
+ png_free(png_ptr, key);
+ return;
+ }
+
+ key[slength] = 0x00;
+
+ for (text = key; *text; text++)
+ /* empty loop to find end of key */ ;
+
+ if (text != key + slength)
+ text++;
+
+ text_ptr = (png_textp)png_malloc_warn(png_ptr,
+ (png_uint_32)png_sizeof(png_text));
+ if (text_ptr == NULL)
+ {
+ png_warning(png_ptr, "Not enough memory to process text chunk.");
+ png_free(png_ptr, key);
+ return;
+ }
+ text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr->key = key;
+#ifdef PNG_iTXt_SUPPORTED
+ text_ptr->lang = NULL;
+ text_ptr->lang_key = NULL;
+ text_ptr->itxt_length = 0;
+#endif
+ text_ptr->text = text;
+ text_ptr->text_length = png_strlen(text);
+
+ ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, key);
+ png_free(png_ptr, text_ptr);
+ if (ret)
+ png_warning(png_ptr, "Insufficient memory to process text chunk.");
+}
+#endif
+
+#if defined(PNG_READ_zTXt_SUPPORTED)
+/* note: this does not correctly handle chunks that are > 64K under DOS */
+void /* PRIVATE */
+png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_textp text_ptr;
+ png_charp chunkdata;
+ png_charp text;
+ int comp_type;
+ int ret;
+ png_size_t slength, prefix_len, data_len;
+
+ png_debug(1, "in png_handle_zTXt\n");
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before zTXt");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ /* We will no doubt have problems with chunks even half this size, but
+ there is no hard and fast rule to tell us where to stop. */
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr,"zTXt chunk too large to fit in memory");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#endif
+
+ chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ if (chunkdata == NULL)
+ {
+ png_warning(png_ptr,"Out of memory processing zTXt chunk.");
+ return;
+ }
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+
+ chunkdata[slength] = 0x00;
+
+ for (text = chunkdata; *text; text++)
+ /* empty loop */ ;
+
+ /* zTXt must have some text after the chunkdataword */
+ if (text == chunkdata + slength - 1)
+ {
+ png_warning(png_ptr, "Truncated zTXt chunk");
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+ else
+ {
+ comp_type = *(++text);
+ if (comp_type != PNG_TEXT_COMPRESSION_zTXt)
+ {
+ png_warning(png_ptr, "Unknown compression type in zTXt chunk");
+ comp_type = PNG_TEXT_COMPRESSION_zTXt;
+ }
+ text++; /* skip the compression_method byte */
+ }
+ prefix_len = text - chunkdata;
+
+ chunkdata = (png_charp)png_decompress_chunk(png_ptr, comp_type, chunkdata,
+ (png_size_t)length, prefix_len, &data_len);
+
+ text_ptr = (png_textp)png_malloc_warn(png_ptr,
+ (png_uint_32)png_sizeof(png_text));
+ if (text_ptr == NULL)
+ {
+ png_warning(png_ptr,"Not enough memory to process zTXt chunk.");
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+ text_ptr->compression = comp_type;
+ text_ptr->key = chunkdata;
+#ifdef PNG_iTXt_SUPPORTED
+ text_ptr->lang = NULL;
+ text_ptr->lang_key = NULL;
+ text_ptr->itxt_length = 0;
+#endif
+ text_ptr->text = chunkdata + prefix_len;
+ text_ptr->text_length = data_len;
+
+ ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+ png_free(png_ptr, chunkdata);
+ if (ret)
+ png_error(png_ptr, "Insufficient memory to store zTXt chunk.");
+}
+#endif
+
+#if defined(PNG_READ_iTXt_SUPPORTED)
+/* note: this does not correctly handle chunks that are > 64K under DOS */
+void /* PRIVATE */
+png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_textp text_ptr;
+ png_charp chunkdata;
+ png_charp key, lang, text, lang_key;
+ int comp_flag;
+ int comp_type = 0;
+ int ret;
+ png_size_t slength, prefix_len, data_len;
+
+ png_debug(1, "in png_handle_iTXt\n");
+
+ if (!(png_ptr->mode & PNG_HAVE_IHDR))
+ png_error(png_ptr, "Missing IHDR before iTXt");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+#ifdef PNG_MAX_MALLOC_64K
+ /* We will no doubt have problems with chunks even half this size, but
+ there is no hard and fast rule to tell us where to stop. */
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr,"iTXt chunk too large to fit in memory");
+ png_crc_finish(png_ptr, length);
+ return;
+ }
+#endif
+
+ chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1);
+ if (chunkdata == NULL)
+ {
+ png_warning(png_ptr, "No memory to process iTXt chunk.");
+ return;
+ }
+ slength = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)chunkdata, slength);
+ if (png_crc_finish(png_ptr, 0))
+ {
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+
+ chunkdata[slength] = 0x00;
+
+ for (lang = chunkdata; *lang; lang++)
+ /* empty loop */ ;
+ lang++; /* skip NUL separator */
+
+ /* iTXt must have a language tag (possibly empty), two compression bytes,
+ translated keyword (possibly empty), and possibly some text after the
+ keyword */
+
+ if (lang >= chunkdata + slength - 3)
+ {
+ png_warning(png_ptr, "Truncated iTXt chunk");
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+ else
+ {
+ comp_flag = *lang++;
+ comp_type = *lang++;
+ }
+
+ for (lang_key = lang; *lang_key; lang_key++)
+ /* empty loop */ ;
+ lang_key++; /* skip NUL separator */
+
+ for (text = lang_key; *text; text++)
+ /* empty loop */ ;
+ text++; /* skip NUL separator */
+ if (text >= chunkdata + slength)
+ {
+ png_warning(png_ptr, "Malformed iTXt chunk");
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+
+ prefix_len = text - chunkdata;
+
+ key=chunkdata;
+ if (comp_flag)
+ chunkdata = png_decompress_chunk(png_ptr, comp_type, chunkdata,
+ (size_t)length, prefix_len, &data_len);
+ else
+ data_len=png_strlen(chunkdata + prefix_len);
+ text_ptr = (png_textp)png_malloc_warn(png_ptr,
+ (png_uint_32)png_sizeof(png_text));
+ if (text_ptr == NULL)
+ {
+ png_warning(png_ptr,"Not enough memory to process iTXt chunk.");
+ png_free(png_ptr, chunkdata);
+ return;
+ }
+ text_ptr->compression = (int)comp_flag + 1;
+ text_ptr->lang_key = chunkdata+(lang_key-key);
+ text_ptr->lang = chunkdata+(lang-key);
+ text_ptr->itxt_length = data_len;
+ text_ptr->text_length = 0;
+ text_ptr->key = chunkdata;
+ text_ptr->text = chunkdata + prefix_len;
+
+ ret=png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
+
+ png_free(png_ptr, text_ptr);
+ png_free(png_ptr, chunkdata);
+ if (ret)
+ png_error(png_ptr, "Insufficient memory to store iTXt chunk.");
+}
+#endif
+
+/* This function is called when we haven't found a handler for a
+ chunk. If there isn't a problem with the chunk itself (ie bad
+ chunk name, CRC, or a critical chunk), the chunk is silently ignored
+ -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which
+ case it will be saved away to be written out later. */
+void /* PRIVATE */
+png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
+{
+ png_uint_32 skip = 0;
+
+ png_debug(1, "in png_handle_unknown\n");
+
+ if (png_ptr->mode & PNG_HAVE_IDAT)
+ {
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_CONST PNG_IDAT;
+#endif
+ if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* not an IDAT */
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ }
+
+ png_check_chunk_name(png_ptr, png_ptr->chunk_name);
+
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ {
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
+ PNG_HANDLE_CHUNK_ALWAYS
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+ && png_ptr->read_user_chunk_fn == NULL
+#endif
+ )
+#endif
+ png_chunk_error(png_ptr, "unknown critical chunk");
+ }
+
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+ if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) ||
+ (png_ptr->read_user_chunk_fn != NULL))
+ {
+#ifdef PNG_MAX_MALLOC_64K
+ if (length > (png_uint_32)65535L)
+ {
+ png_warning(png_ptr, "unknown chunk too large to fit in memory");
+ skip = length - (png_uint_32)65535L;
+ length = (png_uint_32)65535L;
+ }
+#endif
+ png_strncpy((png_charp)png_ptr->unknown_chunk.name,
+ (png_charp)png_ptr->chunk_name,
+ png_sizeof((png_charp)png_ptr->chunk_name));
+ png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length);
+ png_ptr->unknown_chunk.size = (png_size_t)length;
+ png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length);
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+ if(png_ptr->read_user_chunk_fn != NULL)
+ {
+ /* callback to user unknown chunk handler */
+ int ret;
+ ret = (*(png_ptr->read_user_chunk_fn))
+ (png_ptr, &png_ptr->unknown_chunk);
+ if (ret < 0)
+ png_chunk_error(png_ptr, "error in user chunk");
+ if (ret == 0)
+ {
+ if (!(png_ptr->chunk_name[0] & 0x20))
+ if(png_handle_as_unknown(png_ptr, png_ptr->chunk_name) !=
+ PNG_HANDLE_CHUNK_ALWAYS)
+ png_chunk_error(png_ptr, "unknown critical chunk");
+ png_set_unknown_chunks(png_ptr, info_ptr,
+ &png_ptr->unknown_chunk, 1);
+ }
+ }
+#else
+ png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
+#endif
+ png_free(png_ptr, png_ptr->unknown_chunk.data);
+ png_ptr->unknown_chunk.data = NULL;
+ }
+ else
+#endif
+ skip = length;
+
+ png_crc_finish(png_ptr, skip);
+
+#if !defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+ info_ptr = info_ptr; /* quiet compiler warnings about unused info_ptr */
+#endif
+}
+
+/* This function is called to verify that a chunk name is valid.
+ This function can't have the "critical chunk check" incorporated
+ into it, since in the future we will need to be able to call user
+ functions to handle unknown critical chunks after we check that
+ the chunk name itself is valid. */
+
+#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
+
+void /* PRIVATE */
+png_check_chunk_name(png_structp png_ptr, png_bytep chunk_name)
+{
+ png_debug(1, "in png_check_chunk_name\n");
+ if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) ||
+ isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3]))
+ {
+ png_chunk_error(png_ptr, "invalid chunk type");
+ }
+}
+
+/* Combines the row recently read in with the existing pixels in the
+ row. This routine takes care of alpha and transparency if requested.
+ This routine also handles the two methods of progressive display
+ of interlaced images, depending on the mask value.
+ The mask value describes which pixels are to be combined with
+ the row. The pattern always repeats every 8 pixels, so just 8
+ bits are needed. A one indicates the pixel is to be combined,
+ a zero indicates the pixel is to be skipped. This is in addition
+ to any alpha or transparency value associated with the pixel. If
+ you want all pixels to be combined, pass 0xff (255) in mask. */
+
+/* Optimized C version of utilities to read a PNG file
+ *
+ * Based on code contributed by Nirav Chhatrapati, Intel Corp., 1998.
+ * Interface to libpng contributed by Gilles Vollant, 1999.
+ * GNU C port by Greg Roelofs, 1999-2001.
+ *
+ */
+
+#if defined(PNG_OPTIMIZED_CODE_SUPPORTED)
+#if !defined(PNG_HAVE_MMX_COMBINE_ROW)
+
+/*===========================================================================*/
+/* */
+/* P N G _ C O M B I N E _ R O W */
+/* */
+/*===========================================================================*/
+
+
+#define BPP2 2
+#define BPP3 3 /* bytes per pixel (a.k.a. pixel_bytes) */
+#define BPP4 4
+#define BPP6 6 /* (defined only to help avoid cut-and-paste errors) */
+#define BPP8 8
+
+/* Combines the row recently read in with the previous row.
+ This routine takes care of alpha and transparency if requested.
+ This routine also handles the two methods of progressive display
+ of interlaced images, depending on the mask value.
+ The mask value describes which pixels are to be combined with
+ the row. The pattern always repeats every 8 pixels, so just 8
+ bits are needed. A one indicates the pixel is to be combined; a
+ zero indicates the pixel is to be skipped. This is in addition
+ to any alpha or transparency value associated with the pixel.
+ If you want all pixels to be combined, pass 0xff (255) in mask. */
+
+/* Use this routine for the x86 platform - it uses a faster MMX routine
+ if the machine supports MMX. */
+
+void /* PRIVATE */
+png_combine_row(png_structp png_ptr, png_bytep row, int mask)
+{
+
+#if defined(PNG_USE_LOCAL_ARRAYS)
+static PNG_CONST int FARDATA png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+static PNG_CONST int FARDATA png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+static PNG_CONST int FARDATA png_pass_width[7] = {8, 4, 4, 2, 2, 1, 1};
+#endif
+
+ png_debug(1, "in png_combine_row (pngrutil.c OPTIMIZED)\n");
+
+ if (mask == 0xff)
+ {
+ png_debug(2,"mask == 0xff: doing single png_memcpy()\n");
+ png_memcpy(row, png_ptr->row_buf + 1,
+ (png_size_t)PNG_ROWBYTES(png_ptr->row_info.pixel_depth,png_ptr->width));
+ }
+ else /* (png_combine_row() is never called with mask == 0) */
+ {
+ switch (png_ptr->row_info.pixel_depth)
+ {
+ /* most common case: combining 24-bit RGB */
+ case 24: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP3 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP3 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP3 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP3 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff*BPP3;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 24 bpp */
+
+ case 32: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP4 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP4 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP4 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP4 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff*BPP4;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ }
+
+ break;
+ } /* end 32 bpp */
+
+ case 8: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff /* *BPP1 */ ;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ }
+
+ break;
+ } /* end 8 bpp */
+
+ case 1: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_inc, s_start, s_end;
+ int m;
+ int shift;
+ png_uint_32 i;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+ else
+#endif
+ {
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ int value;
+
+ value = (*sp >> shift) & 0x1;
+ *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ } /* end 1 bpp */
+
+ case 2: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+ else
+#endif
+ {
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ } /* end 2 bpp */
+
+ case 4: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+ else
+#endif
+ {
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ } /* end 4 bpp */
+
+ case 16: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP2 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP2 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP2 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP2 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff*BPP2;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ } /* end of else (_mmx_supported) */
+
+ break;
+ } /* end 16 bpp */
+
+
+
+ case 48: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ {
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP6 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP6 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP6 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP6 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff*BPP6;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+ }
+ break;
+ } /* end 48 bpp */
+
+ case 64: /* png_ptr->row_info.pixel_depth */
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ register png_uint_32 i;
+ png_uint_32 initial_val = BPP8 * png_pass_start[png_ptr->pass];
+ /* png.c: png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; */
+ register int stride = BPP8 * png_pass_inc[png_ptr->pass];
+ /* png.c: png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; */
+ register int rep_bytes = BPP8 * png_pass_width[png_ptr->pass];
+ /* png.c: png_pass_width[] = {8, 4, 4, 2, 2, 1, 1}; */
+ png_uint_32 len = png_ptr->width &~7; /* reduce to mult of 8 */
+ int diff = (int) (png_ptr->width & 7); /* amount lost */
+ register png_uint_32 final_val = BPP8 * len; /* GRR bugfix */
+
+ srcptr = png_ptr->row_buf + 1 + initial_val;
+ dstptr = row + initial_val;
+
+ for (i = initial_val; i < final_val; i += stride)
+ {
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ if (diff) /* number of leftover pixels: 3 for pngtest */
+ {
+ final_val += diff*BPP8;
+ for (; i < final_val; i += stride)
+ {
+ if (rep_bytes > (int)(final_val-i))
+ rep_bytes = (int)(final_val-i);
+ png_memcpy(dstptr, srcptr, rep_bytes);
+ srcptr += stride;
+ dstptr += stride;
+ }
+ }
+
+ break;
+ } /* end 64 bpp */
+
+ default: /* png_ptr->row_info.pixel_depth != 1,2,4,8,16,24,32,48,64 */
+ {
+ /* this should never happen */
+ png_warning(png_ptr, "Invalid row_info.pixel_depth in pngrutil");
+ break;
+ }
+ } /* end switch (png_ptr->row_info.pixel_depth) */
+
+ } /* end if (non-trivial mask) */
+
+} /* end png_combine_row() */
+#endif /* PNG_HAVE_MMX_COMBINE_ROW */
+
+
+
+/*===========================================================================*/
+/* */
+/* P N G _ D O _ R E A D _ I N T E R L A C E */
+/* */
+/*===========================================================================*/
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+#if !defined(PNG_HAVE_MMX_READ_INTERLACE)
+
+/* png_do_read_interlace() is called after any 16-bit to 8-bit conversion
+ * has taken place. [GRR: what other steps come before and/or after?]
+ */
+
+void /* PRIVATE */
+png_do_read_interlace(png_structp png_ptr)
+{
+#if defined(PNG_USE_LOCAL_ARRAYS)
+static PNG_CONST int FARDATA png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+#endif
+ png_row_infop row_info = &(png_ptr->row_info);
+ png_bytep row = png_ptr->row_buf + 1;
+ int pass = png_ptr->pass;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ png_uint_32 transformations = png_ptr->transformations;
+#endif
+ png_debug(1,"in png_do_read_interlace (pngrutil.c OPTIMIZED)\n");
+
+ if (row != NULL && row_info != NULL)
+ {
+ png_uint_32 final_width;
+
+ final_width = row_info->width * png_pass_inc[pass];
+
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)((final_width - 1) >> 3);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)((row_info->width + 7) & 7);
+ dshift = (int)((final_width + 7) & 7);
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+ else
+#endif
+ {
+ sshift = 7 - (int)((row_info->width + 7) & 7);
+ dshift = 7 - (int)((final_width + 7) & 7);
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ v = (png_byte)((*sp >> sshift) & 0x1);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ case 2:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)((final_width - 1) >> 2);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
+ dshift = (png_size_t)(((final_width + 3) & 3) << 1);
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
+ dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0x3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ case 4:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)((final_width - 1) >> 1);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
+ dshift = (png_size_t)(((final_width + 1) & 1) << 2);
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
+ dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0xf);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ /*====================================================================*/
+
+ default: /* 8-bit or larger (this is where the routine is modified) */
+ {
+ png_bytep sptr, dp;
+ png_uint_32 i;
+ png_size_t pixel_bytes;
+ int width = (int)row_info->width;
+
+ pixel_bytes = (row_info->pixel_depth >> 3);
+
+ /* point sptr at the last pixel in the pre-expanded row: */
+ sptr = row + (width - 1) * pixel_bytes;
+
+ /* point dp at the last pixel position in the expanded row: */
+ dp = row + (final_width - 1) * pixel_bytes;
+
+ /* MMX not supported: use modified C code - takes advantage
+ * of inlining of png_memcpy for a constant */
+ /* GRR 19991007: does it? or should pixel_bytes in each
+ * block be replaced with immediate value (e.g., 1)? */
+ /* GRR 19991017: replaced with constants in each case */
+ {
+ if (pixel_bytes == 1)
+ {
+ for (i = width; i; i--)
+ {
+ int j;
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ --sptr;
+ }
+ }
+ else if (pixel_bytes == 3)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 3);
+ dp -= 3;
+ }
+ sptr -= 3;
+ }
+ }
+ else if (pixel_bytes == 2)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 2);
+ dp -= 2;
+ }
+ sptr -= 2;
+ }
+ }
+ else if (pixel_bytes == 4)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+#if defined(PNG_DEBUG) && defined(PNG_1_0_X)
+ if (dp < row || dp+3 > row+png_ptr->row_buf_size)
+ {
+ printf("dp out of bounds: row=%d, dp=%d, rp=%d\n",
+ row, dp, row+png_ptr->row_buf_size);
+ printf("row_buf=%d\n",png_ptr->row_buf_size);
+ }
+#endif
+ png_memcpy(dp, v, 4);
+ dp -= 4;
+ }
+ sptr -= 4;
+ }
+ }
+ else if (pixel_bytes == 6)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 6);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 6);
+ dp -= 6;
+ }
+ sptr -= 6;
+ }
+ }
+ else if (pixel_bytes == 8)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 8);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 8);
+ dp -= 8;
+ }
+ sptr -= 8;
+ }
+ }
+ else /* GRR: should never be reached */
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+
+ }
+ break;
+ }
+ } /* end switch (row_info->pixel_depth) */
+
+ row_info->width = final_width;
+
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width);
+ }
+
+} /* end png_do_read_interlace() */
+
+#endif /* PNG_HAVE_MMX_READ_INTERLACE */
+#endif /* PNG_READ_INTERLACING_SUPPORTED */
+
+
+
+#if !defined(PNG_HAVE_MMX_READ_FILTER_ROW)
+/*===========================================================================*/
+/* */
+/* P N G _ R E A D _ F I L T E R _ R O W */
+/* */
+/*===========================================================================*/
+
+
+/* Optimized png_read_filter_row routines */
+
+void /* PRIVATE */
+png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep
+ row, png_bytep prev_row, int filter)
+{
+#if defined(PNG_DEBUG)
+ char filnm[10];
+#endif
+
+
+#if defined(PNG_DEBUG)
+ png_debug(1, "in png_read_filter_row (pngrutil.c OPTIMIZED)\n");
+ switch (filter)
+ {
+ case 0:
+ png_snprintf(filnm, 10, "none");
+ break;
+
+ case 1:
+ png_snprintf(filnm, 10, "sub-%s",
+ "x86");
+ break;
+
+ case 2:
+ png_snprintf(filnm, 10, "up-%s",
+ "x86");
+ break;
+
+ case 3:
+ png_snprintf(filnm, 10, "avg-%s",
+ "x86");
+ break;
+
+ case 4:
+ png_snprintf(filnm, 10, "Paeth-%s",
+ "x86");
+ break;
+
+ default:
+ png_snprintf(filnm, 10, "unknown");
+ break;
+ }
+ png_debug2(0, "row_number=%5ld, %10s, ", png_ptr->row_number, filnm);
+ png_debug1(0, "row=0x%08lx, ", (unsigned long)row);
+ png_debug2(0, "pixdepth=%2d, bytes=%d, ", (int)row_info->pixel_depth,
+ (int)((row_info->pixel_depth + 7) >> 3));
+ png_debug1(0,"rowbytes=%8ld\n", row_info->rowbytes);
+#endif /* PNG_DEBUG */
+
+ switch (filter)
+ {
+ case PNG_FILTER_VALUE_NONE:
+ break;
+
+ case PNG_FILTER_VALUE_SUB:
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_bytep rp = row + bpp;
+ png_bytep lp = row;
+
+ for (i = bpp; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
+ rp++;
+ }
+ }
+ break;
+
+ case PNG_FILTER_VALUE_UP:
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+
+ for (i = 0; i < istop; ++i)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+ }
+ break;
+
+ case PNG_FILTER_VALUE_AVG:
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++) >> 1)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++ + *lp++) >> 1)) & 0xff);
+ rp++;
+ }
+ }
+ break;
+
+ case PNG_FILTER_VALUE_PAETH:
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_bytep cp = prev_row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++) /* use leftover rp,pp */
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ a = *lp++;
+ b = *pp++;
+ c = *cp++;
+
+ p = b - c;
+ pc = a - c;
+
+#if defined(PNG_USE_ABS)
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ /*
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+ */
+
+ p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
+
+ *rp = (png_byte)(((int)(*rp) + p) & 0xff);
+ rp++;
+ }
+ }
+ break;
+
+ default:
+ png_warning(png_ptr, "Ignoring bad row-filter type");
+ *row=0;
+ break;
+ }
+}
+
+#endif /* PNG_HAVE_MMX_READ_FILTER_ROW */
+#endif /* PNG_OPTIMIZED_CODE_SUPPORTED */
+
+#if !defined(PNG_USE_PNGGCCRD) && !defined(PNG_USE_PNGVCRD)
+#if !defined(PNG_OPTIMIZED_CODE_SUPPORTED)
+/* Use the unoptimized original C code. This might be removed from a future
+ * version of libpng if testing proves it to be worthless. */
+void /* PRIVATE */
+png_combine_row(png_structp png_ptr, png_bytep row, int mask)
+{
+ png_debug(1,"in png_combine_row NOT OPTIMIZED\n");
+ if (mask == 0xff)
+ {
+ png_memcpy(row, png_ptr->row_buf + 1,
+ PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width));
+ }
+ else
+ {
+ switch (png_ptr->row_info.pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ int s_inc, s_start, s_end;
+ int m = 0x80;
+ int shift;
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+ else
+#endif
+ {
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ int value;
+
+ value = (*sp >> shift) & 0x01;
+ *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ int s_start, s_end, s_inc;
+ int m = 0x80;
+ int shift;
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+ int value;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+ else
+#endif
+ {
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x03;
+ *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ int s_start, s_end, s_inc;
+ int m = 0x80;
+ int shift;
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+ int value;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+ else
+#endif
+ {
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ shift = s_start;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ default:
+ {
+ png_bytep sp = png_ptr->row_buf + 1;
+ png_bytep dp = row;
+ png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ png_uint_32 i;
+ png_uint_32 row_width = png_ptr->width;
+ png_byte m = 0x80;
+
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (m & mask)
+ {
+ png_memcpy(dp, sp, pixel_bytes);
+ }
+
+ sp += pixel_bytes;
+ dp += pixel_bytes;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+ }
+ }
+}
+
+#ifdef PNG_READ_INTERLACING_SUPPORTED
+/* OLD pre-1.0.9 interface:
+void png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
+ png_uint_32 transformations)
+ */
+void /* PRIVATE */
+png_do_read_interlace(png_structp png_ptr)
+{
+ png_row_infop row_info = &(png_ptr->row_info);
+ png_bytep row = png_ptr->row_buf + 1;
+ int pass = png_ptr->pass;
+ png_uint_32 transformations = png_ptr->transformations;
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+ /* offset to next interlace block */
+ PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+#endif
+
+ png_debug(1,"in png_do_read_interlace (pngrutil.c NOT OPTIMIZED)\n");
+ if (row != NULL && row_info != NULL)
+ {
+ png_uint_32 final_width;
+
+ final_width = row_info->width * png_pass_inc[pass];
+
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ png_bytep dp = row + (png_size_t)((final_width - 1) >> 3);
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ int jstop = png_pass_inc[pass];
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)((row_info->width + 7) & 0x07);
+ dshift = (int)((final_width + 7) & 0x07);
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+ else
+#endif
+ {
+ sshift = 7 - (int)((row_info->width + 7) & 0x07);
+ dshift = 7 - (int)((final_width + 7) & 0x07);
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ v = (png_byte)((*sp >> sshift) & 0x01);
+ for (j = 0; j < jstop; j++)
+ {
+ *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2);
+ png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2);
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ int jstop = png_pass_inc[pass];
+ png_uint_32 i;
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)(((row_info->width + 3) & 0x03) << 1);
+ dshift = (int)(((final_width + 3) & 0x03) << 1);
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+ else
+#endif
+ {
+ sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1);
+ dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1);
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0x03);
+ for (j = 0; j < jstop; j++)
+ {
+ *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ png_bytep dp = row + (png_size_t)((final_width - 1) >> 1);
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+ int jstop = png_pass_inc[pass];
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)(((row_info->width + 1) & 0x01) << 2);
+ dshift = (int)(((final_width + 1) & 0x01) << 2);
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ else
+#endif
+ {
+ sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2);
+ dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2);
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte v = (png_byte)((*sp >> sshift) & 0xf);
+ int j;
+
+ for (j = 0; j < jstop; j++)
+ {
+ *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+ default:
+ {
+ png_size_t pixel_bytes = (row_info->pixel_depth >> 3);
+ png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes;
+ png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes;
+
+ int jstop = png_pass_inc[pass];
+ png_uint_32 i;
+
+ for (i = 0; i < row_info->width; i++)
+ {
+ png_byte v[8];
+ int j;
+
+ png_memcpy(v, sp, pixel_bytes);
+ for (j = 0; j < jstop; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sp -= pixel_bytes;
+ }
+ break;
+ }
+ }
+ row_info->width = final_width;
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width);
+ }
+#if !defined(PNG_READ_PACKSWAP_SUPPORTED)
+ transformations = transformations; /* silence compiler warning */
+#endif
+}
+#endif /* PNG_READ_INTERLACING_SUPPORTED */
+
+void /* PRIVATE */
+png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row,
+ png_bytep prev_row, int filter)
+{
+ png_debug(1, "in png_read_filter_row (NOT OPTIMIZED)\n");
+ png_debug2(2,"row = %lu, filter = %d\n", png_ptr->row_number, filter);
+ switch (filter)
+ {
+ case PNG_FILTER_VALUE_NONE:
+ break;
+ case PNG_FILTER_VALUE_SUB:
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_bytep rp = row + bpp;
+ png_bytep lp = row;
+
+ for (i = bpp; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_UP:
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_AVG:
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++) / 2 )) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ (int)(*pp++ + *lp++) / 2 ) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ case PNG_FILTER_VALUE_PAETH:
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_bytep cp = prev_row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop=row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++) /* use leftover rp,pp */
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ a = *lp++;
+ b = *pp++;
+ c = *cp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ /*
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+ */
+
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+ *rp = (png_byte)(((int)(*rp) + p) & 0xff);
+ rp++;
+ }
+ break;
+ }
+ default:
+ png_warning(png_ptr, "Ignoring bad adaptive filter type");
+ *row=0;
+ break;
+ }
+}
+#endif /* !PNG_OPTIMIZED_CODE_SUPPORTED */
+#endif /* !PNG_USE_PNGGCCRD && !PNG_USE_PNGVCRD */
+
+void /* PRIVATE */
+png_read_finish_row(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* start of interlace block in the y direction */
+ PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* offset to next interlace block in the y direction */
+ PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+#endif
+
+ png_debug(1, "in png_read_finish_row\n");
+ png_ptr->row_number++;
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ png_memset_check(png_ptr, png_ptr->prev_row, 0,
+ png_ptr->rowbytes + 1);
+ do
+ {
+ png_ptr->pass++;
+ if (png_ptr->pass >= 7)
+ break;
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+
+ png_ptr->irowbytes = PNG_ROWBYTES(png_ptr->pixel_depth,
+ png_ptr->iwidth) + 1;
+
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+ if (!(png_ptr->num_rows))
+ continue;
+ }
+ else /* if (png_ptr->transformations & PNG_INTERLACE) */
+ break;
+ } while (png_ptr->iwidth == 0);
+
+ if (png_ptr->pass < 7)
+ return;
+ }
+
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED))
+ {
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_CONST PNG_IDAT;
+#endif
+ char extra;
+ int ret;
+
+ png_ptr->zstream.next_out = (Byte *)&extra;
+ png_ptr->zstream.avail_out = (uInt)1;
+ for(;;)
+ {
+ if (!(png_ptr->zstream.avail_in))
+ {
+ while (!png_ptr->idat_size)
+ {
+ png_byte chunk_length[4];
+
+ png_crc_finish(png_ptr, 0);
+
+ png_read_data(png_ptr, chunk_length, 4);
+ png_ptr->idat_size = png_get_uint_31(png_ptr, chunk_length);
+ png_reset_crc(png_ptr);
+ png_crc_read(png_ptr, png_ptr->chunk_name, 4);
+ if (png_memcmp(png_ptr->chunk_name, (png_bytep)png_IDAT, 4))
+ png_error(png_ptr, "Not enough image data");
+
+ }
+ png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_in = png_ptr->zbuf;
+ if (png_ptr->zbuf_size > png_ptr->idat_size)
+ png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size;
+ png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in);
+ png_ptr->idat_size -= png_ptr->zstream.avail_in;
+ }
+ ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
+ if (ret == Z_STREAM_END)
+ {
+ if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in ||
+ png_ptr->idat_size)
+ png_warning(png_ptr, "Extra compressed data");
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+ if (ret != Z_OK)
+ png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg :
+ "Decompression Error");
+
+ if (!(png_ptr->zstream.avail_out))
+ {
+ png_warning(png_ptr, "Extra compressed data.");
+ png_ptr->mode |= PNG_AFTER_IDAT;
+ png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
+ break;
+ }
+
+ }
+ png_ptr->zstream.avail_out = 0;
+ }
+
+ if (png_ptr->idat_size || png_ptr->zstream.avail_in)
+ png_warning(png_ptr, "Extra compression data");
+
+ inflateReset(&png_ptr->zstream);
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+}
+
+void /* PRIVATE */
+png_read_start_row(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* start of interlace block in the y direction */
+ PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* offset to next interlace block in the y direction */
+ PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+#endif
+
+ int max_pixel_depth;
+ png_uint_32 row_bytes;
+
+ png_debug(1, "in png_read_start_row\n");
+ png_ptr->zstream.avail_in = 0;
+ png_init_read_transformations(png_ptr);
+ if (png_ptr->interlaced)
+ {
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+ png_pass_ystart[0]) / png_pass_yinc[0];
+ else
+ png_ptr->num_rows = png_ptr->height;
+
+ png_ptr->iwidth = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+
+ row_bytes = PNG_ROWBYTES(png_ptr->pixel_depth,png_ptr->iwidth) + 1;
+
+ png_ptr->irowbytes = (png_size_t)row_bytes;
+ if((png_uint_32)png_ptr->irowbytes != row_bytes)
+ png_error(png_ptr, "Rowbytes overflow in png_read_start_row");
+ }
+ else
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->iwidth = png_ptr->width;
+ png_ptr->irowbytes = png_ptr->rowbytes + 1;
+ }
+ max_pixel_depth = png_ptr->pixel_depth;
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+ if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8)
+ max_pixel_depth = 8;
+#endif
+
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ if (png_ptr->transformations & PNG_EXPAND)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (png_ptr->num_trans)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 24;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (max_pixel_depth < 8)
+ max_pixel_depth = 8;
+ if (png_ptr->num_trans)
+ max_pixel_depth *= 2;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if (png_ptr->num_trans)
+ {
+ max_pixel_depth *= 4;
+ max_pixel_depth /= 3;
+ }
+ }
+ }
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & (PNG_FILLER))
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ max_pixel_depth = 32;
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ if (max_pixel_depth <= 8)
+ max_pixel_depth = 16;
+ else
+ max_pixel_depth = 32;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ if (max_pixel_depth <= 32)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 64;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+ if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+ {
+ if (
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+ (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) ||
+#endif
+#if defined(PNG_READ_FILLER_SUPPORTED)
+ (png_ptr->transformations & (PNG_FILLER)) ||
+#endif
+ png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ if (max_pixel_depth <= 16)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 64;
+ }
+ else
+ {
+ if (max_pixel_depth <= 8)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ max_pixel_depth = 32;
+ else
+ max_pixel_depth = 24;
+ }
+ else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ max_pixel_depth = 64;
+ else
+ max_pixel_depth = 48;
+ }
+ }
+#endif
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \
+defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+ if(png_ptr->transformations & PNG_USER_TRANSFORM)
+ {
+ int user_pixel_depth=png_ptr->user_transform_depth*
+ png_ptr->user_transform_channels;
+ if(user_pixel_depth > max_pixel_depth)
+ max_pixel_depth=user_pixel_depth;
+ }
+#endif
+
+ /* align the width on the next larger 8 pixels. Mainly used
+ for interlacing */
+ row_bytes = ((png_ptr->width + 7) & ~((png_uint_32)7));
+ /* calculate the maximum bytes needed, adding a byte and a pixel
+ for safety's sake */
+ row_bytes = PNG_ROWBYTES(max_pixel_depth,row_bytes) +
+ 1 + ((max_pixel_depth + 7) >> 3);
+#ifdef PNG_MAX_MALLOC_64K
+ if (row_bytes > (png_uint_32)65536L)
+ png_error(png_ptr, "This image requires a row greater than 64KB");
+#endif
+ png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes+64);
+ png_ptr->row_buf = png_ptr->big_row_buf+32;
+#if defined(PNG_DEBUG) && defined(PNG_USE_PNGGCCRD) && defined(PNG_1_0_X)
+ png_ptr->row_buf_size = row_bytes;
+#endif
+
+#ifdef PNG_MAX_MALLOC_64K
+ if ((png_uint_32)png_ptr->rowbytes + 1 > (png_uint_32)65536L)
+ png_error(png_ptr, "This image requires a row greater than 64KB");
+#endif
+ if ((png_uint_32)png_ptr->rowbytes > (png_uint_32)(PNG_SIZE_MAX - 1))
+ png_error(png_ptr, "Row has too many bytes to allocate in memory.");
+ png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)(
+ png_ptr->rowbytes + 1));
+
+ png_memset_check(png_ptr, png_ptr->prev_row, 0, png_ptr->rowbytes + 1);
+
+ png_debug1(3, "width = %lu,\n", png_ptr->width);
+ png_debug1(3, "height = %lu,\n", png_ptr->height);
+ png_debug1(3, "iwidth = %lu,\n", png_ptr->iwidth);
+ png_debug1(3, "num_rows = %lu\n", png_ptr->num_rows);
+ png_debug1(3, "rowbytes = %lu,\n", png_ptr->rowbytes);
+ png_debug1(3, "irowbytes = %lu,\n", png_ptr->irowbytes);
+
+ png_ptr->flags |= PNG_FLAG_ROW_INIT;
+}
+#endif /* PNG_READ_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngset.c b/distrib/libpng-1.2.19/pngset.c
new file mode 100644
index 0000000..8d1cbfc
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngset.c
@@ -0,0 +1,1284 @@
+
+/* pngset.c - storage of image information into info struct
+ *
+ * Last changed in libpng 1.2.17 May 15, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * The functions here are used during reads to store data from the file
+ * into the info struct, and during writes to store application data
+ * into the info struct for writing into the file. This abstracts the
+ * info struct and allows us to change the structure in the future.
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+
+#if defined(PNG_bKGD_SUPPORTED)
+void PNGAPI
+png_set_bKGD(png_structp png_ptr, png_infop info_ptr, png_color_16p background)
+{
+ png_debug1(1, "in %s storage function\n", "bKGD");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_memcpy(&(info_ptr->background), background, png_sizeof(png_color_16));
+ info_ptr->valid |= PNG_INFO_bKGD;
+}
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_cHRM(png_structp png_ptr, png_infop info_ptr,
+ double white_x, double white_y, double red_x, double red_y,
+ double green_x, double green_y, double blue_x, double blue_y)
+{
+ png_debug1(1, "in %s storage function\n", "cHRM");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if (white_x < 0.0 || white_y < 0.0 ||
+ red_x < 0.0 || red_y < 0.0 ||
+ green_x < 0.0 || green_y < 0.0 ||
+ blue_x < 0.0 || blue_y < 0.0)
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to set negative chromaticity value");
+ return;
+ }
+ if (white_x > 21474.83 || white_y > 21474.83 ||
+ red_x > 21474.83 || red_y > 21474.83 ||
+ green_x > 21474.83 || green_y > 21474.83 ||
+ blue_x > 21474.83 || blue_y > 21474.83)
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to set chromaticity value exceeding 21474.83");
+ return;
+ }
+
+ info_ptr->x_white = (float)white_x;
+ info_ptr->y_white = (float)white_y;
+ info_ptr->x_red = (float)red_x;
+ info_ptr->y_red = (float)red_y;
+ info_ptr->x_green = (float)green_x;
+ info_ptr->y_green = (float)green_y;
+ info_ptr->x_blue = (float)blue_x;
+ info_ptr->y_blue = (float)blue_y;
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ info_ptr->int_x_white = (png_fixed_point)(white_x*100000.+0.5);
+ info_ptr->int_y_white = (png_fixed_point)(white_y*100000.+0.5);
+ info_ptr->int_x_red = (png_fixed_point)( red_x*100000.+0.5);
+ info_ptr->int_y_red = (png_fixed_point)( red_y*100000.+0.5);
+ info_ptr->int_x_green = (png_fixed_point)(green_x*100000.+0.5);
+ info_ptr->int_y_green = (png_fixed_point)(green_y*100000.+0.5);
+ info_ptr->int_x_blue = (png_fixed_point)( blue_x*100000.+0.5);
+ info_ptr->int_y_blue = (png_fixed_point)( blue_y*100000.+0.5);
+#endif
+ info_ptr->valid |= PNG_INFO_cHRM;
+}
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+void PNGAPI
+png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr,
+ png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,
+ png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
+ png_fixed_point blue_x, png_fixed_point blue_y)
+{
+ png_debug1(1, "in %s storage function\n", "cHRM");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if (white_x < 0 || white_y < 0 ||
+ red_x < 0 || red_y < 0 ||
+ green_x < 0 || green_y < 0 ||
+ blue_x < 0 || blue_y < 0)
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to set negative chromaticity value");
+ return;
+ }
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ if (white_x > (double) PNG_UINT_31_MAX ||
+ white_y > (double) PNG_UINT_31_MAX ||
+ red_x > (double) PNG_UINT_31_MAX ||
+ red_y > (double) PNG_UINT_31_MAX ||
+ green_x > (double) PNG_UINT_31_MAX ||
+ green_y > (double) PNG_UINT_31_MAX ||
+ blue_x > (double) PNG_UINT_31_MAX ||
+ blue_y > (double) PNG_UINT_31_MAX)
+#else
+ if (white_x > (png_fixed_point) PNG_UINT_31_MAX/100000L ||
+ white_y > (png_fixed_point) PNG_UINT_31_MAX/100000L ||
+ red_x > (png_fixed_point) PNG_UINT_31_MAX/100000L ||
+ red_y > (png_fixed_point) PNG_UINT_31_MAX/100000L ||
+ green_x > (png_fixed_point) PNG_UINT_31_MAX/100000L ||
+ green_y > (png_fixed_point) PNG_UINT_31_MAX/100000L ||
+ blue_x > (png_fixed_point) PNG_UINT_31_MAX/100000L ||
+ blue_y > (png_fixed_point) PNG_UINT_31_MAX/100000L)
+#endif
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to set chromaticity value exceeding 21474.83");
+ return;
+ }
+ info_ptr->int_x_white = white_x;
+ info_ptr->int_y_white = white_y;
+ info_ptr->int_x_red = red_x;
+ info_ptr->int_y_red = red_y;
+ info_ptr->int_x_green = green_x;
+ info_ptr->int_y_green = green_y;
+ info_ptr->int_x_blue = blue_x;
+ info_ptr->int_y_blue = blue_y;
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ info_ptr->x_white = (float)(white_x/100000.);
+ info_ptr->y_white = (float)(white_y/100000.);
+ info_ptr->x_red = (float)( red_x/100000.);
+ info_ptr->y_red = (float)( red_y/100000.);
+ info_ptr->x_green = (float)(green_x/100000.);
+ info_ptr->y_green = (float)(green_y/100000.);
+ info_ptr->x_blue = (float)( blue_x/100000.);
+ info_ptr->y_blue = (float)( blue_y/100000.);
+#endif
+ info_ptr->valid |= PNG_INFO_cHRM;
+}
+#endif
+#endif
+
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma)
+{
+ double gamma;
+ png_debug1(1, "in %s storage function\n", "gAMA");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ /* Check for overflow */
+ if (file_gamma > 21474.83)
+ {
+ png_warning(png_ptr, "Limiting gamma to 21474.83");
+ gamma=21474.83;
+ }
+ else
+ gamma=file_gamma;
+ info_ptr->gamma = (float)gamma;
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ info_ptr->int_gamma = (int)(gamma*100000.+.5);
+#endif
+ info_ptr->valid |= PNG_INFO_gAMA;
+ if(gamma == 0.0)
+ png_warning(png_ptr, "Setting gamma=0");
+}
+#endif
+void PNGAPI
+png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point
+ int_gamma)
+{
+ png_fixed_point gamma;
+
+ png_debug1(1, "in %s storage function\n", "gAMA");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if (int_gamma > (png_fixed_point) PNG_UINT_31_MAX)
+ {
+ png_warning(png_ptr, "Limiting gamma to 21474.83");
+ gamma=PNG_UINT_31_MAX;
+ }
+ else
+ {
+ if (int_gamma < 0)
+ {
+ png_warning(png_ptr, "Setting negative gamma to zero");
+ gamma=0;
+ }
+ else
+ gamma=int_gamma;
+ }
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ info_ptr->gamma = (float)(gamma/100000.);
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ info_ptr->int_gamma = gamma;
+#endif
+ info_ptr->valid |= PNG_INFO_gAMA;
+ if(gamma == 0)
+ png_warning(png_ptr, "Setting gamma=0");
+}
+#endif
+
+#if defined(PNG_hIST_SUPPORTED)
+void PNGAPI
+png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_16p hist)
+{
+ int i;
+
+ png_debug1(1, "in %s storage function\n", "hIST");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+ if (info_ptr->num_palette <= 0 || info_ptr->num_palette
+ > PNG_MAX_PALETTE_LENGTH)
+ {
+ png_warning(png_ptr,
+ "Invalid palette size, hIST allocation skipped.");
+ return;
+ }
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
+#endif
+ /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in version
+ 1.2.1 */
+ png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr,
+ (png_uint_32)(PNG_MAX_PALETTE_LENGTH * png_sizeof (png_uint_16)));
+ if (png_ptr->hist == NULL)
+ {
+ png_warning(png_ptr, "Insufficient memory for hIST chunk data.");
+ return;
+ }
+
+ for (i = 0; i < info_ptr->num_palette; i++)
+ png_ptr->hist[i] = hist[i];
+ info_ptr->hist = png_ptr->hist;
+ info_ptr->valid |= PNG_INFO_hIST;
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_HIST;
+#else
+ png_ptr->flags |= PNG_FLAG_FREE_HIST;
+#endif
+}
+#endif
+
+void PNGAPI
+png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 width, png_uint_32 height, int bit_depth,
+ int color_type, int interlace_type, int compression_type,
+ int filter_type)
+{
+ png_debug1(1, "in %s storage function\n", "IHDR");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ /* check for width and height valid values */
+ if (width == 0 || height == 0)
+ png_error(png_ptr, "Image width or height is zero in IHDR");
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ if (width > png_ptr->user_width_max || height > png_ptr->user_height_max)
+ png_error(png_ptr, "image size exceeds user limits in IHDR");
+#else
+ if (width > PNG_USER_WIDTH_MAX || height > PNG_USER_HEIGHT_MAX)
+ png_error(png_ptr, "image size exceeds user limits in IHDR");
+#endif
+ if (width > PNG_UINT_31_MAX || height > PNG_UINT_31_MAX)
+ png_error(png_ptr, "Invalid image size in IHDR");
+ if ( width > (PNG_UINT_32_MAX
+ >> 3) /* 8-byte RGBA pixels */
+ - 64 /* bigrowbuf hack */
+ - 1 /* filter byte */
+ - 7*8 /* rounding of width to multiple of 8 pixels */
+ - 8) /* extra max_pixel_depth pad */
+ png_warning(png_ptr, "Width is too large for libpng to process pixels");
+
+ /* check other values */
+ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
+ bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth in IHDR");
+
+ if (color_type < 0 || color_type == 1 ||
+ color_type == 5 || color_type > 6)
+ png_error(png_ptr, "Invalid color type in IHDR");
+
+ if (((color_type == PNG_COLOR_TYPE_PALETTE) && bit_depth > 8) ||
+ ((color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_GRAY_ALPHA ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA) && bit_depth < 8))
+ png_error(png_ptr, "Invalid color type/bit depth combination in IHDR");
+
+ if (interlace_type >= PNG_INTERLACE_LAST)
+ png_error(png_ptr, "Unknown interlace method in IHDR");
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ png_error(png_ptr, "Unknown compression method in IHDR");
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ /* Accept filter_method 64 (intrapixel differencing) only if
+ * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
+ * 2. Libpng did not read a PNG signature (this filter_method is only
+ * used in PNG datastreams that are embedded in MNG datastreams) and
+ * 3. The application called png_permit_mng_features with a mask that
+ * included PNG_FLAG_MNG_FILTER_64 and
+ * 4. The filter_method is 64 and
+ * 5. The color_type is RGB or RGBA
+ */
+ if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&png_ptr->mng_features_permitted)
+ png_warning(png_ptr,"MNG features are not allowed in a PNG datastream");
+ if(filter_type != PNG_FILTER_TYPE_BASE)
+ {
+ if(!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
+ (filter_type == PNG_INTRAPIXEL_DIFFERENCING) &&
+ ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
+ (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA)))
+ png_error(png_ptr, "Unknown filter method in IHDR");
+ if(png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)
+ png_warning(png_ptr, "Invalid filter method in IHDR");
+ }
+#else
+ if(filter_type != PNG_FILTER_TYPE_BASE)
+ png_error(png_ptr, "Unknown filter method in IHDR");
+#endif
+
+ info_ptr->width = width;
+ info_ptr->height = height;
+ info_ptr->bit_depth = (png_byte)bit_depth;
+ info_ptr->color_type =(png_byte) color_type;
+ info_ptr->compression_type = (png_byte)compression_type;
+ info_ptr->filter_type = (png_byte)filter_type;
+ info_ptr->interlace_type = (png_byte)interlace_type;
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ info_ptr->channels = 1;
+ else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+ info_ptr->channels = 3;
+ else
+ info_ptr->channels = 1;
+ if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+ info_ptr->channels++;
+ info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
+
+ /* check for potential overflow */
+ if (width > (PNG_UINT_32_MAX
+ >> 3) /* 8-byte RGBA pixels */
+ - 64 /* bigrowbuf hack */
+ - 1 /* filter byte */
+ - 7*8 /* rounding of width to multiple of 8 pixels */
+ - 8) /* extra max_pixel_depth pad */
+ info_ptr->rowbytes = (png_size_t)0;
+ else
+ info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,width);
+}
+
+#if defined(PNG_oFFs_SUPPORTED)
+void PNGAPI
+png_set_oFFs(png_structp png_ptr, png_infop info_ptr,
+ png_int_32 offset_x, png_int_32 offset_y, int unit_type)
+{
+ png_debug1(1, "in %s storage function\n", "oFFs");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->x_offset = offset_x;
+ info_ptr->y_offset = offset_y;
+ info_ptr->offset_unit_type = (png_byte)unit_type;
+ info_ptr->valid |= PNG_INFO_oFFs;
+}
+#endif
+
+#if defined(PNG_pCAL_SUPPORTED)
+void PNGAPI
+png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
+ png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams,
+ png_charp units, png_charpp params)
+{
+ png_uint_32 length;
+ int i;
+
+ png_debug1(1, "in %s storage function\n", "pCAL");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ length = png_strlen(purpose) + 1;
+ png_debug1(3, "allocating purpose for info (%lu bytes)\n", length);
+ info_ptr->pcal_purpose = (png_charp)png_malloc_warn(png_ptr, length);
+ if (info_ptr->pcal_purpose == NULL)
+ {
+ png_warning(png_ptr, "Insufficient memory for pCAL purpose.");
+ return;
+ }
+ png_memcpy(info_ptr->pcal_purpose, purpose, (png_size_t)length);
+
+ png_debug(3, "storing X0, X1, type, and nparams in info\n");
+ info_ptr->pcal_X0 = X0;
+ info_ptr->pcal_X1 = X1;
+ info_ptr->pcal_type = (png_byte)type;
+ info_ptr->pcal_nparams = (png_byte)nparams;
+
+ length = png_strlen(units) + 1;
+ png_debug1(3, "allocating units for info (%lu bytes)\n", length);
+ info_ptr->pcal_units = (png_charp)png_malloc_warn(png_ptr, length);
+ if (info_ptr->pcal_units == NULL)
+ {
+ png_warning(png_ptr, "Insufficient memory for pCAL units.");
+ return;
+ }
+ png_memcpy(info_ptr->pcal_units, units, (png_size_t)length);
+
+ info_ptr->pcal_params = (png_charpp)png_malloc_warn(png_ptr,
+ (png_uint_32)((nparams + 1) * png_sizeof(png_charp)));
+ if (info_ptr->pcal_params == NULL)
+ {
+ png_warning(png_ptr, "Insufficient memory for pCAL params.");
+ return;
+ }
+
+ info_ptr->pcal_params[nparams] = NULL;
+
+ for (i = 0; i < nparams; i++)
+ {
+ length = png_strlen(params[i]) + 1;
+ png_debug2(3, "allocating parameter %d for info (%lu bytes)\n", i, length);
+ info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length);
+ if (info_ptr->pcal_params[i] == NULL)
+ {
+ png_warning(png_ptr, "Insufficient memory for pCAL parameter.");
+ return;
+ }
+ png_memcpy(info_ptr->pcal_params[i], params[i], (png_size_t)length);
+ }
+
+ info_ptr->valid |= PNG_INFO_pCAL;
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_PCAL;
+#endif
+}
+#endif
+
+#if defined(PNG_READ_sCAL_SUPPORTED) || defined(PNG_WRITE_sCAL_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+void PNGAPI
+png_set_sCAL(png_structp png_ptr, png_infop info_ptr,
+ int unit, double width, double height)
+{
+ png_debug1(1, "in %s storage function\n", "sCAL");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->scal_unit = (png_byte)unit;
+ info_ptr->scal_pixel_width = width;
+ info_ptr->scal_pixel_height = height;
+
+ info_ptr->valid |= PNG_INFO_sCAL;
+}
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+void PNGAPI
+png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr,
+ int unit, png_charp swidth, png_charp sheight)
+{
+ png_uint_32 length;
+
+ png_debug1(1, "in %s storage function\n", "sCAL");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->scal_unit = (png_byte)unit;
+
+ length = png_strlen(swidth) + 1;
+ png_debug1(3, "allocating unit for info (%d bytes)\n", length);
+ info_ptr->scal_s_width = (png_charp)png_malloc_warn(png_ptr, length);
+ if (info_ptr->scal_s_width == NULL)
+ {
+ png_warning(png_ptr,
+ "Memory allocation failed while processing sCAL.");
+ }
+ png_memcpy(info_ptr->scal_s_width, swidth, (png_size_t)length);
+
+ length = png_strlen(sheight) + 1;
+ png_debug1(3, "allocating unit for info (%d bytes)\n", length);
+ info_ptr->scal_s_height = (png_charp)png_malloc_warn(png_ptr, length);
+ if (info_ptr->scal_s_height == NULL)
+ {
+ png_free (png_ptr, info_ptr->scal_s_width);
+ png_warning(png_ptr,
+ "Memory allocation failed while processing sCAL.");
+ }
+ png_memcpy(info_ptr->scal_s_height, sheight, (png_size_t)length);
+
+ info_ptr->valid |= PNG_INFO_sCAL;
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_SCAL;
+#endif
+}
+#endif
+#endif
+#endif
+
+#if defined(PNG_pHYs_SUPPORTED)
+void PNGAPI
+png_set_pHYs(png_structp png_ptr, png_infop info_ptr,
+ png_uint_32 res_x, png_uint_32 res_y, int unit_type)
+{
+ png_debug1(1, "in %s storage function\n", "pHYs");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->x_pixels_per_unit = res_x;
+ info_ptr->y_pixels_per_unit = res_y;
+ info_ptr->phys_unit_type = (png_byte)unit_type;
+ info_ptr->valid |= PNG_INFO_pHYs;
+}
+#endif
+
+void PNGAPI
+png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
+ png_colorp palette, int num_palette)
+{
+
+ png_debug1(1, "in %s storage function\n", "PLTE");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH)
+ {
+ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ png_error(png_ptr, "Invalid palette length");
+ else
+ {
+ png_warning(png_ptr, "Invalid palette length");
+ return;
+ }
+ }
+
+ /*
+ * It may not actually be necessary to set png_ptr->palette here;
+ * we do it for backward compatibility with the way the png_handle_tRNS
+ * function used to do the allocation.
+ */
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
+#endif
+
+ /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
+ of num_palette entries,
+ in case of an invalid PNG file that has too-large sample values. */
+ png_ptr->palette = (png_colorp)png_malloc(png_ptr,
+ PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color));
+ png_memset(png_ptr->palette, 0, PNG_MAX_PALETTE_LENGTH *
+ png_sizeof(png_color));
+ png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof (png_color));
+ info_ptr->palette = png_ptr->palette;
+ info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
+
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_PLTE;
+#else
+ png_ptr->flags |= PNG_FLAG_FREE_PLTE;
+#endif
+
+ info_ptr->valid |= PNG_INFO_PLTE;
+}
+
+#if defined(PNG_sBIT_SUPPORTED)
+void PNGAPI
+png_set_sBIT(png_structp png_ptr, png_infop info_ptr,
+ png_color_8p sig_bit)
+{
+ png_debug1(1, "in %s storage function\n", "sBIT");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_memcpy(&(info_ptr->sig_bit), sig_bit, png_sizeof (png_color_8));
+ info_ptr->valid |= PNG_INFO_sBIT;
+}
+#endif
+
+#if defined(PNG_sRGB_SUPPORTED)
+void PNGAPI
+png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int intent)
+{
+ png_debug1(1, "in %s storage function\n", "sRGB");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ info_ptr->srgb_intent = (png_byte)intent;
+ info_ptr->valid |= PNG_INFO_sRGB;
+}
+
+void PNGAPI
+png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr,
+ int intent)
+{
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float file_gamma;
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_fixed_point int_file_gamma;
+#endif
+#endif
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ float white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y;
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_fixed_point int_white_x, int_white_y, int_red_x, int_red_y, int_green_x,
+ int_green_y, int_blue_x, int_blue_y;
+#endif
+#endif
+ png_debug1(1, "in %s storage function\n", "sRGB_gAMA_and_cHRM");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_set_sRGB(png_ptr, info_ptr, intent);
+
+#if defined(PNG_gAMA_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ file_gamma = (float).45455;
+ png_set_gAMA(png_ptr, info_ptr, file_gamma);
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ int_file_gamma = 45455L;
+ png_set_gAMA_fixed(png_ptr, info_ptr, int_file_gamma);
+#endif
+#endif
+
+#if defined(PNG_cHRM_SUPPORTED)
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ int_white_x = 31270L;
+ int_white_y = 32900L;
+ int_red_x = 64000L;
+ int_red_y = 33000L;
+ int_green_x = 30000L;
+ int_green_y = 60000L;
+ int_blue_x = 15000L;
+ int_blue_y = 6000L;
+
+ png_set_cHRM_fixed(png_ptr, info_ptr,
+ int_white_x, int_white_y, int_red_x, int_red_y, int_green_x, int_green_y,
+ int_blue_x, int_blue_y);
+#endif
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ white_x = (float).3127;
+ white_y = (float).3290;
+ red_x = (float).64;
+ red_y = (float).33;
+ green_x = (float).30;
+ green_y = (float).60;
+ blue_x = (float).15;
+ blue_y = (float).06;
+
+ png_set_cHRM(png_ptr, info_ptr,
+ white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y);
+#endif
+#endif
+}
+#endif
+
+
+#if defined(PNG_iCCP_SUPPORTED)
+void PNGAPI
+png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
+ png_charp name, int compression_type,
+ png_charp profile, png_uint_32 proflen)
+{
+ png_charp new_iccp_name;
+ png_charp new_iccp_profile;
+
+ png_debug1(1, "in %s storage function\n", "iCCP");
+ if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
+ return;
+
+ new_iccp_name = (png_charp)png_malloc_warn(png_ptr, png_strlen(name)+1);
+ if (new_iccp_name == NULL)
+ {
+ png_warning(png_ptr, "Insufficient memory to process iCCP chunk.");
+ return;
+ }
+ png_strncpy(new_iccp_name, name, png_sizeof(new_iccp_name));
+ new_iccp_profile = (png_charp)png_malloc_warn(png_ptr, proflen);
+ if (new_iccp_profile == NULL)
+ {
+ png_free (png_ptr, new_iccp_name);
+ png_warning(png_ptr, "Insufficient memory to process iCCP profile.");
+ return;
+ }
+ png_memcpy(new_iccp_profile, profile, (png_size_t)proflen);
+
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
+
+ info_ptr->iccp_proflen = proflen;
+ info_ptr->iccp_name = new_iccp_name;
+ info_ptr->iccp_profile = new_iccp_profile;
+ /* Compression is always zero but is here so the API and info structure
+ * does not have to change if we introduce multiple compression types */
+ info_ptr->iccp_compression = (png_byte)compression_type;
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_ICCP;
+#endif
+ info_ptr->valid |= PNG_INFO_iCCP;
+}
+#endif
+
+#if defined(PNG_TEXT_SUPPORTED)
+void PNGAPI
+png_set_text(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr,
+ int num_text)
+{
+ int ret;
+ ret=png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
+ if (ret)
+ png_error(png_ptr, "Insufficient memory to store text");
+}
+
+int /* PRIVATE */
+png_set_text_2(png_structp png_ptr, png_infop info_ptr, png_textp text_ptr,
+ int num_text)
+{
+ int i;
+
+ png_debug1(1, "in %s storage function\n", (png_ptr->chunk_name[0] == '\0' ?
+ "text" : (png_const_charp)png_ptr->chunk_name));
+
+ if (png_ptr == NULL || info_ptr == NULL || num_text == 0)
+ return(0);
+
+ /* Make sure we have enough space in the "text" array in info_struct
+ * to hold all of the incoming text_ptr objects.
+ */
+ if (info_ptr->num_text + num_text > info_ptr->max_text)
+ {
+ if (info_ptr->text != NULL)
+ {
+ png_textp old_text;
+ int old_max;
+
+ old_max = info_ptr->max_text;
+ info_ptr->max_text = info_ptr->num_text + num_text + 8;
+ old_text = info_ptr->text;
+ info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
+ (png_uint_32)(info_ptr->max_text * png_sizeof (png_text)));
+ if (info_ptr->text == NULL)
+ {
+ png_free(png_ptr, old_text);
+ return(1);
+ }
+ png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max *
+ png_sizeof(png_text)));
+ png_free(png_ptr, old_text);
+ }
+ else
+ {
+ info_ptr->max_text = num_text + 8;
+ info_ptr->num_text = 0;
+ info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
+ (png_uint_32)(info_ptr->max_text * png_sizeof (png_text)));
+ if (info_ptr->text == NULL)
+ return(1);
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_TEXT;
+#endif
+ }
+ png_debug1(3, "allocated %d entries for info_ptr->text\n",
+ info_ptr->max_text);
+ }
+ for (i = 0; i < num_text; i++)
+ {
+ png_size_t text_length,key_len;
+ png_size_t lang_len,lang_key_len;
+ png_textp textp = &(info_ptr->text[info_ptr->num_text]);
+
+ if (text_ptr[i].key == NULL)
+ continue;
+
+ key_len = png_strlen(text_ptr[i].key);
+
+ if(text_ptr[i].compression <= 0)
+ {
+ lang_len = 0;
+ lang_key_len = 0;
+ }
+ else
+#ifdef PNG_iTXt_SUPPORTED
+ {
+ /* set iTXt data */
+ if (text_ptr[i].lang != NULL)
+ lang_len = png_strlen(text_ptr[i].lang);
+ else
+ lang_len = 0;
+ if (text_ptr[i].lang_key != NULL)
+ lang_key_len = png_strlen(text_ptr[i].lang_key);
+ else
+ lang_key_len = 0;
+ }
+#else
+ {
+ png_warning(png_ptr, "iTXt chunk not supported.");
+ continue;
+ }
+#endif
+
+ if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
+ {
+ text_length = 0;
+#ifdef PNG_iTXt_SUPPORTED
+ if(text_ptr[i].compression > 0)
+ textp->compression = PNG_ITXT_COMPRESSION_NONE;
+ else
+#endif
+ textp->compression = PNG_TEXT_COMPRESSION_NONE;
+ }
+ else
+ {
+ text_length = png_strlen(text_ptr[i].text);
+ textp->compression = text_ptr[i].compression;
+ }
+
+ textp->key = (png_charp)png_malloc_warn(png_ptr,
+ (png_uint_32)(key_len + text_length + lang_len + lang_key_len + 4));
+ if (textp->key == NULL)
+ return(1);
+ png_debug2(2, "Allocated %lu bytes at %x in png_set_text\n",
+ (png_uint_32)(key_len + lang_len + lang_key_len + text_length + 4),
+ (int)textp->key);
+
+ png_memcpy(textp->key, text_ptr[i].key,
+ (png_size_t)(key_len));
+ *(textp->key+key_len) = '\0';
+#ifdef PNG_iTXt_SUPPORTED
+ if (text_ptr[i].compression > 0)
+ {
+ textp->lang=textp->key + key_len + 1;
+ png_memcpy(textp->lang, text_ptr[i].lang, lang_len);
+ *(textp->lang+lang_len) = '\0';
+ textp->lang_key=textp->lang + lang_len + 1;
+ png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
+ *(textp->lang_key+lang_key_len) = '\0';
+ textp->text=textp->lang_key + lang_key_len + 1;
+ }
+ else
+#endif
+ {
+#ifdef PNG_iTXt_SUPPORTED
+ textp->lang=NULL;
+ textp->lang_key=NULL;
+#endif
+ textp->text=textp->key + key_len + 1;
+ }
+ if(text_length)
+ png_memcpy(textp->text, text_ptr[i].text,
+ (png_size_t)(text_length));
+ *(textp->text+text_length) = '\0';
+
+#ifdef PNG_iTXt_SUPPORTED
+ if(textp->compression > 0)
+ {
+ textp->text_length = 0;
+ textp->itxt_length = text_length;
+ }
+ else
+#endif
+ {
+ textp->text_length = text_length;
+#ifdef PNG_iTXt_SUPPORTED
+ textp->itxt_length = 0;
+#endif
+ }
+ info_ptr->num_text++;
+ png_debug1(3, "transferred text chunk %d\n", info_ptr->num_text);
+ }
+ return(0);
+}
+#endif
+
+#if defined(PNG_tIME_SUPPORTED)
+void PNGAPI
+png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_timep mod_time)
+{
+ png_debug1(1, "in %s storage function\n", "tIME");
+ if (png_ptr == NULL || info_ptr == NULL ||
+ (png_ptr->mode & PNG_WROTE_tIME))
+ return;
+
+ png_memcpy(&(info_ptr->mod_time), mod_time, png_sizeof (png_time));
+ info_ptr->valid |= PNG_INFO_tIME;
+}
+#endif
+
+#if defined(PNG_tRNS_SUPPORTED)
+void PNGAPI
+png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
+ png_bytep trans, int num_trans, png_color_16p trans_values)
+{
+ png_debug1(1, "in %s storage function\n", "tRNS");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if (trans != NULL)
+ {
+ /*
+ * It may not actually be necessary to set png_ptr->trans here;
+ * we do it for backward compatibility with the way the png_handle_tRNS
+ * function used to do the allocation.
+ */
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
+#endif
+ /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
+ png_ptr->trans = info_ptr->trans = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)PNG_MAX_PALETTE_LENGTH);
+ if (num_trans <= PNG_MAX_PALETTE_LENGTH)
+ png_memcpy(info_ptr->trans, trans, (png_size_t)num_trans);
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_TRNS;
+#else
+ png_ptr->flags |= PNG_FLAG_FREE_TRNS;
+#endif
+ }
+
+ if (trans_values != NULL)
+ {
+ png_memcpy(&(info_ptr->trans_values), trans_values,
+ png_sizeof(png_color_16));
+ if (num_trans == 0)
+ num_trans = 1;
+ }
+ info_ptr->num_trans = (png_uint_16)num_trans;
+ info_ptr->valid |= PNG_INFO_tRNS;
+}
+#endif
+
+#if defined(PNG_sPLT_SUPPORTED)
+void PNGAPI
+png_set_sPLT(png_structp png_ptr,
+ png_infop info_ptr, png_sPLT_tp entries, int nentries)
+{
+ png_sPLT_tp np;
+ int i;
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ np = (png_sPLT_tp)png_malloc_warn(png_ptr,
+ (info_ptr->splt_palettes_num + nentries) * png_sizeof(png_sPLT_t));
+ if (np == NULL)
+ {
+ png_warning(png_ptr, "No memory for sPLT palettes.");
+ return;
+ }
+
+ png_memcpy(np, info_ptr->splt_palettes,
+ info_ptr->splt_palettes_num * png_sizeof(png_sPLT_t));
+ png_free(png_ptr, info_ptr->splt_palettes);
+ info_ptr->splt_palettes=NULL;
+
+ for (i = 0; i < nentries; i++)
+ {
+ png_sPLT_tp to = np + info_ptr->splt_palettes_num + i;
+ png_sPLT_tp from = entries + i;
+
+ to->name = (png_charp)png_malloc_warn(png_ptr,
+ png_strlen(from->name) + 1);
+ if (to->name == NULL)
+ {
+ png_warning(png_ptr,
+ "Out of memory while processing sPLT chunk");
+ }
+ /* TODO: use png_malloc_warn */
+ png_strncpy(to->name, from->name, png_strlen(from->name));
+ to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr,
+ from->nentries * png_sizeof(png_sPLT_entry));
+ /* TODO: use png_malloc_warn */
+ png_memcpy(to->entries, from->entries,
+ from->nentries * png_sizeof(png_sPLT_entry));
+ if (to->entries == NULL)
+ {
+ png_warning(png_ptr,
+ "Out of memory while processing sPLT chunk");
+ png_free(png_ptr,to->name);
+ to->name = NULL;
+ }
+ to->nentries = from->nentries;
+ to->depth = from->depth;
+ }
+
+ info_ptr->splt_palettes = np;
+ info_ptr->splt_palettes_num += nentries;
+ info_ptr->valid |= PNG_INFO_sPLT;
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_SPLT;
+#endif
+}
+#endif /* PNG_sPLT_SUPPORTED */
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+void PNGAPI
+png_set_unknown_chunks(png_structp png_ptr,
+ png_infop info_ptr, png_unknown_chunkp unknowns, int num_unknowns)
+{
+ png_unknown_chunkp np;
+ int i;
+
+ if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0)
+ return;
+
+ np = (png_unknown_chunkp)png_malloc_warn(png_ptr,
+ (info_ptr->unknown_chunks_num + num_unknowns) *
+ png_sizeof(png_unknown_chunk));
+ if (np == NULL)
+ {
+ png_warning(png_ptr,
+ "Out of memory while processing unknown chunk.");
+ return;
+ }
+
+ png_memcpy(np, info_ptr->unknown_chunks,
+ info_ptr->unknown_chunks_num * png_sizeof(png_unknown_chunk));
+ png_free(png_ptr, info_ptr->unknown_chunks);
+ info_ptr->unknown_chunks=NULL;
+
+ for (i = 0; i < num_unknowns; i++)
+ {
+ png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i;
+ png_unknown_chunkp from = unknowns + i;
+
+ png_strncpy((png_charp)to->name, (png_charp)from->name, 5);
+ to->data = (png_bytep)png_malloc_warn(png_ptr, from->size);
+ if (to->data == NULL)
+ {
+ png_warning(png_ptr,
+ "Out of memory while processing unknown chunk.");
+ }
+ else
+ {
+ png_memcpy(to->data, from->data, from->size);
+ to->size = from->size;
+
+ /* note our location in the read or write sequence */
+ to->location = (png_byte)(png_ptr->mode & 0xff);
+ }
+ }
+
+ info_ptr->unknown_chunks = np;
+ info_ptr->unknown_chunks_num += num_unknowns;
+#ifdef PNG_FREE_ME_SUPPORTED
+ info_ptr->free_me |= PNG_FREE_UNKN;
+#endif
+}
+void PNGAPI
+png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr,
+ int chunk, int location)
+{
+ if(png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk <
+ (int)info_ptr->unknown_chunks_num)
+ info_ptr->unknown_chunks[chunk].location = (png_byte)location;
+}
+#endif
+
+#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
+#if defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
+ defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
+void PNGAPI
+png_permit_empty_plte (png_structp png_ptr, int empty_plte_permitted)
+{
+ /* This function is deprecated in favor of png_permit_mng_features()
+ and will be removed from libpng-1.3.0 */
+ png_debug(1, "in png_permit_empty_plte, DEPRECATED.\n");
+ if (png_ptr == NULL)
+ return;
+ png_ptr->mng_features_permitted = (png_byte)
+ ((png_ptr->mng_features_permitted & (~(PNG_FLAG_MNG_EMPTY_PLTE))) |
+ ((empty_plte_permitted & PNG_FLAG_MNG_EMPTY_PLTE)));
+}
+#endif
+#endif
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+png_uint_32 PNGAPI
+png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features)
+{
+ png_debug(1, "in png_permit_mng_features\n");
+ if (png_ptr == NULL)
+ return (png_uint_32)0;
+ png_ptr->mng_features_permitted =
+ (png_byte)(mng_features & PNG_ALL_MNG_FEATURES);
+ return (png_uint_32)png_ptr->mng_features_permitted;
+}
+#endif
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+void PNGAPI
+png_set_keep_unknown_chunks(png_structp png_ptr, int keep, png_bytep
+ chunk_list, int num_chunks)
+{
+ png_bytep new_list, p;
+ int i, old_num_chunks;
+ if (png_ptr == NULL)
+ return;
+ if (num_chunks == 0)
+ {
+ if(keep == PNG_HANDLE_CHUNK_ALWAYS || keep == PNG_HANDLE_CHUNK_IF_SAFE)
+ png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS;
+ else
+ png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS;
+
+ if(keep == PNG_HANDLE_CHUNK_ALWAYS)
+ png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS;
+ else
+ png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS;
+ return;
+ }
+ if (chunk_list == NULL)
+ return;
+ old_num_chunks=png_ptr->num_chunk_list;
+ new_list=(png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(5*(num_chunks+old_num_chunks)));
+ if(png_ptr->chunk_list != NULL)
+ {
+ png_memcpy(new_list, png_ptr->chunk_list,
+ (png_size_t)(5*old_num_chunks));
+ png_free(png_ptr, png_ptr->chunk_list);
+ png_ptr->chunk_list=NULL;
+ }
+ png_memcpy(new_list+5*old_num_chunks, chunk_list,
+ (png_size_t)(5*num_chunks));
+ for (p=new_list+5*old_num_chunks+4, i=0; i<num_chunks; i++, p+=5)
+ *p=(png_byte)keep;
+ png_ptr->num_chunk_list=old_num_chunks+num_chunks;
+ png_ptr->chunk_list=new_list;
+#ifdef PNG_FREE_ME_SUPPORTED
+ png_ptr->free_me |= PNG_FREE_LIST;
+#endif
+}
+#endif
+
+#if defined(PNG_READ_USER_CHUNKS_SUPPORTED)
+void PNGAPI
+png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr,
+ png_user_chunk_ptr read_user_chunk_fn)
+{
+ png_debug(1, "in png_set_read_user_chunk_fn\n");
+ if (png_ptr == NULL)
+ return;
+ png_ptr->read_user_chunk_fn = read_user_chunk_fn;
+ png_ptr->user_chunk_ptr = user_chunk_ptr;
+}
+#endif
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+void PNGAPI
+png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers)
+{
+ png_debug1(1, "in %s storage function\n", "rows");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ if(info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers))
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
+ info_ptr->row_pointers = row_pointers;
+ if(row_pointers)
+ info_ptr->valid |= PNG_INFO_IDAT;
+}
+#endif
+
+#ifdef PNG_WRITE_SUPPORTED
+void PNGAPI
+png_set_compression_buffer_size(png_structp png_ptr, png_uint_32 size)
+{
+ if (png_ptr == NULL)
+ return;
+ if(png_ptr->zbuf)
+ png_free(png_ptr, png_ptr->zbuf);
+ png_ptr->zbuf_size = (png_size_t)size;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+}
+#endif
+
+void PNGAPI
+png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask)
+{
+ if (png_ptr && info_ptr)
+ info_ptr->valid &= ~(mask);
+}
+
+
+#ifndef PNG_1_0_X
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+/* this function was added to libpng 1.2.0 and should always exist by default */
+void PNGAPI
+png_set_asm_flags (png_structp png_ptr, png_uint_32 asm_flags)
+{
+#ifdef PNG_MMX_CODE_SUPPORTED
+ png_uint_32 settable_asm_flags;
+ png_uint_32 settable_mmx_flags;
+#endif
+ if (png_ptr == NULL)
+ return;
+#ifdef PNG_MMX_CODE_SUPPORTED
+
+ settable_mmx_flags =
+#ifdef PNG_HAVE_MMX_COMBINE_ROW
+ PNG_ASM_FLAG_MMX_READ_COMBINE_ROW |
+#endif
+#ifdef PNG_HAVE_MMX_READ_INTERLACE
+ PNG_ASM_FLAG_MMX_READ_INTERLACE |
+#endif
+#ifdef PNG_HAVE_MMX_READ_FILTER_ROW
+ PNG_ASM_FLAG_MMX_READ_FILTER_SUB |
+ PNG_ASM_FLAG_MMX_READ_FILTER_UP |
+ PNG_ASM_FLAG_MMX_READ_FILTER_AVG |
+ PNG_ASM_FLAG_MMX_READ_FILTER_PAETH |
+#endif
+ 0;
+
+ /* could be some non-MMX ones in the future, but not currently: */
+ settable_asm_flags = settable_mmx_flags;
+
+ if (!(png_ptr->asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_COMPILED) ||
+ !(png_ptr->asm_flags & PNG_ASM_FLAG_MMX_SUPPORT_IN_CPU))
+ {
+ /* clear all MMX flags if MMX isn't supported */
+ settable_asm_flags &= ~settable_mmx_flags;
+ png_ptr->asm_flags &= ~settable_mmx_flags;
+ }
+
+ /* we're replacing the settable bits with those passed in by the user,
+ * so first zero them out of the master copy, then bitwise-OR in the
+ * allowed subset that was requested */
+
+ png_ptr->asm_flags &= ~settable_asm_flags; /* zero them */
+ png_ptr->asm_flags |= (asm_flags & settable_asm_flags); /* set them */
+#endif /* ?PNG_MMX_CODE_SUPPORTED */
+}
+
+/* this function was added to libpng 1.2.0 */
+void PNGAPI
+png_set_mmx_thresholds (png_structp png_ptr,
+ png_byte mmx_bitdepth_threshold,
+ png_uint_32 mmx_rowbytes_threshold)
+{
+ if (png_ptr == NULL)
+ return;
+#ifdef PNG_MMX_CODE_SUPPORTED
+ png_ptr->mmx_bitdepth_threshold = mmx_bitdepth_threshold;
+ png_ptr->mmx_rowbytes_threshold = mmx_rowbytes_threshold;
+#endif /* ?PNG_MMX_CODE_SUPPORTED */
+}
+#endif /* ?PNG_ASSEMBLER_CODE_SUPPORTED */
+
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+/* this function was added to libpng 1.2.6 */
+void PNGAPI
+png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max,
+ png_uint_32 user_height_max)
+{
+ /* Images with dimensions larger than these limits will be
+ * rejected by png_set_IHDR(). To accept any PNG datastream
+ * regardless of dimensions, set both limits to 0x7ffffffL.
+ */
+ if(png_ptr == NULL) return;
+ png_ptr->user_width_max = user_width_max;
+ png_ptr->user_height_max = user_height_max;
+}
+#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */
+
+#endif /* ?PNG_1_0_X */
+#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngtrans.c b/distrib/libpng-1.2.19/pngtrans.c
new file mode 100644
index 0000000..1640095
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngtrans.c
@@ -0,0 +1,662 @@
+
+/* pngtrans.c - transforms the data in a row (used by both readers and writers)
+ *
+ * Last changed in libpng 1.2.17 May 15, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* turn on BGR-to-RGB mapping */
+void PNGAPI
+png_set_bgr(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_bgr\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= PNG_BGR;
+}
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* turn on 16 bit byte swapping */
+void PNGAPI
+png_set_swap(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_swap\n");
+ if(png_ptr == NULL) return;
+ if (png_ptr->bit_depth == 16)
+ png_ptr->transformations |= PNG_SWAP_BYTES;
+}
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED)
+/* turn on pixel packing */
+void PNGAPI
+png_set_packing(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_packing\n");
+ if(png_ptr == NULL) return;
+ if (png_ptr->bit_depth < 8)
+ {
+ png_ptr->transformations |= PNG_PACK;
+ png_ptr->usr_bit_depth = 8;
+ }
+}
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+/* turn on packed pixel swapping */
+void PNGAPI
+png_set_packswap(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_packswap\n");
+ if(png_ptr == NULL) return;
+ if (png_ptr->bit_depth < 8)
+ png_ptr->transformations |= PNG_PACKSWAP;
+}
+#endif
+
+#if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED)
+void PNGAPI
+png_set_shift(png_structp png_ptr, png_color_8p true_bits)
+{
+ png_debug(1, "in png_set_shift\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= PNG_SHIFT;
+ png_ptr->shift = *true_bits;
+}
+#endif
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED) || \
+ defined(PNG_WRITE_INTERLACING_SUPPORTED)
+int PNGAPI
+png_set_interlace_handling(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_interlace handling\n");
+ if (png_ptr && png_ptr->interlaced)
+ {
+ png_ptr->transformations |= PNG_INTERLACE;
+ return (7);
+ }
+
+ return (1);
+}
+#endif
+
+#if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED)
+/* Add a filler byte on read, or remove a filler or alpha byte on write.
+ * The filler type has changed in v0.95 to allow future 2-byte fillers
+ * for 48-bit input data, as well as to avoid problems with some compilers
+ * that don't like bytes as parameters.
+ */
+void PNGAPI
+png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc)
+{
+ png_debug(1, "in png_set_filler\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= PNG_FILLER;
+ png_ptr->filler = (png_byte)filler;
+ if (filler_loc == PNG_FILLER_AFTER)
+ png_ptr->flags |= PNG_FLAG_FILLER_AFTER;
+ else
+ png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER;
+
+ /* This should probably go in the "do_read_filler" routine.
+ * I attempted to do that in libpng-1.0.1a but that caused problems
+ * so I restored it in libpng-1.0.2a
+ */
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_ptr->usr_channels = 4;
+ }
+
+ /* Also I added this in libpng-1.0.2a (what happens when we expand
+ * a less-than-8-bit grayscale to GA? */
+
+ if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8)
+ {
+ png_ptr->usr_channels = 2;
+ }
+}
+
+#if !defined(PNG_1_0_X)
+/* Added to libpng-1.2.7 */
+void PNGAPI
+png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc)
+{
+ png_debug(1, "in png_set_add_alpha\n");
+ if(png_ptr == NULL) return;
+ png_set_filler(png_ptr, filler, filler_loc);
+ png_ptr->transformations |= PNG_ADD_ALPHA;
+}
+#endif
+
+#endif
+
+#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+void PNGAPI
+png_set_swap_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_swap_alpha\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= PNG_SWAP_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \
+ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+void PNGAPI
+png_set_invert_alpha(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_invert_alpha\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= PNG_INVERT_ALPHA;
+}
+#endif
+
+#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED)
+void PNGAPI
+png_set_invert_mono(png_structp png_ptr)
+{
+ png_debug(1, "in png_set_invert_mono\n");
+ if(png_ptr == NULL) return;
+ png_ptr->transformations |= PNG_INVERT_MONO;
+}
+
+/* invert monochrome grayscale data */
+void /* PRIVATE */
+png_do_invert(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_invert\n");
+ /* This test removed from libpng version 1.0.13 and 1.2.0:
+ * if (row_info->bit_depth == 1 &&
+ */
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row == NULL || row_info == NULL)
+ return;
+#endif
+ if (row_info->color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ png_bytep rp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(~(*rp));
+ rp++;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
+ row_info->bit_depth == 8)
+ {
+ png_bytep rp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+
+ for (i = 0; i < istop; i+=2)
+ {
+ *rp = (png_byte)(~(*rp));
+ rp+=2;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
+ row_info->bit_depth == 16)
+ {
+ png_bytep rp = row;
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+
+ for (i = 0; i < istop; i+=4)
+ {
+ *rp = (png_byte)(~(*rp));
+ *(rp+1) = (png_byte)(~(*(rp+1)));
+ rp+=4;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED)
+/* swaps byte order on 16 bit depth images */
+void /* PRIVATE */
+png_do_swap(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_swap\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->bit_depth == 16)
+ {
+ png_bytep rp = row;
+ png_uint_32 i;
+ png_uint_32 istop= row_info->width * row_info->channels;
+
+ for (i = 0; i < istop; i++, rp += 2)
+ {
+ png_byte t = *rp;
+ *rp = *(rp + 1);
+ *(rp + 1) = t;
+ }
+ }
+}
+#endif
+
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+static PNG_CONST png_byte onebppswaptable[256] = {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
+};
+
+static PNG_CONST png_byte twobppswaptable[256] = {
+ 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0,
+ 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0,
+ 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4,
+ 0x24, 0x64, 0xA4, 0xE4, 0x34, 0x74, 0xB4, 0xF4,
+ 0x08, 0x48, 0x88, 0xC8, 0x18, 0x58, 0x98, 0xD8,
+ 0x28, 0x68, 0xA8, 0xE8, 0x38, 0x78, 0xB8, 0xF8,
+ 0x0C, 0x4C, 0x8C, 0xCC, 0x1C, 0x5C, 0x9C, 0xDC,
+ 0x2C, 0x6C, 0xAC, 0xEC, 0x3C, 0x7C, 0xBC, 0xFC,
+ 0x01, 0x41, 0x81, 0xC1, 0x11, 0x51, 0x91, 0xD1,
+ 0x21, 0x61, 0xA1, 0xE1, 0x31, 0x71, 0xB1, 0xF1,
+ 0x05, 0x45, 0x85, 0xC5, 0x15, 0x55, 0x95, 0xD5,
+ 0x25, 0x65, 0xA5, 0xE5, 0x35, 0x75, 0xB5, 0xF5,
+ 0x09, 0x49, 0x89, 0xC9, 0x19, 0x59, 0x99, 0xD9,
+ 0x29, 0x69, 0xA9, 0xE9, 0x39, 0x79, 0xB9, 0xF9,
+ 0x0D, 0x4D, 0x8D, 0xCD, 0x1D, 0x5D, 0x9D, 0xDD,
+ 0x2D, 0x6D, 0xAD, 0xED, 0x3D, 0x7D, 0xBD, 0xFD,
+ 0x02, 0x42, 0x82, 0xC2, 0x12, 0x52, 0x92, 0xD2,
+ 0x22, 0x62, 0xA2, 0xE2, 0x32, 0x72, 0xB2, 0xF2,
+ 0x06, 0x46, 0x86, 0xC6, 0x16, 0x56, 0x96, 0xD6,
+ 0x26, 0x66, 0xA6, 0xE6, 0x36, 0x76, 0xB6, 0xF6,
+ 0x0A, 0x4A, 0x8A, 0xCA, 0x1A, 0x5A, 0x9A, 0xDA,
+ 0x2A, 0x6A, 0xAA, 0xEA, 0x3A, 0x7A, 0xBA, 0xFA,
+ 0x0E, 0x4E, 0x8E, 0xCE, 0x1E, 0x5E, 0x9E, 0xDE,
+ 0x2E, 0x6E, 0xAE, 0xEE, 0x3E, 0x7E, 0xBE, 0xFE,
+ 0x03, 0x43, 0x83, 0xC3, 0x13, 0x53, 0x93, 0xD3,
+ 0x23, 0x63, 0xA3, 0xE3, 0x33, 0x73, 0xB3, 0xF3,
+ 0x07, 0x47, 0x87, 0xC7, 0x17, 0x57, 0x97, 0xD7,
+ 0x27, 0x67, 0xA7, 0xE7, 0x37, 0x77, 0xB7, 0xF7,
+ 0x0B, 0x4B, 0x8B, 0xCB, 0x1B, 0x5B, 0x9B, 0xDB,
+ 0x2B, 0x6B, 0xAB, 0xEB, 0x3B, 0x7B, 0xBB, 0xFB,
+ 0x0F, 0x4F, 0x8F, 0xCF, 0x1F, 0x5F, 0x9F, 0xDF,
+ 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF
+};
+
+static PNG_CONST png_byte fourbppswaptable[256] = {
+ 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
+ 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0,
+ 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
+ 0x81, 0x91, 0xA1, 0xB1, 0xC1, 0xD1, 0xE1, 0xF1,
+ 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
+ 0x82, 0x92, 0xA2, 0xB2, 0xC2, 0xD2, 0xE2, 0xF2,
+ 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
+ 0x83, 0x93, 0xA3, 0xB3, 0xC3, 0xD3, 0xE3, 0xF3,
+ 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
+ 0x84, 0x94, 0xA4, 0xB4, 0xC4, 0xD4, 0xE4, 0xF4,
+ 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
+ 0x85, 0x95, 0xA5, 0xB5, 0xC5, 0xD5, 0xE5, 0xF5,
+ 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
+ 0x86, 0x96, 0xA6, 0xB6, 0xC6, 0xD6, 0xE6, 0xF6,
+ 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
+ 0x87, 0x97, 0xA7, 0xB7, 0xC7, 0xD7, 0xE7, 0xF7,
+ 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
+ 0x88, 0x98, 0xA8, 0xB8, 0xC8, 0xD8, 0xE8, 0xF8,
+ 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
+ 0x89, 0x99, 0xA9, 0xB9, 0xC9, 0xD9, 0xE9, 0xF9,
+ 0x0A, 0x1A, 0x2A, 0x3A, 0x4A, 0x5A, 0x6A, 0x7A,
+ 0x8A, 0x9A, 0xAA, 0xBA, 0xCA, 0xDA, 0xEA, 0xFA,
+ 0x0B, 0x1B, 0x2B, 0x3B, 0x4B, 0x5B, 0x6B, 0x7B,
+ 0x8B, 0x9B, 0xAB, 0xBB, 0xCB, 0xDB, 0xEB, 0xFB,
+ 0x0C, 0x1C, 0x2C, 0x3C, 0x4C, 0x5C, 0x6C, 0x7C,
+ 0x8C, 0x9C, 0xAC, 0xBC, 0xCC, 0xDC, 0xEC, 0xFC,
+ 0x0D, 0x1D, 0x2D, 0x3D, 0x4D, 0x5D, 0x6D, 0x7D,
+ 0x8D, 0x9D, 0xAD, 0xBD, 0xCD, 0xDD, 0xED, 0xFD,
+ 0x0E, 0x1E, 0x2E, 0x3E, 0x4E, 0x5E, 0x6E, 0x7E,
+ 0x8E, 0x9E, 0xAE, 0xBE, 0xCE, 0xDE, 0xEE, 0xFE,
+ 0x0F, 0x1F, 0x2F, 0x3F, 0x4F, 0x5F, 0x6F, 0x7F,
+ 0x8F, 0x9F, 0xAF, 0xBF, 0xCF, 0xDF, 0xEF, 0xFF
+};
+
+/* swaps pixel packing order within bytes */
+void /* PRIVATE */
+png_do_packswap(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_packswap\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->bit_depth < 8)
+ {
+ png_bytep rp, end, table;
+
+ end = row + row_info->rowbytes;
+
+ if (row_info->bit_depth == 1)
+ table = (png_bytep)onebppswaptable;
+ else if (row_info->bit_depth == 2)
+ table = (png_bytep)twobppswaptable;
+ else if (row_info->bit_depth == 4)
+ table = (png_bytep)fourbppswaptable;
+ else
+ return;
+
+ for (rp = row; rp < end; rp++)
+ *rp = table[*rp];
+ }
+}
+#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED) || \
+ defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+/* remove filler or alpha byte(s) */
+void /* PRIVATE */
+png_do_strip_filler(png_row_infop row_info, png_bytep row, png_uint_32 flags)
+{
+ png_debug(1, "in png_do_strip_filler\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ png_bytep sp=row;
+ png_bytep dp=row;
+ png_uint_32 row_width=row_info->width;
+ png_uint_32 i;
+
+ if ((row_info->color_type == PNG_COLOR_TYPE_RGB ||
+ (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA &&
+ (flags & PNG_FLAG_STRIP_ALPHA))) &&
+ row_info->channels == 4)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ /* This converts from RGBX or RGBA to RGB */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ dp+=3; sp+=4;
+ for (i = 1; i < row_width; i++)
+ {
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp++;
+ }
+ }
+ /* This converts from XRGB or ARGB to RGB */
+ else
+ {
+ for (i = 0; i < row_width; i++)
+ {
+ sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 24;
+ row_info->rowbytes = row_width * 3;
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ /* This converts from RRGGBBXX or RRGGBBAA to RRGGBB */
+ sp += 8; dp += 6;
+ for (i = 1; i < row_width; i++)
+ {
+ /* This could be (although png_memcpy is probably slower):
+ png_memcpy(dp, sp, 6);
+ sp += 8;
+ dp += 6;
+ */
+
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp += 2;
+ }
+ }
+ else
+ {
+ /* This converts from XXRRGGBB or AARRGGBB to RRGGBB */
+ for (i = 0; i < row_width; i++)
+ {
+ /* This could be (although png_memcpy is probably slower):
+ png_memcpy(dp, sp, 6);
+ sp += 8;
+ dp += 6;
+ */
+
+ sp+=2;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 48;
+ row_info->rowbytes = row_width * 6;
+ }
+ row_info->channels = 3;
+ }
+ else if ((row_info->color_type == PNG_COLOR_TYPE_GRAY ||
+ (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA &&
+ (flags & PNG_FLAG_STRIP_ALPHA))) &&
+ row_info->channels == 2)
+ {
+ if (row_info->bit_depth == 8)
+ {
+ /* This converts from GX or GA to G */
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ for (i = 0; i < row_width; i++)
+ {
+ *dp++ = *sp++;
+ sp++;
+ }
+ }
+ /* This converts from XG or AG to G */
+ else
+ {
+ for (i = 0; i < row_width; i++)
+ {
+ sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 8;
+ row_info->rowbytes = row_width;
+ }
+ else /* if (row_info->bit_depth == 16) */
+ {
+ if (flags & PNG_FLAG_FILLER_AFTER)
+ {
+ /* This converts from GGXX or GGAA to GG */
+ sp += 4; dp += 2;
+ for (i = 1; i < row_width; i++)
+ {
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ sp += 2;
+ }
+ }
+ else
+ {
+ /* This converts from XXGG or AAGG to GG */
+ for (i = 0; i < row_width; i++)
+ {
+ sp += 2;
+ *dp++ = *sp++;
+ *dp++ = *sp++;
+ }
+ }
+ row_info->pixel_depth = 16;
+ row_info->rowbytes = row_width * 2;
+ }
+ row_info->channels = 1;
+ }
+ if (flags & PNG_FLAG_STRIP_ALPHA)
+ row_info->color_type &= ~PNG_COLOR_MASK_ALPHA;
+ }
+}
+#endif
+
+#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED)
+/* swaps red and blue bytes within a pixel */
+void /* PRIVATE */
+png_do_bgr(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_bgr\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ png_uint_32 row_width = row_info->width;
+ if (row_info->bit_depth == 8)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 3)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 2);
+ *(rp + 2) = save;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 4)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 2);
+ *(rp + 2) = save;
+ }
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 6)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 4);
+ *(rp + 4) = save;
+ save = *(rp + 1);
+ *(rp + 1) = *(rp + 5);
+ *(rp + 5) = save;
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += 8)
+ {
+ png_byte save = *rp;
+ *rp = *(rp + 4);
+ *(rp + 4) = save;
+ save = *(rp + 1);
+ *(rp + 1) = *(rp + 5);
+ *(rp + 5) = save;
+ }
+ }
+ }
+ }
+}
+#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
+
+#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) || \
+ defined(PNG_LEGACY_SUPPORTED)
+void PNGAPI
+png_set_user_transform_info(png_structp png_ptr, png_voidp
+ user_transform_ptr, int user_transform_depth, int user_transform_channels)
+{
+ png_debug(1, "in png_set_user_transform_info\n");
+ if(png_ptr == NULL) return;
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+ png_ptr->user_transform_ptr = user_transform_ptr;
+ png_ptr->user_transform_depth = (png_byte)user_transform_depth;
+ png_ptr->user_transform_channels = (png_byte)user_transform_channels;
+#else
+ if(user_transform_ptr || user_transform_depth || user_transform_channels)
+ png_warning(png_ptr,
+ "This version of libpng does not support user transform info");
+#endif
+}
+#endif
+
+/* This function returns a pointer to the user_transform_ptr associated with
+ * the user transform functions. The application should free any memory
+ * associated with this pointer before png_write_destroy and png_read_destroy
+ * are called.
+ */
+png_voidp PNGAPI
+png_get_user_transform_ptr(png_structp png_ptr)
+{
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED)
+ if (png_ptr == NULL) return (NULL);
+ return ((png_voidp)png_ptr->user_transform_ptr);
+#else
+ return (NULL);
+#endif
+}
+#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngvcrd.c b/distrib/libpng-1.2.19/pngvcrd.c
new file mode 100644
index 0000000..34d42c9
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngvcrd.c
@@ -0,0 +1,3922 @@
+
+/* pngvcrd.c - mixed C/assembler version of utilities to read a PNG file
+ *
+ * For Intel x86 CPU and Microsoft Visual C++ compiler
+ *
+ * Last changed in libpng 1.2.19 August 18, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * Copyright (c) 1998, Intel Corporation
+ *
+ * Contributed by Nirav Chhatrapati, Intel Corporation, 1998
+ * Interface to libpng contributed by Gilles Vollant, 1999
+ *
+ *
+ * In png_do_read_interlace() in libpng versions 1.0.3a through 1.0.4d,
+ * a sign error in the post-MMX cleanup code for each pixel_depth resulted
+ * in bad pixels at the beginning of some rows of some images, and also
+ * (due to out-of-range memory reads and writes) caused heap corruption
+ * when compiled with MSVC 6.0. The error was fixed in version 1.0.4e.
+ *
+ * [png_read_filter_row_mmx_avg() bpp == 2 bugfix, GRR 20000916]
+ *
+ * [runtime MMX configuration, GRR 20010102]
+ *
+ * [Copy 6 bytes per pixel, not 4, and use stride of 6, not 4, in the
+ * second loop of interlace processing of 48-bit pixels, GR-P 20070717]
+ *
+ * [move instances of uAll union into local, except for two constant
+ * instances, GR-P 20070805]
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+
+#if defined(PNG_MMX_CODE_SUPPORTED) && defined(PNG_USE_PNGVCRD)
+
+
+static int mmx_supported=2;
+
+int PNGAPI
+png_mmx_support(void)
+{
+ int mmx_supported_local = 0;
+ _asm {
+ push ebx //CPUID will trash these
+ push ecx
+ push edx
+
+ pushfd //Save Eflag to stack
+ pop eax //Get Eflag from stack into eax
+ mov ecx, eax //Make another copy of Eflag in ecx
+ xor eax, 0x200000 //Toggle ID bit in Eflag [i.e. bit(21)]
+ push eax //Save modified Eflag back to stack
+
+ popfd //Restored modified value back to Eflag reg
+ pushfd //Save Eflag to stack
+ pop eax //Get Eflag from stack
+ push ecx // save original Eflag to stack
+ popfd // restore original Eflag
+ xor eax, ecx //Compare the new Eflag with the original Eflag
+ jz NOT_SUPPORTED //If the same, CPUID instruction is not supported,
+ //skip following instructions and jump to
+ //NOT_SUPPORTED label
+
+ xor eax, eax //Set eax to zero
+
+ _asm _emit 0x0f //CPUID instruction (two bytes opcode)
+ _asm _emit 0xa2
+
+ cmp eax, 1 //make sure eax return non-zero value
+ jl NOT_SUPPORTED //If eax is zero, mmx not supported
+
+ xor eax, eax //set eax to zero
+ inc eax //Now increment eax to 1. This instruction is
+ //faster than the instruction "mov eax, 1"
+
+ _asm _emit 0x0f //CPUID instruction
+ _asm _emit 0xa2
+
+ and edx, 0x00800000 //mask out all bits but mmx bit(24)
+ cmp edx, 0 // 0 = mmx not supported
+ jz NOT_SUPPORTED // non-zero = Yes, mmx IS supported
+
+ mov mmx_supported_local, 1 //set return value to 1
+
+NOT_SUPPORTED:
+ mov eax, mmx_supported_local //move return value to eax
+ pop edx //CPUID trashed these
+ pop ecx
+ pop ebx
+ }
+
+ //mmx_supported_local=0; // test code for force don't support MMX
+ //printf("MMX : %u (1=MMX supported)\n",mmx_supported_local);
+
+ mmx_supported = mmx_supported_local;
+ return mmx_supported_local;
+}
+
+/* Combines the row recently read in with the previous row.
+ This routine takes care of alpha and transparency if requested.
+ This routine also handles the two methods of progressive display
+ of interlaced images, depending on the mask value.
+ The mask value describes which pixels are to be combined with
+ the row. The pattern always repeats every 8 pixels, so just 8
+ bits are needed. A one indicates the pixel is to be combined; a
+ zero indicates the pixel is to be skipped. This is in addition
+ to any alpha or transparency value associated with the pixel. If
+ you want all pixels to be combined, pass 0xff (255) in mask. */
+
+/* Use this routine for x86 platform - uses faster MMX routine if machine
+ supports MMX */
+
+void /* PRIVATE */
+png_combine_row(png_structp png_ptr, png_bytep row, int mask)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+#endif
+
+ png_debug(1,"in png_combine_row_asm\n");
+
+ if (mmx_supported == 2) {
+#if !defined(PNG_1_0_X)
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+#endif
+ png_mmx_support();
+ }
+
+ if (mask == 0xff)
+ {
+ png_memcpy(row, png_ptr->row_buf + 1,
+ (png_size_t)PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
+ png_ptr->width));
+ }
+ /* GRR: add "else if (mask == 0)" case?
+ * or does png_combine_row() not even get called in that case? */
+ else
+ {
+ switch (png_ptr->row_info.pixel_depth)
+ {
+ case 24:
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ png_uint_32 len;
+ int unmask, diff;
+
+ __int64 mask2=0x0101010202020404, //24bpp
+ mask1=0x0408080810101020,
+ mask0=0x2020404040808080;
+
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+
+ unmask = ~mask;
+ len = (png_ptr->width)&~7;
+ diff = (png_ptr->width)&7;
+
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && mmx_supported */ )
+#else
+ if (mmx_supported)
+#endif
+ {
+ _asm
+ {
+ movd mm7, unmask //load bit pattern
+ psubb mm6,mm6 //zero mm6
+ punpcklbw mm7,mm7
+ punpcklwd mm7,mm7
+ punpckldq mm7,mm7 //fill register with 8 masks
+
+ movq mm0,mask0
+ movq mm1,mask1
+ movq mm2,mask2
+
+ pand mm0,mm7
+ pand mm1,mm7
+ pand mm2,mm7
+
+ pcmpeqb mm0,mm6
+ pcmpeqb mm1,mm6
+ pcmpeqb mm2,mm6
+
+ mov ecx,len //load length of line
+ mov esi,srcptr //load source
+ mov ebx,dstptr //load dest
+ cmp ecx,0
+ jz mainloop24end
+
+mainloop24:
+ movq mm4,[esi]
+ pand mm4,mm0
+ movq mm6,mm0
+ movq mm7,[ebx]
+ pandn mm6,mm7
+ por mm4,mm6
+ movq [ebx],mm4
+
+
+ movq mm5,[esi+8]
+ pand mm5,mm1
+ movq mm7,mm1
+ movq mm6,[ebx+8]
+ pandn mm7,mm6
+ por mm5,mm7
+ movq [ebx+8],mm5
+
+ movq mm6,[esi+16]
+ pand mm6,mm2
+ movq mm4,mm2
+ movq mm7,[ebx+16]
+ pandn mm4,mm7
+ por mm6,mm4
+ movq [ebx+16],mm6
+
+ add esi,24 //inc by 24 bytes processed
+ add ebx,24
+ sub ecx,8 //dec by 8 pixels processed
+
+ ja mainloop24
+
+mainloop24end:
+ mov ecx,diff
+ cmp ecx,0
+ jz end24
+
+ mov edx,mask
+ sal edx,24 //make low byte the high byte
+secondloop24:
+ sal edx,1 //move high bit to CF
+ jnc skip24 //if CF = 0
+ mov ax,[esi]
+ mov [ebx],ax
+ xor eax,eax
+ mov al,[esi+2]
+ mov [ebx+2],al
+skip24:
+ add esi,3
+ add ebx,3
+
+ dec ecx
+ jnz secondloop24
+
+end24:
+ emms
+ }
+ }
+ else /* mmx not supported - use modified C routine */
+ {
+ register unsigned int incr1, initial_val, final_val;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ register int disp = png_pass_inc[png_ptr->pass];
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dstptr, srcptr, pixel_bytes);
+ srcptr += incr1;
+ dstptr += incr1;
+ }
+ } /* end of else */
+
+ break;
+ } // end 24 bpp
+
+ case 32:
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ png_uint_32 len;
+ int unmask, diff;
+
+ __int64 mask3=0x0101010102020202, //32bpp
+ mask2=0x0404040408080808,
+ mask1=0x1010101020202020,
+ mask0=0x4040404080808080;
+
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+
+ unmask = ~mask;
+ len = (png_ptr->width)&~7;
+ diff = (png_ptr->width)&7;
+
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && mmx_supported */ )
+#else
+ if (mmx_supported)
+#endif
+ {
+ _asm
+ {
+ movd mm7, unmask //load bit pattern
+ psubb mm6,mm6 //zero mm6
+ punpcklbw mm7,mm7
+ punpcklwd mm7,mm7
+ punpckldq mm7,mm7 //fill register with 8 masks
+
+ movq mm0,mask0
+ movq mm1,mask1
+ movq mm2,mask2
+ movq mm3,mask3
+
+ pand mm0,mm7
+ pand mm1,mm7
+ pand mm2,mm7
+ pand mm3,mm7
+
+ pcmpeqb mm0,mm6
+ pcmpeqb mm1,mm6
+ pcmpeqb mm2,mm6
+ pcmpeqb mm3,mm6
+
+ mov ecx,len //load length of line
+ mov esi,srcptr //load source
+ mov ebx,dstptr //load dest
+
+ cmp ecx,0 //lcr
+ jz mainloop32end
+
+mainloop32:
+ movq mm4,[esi]
+ pand mm4,mm0
+ movq mm6,mm0
+ movq mm7,[ebx]
+ pandn mm6,mm7
+ por mm4,mm6
+ movq [ebx],mm4
+
+ movq mm5,[esi+8]
+ pand mm5,mm1
+ movq mm7,mm1
+ movq mm6,[ebx+8]
+ pandn mm7,mm6
+ por mm5,mm7
+ movq [ebx+8],mm5
+
+ movq mm6,[esi+16]
+ pand mm6,mm2
+ movq mm4,mm2
+ movq mm7,[ebx+16]
+ pandn mm4,mm7
+ por mm6,mm4
+ movq [ebx+16],mm6
+
+ movq mm7,[esi+24]
+ pand mm7,mm3
+ movq mm5,mm3
+ movq mm4,[ebx+24]
+ pandn mm5,mm4
+ por mm7,mm5
+ movq [ebx+24],mm7
+
+ add esi,32 //inc by 32 bytes processed
+ add ebx,32
+ sub ecx,8 //dec by 8 pixels processed
+
+ ja mainloop32
+
+mainloop32end:
+ mov ecx,diff
+ cmp ecx,0
+ jz end32
+
+ mov edx,mask
+ sal edx,24 //make low byte the high byte
+secondloop32:
+ sal edx,1 //move high bit to CF
+ jnc skip32 //if CF = 0
+ mov eax,[esi]
+ mov [ebx],eax
+skip32:
+ add esi,4
+ add ebx,4
+
+ dec ecx
+ jnz secondloop32
+
+end32:
+ emms
+ }
+ }
+ else /* mmx _not supported - Use modified C routine */
+ {
+ register unsigned int incr1, initial_val, final_val;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ register int disp = png_pass_inc[png_ptr->pass];
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dstptr, srcptr, pixel_bytes);
+ srcptr += incr1;
+ dstptr += incr1;
+ }
+ } /* end of else */
+
+ break;
+ } // end 32 bpp
+
+ case 8:
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ png_uint_32 len;
+ int m;
+ int diff, unmask;
+
+ __int64 mask0=0x0102040810204080;
+
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && mmx_supported */ )
+#else
+ if (mmx_supported)
+#endif
+ {
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+ m = 0x80;
+ unmask = ~mask;
+ len = png_ptr->width &~7; //reduce to multiple of 8
+ diff = png_ptr->width & 7; //amount lost
+
+ _asm
+ {
+ movd mm7, unmask //load bit pattern
+ psubb mm6,mm6 //zero mm6
+ punpcklbw mm7,mm7
+ punpcklwd mm7,mm7
+ punpckldq mm7,mm7 //fill register with 8 masks
+
+ movq mm0,mask0
+
+ pand mm0,mm7 //nonzero if keep byte
+ pcmpeqb mm0,mm6 //zeros->1s, v versa
+
+ mov ecx,len //load length of line (pixels)
+ mov esi,srcptr //load source
+ mov ebx,dstptr //load dest
+ cmp ecx,0 //lcr
+ je mainloop8end
+
+mainloop8:
+ movq mm4,[esi]
+ pand mm4,mm0
+ movq mm6,mm0
+ pandn mm6,[ebx]
+ por mm4,mm6
+ movq [ebx],mm4
+
+ add esi,8 //inc by 8 bytes processed
+ add ebx,8
+ sub ecx,8 //dec by 8 pixels processed
+
+ ja mainloop8
+mainloop8end:
+
+ mov ecx,diff
+ cmp ecx,0
+ jz end8
+
+ mov edx,mask
+ sal edx,24 //make low byte the high byte
+
+secondloop8:
+ sal edx,1 //move high bit to CF
+ jnc skip8 //if CF = 0
+ mov al,[esi]
+ mov [ebx],al
+skip8:
+ inc esi
+ inc ebx
+
+ dec ecx
+ jnz secondloop8
+end8:
+ emms
+ }
+ }
+ else /* mmx not supported - use modified C routine */
+ {
+ register unsigned int incr1, initial_val, final_val;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ register int disp = png_pass_inc[png_ptr->pass];
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dstptr, srcptr, pixel_bytes);
+ srcptr += incr1;
+ dstptr += incr1;
+ }
+ } /* end of else */
+
+ break;
+ } // end 8 bpp
+
+ case 1:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_inc, s_start, s_end;
+ int m;
+ int shift;
+ png_uint_32 i;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+ else
+#endif
+ {
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ int value;
+
+ value = (*sp >> shift) & 0x1;
+ *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+
+ case 2:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+ else
+#endif
+ {
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0x3;
+ *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+
+ case 4:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int s_start, s_end, s_inc;
+ int m;
+ int shift;
+ png_uint_32 i;
+ int value;
+
+ sp = png_ptr->row_buf + 1;
+ dp = row;
+ m = 0x80;
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ {
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+ else
+#endif
+ {
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ shift = s_start;
+
+ for (i = 0; i < png_ptr->width; i++)
+ {
+ if (m & mask)
+ {
+ value = (*sp >> shift) & 0xf;
+ *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff);
+ *dp |= (png_byte)(value << shift);
+ }
+
+ if (shift == s_end)
+ {
+ shift = s_start;
+ sp++;
+ dp++;
+ }
+ else
+ shift += s_inc;
+ if (m == 1)
+ m = 0x80;
+ else
+ m >>= 1;
+ }
+ break;
+ }
+
+ case 16:
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ png_uint_32 len;
+ int unmask, diff;
+ __int64 mask1=0x0101020204040808,
+ mask0=0x1010202040408080;
+
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && mmx_supported */ )
+#else
+ if (mmx_supported)
+#endif
+ {
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+
+ unmask = ~mask;
+ len = (png_ptr->width)&~7;
+ diff = (png_ptr->width)&7;
+ _asm
+ {
+ movd mm7, unmask //load bit pattern
+ psubb mm6,mm6 //zero mm6
+ punpcklbw mm7,mm7
+ punpcklwd mm7,mm7
+ punpckldq mm7,mm7 //fill register with 8 masks
+
+ movq mm0,mask0
+ movq mm1,mask1
+
+ pand mm0,mm7
+ pand mm1,mm7
+
+ pcmpeqb mm0,mm6
+ pcmpeqb mm1,mm6
+
+ mov ecx,len //load length of line
+ mov esi,srcptr //load source
+ mov ebx,dstptr //load dest
+ cmp ecx,0 //lcr
+ jz mainloop16end
+
+mainloop16:
+ movq mm4,[esi]
+ pand mm4,mm0
+ movq mm6,mm0
+ movq mm7,[ebx]
+ pandn mm6,mm7
+ por mm4,mm6
+ movq [ebx],mm4
+
+ movq mm5,[esi+8]
+ pand mm5,mm1
+ movq mm7,mm1
+ movq mm6,[ebx+8]
+ pandn mm7,mm6
+ por mm5,mm7
+ movq [ebx+8],mm5
+
+ add esi,16 //inc by 16 bytes processed
+ add ebx,16
+ sub ecx,8 //dec by 8 pixels processed
+
+ ja mainloop16
+
+mainloop16end:
+ mov ecx,diff
+ cmp ecx,0
+ jz end16
+
+ mov edx,mask
+ sal edx,24 //make low byte the high byte
+secondloop16:
+ sal edx,1 //move high bit to CF
+ jnc skip16 //if CF = 0
+ mov ax,[esi]
+ mov [ebx],ax
+skip16:
+ add esi,2
+ add ebx,2
+
+ dec ecx
+ jnz secondloop16
+end16:
+ emms
+ }
+ }
+ else /* mmx not supported - use modified C routine */
+ {
+ register unsigned int incr1, initial_val, final_val;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ register int disp = png_pass_inc[png_ptr->pass];
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dstptr, srcptr, pixel_bytes);
+ srcptr += incr1;
+ dstptr += incr1;
+ }
+ } /* end of else */
+
+ break;
+ } // end 16 bpp
+
+ case 48:
+ {
+ png_bytep srcptr;
+ png_bytep dstptr;
+ png_uint_32 len;
+ int unmask, diff;
+
+ __int64 mask5=0x0101010101010202,
+ mask4=0x0202020204040404,
+ mask3=0x0404080808080808,
+ mask2=0x1010101010102020,
+ mask1=0x2020202040404040,
+ mask0=0x4040808080808080;
+
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_COMBINE_ROW)
+ /* && mmx_supported */ )
+#else
+ if (mmx_supported)
+#endif
+ {
+ srcptr = png_ptr->row_buf + 1;
+ dstptr = row;
+
+ unmask = ~mask;
+ len = (png_ptr->width)&~7;
+ diff = (png_ptr->width)&7;
+ _asm
+ {
+ movd mm7, unmask //load bit pattern
+ psubb mm6,mm6 //zero mm6
+ punpcklbw mm7,mm7
+ punpcklwd mm7,mm7
+ punpckldq mm7,mm7 //fill register with 8 masks
+
+ movq mm0,mask0
+ movq mm1,mask1
+ movq mm2,mask2
+ movq mm3,mask3
+ movq mm4,mask4
+ movq mm5,mask5
+
+ pand mm0,mm7
+ pand mm1,mm7
+ pand mm2,mm7
+ pand mm3,mm7
+ pand mm4,mm7
+ pand mm5,mm7
+
+ pcmpeqb mm0,mm6
+ pcmpeqb mm1,mm6
+ pcmpeqb mm2,mm6
+ pcmpeqb mm3,mm6
+ pcmpeqb mm4,mm6
+ pcmpeqb mm5,mm6
+
+ mov ecx,len //load length of line
+ mov esi,srcptr //load source
+ mov ebx,dstptr //load dest
+
+ cmp ecx,0
+ jz mainloop48end
+
+mainloop48:
+ movq mm7,[esi]
+ pand mm7,mm0
+ movq mm6,mm0
+ pandn mm6,[ebx]
+ por mm7,mm6
+ movq [ebx],mm7
+
+ movq mm6,[esi+8]
+ pand mm6,mm1
+ movq mm7,mm1
+ pandn mm7,[ebx+8]
+ por mm6,mm7
+ movq [ebx+8],mm6
+
+ movq mm6,[esi+16]
+ pand mm6,mm2
+ movq mm7,mm2
+ pandn mm7,[ebx+16]
+ por mm6,mm7
+ movq [ebx+16],mm6
+
+ movq mm7,[esi+24]
+ pand mm7,mm3
+ movq mm6,mm3
+ pandn mm6,[ebx+24]
+ por mm7,mm6
+ movq [ebx+24],mm7
+
+ movq mm6,[esi+32]
+ pand mm6,mm4
+ movq mm7,mm4
+ pandn mm7,[ebx+32]
+ por mm6,mm7
+ movq [ebx+32],mm6
+
+ movq mm7,[esi+40]
+ pand mm7,mm5
+ movq mm6,mm5
+ pandn mm6,[ebx+40]
+ por mm7,mm6
+ movq [ebx+40],mm7
+
+ add esi,48 //inc by 32 bytes processed
+ add ebx,48
+ sub ecx,8 //dec by 8 pixels processed
+
+ ja mainloop48
+mainloop48end:
+
+ mov ecx,diff
+ cmp ecx,0
+ jz end48
+
+ mov edx,mask
+ sal edx,24 //make low byte the high byte
+
+secondloop48:
+ sal edx,1 //move high bit to CF
+ jnc skip48 //if CF = 0
+ mov eax,[esi]
+ mov [ebx],eax
+ mov ax,[esi+4] // These 2 lines added 20070717
+ mov [ebx+4],ax // Glenn R-P
+skip48:
+ add esi,6 // Changed 4 to 6 on these 2
+ add ebx,6 // lines. Glenn R-P 20070717
+
+ dec ecx
+ jnz secondloop48
+
+end48:
+ emms
+ }
+ }
+ else /* mmx _not supported - Use modified C routine */
+ {
+ register unsigned int incr1, initial_val, final_val;
+ png_size_t pixel_bytes;
+ png_uint_32 i;
+ register int disp = png_pass_inc[png_ptr->pass];
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ srcptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dstptr = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dstptr, srcptr, pixel_bytes);
+ srcptr += incr1;
+ dstptr += incr1;
+ }
+ } /* end of else */
+
+ break;
+ } // end 48 bpp
+
+ default:
+ {
+ png_bytep sptr;
+ png_bytep dp;
+ png_size_t pixel_bytes;
+ int offset_table[7] = {0, 4, 0, 2, 0, 1, 0};
+ unsigned int i;
+ register int disp = png_pass_inc[png_ptr->pass]; // get the offset
+ register unsigned int incr1, initial_val, final_val;
+
+ pixel_bytes = (png_ptr->row_info.pixel_depth >> 3);
+ sptr = png_ptr->row_buf + 1 + offset_table[png_ptr->pass]*
+ pixel_bytes;
+ dp = row + offset_table[png_ptr->pass]*pixel_bytes;
+ initial_val = offset_table[png_ptr->pass]*pixel_bytes;
+ final_val = png_ptr->width*pixel_bytes;
+ incr1 = (disp)*pixel_bytes;
+ for (i = initial_val; i < final_val; i += incr1)
+ {
+ png_memcpy(dp, sptr, pixel_bytes);
+ sptr += incr1;
+ dp += incr1;
+ }
+ break;
+ }
+ } /* end switch (png_ptr->row_info.pixel_depth) */
+ } /* end if (non-trivial mask) */
+
+} /* end png_combine_row() */
+
+
+#if defined(PNG_READ_INTERLACING_SUPPORTED)
+
+void /* PRIVATE */
+png_do_read_interlace(png_structp png_ptr)
+{
+ png_row_infop row_info = &(png_ptr->row_info);
+ png_bytep row = png_ptr->row_buf + 1;
+ int pass = png_ptr->pass;
+ png_uint_32 transformations = png_ptr->transformations;
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+#endif
+
+ png_debug(1,"in png_do_read_interlace\n");
+
+ if (mmx_supported == 2) {
+#if !defined(PNG_1_0_X)
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+#endif
+ png_mmx_support();
+ }
+
+ if (row != NULL && row_info != NULL)
+ {
+ png_uint_32 final_width;
+
+ final_width = row_info->width * png_pass_inc[pass];
+
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_byte v;
+ png_uint_32 i;
+ int j;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 3);
+ dp = row + (png_size_t)((final_width - 1) >> 3);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (int)((row_info->width + 7) & 7);
+ dshift = (int)((final_width + 7) & 7);
+ s_start = 7;
+ s_end = 0;
+ s_inc = -1;
+ }
+ else
+#endif
+ {
+ sshift = 7 - (int)((row_info->width + 7) & 7);
+ dshift = 7 - (int)((final_width + 7) & 7);
+ s_start = 0;
+ s_end = 7;
+ s_inc = 1;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ v = (png_byte)((*sp >> sshift) & 0x1);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ case 2:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 2);
+ dp = row + (png_size_t)((final_width - 1) >> 2);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 3) & 3) << 1);
+ dshift = (png_size_t)(((final_width + 3) & 3) << 1);
+ s_start = 6;
+ s_end = 0;
+ s_inc = -2;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((3 - ((row_info->width + 3) & 3)) << 1);
+ dshift = (png_size_t)((3 - ((final_width + 3) & 3)) << 1);
+ s_start = 0;
+ s_end = 6;
+ s_inc = 2;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0x3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ case 4:
+ {
+ png_bytep sp, dp;
+ int sshift, dshift;
+ int s_start, s_end, s_inc;
+ png_uint_32 i;
+
+ sp = row + (png_size_t)((row_info->width - 1) >> 1);
+ dp = row + (png_size_t)((final_width - 1) >> 1);
+#if defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (transformations & PNG_PACKSWAP)
+ {
+ sshift = (png_size_t)(((row_info->width + 1) & 1) << 2);
+ dshift = (png_size_t)(((final_width + 1) & 1) << 2);
+ s_start = 4;
+ s_end = 0;
+ s_inc = -4;
+ }
+ else
+#endif
+ {
+ sshift = (png_size_t)((1 - ((row_info->width + 1) & 1)) << 2);
+ dshift = (png_size_t)((1 - ((final_width + 1) & 1)) << 2);
+ s_start = 0;
+ s_end = 4;
+ s_inc = 4;
+ }
+
+ for (i = row_info->width; i; i--)
+ {
+ png_byte v;
+ int j;
+
+ v = (png_byte)((*sp >> sshift) & 0xf);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff);
+ *dp |= (png_byte)(v << dshift);
+ if (dshift == s_end)
+ {
+ dshift = s_start;
+ dp--;
+ }
+ else
+ dshift += s_inc;
+ }
+ if (sshift == s_end)
+ {
+ sshift = s_start;
+ sp--;
+ }
+ else
+ sshift += s_inc;
+ }
+ break;
+ }
+
+ default: // This is the place where the routine is modified
+ {
+ __int64 const4 = 0x0000000000FFFFFF;
+ // __int64 const5 = 0x000000FFFFFF0000; // unused...
+ __int64 const6 = 0x00000000000000FF;
+ png_bytep sptr, dp;
+ png_uint_32 i;
+ png_size_t pixel_bytes;
+ int width = row_info->width;
+
+ pixel_bytes = (row_info->pixel_depth >> 3);
+
+ sptr = row + (width - 1) * pixel_bytes;
+ dp = row + (final_width - 1) * pixel_bytes;
+ // New code by Nirav Chhatrapati - Intel Corporation
+ // sign fix by GRR
+ // NOTE: there is NO MMX code for 48-bit and 64-bit images
+
+ // use MMX routine if machine supports it
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_INTERLACE)
+ /* && mmx_supported */ )
+#else
+ if (mmx_supported)
+#endif
+ {
+ if (pixel_bytes == 3)
+ {
+ if (((pass == 4) || (pass == 5)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) - 8;
+ if (width_mmx < 0)
+ width_mmx = 0;
+ width -= width_mmx; // 8 or 9 pix, 24 or 27 bytes
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 3
+ sub edi, 9
+loop_pass4:
+ movq mm0, [esi] ; X X v2 v1 v0 v5 v4 v3
+ movq mm7, mm0 ; X X v2 v1 v0 v5 v4 v3
+ movq mm6, mm0 ; X X v2 v1 v0 v5 v4 v3
+ psllq mm0, 24 ; v1 v0 v5 v4 v3 0 0 0
+ pand mm7, const4 ; 0 0 0 0 0 v5 v4 v3
+ psrlq mm6, 24 ; 0 0 0 X X v2 v1 v0
+ por mm0, mm7 ; v1 v0 v5 v4 v3 v5 v4 v3
+ movq mm5, mm6 ; 0 0 0 X X v2 v1 v0
+ psllq mm6, 8 ; 0 0 X X v2 v1 v0 0
+ movq [edi], mm0 ; move quad to memory
+ psrlq mm5, 16 ; 0 0 0 0 0 X X v2
+ pand mm5, const6 ; 0 0 0 0 0 0 0 v2
+ por mm6, mm5 ; 0 0 X X v2 v1 v0 v2
+ movd [edi+8], mm6 ; move double to memory
+ sub esi, 6
+ sub edi, 12
+ sub ecx, 2
+ jnz loop_pass4
+ EMMS
+ }
+ }
+
+ sptr -= width_mmx*3;
+ dp -= width_mmx*6;
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+
+ png_memcpy(v, sptr, 3);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 3);
+ dp -= 3;
+ }
+ sptr -= 3;
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width
+ sub edi, 9 // (png_pass_inc[pass] - 1)*pixel_bytes
+loop_pass2:
+ movd mm0, [esi] ; X X X X X v2 v1 v0
+ pand mm0, const4 ; 0 0 0 0 0 v2 v1 v0
+ movq mm1, mm0 ; 0 0 0 0 0 v2 v1 v0
+ psllq mm0, 16 ; 0 0 0 v2 v1 v0 0 0
+ movq mm2, mm0 ; 0 0 0 v2 v1 v0 0 0
+ psllq mm0, 24 ; v2 v1 v0 0 0 0 0 0
+ psrlq mm1, 8 ; 0 0 0 0 0 0 v2 v1
+ por mm0, mm2 ; v2 v1 v0 v2 v1 v0 0 0
+ por mm0, mm1 ; v2 v1 v0 v2 v1 v0 v2 v1
+ movq [edi+4], mm0 ; move to memory
+ psrlq mm0, 16 ; 0 0 v2 v1 v0 v2 v1 v0
+ movd [edi], mm0 ; move to memory
+ sub esi, 3
+ sub edi, 12
+ dec ecx
+ jnz loop_pass2
+ EMMS
+ }
+ }
+ else if (width) /* && ((pass == 0) || (pass == 1))) */
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width
+ sub edi, 21 // (png_pass_inc[pass] - 1)*pixel_bytes
+loop_pass0:
+ movd mm0, [esi] ; X X X X X v2 v1 v0
+ pand mm0, const4 ; 0 0 0 0 0 v2 v1 v0
+ movq mm1, mm0 ; 0 0 0 0 0 v2 v1 v0
+ psllq mm0, 16 ; 0 0 0 v2 v1 v0 0 0
+ movq mm2, mm0 ; 0 0 0 v2 v1 v0 0 0
+ psllq mm0, 24 ; v2 v1 v0 0 0 0 0 0
+ psrlq mm1, 8 ; 0 0 0 0 0 0 v2 v1
+ por mm0, mm2 ; v2 v1 v0 v2 v1 v0 0 0
+ por mm0, mm1 ; v2 v1 v0 v2 v1 v0 v2 v1
+ movq mm3, mm0 ; v2 v1 v0 v2 v1 v0 v2 v1
+ psllq mm0, 16 ; v0 v2 v1 v0 v2 v1 0 0
+ movq mm4, mm3 ; v2 v1 v0 v2 v1 v0 v2 v1
+ punpckhdq mm3, mm0 ; v0 v2 v1 v0 v2 v1 v0 v2
+ movq [edi+16] , mm4
+ psrlq mm0, 32 ; 0 0 0 0 v0 v2 v1 v0
+ movq [edi+8] , mm3
+ punpckldq mm0, mm4 ; v1 v0 v2 v1 v0 v2 v1 v0
+ sub esi, 3
+ movq [edi], mm0
+ sub edi, 24
+ //sub esi, 3
+ dec ecx
+ jnz loop_pass0
+ EMMS
+ }
+ }
+ } /* end of pixel_bytes == 3 */
+
+ else if (pixel_bytes == 1)
+ {
+ if (((pass == 4) || (pass == 5)) && width)
+ {
+ int width_mmx = ((width >> 3) << 3);
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub edi, 15
+ sub esi, 7
+loop1_pass4:
+ movq mm0, [esi] ; v0 v1 v2 v3 v4 v5 v6 v7
+ movq mm1, mm0 ; v0 v1 v2 v3 v4 v5 v6 v7
+ punpcklbw mm0, mm0 ; v4 v4 v5 v5 v6 v6 v7 v7
+ //movq mm1, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3
+ punpckhbw mm1, mm1 ;v0 v0 v1 v1 v2 v2 v3 v3
+ movq [edi+8], mm1 ; move to memory v0 v1 v2 and v3
+ sub esi, 8
+ movq [edi], mm0 ; move to memory v4 v5 v6 and v7
+ //sub esi, 4
+ sub edi, 16
+ sub ecx, 8
+ jnz loop1_pass4
+ EMMS
+ }
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*2;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ sptr --;
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 2) << 2);
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub edi, 15
+ sub esi, 3
+loop1_pass2:
+ movd mm0, [esi] ; X X X X v0 v1 v2 v3
+ punpcklbw mm0, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3
+ movq mm1, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3
+ punpcklwd mm0, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3
+ punpckhwd mm1, mm1 ; v0 v0 v0 v0 v1 v1 v1 v1
+ movq [edi], mm0 ; move to memory v2 and v3
+ sub esi, 4
+ movq [edi+8], mm1 ; move to memory v1 and v0
+ sub edi, 16
+ sub ecx, 4
+ jnz loop1_pass2
+ EMMS
+ }
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*4;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ *dp-- = *sptr;
+ }
+ sptr --;
+ }
+ }
+ else if (width) /* && ((pass == 0) || (pass == 1))) */
+ {
+ int width_mmx = ((width >> 2) << 2);
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub edi, 31
+ sub esi, 3
+loop1_pass0:
+ movd mm0, [esi] ; X X X X v0 v1 v2 v3
+ movq mm1, mm0 ; X X X X v0 v1 v2 v3
+ punpcklbw mm0, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3
+ movq mm2, mm0 ; v0 v0 v1 v1 v2 v2 v3 v3
+ punpcklwd mm0, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3
+ movq mm3, mm0 ; v2 v2 v2 v2 v3 v3 v3 v3
+ punpckldq mm0, mm0 ; v3 v3 v3 v3 v3 v3 v3 v3
+ punpckhdq mm3, mm3 ; v2 v2 v2 v2 v2 v2 v2 v2
+ movq [edi], mm0 ; move to memory v3
+ punpckhwd mm2, mm2 ; v0 v0 v0 v0 v1 v1 v1 v1
+ movq [edi+8], mm3 ; move to memory v2
+ movq mm4, mm2 ; v0 v0 v0 v0 v1 v1 v1 v1
+ punpckldq mm2, mm2 ; v1 v1 v1 v1 v1 v1 v1 v1
+ punpckhdq mm4, mm4 ; v0 v0 v0 v0 v0 v0 v0 v0
+ movq [edi+16], mm2 ; move to memory v1
+ movq [edi+24], mm4 ; move to memory v0
+ sub esi, 4
+ sub edi, 32
+ sub ecx, 4
+ jnz loop1_pass0
+ EMMS
+ }
+ }
+
+ sptr -= width_mmx;
+ dp -= width_mmx*8;
+ for (i = width; i; i--)
+ {
+ int j;
+
+ /* I simplified this part in version 1.0.4e
+ * here and in several other instances where
+ * pixel_bytes == 1 -- GR-P
+ *
+ * Original code:
+ *
+ * png_byte v[8];
+ * png_memcpy(v, sptr, pixel_bytes);
+ * for (j = 0; j < png_pass_inc[pass]; j++)
+ * {
+ * png_memcpy(dp, v, pixel_bytes);
+ * dp -= pixel_bytes;
+ * }
+ * sptr -= pixel_bytes;
+ *
+ * Replacement code is in the next three lines:
+ */
+
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ *dp-- = *sptr;
+ sptr--;
+ }
+ }
+ } /* end of pixel_bytes == 1 */
+
+ else if (pixel_bytes == 2)
+ {
+ if (((pass == 4) || (pass == 5)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 2
+ sub edi, 6
+loop2_pass4:
+ movd mm0, [esi] ; X X X X v1 v0 v3 v2
+ punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2
+ sub esi, 4
+ movq [edi], mm0
+ sub edi, 8
+ sub ecx, 2
+ jnz loop2_pass4
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*4 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 2
+ sub edi, 14
+loop2_pass2:
+ movd mm0, [esi] ; X X X X v1 v0 v3 v2
+ punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2
+ movq mm1, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2
+ punpckldq mm0, mm0 ; v3 v2 v3 v2 v3 v2 v3 v2
+ punpckhdq mm1, mm1 ; v1 v0 v1 v0 v1 v0 v1 v0
+ movq [edi], mm0
+ sub esi, 4
+ movq [edi + 8], mm1
+ //sub esi, 4
+ sub edi, 16
+ sub ecx, 2
+ jnz loop2_pass2
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*8 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ else if (width) /* && ((pass == 0) || (pass == 1))) */
+ {
+ int width_mmx = ((width >> 1) << 1);
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 2
+ sub edi, 30
+loop2_pass0:
+ movd mm0, [esi] ; X X X X v1 v0 v3 v2
+ punpcklwd mm0, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2
+ movq mm1, mm0 ; v1 v0 v1 v0 v3 v2 v3 v2
+ punpckldq mm0, mm0 ; v3 v2 v3 v2 v3 v2 v3 v2
+ punpckhdq mm1, mm1 ; v1 v0 v1 v0 v1 v0 v1 v0
+ movq [edi], mm0
+ movq [edi + 8], mm0
+ movq [edi + 16], mm1
+ movq [edi + 24], mm1
+ sub esi, 4
+ sub edi, 32
+ sub ecx, 2
+ jnz loop2_pass0
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*2 - 2); // sign fixed
+ dp -= (width_mmx*16 - 2); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 2;
+ png_memcpy(v, sptr, 2);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 2;
+ png_memcpy(dp, v, 2);
+ }
+ }
+ }
+ } /* end of pixel_bytes == 2 */
+
+ else if (pixel_bytes == 4)
+ {
+ if (((pass == 4) || (pass == 5)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 4
+ sub edi, 12
+loop4_pass4:
+ movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4
+ movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4
+ punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4
+ punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0
+ movq [edi], mm0
+ sub esi, 8
+ movq [edi + 8], mm1
+ sub edi, 16
+ sub ecx, 2
+ jnz loop4_pass4
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*8 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+ else if (((pass == 2) || (pass == 3)) && width)
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 4
+ sub edi, 28
+loop4_pass2:
+ movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4
+ movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4
+ punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4
+ punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0
+ movq [edi], mm0
+ movq [edi + 8], mm0
+ movq [edi+16], mm1
+ movq [edi + 24], mm1
+ sub esi, 8
+ sub edi, 32
+ sub ecx, 2
+ jnz loop4_pass2
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*16 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+ else if (width) /* && ((pass == 0) || (pass == 1))) */
+ {
+ int width_mmx = ((width >> 1) << 1) ;
+ width -= width_mmx;
+ if (width_mmx)
+ {
+ _asm
+ {
+ mov esi, sptr
+ mov edi, dp
+ mov ecx, width_mmx
+ sub esi, 4
+ sub edi, 60
+loop4_pass0:
+ movq mm0, [esi] ; v3 v2 v1 v0 v7 v6 v5 v4
+ movq mm1, mm0 ; v3 v2 v1 v0 v7 v6 v5 v4
+ punpckldq mm0, mm0 ; v7 v6 v5 v4 v7 v6 v5 v4
+ punpckhdq mm1, mm1 ; v3 v2 v1 v0 v3 v2 v1 v0
+ movq [edi], mm0
+ movq [edi + 8], mm0
+ movq [edi + 16], mm0
+ movq [edi + 24], mm0
+ movq [edi+32], mm1
+ movq [edi + 40], mm1
+ movq [edi+ 48], mm1
+ sub esi, 8
+ movq [edi + 56], mm1
+ sub edi, 64
+ sub ecx, 2
+ jnz loop4_pass0
+ EMMS
+ }
+ }
+
+ sptr -= (width_mmx*4 - 4); // sign fixed
+ dp -= (width_mmx*32 - 4); // sign fixed
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ sptr -= 4;
+ png_memcpy(v, sptr, 4);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ dp -= 4;
+ png_memcpy(dp, v, 4);
+ }
+ }
+ }
+
+ } /* end of pixel_bytes == 4 */
+
+ else if (pixel_bytes == 6)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, 6);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, 6);
+ dp -= 6;
+ }
+ sptr -= 6;
+ }
+ } /* end of pixel_bytes == 6 */
+
+ else
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr-= pixel_bytes;
+ }
+ }
+ } /* end of mmx_supported */
+
+ else /* MMX not supported: use modified C code - takes advantage
+ * of inlining of memcpy for a constant */
+ {
+ if (pixel_bytes == 1)
+ {
+ for (i = width; i; i--)
+ {
+ int j;
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ *dp-- = *sptr;
+ sptr--;
+ }
+ }
+ else if (pixel_bytes == 3)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+ else if (pixel_bytes == 2)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+ else if (pixel_bytes == 4)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+ else if (pixel_bytes == 6)
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+ else
+ {
+ for (i = width; i; i--)
+ {
+ png_byte v[8];
+ int j;
+ png_memcpy(v, sptr, pixel_bytes);
+ for (j = 0; j < png_pass_inc[pass]; j++)
+ {
+ png_memcpy(dp, v, pixel_bytes);
+ dp -= pixel_bytes;
+ }
+ sptr -= pixel_bytes;
+ }
+ }
+
+ } /* end of MMX not supported */
+ break;
+ }
+ } /* end switch (row_info->pixel_depth) */
+
+ row_info->width = final_width;
+
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,final_width);
+ }
+
+}
+
+#endif /* PNG_READ_INTERLACING_SUPPORTED */
+
+
+// These global constants are declared
+// here to ensure alignment on 8-byte boundaries.
+ union uAll {
+ __int64 use;
+ double double_align;
+ long long long_long_align;
+ } ;
+ static PNG_CONST union uAll LBCarryMask = {0x0101010101010101},
+ HBClearMask = {0x7f7f7f7f7f7f7f7f};
+
+// Optimized code for PNG Average filter decoder
+void /* PRIVATE */
+png_read_filter_row_mmx_avg(png_row_infop row_info, png_bytep row
+ , png_bytep prev_row)
+{
+ // These variables are declared
+ // here to ensure alignment on 8-byte boundaries.
+ union uAll ActiveMask, ShiftBpp, ShiftRem;
+
+ int bpp;
+ png_uint_32 FullLength;
+ png_uint_32 MMXLength;
+ //png_uint_32 len;
+ int diff;
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
+ FullLength = row_info->rowbytes; // # of bytes to filter
+ _asm {
+ // Init address pointers and offset
+ mov edi, row // edi ==> Avg(x)
+ xor ebx, ebx // ebx ==> x
+ mov edx, edi
+ mov esi, prev_row // esi ==> Prior(x)
+ sub edx, bpp // edx ==> Raw(x-bpp)
+
+ xor eax, eax
+ // Compute the Raw value for the first bpp bytes
+ // Raw(x) = Avg(x) + (Prior(x)/2)
+davgrlp:
+ mov al, [esi + ebx] // Load al with Prior(x)
+ inc ebx
+ shr al, 1 // divide by 2
+ add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx
+ cmp ebx, bpp
+ mov [edi+ebx-1], al // Write back Raw(x);
+ // mov does not affect flags; -1 to offset inc ebx
+ jb davgrlp
+ // get # of bytes to alignment
+ mov diff, edi // take start of row
+ add diff, ebx // add bpp
+ add diff, 0xf // add 7 + 8 to incr past alignment boundary
+ and diff, 0xfffffff8 // mask to alignment boundary
+ sub diff, edi // subtract from start ==> value ebx at alignment
+ jz davggo
+ // fix alignment
+ // Compute the Raw value for the bytes upto the alignment boundary
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ xor ecx, ecx
+davglp1:
+ xor eax, eax
+ mov cl, [esi + ebx] // load cl with Prior(x)
+ mov al, [edx + ebx] // load al with Raw(x-bpp)
+ add ax, cx
+ inc ebx
+ shr ax, 1 // divide by 2
+ add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx
+ cmp ebx, diff // Check if at alignment boundary
+ mov [edi+ebx-1], al // Write back Raw(x);
+ // mov does not affect flags; -1 to offset inc ebx
+ jb davglp1 // Repeat until at alignment boundary
+davggo:
+ mov eax, FullLength
+ mov ecx, eax
+ sub eax, ebx // subtract alignment fix
+ and eax, 0x00000007 // calc bytes over mult of 8
+ sub ecx, eax // drop over bytes from original length
+ mov MMXLength, ecx
+ } // end _asm block
+ // Now do the math for the rest of the row
+ switch ( bpp )
+ {
+ case 3:
+ {
+ ActiveMask.use = 0x0000000000ffffff;
+ ShiftBpp.use = 24; // == 3 * 8
+ ShiftRem.use = 40; // == 64 - 24
+ _asm {
+ // Re-init address pointers and offset
+ movq mm7, ActiveMask
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ movq mm5, LBCarryMask
+ mov edi, row // edi ==> Avg(x)
+ movq mm4, HBClearMask
+ mov esi, prev_row // esi ==> Prior(x)
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes
+ // (we correct position in loop below)
+davg3lp:
+ movq mm0, [edi + ebx] // Load mm0 with Avg(x)
+ // Add (Prev_row/2) to Average
+ movq mm3, mm5
+ psrlq mm2, ShiftRem // Correct position Raw(x-bpp) data
+ movq mm1, [esi + ebx] // Load mm1 with Prior(x)
+ movq mm6, mm7
+ pand mm3, mm1 // get lsb for each prev_row byte
+ psrlq mm1, 1 // divide prev_row bytes by 2
+ pand mm1, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte
+ // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 1 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active
+ // byte
+ // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry
+ psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 3-5
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active
+ // byte
+
+ // Add 3rd active group (Raw(x-bpp)/2) to Average with LBCarry
+ psllq mm6, ShiftBpp // shift the mm6 mask to cover the last two
+ // bytes
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ // Data only needs to be shifted once here to
+ // get the correct x-bpp offset.
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ add ebx, 8
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active
+ // byte
+
+ // Now ready to write back to memory
+ movq [edi + ebx - 8], mm0
+ // Move updated Raw(x) to use as Raw(x-bpp) for next loop
+ cmp ebx, MMXLength
+ movq mm2, mm0 // mov updated Raw(x) to mm2
+ jb davg3lp
+ } // end _asm block
+ }
+ break;
+
+ case 6:
+ case 4:
+ case 7:
+ case 5:
+ {
+ ActiveMask.use = 0xffffffffffffffff; // use shift below to clear
+ // appropriate inactive bytes
+ ShiftBpp.use = bpp << 3;
+ ShiftRem.use = 64 - ShiftBpp.use;
+ _asm {
+ movq mm4, HBClearMask
+ // Re-init address pointers and offset
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ // Load ActiveMask and clear all bytes except for 1st active group
+ movq mm7, ActiveMask
+ mov edi, row // edi ==> Avg(x)
+ psrlq mm7, ShiftRem
+ mov esi, prev_row // esi ==> Prior(x)
+ movq mm6, mm7
+ movq mm5, LBCarryMask
+ psllq mm6, ShiftBpp // Create mask for 2nd active group
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes
+ // (we correct position in loop below)
+davg4lp:
+ movq mm0, [edi + ebx]
+ psrlq mm2, ShiftRem // shift data to position correctly
+ movq mm1, [esi + ebx]
+ // Add (Prev_row/2) to Average
+ movq mm3, mm5
+ pand mm3, mm1 // get lsb for each prev_row byte
+ psrlq mm1, 1 // divide prev_row bytes by 2
+ pand mm1, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte
+ // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm7 // Leave only Active Group 1 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active
+ // byte
+ // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ add ebx, 8
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active
+ // byte
+ cmp ebx, MMXLength
+ // Now ready to write back to memory
+ movq [edi + ebx - 8], mm0
+ // Prep Raw(x-bpp) for next loop
+ movq mm2, mm0 // mov updated Raws to mm2
+ jb davg4lp
+ } // end _asm block
+ }
+ break;
+ case 2:
+ {
+ ActiveMask.use = 0x000000000000ffff;
+ ShiftBpp.use = 16; // == 2 * 8 [BUGFIX]
+ ShiftRem.use = 48; // == 64 - 16 [BUGFIX]
+ _asm {
+ // Load ActiveMask
+ movq mm7, ActiveMask
+ // Re-init address pointers and offset
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ movq mm5, LBCarryMask
+ mov edi, row // edi ==> Avg(x)
+ movq mm4, HBClearMask
+ mov esi, prev_row // esi ==> Prior(x)
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes
+ // (we correct position in loop below)
+davg2lp:
+ movq mm0, [edi + ebx]
+ psrlq mm2, ShiftRem // shift data to position correctly [BUGFIX]
+ movq mm1, [esi + ebx]
+ // Add (Prev_row/2) to Average
+ movq mm3, mm5
+ pand mm3, mm1 // get lsb for each prev_row byte
+ psrlq mm1, 1 // divide prev_row bytes by 2
+ pand mm1, mm4 // clear invalid bit 7 of each byte
+ movq mm6, mm7
+ paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte
+ // Add 1st active group (Raw(x-bpp)/2) to Average with LBCarry
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 1 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
+ // Add 2nd active group (Raw(x-bpp)/2) to Average with LBCarry
+ psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 2 & 3
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
+
+ // Add rdd active group (Raw(x-bpp)/2) to Average with LBCarry
+ psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 4 & 5
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ // Data only needs to be shifted once here to
+ // get the correct x-bpp offset.
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
+
+ // Add 4th active group (Raw(x-bpp)/2) to Average with LBCarry
+ psllq mm6, ShiftBpp // shift the mm6 mask to cover bytes 6 & 7
+ movq mm2, mm0 // mov updated Raws to mm2
+ psllq mm2, ShiftBpp // shift data to position correctly
+ // Data only needs to be shifted once here to
+ // get the correct x-bpp offset.
+ add ebx, 8
+ movq mm1, mm3 // now use mm1 for getting LBCarrys
+ pand mm1, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1 (Only valid for active group)
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm2, mm1 // add LBCarrys to (Raw(x-bpp)/2) for each byte
+ pand mm2, mm6 // Leave only Active Group 2 bytes to add to Avg
+ paddb mm0, mm2 // add (Raw/2) + LBCarrys to Avg for each Active byte
+
+ cmp ebx, MMXLength
+ // Now ready to write back to memory
+ movq [edi + ebx - 8], mm0
+ // Prep Raw(x-bpp) for next loop
+ movq mm2, mm0 // mov updated Raws to mm2
+ jb davg2lp
+ } // end _asm block
+ }
+ break;
+
+ case 1: // bpp == 1
+ {
+ _asm {
+ // Re-init address pointers and offset
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ mov edi, row // edi ==> Avg(x)
+ cmp ebx, FullLength // Test if offset at end of array
+ jnb davg1end
+ // Do Paeth decode for remaining bytes
+ mov esi, prev_row // esi ==> Prior(x)
+ mov edx, edi
+ xor ecx, ecx // zero ecx before using cl & cx in loop below
+ sub edx, bpp // edx ==> Raw(x-bpp)
+davg1lp:
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ xor eax, eax
+ mov cl, [esi + ebx] // load cl with Prior(x)
+ mov al, [edx + ebx] // load al with Raw(x-bpp)
+ add ax, cx
+ inc ebx
+ shr ax, 1 // divide by 2
+ add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx
+ cmp ebx, FullLength // Check if at end of array
+ mov [edi+ebx-1], al // Write back Raw(x);
+ // mov does not affect flags; -1 to offset inc ebx
+ jb davg1lp
+davg1end:
+ } // end _asm block
+ }
+ return;
+
+ case 8: // bpp == 8
+ {
+ _asm {
+ // Re-init address pointers and offset
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ movq mm5, LBCarryMask
+ mov edi, row // edi ==> Avg(x)
+ movq mm4, HBClearMask
+ mov esi, prev_row // esi ==> Prior(x)
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm2, [edi + ebx - 8] // Load previous aligned 8 bytes
+ // (NO NEED to correct position in loop below)
+davg8lp:
+ movq mm0, [edi + ebx]
+ movq mm3, mm5
+ movq mm1, [esi + ebx]
+ add ebx, 8
+ pand mm3, mm1 // get lsb for each prev_row byte
+ psrlq mm1, 1 // divide prev_row bytes by 2
+ pand mm3, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm1, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm3 // add LBCarrys to Avg for each byte
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte
+ paddb mm0, mm2 // add (Raw/2) to Avg for each byte
+ cmp ebx, MMXLength
+ movq [edi + ebx - 8], mm0
+ movq mm2, mm0 // reuse as Raw(x-bpp)
+ jb davg8lp
+ } // end _asm block
+ }
+ break;
+ default: // bpp greater than 8
+ {
+ _asm {
+ movq mm5, LBCarryMask
+ // Re-init address pointers and offset
+ mov ebx, diff // ebx ==> x = offset to alignment boundary
+ mov edi, row // edi ==> Avg(x)
+ movq mm4, HBClearMask
+ mov edx, edi
+ mov esi, prev_row // esi ==> Prior(x)
+ sub edx, bpp // edx ==> Raw(x-bpp)
+davgAlp:
+ movq mm0, [edi + ebx]
+ movq mm3, mm5
+ movq mm1, [esi + ebx]
+ pand mm3, mm1 // get lsb for each prev_row byte
+ movq mm2, [edx + ebx]
+ psrlq mm1, 1 // divide prev_row bytes by 2
+ pand mm3, mm2 // get LBCarrys for each byte where both
+ // lsb's were == 1
+ psrlq mm2, 1 // divide raw bytes by 2
+ pand mm1, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm3 // add LBCarrys to Avg for each byte
+ pand mm2, mm4 // clear invalid bit 7 of each byte
+ paddb mm0, mm1 // add (Prev_row/2) to Avg for each byte
+ add ebx, 8
+ paddb mm0, mm2 // add (Raw/2) to Avg for each byte
+ cmp ebx, MMXLength
+ movq [edi + ebx - 8], mm0
+ jb davgAlp
+ } // end _asm block
+ }
+ break;
+ } // end switch ( bpp )
+
+ _asm {
+ // MMX acceleration complete now do clean-up
+ // Check if any remaining bytes left to decode
+ mov ebx, MMXLength // ebx ==> x = offset bytes remaining after MMX
+ mov edi, row // edi ==> Avg(x)
+ cmp ebx, FullLength // Test if offset at end of array
+ jnb davgend
+ // Do Paeth decode for remaining bytes
+ mov esi, prev_row // esi ==> Prior(x)
+ mov edx, edi
+ xor ecx, ecx // zero ecx before using cl & cx in loop below
+ sub edx, bpp // edx ==> Raw(x-bpp)
+davglp2:
+ // Raw(x) = Avg(x) + ((Raw(x-bpp) + Prior(x))/2)
+ xor eax, eax
+ mov cl, [esi + ebx] // load cl with Prior(x)
+ mov al, [edx + ebx] // load al with Raw(x-bpp)
+ add ax, cx
+ inc ebx
+ shr ax, 1 // divide by 2
+ add al, [edi+ebx-1] // Add Avg(x); -1 to offset inc ebx
+ cmp ebx, FullLength // Check if at end of array
+ mov [edi+ebx-1], al // Write back Raw(x);
+ // mov does not affect flags; -1 to offset inc ebx
+ jb davglp2
+davgend:
+ emms // End MMX instructions; prep for possible FP instrs.
+ } // end _asm block
+}
+
+// Optimized code for PNG Paeth filter decoder
+void /* PRIVATE */
+png_read_filter_row_mmx_paeth(png_row_infop row_info, png_bytep row,
+ png_bytep prev_row)
+{
+ // These variables are declared
+ // here to ensure alignment on 8-byte boundaries.
+ union uAll ActiveMask, ActiveMask2, ActiveMaskEnd, ShiftBpp, ShiftRem;
+
+ png_uint_32 FullLength;
+ png_uint_32 MMXLength;
+ //png_uint_32 len;
+ int bpp;
+ int diff;
+ //int ptemp;
+ int patemp, pbtemp, pctemp;
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
+ FullLength = row_info->rowbytes; // # of bytes to filter
+ _asm
+ {
+ xor ebx, ebx // ebx ==> x offset
+ mov edi, row
+ xor edx, edx // edx ==> x-bpp offset
+ mov esi, prev_row
+ xor eax, eax
+
+ // Compute the Raw value for the first bpp bytes
+ // Note: the formula works out to be always
+ // Paeth(x) = Raw(x) + Prior(x) where x < bpp
+dpthrlp:
+ mov al, [edi + ebx]
+ add al, [esi + ebx]
+ inc ebx
+ cmp ebx, bpp
+ mov [edi + ebx - 1], al
+ jb dpthrlp
+ // get # of bytes to alignment
+ mov diff, edi // take start of row
+ add diff, ebx // add bpp
+ xor ecx, ecx
+ add diff, 0xf // add 7 + 8 to incr past alignment boundary
+ and diff, 0xfffffff8 // mask to alignment boundary
+ sub diff, edi // subtract from start ==> value ebx at alignment
+ jz dpthgo
+ // fix alignment
+dpthlp1:
+ xor eax, eax
+ // pav = p - a = (a + b - c) - a = b - c
+ mov al, [esi + ebx] // load Prior(x) into al
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov patemp, eax // Save pav for later use
+ xor eax, eax
+ // pbv = p - b = (a + b - c) - b = a - c
+ mov al, [edi + edx] // load Raw(x-bpp) into al
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov ecx, eax
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ add eax, patemp // pcv = pav + pbv
+ // pc = abs(pcv)
+ test eax, 0x80000000
+ jz dpthpca
+ neg eax // reverse sign of neg values
+dpthpca:
+ mov pctemp, eax // save pc for later use
+ // pb = abs(pbv)
+ test ecx, 0x80000000
+ jz dpthpba
+ neg ecx // reverse sign of neg values
+dpthpba:
+ mov pbtemp, ecx // save pb for later use
+ // pa = abs(pav)
+ mov eax, patemp
+ test eax, 0x80000000
+ jz dpthpaa
+ neg eax // reverse sign of neg values
+dpthpaa:
+ mov patemp, eax // save pa for later use
+ // test if pa <= pb
+ cmp eax, ecx
+ jna dpthabb
+ // pa > pb; now test if pb <= pc
+ cmp ecx, pctemp
+ jna dpthbbc
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthpaeth
+dpthbbc:
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ mov cl, [esi + ebx] // load Prior(x) into cl
+ jmp dpthpaeth
+dpthabb:
+ // pa <= pb; now test if pa <= pc
+ cmp eax, pctemp
+ jna dpthabc
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthpaeth
+dpthabc:
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ mov cl, [edi + edx] // load Raw(x-bpp) into cl
+dpthpaeth:
+ inc ebx
+ inc edx
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ add [edi + ebx - 1], cl
+ cmp ebx, diff
+ jb dpthlp1
+dpthgo:
+ mov ecx, FullLength
+ mov eax, ecx
+ sub eax, ebx // subtract alignment fix
+ and eax, 0x00000007 // calc bytes over mult of 8
+ sub ecx, eax // drop over bytes from original length
+ mov MMXLength, ecx
+ } // end _asm block
+ // Now do the math for the rest of the row
+ switch ( bpp )
+ {
+ case 3:
+ {
+ ActiveMask.use = 0x0000000000ffffff;
+ ActiveMaskEnd.use = 0xffff000000000000;
+ ShiftBpp.use = 24; // == bpp(3) * 8
+ ShiftRem.use = 40; // == 64 - 24
+ _asm
+ {
+ mov ebx, diff
+ mov edi, row
+ mov esi, prev_row
+ pxor mm0, mm0
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8]
+dpth3lp:
+ psrlq mm1, ShiftRem // shift last 3 bytes to 1st 3 bytes
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ punpcklbw mm1, mm0 // Unpack High bytes of a
+ movq mm3, [esi+ebx-8] // Prep c=Prior(x-bpp) bytes
+ punpcklbw mm2, mm0 // Unpack High bytes of b
+ psrlq mm3, ShiftRem // shift last 3 bytes to 1st 3 bytes
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ punpcklbw mm3, mm0 // Unpack High bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ paddw mm7, mm3
+ pxor mm0, mm0
+ packuswb mm7, mm1
+ movq mm3, [esi + ebx] // load c=Prior(x-bpp)
+ pand mm7, ActiveMask
+ movq mm2, mm3 // load b=Prior(x) step 1
+ paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x)
+ punpcklbw mm3, mm0 // Unpack High bytes of c
+ movq [edi + ebx], mm7 // write back updated value
+ movq mm1, mm7 // Now mm1 will be used as Raw(x-bpp)
+ // Now do Paeth for 2nd set of bytes (3-5)
+ psrlq mm2, ShiftBpp // load b=Prior(x) step 2
+ punpcklbw mm1, mm0 // Unpack High bytes of a
+ pxor mm7, mm7
+ punpcklbw mm2, mm0 // Unpack High bytes of b
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ psubw mm5, mm3
+ psubw mm4, mm3
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) =
+ // pav + pbv = pbv + pav
+ movq mm6, mm5
+ paddw mm6, mm4
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm5 // Create mask pbv bytes < 0
+ pcmpgtw mm7, mm4 // Create mask pav bytes < 0
+ pand mm0, mm5 // Only pbv bytes < 0 in mm0
+ pand mm7, mm4 // Only pav bytes < 0 in mm7
+ psubw mm5, mm0
+ psubw mm4, mm7
+ psubw mm5, mm0
+ psubw mm4, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ pand mm3, mm7
+ pandn mm7, mm0
+ pxor mm1, mm1
+ paddw mm7, mm3
+ pxor mm0, mm0
+ packuswb mm7, mm1
+ movq mm3, mm2 // load c=Prior(x-bpp) step 1
+ pand mm7, ActiveMask
+ punpckhbw mm2, mm0 // Unpack High bytes of b
+ psllq mm7, ShiftBpp // Shift bytes to 2nd group of 3 bytes
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x)
+ psllq mm3, ShiftBpp // load c=Prior(x-bpp) step 2
+ movq [edi + ebx], mm7 // write back updated value
+ movq mm1, mm7
+ punpckhbw mm3, mm0 // Unpack High bytes of c
+ psllq mm1, ShiftBpp // Shift bytes
+ // Now mm1 will be used as Raw(x-bpp)
+ // Now do Paeth for 3rd, and final, set of bytes (6-7)
+ pxor mm7, mm7
+ punpckhbw mm1, mm0 // Unpack High bytes of a
+ psubw mm4, mm3
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ pxor mm0, mm0
+ paddw mm6, mm5
+
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ pandn mm0, mm1
+ pandn mm7, mm4
+ paddw mm0, mm2
+ paddw mm7, mm5
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pand mm3, mm7
+ pandn mm7, mm0
+ paddw mm7, mm3
+ pxor mm1, mm1
+ packuswb mm1, mm7
+ // Step ebx to next set of 8 bytes and repeat loop til done
+ add ebx, 8
+ pand mm1, ActiveMaskEnd
+ paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x)
+
+ cmp ebx, MMXLength
+ pxor mm0, mm0 // pxor does not affect flags
+ movq [edi + ebx - 8], mm1 // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ // mm3 ready to be used as Prior(x-bpp) next loop
+ jb dpth3lp
+ } // end _asm block
+ }
+ break;
+
+ case 6:
+ case 7:
+ case 5:
+ {
+ ActiveMask.use = 0x00000000ffffffff;
+ ActiveMask2.use = 0xffffffff00000000;
+ ShiftBpp.use = bpp << 3; // == bpp * 8
+ ShiftRem.use = 64 - ShiftBpp.use;
+ _asm
+ {
+ mov ebx, diff
+ mov edi, row
+ mov esi, prev_row
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8]
+ pxor mm0, mm0
+dpth6lp:
+ // Must shift to position Raw(x-bpp) data
+ psrlq mm1, ShiftRem
+ // Do first set of 4 bytes
+ movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes
+ punpcklbw mm1, mm0 // Unpack Low bytes of a
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ punpcklbw mm2, mm0 // Unpack Low bytes of b
+ // Must shift to position Prior(x-bpp) data
+ psrlq mm3, ShiftRem
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ punpcklbw mm3, mm0 // Unpack Low bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ paddw mm7, mm3
+ pxor mm0, mm0
+ packuswb mm7, mm1
+ movq mm3, [esi + ebx - 8] // load c=Prior(x-bpp)
+ pand mm7, ActiveMask
+ psrlq mm3, ShiftRem
+ movq mm2, [esi + ebx] // load b=Prior(x) step 1
+ paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x)
+ movq mm6, mm2
+ movq [edi + ebx], mm7 // write back updated value
+ movq mm1, [edi+ebx-8]
+ psllq mm6, ShiftBpp
+ movq mm5, mm7
+ psrlq mm1, ShiftRem
+ por mm3, mm6
+ psllq mm5, ShiftBpp
+ punpckhbw mm3, mm0 // Unpack High bytes of c
+ por mm1, mm5
+ // Do second set of 4 bytes
+ punpckhbw mm2, mm0 // Unpack High bytes of b
+ punpckhbw mm1, mm0 // Unpack High bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ pxor mm1, mm1
+ paddw mm7, mm3
+ pxor mm0, mm0
+ // Step ex to next set of 8 bytes and repeat loop til done
+ add ebx, 8
+ packuswb mm1, mm7
+ paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x)
+ cmp ebx, MMXLength
+ movq [edi + ebx - 8], mm1 // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ jb dpth6lp
+ } // end _asm block
+ }
+ break;
+
+ case 4:
+ {
+ ActiveMask.use = 0x00000000ffffffff;
+ _asm {
+ mov ebx, diff
+ mov edi, row
+ mov esi, prev_row
+ pxor mm0, mm0
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8] // Only time should need to read
+ // a=Raw(x-bpp) bytes
+dpth4lp:
+ // Do first set of 4 bytes
+ movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes
+ punpckhbw mm1, mm0 // Unpack Low bytes of a
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ punpcklbw mm2, mm0 // Unpack High bytes of b
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ punpckhbw mm3, mm0 // Unpack High bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ paddw mm7, mm3
+ pxor mm0, mm0
+ packuswb mm7, mm1
+ movq mm3, [esi + ebx] // load c=Prior(x-bpp)
+ pand mm7, ActiveMask
+ movq mm2, mm3 // load b=Prior(x) step 1
+ paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x)
+ punpcklbw mm3, mm0 // Unpack High bytes of c
+ movq [edi + ebx], mm7 // write back updated value
+ movq mm1, mm7 // Now mm1 will be used as Raw(x-bpp)
+ // Do second set of 4 bytes
+ punpckhbw mm2, mm0 // Unpack Low bytes of b
+ punpcklbw mm1, mm0 // Unpack Low bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ pxor mm1, mm1
+ paddw mm7, mm3
+ pxor mm0, mm0
+ // Step ex to next set of 8 bytes and repeat loop til done
+ add ebx, 8
+ packuswb mm1, mm7
+ paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x)
+ cmp ebx, MMXLength
+ movq [edi + ebx - 8], mm1 // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ jb dpth4lp
+ } // end _asm block
+ }
+ break;
+ case 8: // bpp == 8
+ {
+ ActiveMask.use = 0x00000000ffffffff;
+ _asm {
+ mov ebx, diff
+ mov edi, row
+ mov esi, prev_row
+ pxor mm0, mm0
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8] // Only time should need to read
+ // a=Raw(x-bpp) bytes
+dpth8lp:
+ // Do first set of 4 bytes
+ movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes
+ punpcklbw mm1, mm0 // Unpack Low bytes of a
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ punpcklbw mm2, mm0 // Unpack Low bytes of b
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ punpcklbw mm3, mm0 // Unpack Low bytes of c
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ paddw mm7, mm3
+ pxor mm0, mm0
+ packuswb mm7, mm1
+ movq mm3, [esi+ebx-8] // read c=Prior(x-bpp) bytes
+ pand mm7, ActiveMask
+ movq mm2, [esi + ebx] // load b=Prior(x)
+ paddb mm7, [edi + ebx] // add Paeth predictor with Raw(x)
+ punpckhbw mm3, mm0 // Unpack High bytes of c
+ movq [edi + ebx], mm7 // write back updated value
+ movq mm1, [edi+ebx-8] // read a=Raw(x-bpp) bytes
+
+ // Do second set of 4 bytes
+ punpckhbw mm2, mm0 // Unpack High bytes of b
+ punpckhbw mm1, mm0 // Unpack High bytes of a
+ // pav = p - a = (a + b - c) - a = b - c
+ movq mm4, mm2
+ // pbv = p - b = (a + b - c) - b = a - c
+ movq mm5, mm1
+ psubw mm4, mm3
+ pxor mm7, mm7
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ movq mm6, mm4
+ psubw mm5, mm3
+ // pa = abs(p-a) = abs(pav)
+ // pb = abs(p-b) = abs(pbv)
+ // pc = abs(p-c) = abs(pcv)
+ pcmpgtw mm0, mm4 // Create mask pav bytes < 0
+ paddw mm6, mm5
+ pand mm0, mm4 // Only pav bytes < 0 in mm7
+ pcmpgtw mm7, mm5 // Create mask pbv bytes < 0
+ psubw mm4, mm0
+ pand mm7, mm5 // Only pbv bytes < 0 in mm0
+ psubw mm4, mm0
+ psubw mm5, mm7
+ pxor mm0, mm0
+ pcmpgtw mm0, mm6 // Create mask pcv bytes < 0
+ pand mm0, mm6 // Only pav bytes < 0 in mm7
+ psubw mm5, mm7
+ psubw mm6, mm0
+ // test pa <= pb
+ movq mm7, mm4
+ psubw mm6, mm0
+ pcmpgtw mm7, mm5 // pa > pb?
+ movq mm0, mm7
+ // use mm7 mask to merge pa & pb
+ pand mm5, mm7
+ // use mm0 mask copy to merge a & b
+ pand mm2, mm0
+ pandn mm7, mm4
+ pandn mm0, mm1
+ paddw mm7, mm5
+ paddw mm0, mm2
+ // test ((pa <= pb)? pa:pb) <= pc
+ pcmpgtw mm7, mm6 // pab > pc?
+ pxor mm1, mm1
+ pand mm3, mm7
+ pandn mm7, mm0
+ pxor mm1, mm1
+ paddw mm7, mm3
+ pxor mm0, mm0
+ // Step ex to next set of 8 bytes and repeat loop til done
+ add ebx, 8
+ packuswb mm1, mm7
+ paddb mm1, [edi + ebx - 8] // add Paeth predictor with Raw(x)
+ cmp ebx, MMXLength
+ movq [edi + ebx - 8], mm1 // write back updated value
+ // mm1 will be used as Raw(x-bpp) next loop
+ jb dpth8lp
+ } // end _asm block
+ }
+ break;
+
+ case 1: // bpp = 1
+ case 2: // bpp = 2
+ default: // bpp > 8
+ {
+ _asm {
+ mov ebx, diff
+ cmp ebx, FullLength
+ jnb dpthdend
+ mov edi, row
+ mov esi, prev_row
+ // Do Paeth decode for remaining bytes
+ mov edx, ebx
+ xor ecx, ecx // zero ecx before using cl & cx in loop below
+ sub edx, bpp // Set edx = ebx - bpp
+dpthdlp:
+ xor eax, eax
+ // pav = p - a = (a + b - c) - a = b - c
+ mov al, [esi + ebx] // load Prior(x) into al
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov patemp, eax // Save pav for later use
+ xor eax, eax
+ // pbv = p - b = (a + b - c) - b = a - c
+ mov al, [edi + edx] // load Raw(x-bpp) into al
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov ecx, eax
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ add eax, patemp // pcv = pav + pbv
+ // pc = abs(pcv)
+ test eax, 0x80000000
+ jz dpthdpca
+ neg eax // reverse sign of neg values
+dpthdpca:
+ mov pctemp, eax // save pc for later use
+ // pb = abs(pbv)
+ test ecx, 0x80000000
+ jz dpthdpba
+ neg ecx // reverse sign of neg values
+dpthdpba:
+ mov pbtemp, ecx // save pb for later use
+ // pa = abs(pav)
+ mov eax, patemp
+ test eax, 0x80000000
+ jz dpthdpaa
+ neg eax // reverse sign of neg values
+dpthdpaa:
+ mov patemp, eax // save pa for later use
+ // test if pa <= pb
+ cmp eax, ecx
+ jna dpthdabb
+ // pa > pb; now test if pb <= pc
+ cmp ecx, pctemp
+ jna dpthdbbc
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthdpaeth
+dpthdbbc:
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ mov cl, [esi + ebx] // load Prior(x) into cl
+ jmp dpthdpaeth
+dpthdabb:
+ // pa <= pb; now test if pa <= pc
+ cmp eax, pctemp
+ jna dpthdabc
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthdpaeth
+dpthdabc:
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ mov cl, [edi + edx] // load Raw(x-bpp) into cl
+dpthdpaeth:
+ inc ebx
+ inc edx
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ add [edi + ebx - 1], cl
+ cmp ebx, FullLength
+ jb dpthdlp
+dpthdend:
+ } // end _asm block
+ }
+ return; // No need to go further with this one
+ } // end switch ( bpp )
+ _asm
+ {
+ // MMX acceleration complete now do clean-up
+ // Check if any remaining bytes left to decode
+ mov ebx, MMXLength
+ cmp ebx, FullLength
+ jnb dpthend
+ mov edi, row
+ mov esi, prev_row
+ // Do Paeth decode for remaining bytes
+ mov edx, ebx
+ xor ecx, ecx // zero ecx before using cl & cx in loop below
+ sub edx, bpp // Set edx = ebx - bpp
+dpthlp2:
+ xor eax, eax
+ // pav = p - a = (a + b - c) - a = b - c
+ mov al, [esi + ebx] // load Prior(x) into al
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov patemp, eax // Save pav for later use
+ xor eax, eax
+ // pbv = p - b = (a + b - c) - b = a - c
+ mov al, [edi + edx] // load Raw(x-bpp) into al
+ sub eax, ecx // subtract Prior(x-bpp)
+ mov ecx, eax
+ // pcv = p - c = (a + b - c) -c = (a - c) + (b - c) = pav + pbv
+ add eax, patemp // pcv = pav + pbv
+ // pc = abs(pcv)
+ test eax, 0x80000000
+ jz dpthpca2
+ neg eax // reverse sign of neg values
+dpthpca2:
+ mov pctemp, eax // save pc for later use
+ // pb = abs(pbv)
+ test ecx, 0x80000000
+ jz dpthpba2
+ neg ecx // reverse sign of neg values
+dpthpba2:
+ mov pbtemp, ecx // save pb for later use
+ // pa = abs(pav)
+ mov eax, patemp
+ test eax, 0x80000000
+ jz dpthpaa2
+ neg eax // reverse sign of neg values
+dpthpaa2:
+ mov patemp, eax // save pa for later use
+ // test if pa <= pb
+ cmp eax, ecx
+ jna dpthabb2
+ // pa > pb; now test if pb <= pc
+ cmp ecx, pctemp
+ jna dpthbbc2
+ // pb > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthpaeth2
+dpthbbc2:
+ // pb <= pc; Raw(x) = Paeth(x) + Prior(x)
+ mov cl, [esi + ebx] // load Prior(x) into cl
+ jmp dpthpaeth2
+dpthabb2:
+ // pa <= pb; now test if pa <= pc
+ cmp eax, pctemp
+ jna dpthabc2
+ // pa > pc; Raw(x) = Paeth(x) + Prior(x-bpp)
+ mov cl, [esi + edx] // load Prior(x-bpp) into cl
+ jmp dpthpaeth2
+dpthabc2:
+ // pa <= pc; Raw(x) = Paeth(x) + Raw(x-bpp)
+ mov cl, [edi + edx] // load Raw(x-bpp) into cl
+dpthpaeth2:
+ inc ebx
+ inc edx
+ // Raw(x) = (Paeth(x) + Paeth_Predictor( a, b, c )) mod 256
+ add [edi + ebx - 1], cl
+ cmp ebx, FullLength
+ jb dpthlp2
+dpthend:
+ emms // End MMX instructions; prep for possible FP instrs.
+ } // end _asm block
+}
+
+// Optimized code for PNG Sub filter decoder
+void /* PRIVATE */
+png_read_filter_row_mmx_sub(png_row_infop row_info, png_bytep row)
+{
+ // These variables are declared
+ // here to ensure alignment on 8-byte boundaries.
+ union uAll ActiveMask, ShiftBpp, ShiftRem;
+
+ //int test;
+ int bpp;
+ png_uint_32 FullLength;
+ png_uint_32 MMXLength;
+ int diff;
+
+ bpp = (row_info->pixel_depth + 7) >> 3; // Get # bytes per pixel
+ FullLength = row_info->rowbytes - bpp; // # of bytes to filter
+ _asm {
+ mov edi, row
+ mov esi, edi // lp = row
+ add edi, bpp // rp = row + bpp
+ xor eax, eax
+ // get # of bytes to alignment
+ mov diff, edi // take start of row
+ add diff, 0xf // add 7 + 8 to incr past
+ // alignment boundary
+ xor ebx, ebx
+ and diff, 0xfffffff8 // mask to alignment boundary
+ sub diff, edi // subtract from start ==> value
+ // ebx at alignment
+ jz dsubgo
+ // fix alignment
+dsublp1:
+ mov al, [esi+ebx]
+ add [edi+ebx], al
+ inc ebx
+ cmp ebx, diff
+ jb dsublp1
+dsubgo:
+ mov ecx, FullLength
+ mov edx, ecx
+ sub edx, ebx // subtract alignment fix
+ and edx, 0x00000007 // calc bytes over mult of 8
+ sub ecx, edx // drop over bytes from length
+ mov MMXLength, ecx
+ } // end _asm block
+
+ // Now do the math for the rest of the row
+ switch ( bpp )
+ {
+ case 3:
+ {
+ ActiveMask.use = 0x0000ffffff000000;
+ ShiftBpp.use = 24; // == 3 * 8
+ ShiftRem.use = 40; // == 64 - 24
+ _asm {
+ mov edi, row
+ movq mm7, ActiveMask // Load ActiveMask for 2nd active byte group
+ mov esi, edi // lp = row
+ add edi, bpp // rp = row + bpp
+ movq mm6, mm7
+ mov ebx, diff
+ psllq mm6, ShiftBpp // Move mask in mm6 to cover 3rd active
+ // byte group
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8]
+dsub3lp:
+ psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes
+ // no need for mask; shift clears inactive bytes
+ // Add 1st active group
+ movq mm0, [edi+ebx]
+ paddb mm0, mm1
+ // Add 2nd active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ pand mm1, mm7 // mask to use only 2nd active group
+ paddb mm0, mm1
+ // Add 3rd active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ pand mm1, mm6 // mask to use only 3rd active group
+ add ebx, 8
+ paddb mm0, mm1
+ cmp ebx, MMXLength
+ movq [edi+ebx-8], mm0 // Write updated Raws back to array
+ // Prep for doing 1st add at top of loop
+ movq mm1, mm0
+ jb dsub3lp
+ } // end _asm block
+ }
+ break;
+
+ case 1:
+ {
+ // Placed here just in case this is a duplicate of the
+ // non-MMX code for the SUB filter in png_read_filter_row below
+ //
+ // png_bytep rp;
+ // png_bytep lp;
+ // png_uint_32 i;
+ // bpp = (row_info->pixel_depth + 7) >> 3;
+ // for (i = (png_uint_32)bpp, rp = row + bpp, lp = row;
+ // i < row_info->rowbytes; i++, rp++, lp++)
+ // {
+ // *rp = (png_byte)(((int)(*rp) + (int)(*lp)) & 0xff);
+ // }
+ _asm {
+ mov ebx, diff
+ mov edi, row
+ cmp ebx, FullLength
+ jnb dsub1end
+ mov esi, edi // lp = row
+ xor eax, eax
+ add edi, bpp // rp = row + bpp
+dsub1lp:
+ mov al, [esi+ebx]
+ add [edi+ebx], al
+ inc ebx
+ cmp ebx, FullLength
+ jb dsub1lp
+dsub1end:
+ } // end _asm block
+ }
+ return;
+
+ case 6:
+ case 7:
+ case 4:
+ case 5:
+ {
+ ShiftBpp.use = bpp << 3;
+ ShiftRem.use = 64 - ShiftBpp.use;
+ _asm {
+ mov edi, row
+ mov ebx, diff
+ mov esi, edi // lp = row
+ add edi, bpp // rp = row + bpp
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8]
+dsub4lp:
+ psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes
+ // no need for mask; shift clears inactive bytes
+ movq mm0, [edi+ebx]
+ paddb mm0, mm1
+ // Add 2nd active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ // there is no need for any mask
+ // since shift clears inactive bits/bytes
+ add ebx, 8
+ paddb mm0, mm1
+ cmp ebx, MMXLength
+ movq [edi+ebx-8], mm0
+ movq mm1, mm0 // Prep for doing 1st add at top of loop
+ jb dsub4lp
+ } // end _asm block
+ }
+ break;
+
+ case 2:
+ {
+ ActiveMask.use = 0x00000000ffff0000;
+ ShiftBpp.use = 16; // == 2 * 8
+ ShiftRem.use = 48; // == 64 - 16
+ _asm {
+ movq mm7, ActiveMask // Load ActiveMask for 2nd active byte group
+ mov ebx, diff
+ movq mm6, mm7
+ mov edi, row
+ psllq mm6, ShiftBpp // Move mask in mm6 to cover 3rd active
+ // byte group
+ mov esi, edi // lp = row
+ movq mm5, mm6
+ add edi, bpp // rp = row + bpp
+ psllq mm5, ShiftBpp // Move mask in mm5 to cover 4th active
+ // byte group
+ // PRIME the pump (load the first Raw(x-bpp) data set
+ movq mm1, [edi+ebx-8]
+dsub2lp:
+ // Add 1st active group
+ psrlq mm1, ShiftRem // Shift data for adding 1st bpp bytes
+ // no need for mask; shift clears inactive
+ // bytes
+ movq mm0, [edi+ebx]
+ paddb mm0, mm1
+ // Add 2nd active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ pand mm1, mm7 // mask to use only 2nd active group
+ paddb mm0, mm1
+ // Add 3rd active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ pand mm1, mm6 // mask to use only 3rd active group
+ paddb mm0, mm1
+ // Add 4th active group
+ movq mm1, mm0 // mov updated Raws to mm1
+ psllq mm1, ShiftBpp // shift data to position correctly
+ pand mm1, mm5 // mask to use only 4th active group
+ add ebx, 8
+ paddb mm0, mm1
+ cmp ebx, MMXLength
+ movq [edi+ebx-8], mm0 // Write updated Raws back to array
+ movq mm1, mm0 // Prep for doing 1st add at top of loop
+ jb dsub2lp
+ } // end _asm block
+ }
+ break;
+ case 8:
+ {
+ _asm {
+ mov edi, row
+ mov ebx, diff
+ mov esi, edi // lp = row
+ add edi, bpp // rp = row + bpp
+ mov ecx, MMXLength
+ movq mm7, [edi+ebx-8] // PRIME the pump (load the first
+ // Raw(x-bpp) data set
+ and ecx, 0x0000003f // calc bytes over mult of 64
+dsub8lp:
+ movq mm0, [edi+ebx] // Load Sub(x) for 1st 8 bytes
+ paddb mm0, mm7
+ movq mm1, [edi+ebx+8] // Load Sub(x) for 2nd 8 bytes
+ movq [edi+ebx], mm0 // Write Raw(x) for 1st 8 bytes
+ // Now mm0 will be used as Raw(x-bpp) for
+ // the 2nd group of 8 bytes. This will be
+ // repeated for each group of 8 bytes with
+ // the 8th group being used as the Raw(x-bpp)
+ // for the 1st group of the next loop.
+ paddb mm1, mm0
+ movq mm2, [edi+ebx+16] // Load Sub(x) for 3rd 8 bytes
+ movq [edi+ebx+8], mm1 // Write Raw(x) for 2nd 8 bytes
+ paddb mm2, mm1
+ movq mm3, [edi+ebx+24] // Load Sub(x) for 4th 8 bytes
+ movq [edi+ebx+16], mm2 // Write Raw(x) for 3rd 8 bytes
+ paddb mm3, mm2
+ movq mm4, [edi+ebx+32] // Load Sub(x) for 5th 8 bytes
+ movq [edi+ebx+24], mm3 // Write Raw(x) for 4th 8 bytes
+ paddb mm4, mm3
+ movq mm5, [edi+ebx+40] // Load Sub(x) for 6th 8 bytes
+ movq [edi+ebx+32], mm4 // Write Raw(x) for 5th 8 bytes
+ paddb mm5, mm4
+ movq mm6, [edi+ebx+48] // Load Sub(x) for 7th 8 bytes
+ movq [edi+ebx+40], mm5 // Write Raw(x) for 6th 8 bytes
+ paddb mm6, mm5
+ movq mm7, [edi+ebx+56] // Load Sub(x) for 8th 8 bytes
+ movq [edi+ebx+48], mm6 // Write Raw(x) for 7th 8 bytes
+ add ebx, 64
+ paddb mm7, mm6
+ cmp ebx, ecx
+ movq [edi+ebx-8], mm7 // Write Raw(x) for 8th 8 bytes
+ jb dsub8lp
+ cmp ebx, MMXLength
+ jnb dsub8lt8
+dsub8lpA:
+ movq mm0, [edi+ebx]
+ add ebx, 8
+ paddb mm0, mm7
+ cmp ebx, MMXLength
+ movq [edi+ebx-8], mm0 // use -8 to offset early add to ebx
+ movq mm7, mm0 // Move calculated Raw(x) data to mm1 to
+ // be the new Raw(x-bpp) for the next loop
+ jb dsub8lpA
+dsub8lt8:
+ } // end _asm block
+ }
+ break;
+
+ default: // bpp greater than 8 bytes
+ {
+ _asm {
+ mov ebx, diff
+ mov edi, row
+ mov esi, edi // lp = row
+ add edi, bpp // rp = row + bpp
+dsubAlp:
+ movq mm0, [edi+ebx]
+ movq mm1, [esi+ebx]
+ add ebx, 8
+ paddb mm0, mm1
+ cmp ebx, MMXLength
+ movq [edi+ebx-8], mm0 // mov does not affect flags; -8 to offset
+ // add ebx
+ jb dsubAlp
+ } // end _asm block
+ }
+ break;
+
+ } // end switch ( bpp )
+
+ _asm {
+ mov ebx, MMXLength
+ mov edi, row
+ cmp ebx, FullLength
+ jnb dsubend
+ mov esi, edi // lp = row
+ xor eax, eax
+ add edi, bpp // rp = row + bpp
+dsublp2:
+ mov al, [esi+ebx]
+ add [edi+ebx], al
+ inc ebx
+ cmp ebx, FullLength
+ jb dsublp2
+dsubend:
+ emms // End MMX instructions; prep for possible FP instrs.
+ } // end _asm block
+}
+
+// Optimized code for PNG Up filter decoder
+void /* PRIVATE */
+png_read_filter_row_mmx_up(png_row_infop row_info, png_bytep row,
+ png_bytep prev_row)
+{
+ png_uint_32 len;
+ len = row_info->rowbytes; // # of bytes to filter
+ _asm {
+ mov edi, row
+ // get # of bytes to alignment
+ mov ecx, edi
+ xor ebx, ebx
+ add ecx, 0x7
+ xor eax, eax
+ and ecx, 0xfffffff8
+ mov esi, prev_row
+ sub ecx, edi
+ jz dupgo
+ // fix alignment
+duplp1:
+ mov al, [edi+ebx]
+ add al, [esi+ebx]
+ inc ebx
+ cmp ebx, ecx
+ mov [edi + ebx-1], al // mov does not affect flags; -1 to offset inc ebx
+ jb duplp1
+dupgo:
+ mov ecx, len
+ mov edx, ecx
+ sub edx, ebx // subtract alignment fix
+ and edx, 0x0000003f // calc bytes over mult of 64
+ sub ecx, edx // drop over bytes from length
+ // Unrolled loop - use all MMX registers and interleave to reduce
+ // number of branch instructions (loops) and reduce partial stalls
+duploop:
+ movq mm1, [esi+ebx]
+ movq mm0, [edi+ebx]
+ movq mm3, [esi+ebx+8]
+ paddb mm0, mm1
+ movq mm2, [edi+ebx+8]
+ movq [edi+ebx], mm0
+ paddb mm2, mm3
+ movq mm5, [esi+ebx+16]
+ movq [edi+ebx+8], mm2
+ movq mm4, [edi+ebx+16]
+ movq mm7, [esi+ebx+24]
+ paddb mm4, mm5
+ movq mm6, [edi+ebx+24]
+ movq [edi+ebx+16], mm4
+ paddb mm6, mm7
+ movq mm1, [esi+ebx+32]
+ movq [edi+ebx+24], mm6
+ movq mm0, [edi+ebx+32]
+ movq mm3, [esi+ebx+40]
+ paddb mm0, mm1
+ movq mm2, [edi+ebx+40]
+ movq [edi+ebx+32], mm0
+ paddb mm2, mm3
+ movq mm5, [esi+ebx+48]
+ movq [edi+ebx+40], mm2
+ movq mm4, [edi+ebx+48]
+ movq mm7, [esi+ebx+56]
+ paddb mm4, mm5
+ movq mm6, [edi+ebx+56]
+ movq [edi+ebx+48], mm4
+ add ebx, 64
+ paddb mm6, mm7
+ cmp ebx, ecx
+ movq [edi+ebx-8], mm6 // (+56)movq does not affect flags;
+ // -8 to offset add ebx
+ jb duploop
+
+ cmp edx, 0 // Test for bytes over mult of 64
+ jz dupend
+
+
+ // 2 lines added by lcreeve at netins.net
+ // (mail 11 Jul 98 in png-implement list)
+ cmp edx, 8 //test for less than 8 bytes
+ jb duplt8
+
+
+ add ecx, edx
+ and edx, 0x00000007 // calc bytes over mult of 8
+ sub ecx, edx // drop over bytes from length
+ jz duplt8
+ // Loop using MMX registers mm0 & mm1 to update 8 bytes simultaneously
+duplpA:
+ movq mm1, [esi+ebx]
+ movq mm0, [edi+ebx]
+ add ebx, 8
+ paddb mm0, mm1
+ cmp ebx, ecx
+ movq [edi+ebx-8], mm0 // movq does not affect flags; -8 to offset add ebx
+ jb duplpA
+ cmp edx, 0 // Test for bytes over mult of 8
+ jz dupend
+duplt8:
+ xor eax, eax
+ add ecx, edx // move over byte count into counter
+ // Loop using x86 registers to update remaining bytes
+duplp2:
+ mov al, [edi + ebx]
+ add al, [esi + ebx]
+ inc ebx
+ cmp ebx, ecx
+ mov [edi + ebx-1], al // mov does not affect flags; -1 to offset inc ebx
+ jb duplp2
+dupend:
+ // Conversion of filtered row completed
+ emms // End MMX instructions; prep for possible FP instrs.
+ } // end _asm block
+}
+
+
+// Optimized png_read_filter_row routines
+void /* PRIVATE */
+png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep
+ row, png_bytep prev_row, int filter)
+{
+#ifdef PNG_DEBUG
+ char filnm[10];
+#endif
+
+ if (mmx_supported == 2) {
+#if !defined(PNG_1_0_X)
+ /* this should have happened in png_init_mmx_flags() already */
+ png_warning(png_ptr, "asm_flags may not have been initialized");
+#endif
+ png_mmx_support();
+ }
+
+#ifdef PNG_DEBUG
+ png_debug(1, "in png_read_filter_row\n");
+ switch (filter)
+ {
+ case 0: png_snprintf(filnm, 10, "none");
+ break;
+#if !defined(PNG_1_0_X)
+ case 1: png_snprintf(filnm, 10, "sub-%s",
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB)? "MMX" : "x86");
+ break;
+ case 2: png_snprintf(filnm, 10, "up-%s",
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP)? "MMX" : "x86");
+ break;
+ case 3: png_snprintf(filnm, 10, "avg-%s",
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG)? "MMX" : "x86");
+ break;
+ case 4: png_snprintf(filnm, 10, "Paeth-%s",
+ (png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH)? "MMX":"x86");
+ break;
+#else
+ case 1: png_snprintf(filnm, 10, "sub");
+ break;
+ case 2: png_snprintf(filnm, 10, "up");
+ break;
+ case 3: png_snprintf(filnm, 10, "avg");
+ break;
+ case 4: png_snprintf(filnm, 10, "Paeth");
+ break;
+#endif
+ default: png_snprintf(filnm, 10, "unknw");
+ break;
+ }
+ png_debug2(0,"row=%5d, %s, ", png_ptr->row_number, filnm);
+ png_debug2(0, "pd=%2d, b=%d, ", (int)row_info->pixel_depth,
+ (int)((row_info->pixel_depth + 7) >> 3));
+ png_debug1(0,"len=%8d, ", row_info->rowbytes);
+#endif /* PNG_DEBUG */
+
+ switch (filter)
+ {
+ case PNG_FILTER_VALUE_NONE:
+ break;
+
+ case PNG_FILTER_VALUE_SUB:
+ {
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_SUB) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ if (mmx_supported)
+#endif
+ {
+ png_read_filter_row_mmx_sub(row_info, row);
+ }
+ else
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_bytep rp = row + bpp;
+ png_bytep lp = row;
+
+ for (i = bpp; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff);
+ rp++;
+ }
+ }
+ break;
+ }
+
+ case PNG_FILTER_VALUE_UP:
+ {
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_UP) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ if (mmx_supported)
+#endif
+ {
+ png_read_filter_row_mmx_up(row_info, row, prev_row);
+ }
+ else
+ {
+ png_uint_32 i;
+ png_uint_32 istop = row_info->rowbytes;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+
+ for (i = 0; i < istop; ++i)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+ }
+ break;
+ }
+
+ case PNG_FILTER_VALUE_AVG:
+ {
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_AVG) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ if (mmx_supported)
+#endif
+ {
+ png_read_filter_row_mmx_avg(row_info, row, prev_row);
+ }
+ else
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop = row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++) >> 1)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) +
+ ((int)(*pp++ + *lp++) >> 1)) & 0xff);
+ rp++;
+ }
+ }
+ break;
+ }
+
+ case PNG_FILTER_VALUE_PAETH:
+ {
+#if !defined(PNG_1_0_X)
+ if ((png_ptr->asm_flags & PNG_ASM_FLAG_MMX_READ_FILTER_PAETH) &&
+ (row_info->pixel_depth >= png_ptr->mmx_bitdepth_threshold) &&
+ (row_info->rowbytes >= png_ptr->mmx_rowbytes_threshold))
+#else
+ if (mmx_supported)
+#endif
+ {
+ png_read_filter_row_mmx_paeth(row_info, row, prev_row);
+ }
+ else
+ {
+ png_uint_32 i;
+ png_bytep rp = row;
+ png_bytep pp = prev_row;
+ png_bytep lp = row;
+ png_bytep cp = prev_row;
+ png_uint_32 bpp = (row_info->pixel_depth + 7) >> 3;
+ png_uint_32 istop=row_info->rowbytes - bpp;
+
+ for (i = 0; i < bpp; i++)
+ {
+ *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff);
+ rp++;
+ }
+
+ for (i = 0; i < istop; i++) // use leftover rp,pp
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ a = *lp++;
+ b = *pp++;
+ c = *cp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ /*
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+ */
+
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+ *rp = (png_byte)(((int)(*rp) + p) & 0xff);
+ rp++;
+ }
+ }
+ break;
+ }
+
+ default:
+ png_warning(png_ptr, "Ignoring bad row filter type");
+ *row=0;
+ break;
+ }
+}
+
+#endif /* PNG_MMX_CODE_SUPPORTED && PNG_USE_PNGVCRD */
diff --git a/distrib/libpng-1.2.19/pngwio.c b/distrib/libpng-1.2.19/pngwio.c
new file mode 100644
index 0000000..371a4fa
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngwio.c
@@ -0,0 +1,234 @@
+
+/* pngwio.c - functions for data output
+ *
+ * Last changed in libpng 1.2.13 November 13, 2006
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2006 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ *
+ * This file provides a location for all output. Users who need
+ * special handling are expected to write functions that have the same
+ * arguments as these and perform similar functions, but that possibly
+ * use different output methods. Note that you shouldn't change these
+ * functions, but rather write replacement functions and then change
+ * them at run time with png_set_write_fn(...).
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+#ifdef PNG_WRITE_SUPPORTED
+
+/* Write the data to whatever output you are using. The default routine
+ writes to a file pointer. Note that this routine sometimes gets called
+ with very small lengths, so you should implement some kind of simple
+ buffering if you are using unbuffered writes. This should never be asked
+ to write more than 64K on a 16 bit machine. */
+
+void /* PRIVATE */
+png_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ if (png_ptr->write_data_fn != NULL )
+ (*(png_ptr->write_data_fn))(png_ptr, data, length);
+ else
+ png_error(png_ptr, "Call to NULL write function");
+}
+
+#if !defined(PNG_NO_STDIO)
+/* This is the function that does the actual writing of data. If you are
+ not writing to a standard C stream, you should create a replacement
+ write_data function and use it at run time with png_set_write_fn(), rather
+ than changing the library. */
+#ifndef USE_FAR_KEYWORD
+void PNGAPI
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+
+ if(png_ptr == NULL) return;
+#if defined(_WIN32_WCE)
+ if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
+ check = 0;
+#else
+ check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));
+#endif
+ if (check != length)
+ png_error(png_ptr, "Write Error");
+}
+#else
+/* this is the model-independent version. Since the standard I/O library
+ can't handle far buffers in the medium and small models, we have to copy
+ the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+void PNGAPI
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ png_uint_32 check;
+ png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */
+ png_FILE_p io_ptr;
+
+ if(png_ptr == NULL) return;
+ /* Check if data really is near. If so, use usual code. */
+ near_data = (png_byte *)CVT_PTR_NOCHECK(data);
+ io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
+ if ((png_bytep)near_data == data)
+ {
+#if defined(_WIN32_WCE)
+ if ( !WriteFile(io_ptr, near_data, length, &check, NULL) )
+ check = 0;
+#else
+ check = fwrite(near_data, 1, length, io_ptr);
+#endif
+ }
+ else
+ {
+ png_byte buf[NEAR_BUF_SIZE];
+ png_size_t written, remaining, err;
+ check = 0;
+ remaining = length;
+ do
+ {
+ written = MIN(NEAR_BUF_SIZE, remaining);
+ png_memcpy(buf, data, written); /* copy far buffer to near buffer */
+#if defined(_WIN32_WCE)
+ if ( !WriteFile(io_ptr, buf, written, &err, NULL) )
+ err = 0;
+#else
+ err = fwrite(buf, 1, written, io_ptr);
+#endif
+ if (err != written)
+ break;
+ else
+ check += err;
+ data += written;
+ remaining -= written;
+ }
+ while (remaining != 0);
+ }
+ if (check != length)
+ png_error(png_ptr, "Write Error");
+}
+
+#endif
+#endif
+
+/* This function is called to output any data pending writing (normally
+ to disk). After png_flush is called, there should be no data pending
+ writing in any buffers. */
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+void /* PRIVATE */
+png_flush(png_structp png_ptr)
+{
+ if (png_ptr->output_flush_fn != NULL)
+ (*(png_ptr->output_flush_fn))(png_ptr);
+}
+
+#if !defined(PNG_NO_STDIO)
+void PNGAPI
+png_default_flush(png_structp png_ptr)
+{
+#if !defined(_WIN32_WCE)
+ png_FILE_p io_ptr;
+#endif
+ if(png_ptr == NULL) return;
+#if !defined(_WIN32_WCE)
+ io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr));
+ if (io_ptr != NULL)
+ fflush(io_ptr);
+#endif
+}
+#endif
+#endif
+
+/* This function allows the application to supply new output functions for
+ libpng if standard C streams aren't being used.
+
+ This function takes as its arguments:
+ png_ptr - pointer to a png output data structure
+ io_ptr - pointer to user supplied structure containing info about
+ the output functions. May be NULL.
+ write_data_fn - pointer to a new output function that takes as its
+ arguments a pointer to a png_struct, a pointer to
+ data to be written, and a 32-bit unsigned int that is
+ the number of bytes to be written. The new write
+ function should call png_error(png_ptr, "Error msg")
+ to exit and output any fatal error messages.
+ flush_data_fn - pointer to a new flush function that takes as its
+ arguments a pointer to a png_struct. After a call to
+ the flush function, there should be no data in any buffers
+ or pending transmission. If the output method doesn't do
+ any buffering of ouput, a function prototype must still be
+ supplied although it doesn't have to do anything. If
+ PNG_WRITE_FLUSH_SUPPORTED is not defined at libpng compile
+ time, output_flush_fn will be ignored, although it must be
+ supplied for compatibility. */
+void PNGAPI
+png_set_write_fn(png_structp png_ptr, png_voidp io_ptr,
+ png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)
+{
+ if(png_ptr == NULL) return;
+ png_ptr->io_ptr = io_ptr;
+
+#if !defined(PNG_NO_STDIO)
+ if (write_data_fn != NULL)
+ png_ptr->write_data_fn = write_data_fn;
+ else
+ png_ptr->write_data_fn = png_default_write_data;
+#else
+ png_ptr->write_data_fn = write_data_fn;
+#endif
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+#if !defined(PNG_NO_STDIO)
+ if (output_flush_fn != NULL)
+ png_ptr->output_flush_fn = output_flush_fn;
+ else
+ png_ptr->output_flush_fn = png_default_flush;
+#else
+ png_ptr->output_flush_fn = output_flush_fn;
+#endif
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+
+ /* It is an error to read while writing a png file */
+ if (png_ptr->read_data_fn != NULL)
+ {
+ png_ptr->read_data_fn = NULL;
+ png_warning(png_ptr,
+ "Attempted to set both read_data_fn and write_data_fn in");
+ png_warning(png_ptr,
+ "the same structure. Resetting read_data_fn to NULL.");
+ }
+}
+
+#if defined(USE_FAR_KEYWORD)
+#if defined(_MSC_VER)
+void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check)
+{
+ void *near_ptr;
+ void FAR *far_ptr;
+ FP_OFF(near_ptr) = FP_OFF(ptr);
+ far_ptr = (void FAR *)near_ptr;
+ if(check != 0)
+ if(FP_SEG(ptr) != FP_SEG(far_ptr))
+ png_error(png_ptr,"segment lost in conversion");
+ return(near_ptr);
+}
+# else
+void *png_far_to_near(png_structp png_ptr,png_voidp ptr, int check)
+{
+ void *near_ptr;
+ void FAR *far_ptr;
+ near_ptr = (void FAR *)ptr;
+ far_ptr = (void FAR *)near_ptr;
+ if(check != 0)
+ if(far_ptr != ptr)
+ png_error(png_ptr,"segment lost in conversion");
+ return(near_ptr);
+}
+# endif
+# endif
+#endif /* PNG_WRITE_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngwrite.c b/distrib/libpng-1.2.19/pngwrite.c
new file mode 100644
index 0000000..8d5b98a
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngwrite.c
@@ -0,0 +1,1530 @@
+
+/* pngwrite.c - general routines to write a PNG file
+ *
+ * Last changed in libpng 1.2.15 January 5, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+/* get internal access to png.h */
+#define PNG_INTERNAL
+#include "png.h"
+#ifdef PNG_WRITE_SUPPORTED
+
+/* Writes all the PNG information. This is the suggested way to use the
+ * library. If you have a new chunk to add, make a function to write it,
+ * and put it in the correct location here. If you want the chunk written
+ * after the image data, put it in png_write_end(). I strongly encourage
+ * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing
+ * the chunk, as that will keep the code from breaking if you want to just
+ * write a plain PNG file. If you have long comments, I suggest writing
+ * them in png_write_end(), and compressing them.
+ */
+void PNGAPI
+png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_write_info_before_PLTE\n");
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+ if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
+ {
+ png_write_sig(png_ptr); /* write PNG signature */
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ if((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE)&&(png_ptr->mng_features_permitted))
+ {
+ png_warning(png_ptr,"MNG features are not allowed in a PNG datastream");
+ png_ptr->mng_features_permitted=0;
+ }
+#endif
+ /* write IHDR information. */
+ png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
+ info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
+ info_ptr->filter_type,
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ info_ptr->interlace_type);
+#else
+ 0);
+#endif
+ /* the rest of these check to see if the valid field has the appropriate
+ flag set, and if it does, writes the chunk. */
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_gAMA)
+ {
+# ifdef PNG_FLOATING_POINT_SUPPORTED
+ png_write_gAMA(png_ptr, info_ptr->gamma);
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_write_gAMA_fixed(png_ptr, info_ptr->int_gamma);
+# endif
+#endif
+ }
+#endif
+#if defined(PNG_WRITE_sRGB_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sRGB)
+ png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
+#endif
+#if defined(PNG_WRITE_iCCP_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_iCCP)
+ png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
+ info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
+#endif
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sBIT)
+ png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
+#endif
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_cHRM)
+ {
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+ png_write_cHRM(png_ptr,
+ info_ptr->x_white, info_ptr->y_white,
+ info_ptr->x_red, info_ptr->y_red,
+ info_ptr->x_green, info_ptr->y_green,
+ info_ptr->x_blue, info_ptr->y_blue);
+#else
+# ifdef PNG_FIXED_POINT_SUPPORTED
+ png_write_cHRM_fixed(png_ptr,
+ info_ptr->int_x_white, info_ptr->int_y_white,
+ info_ptr->int_x_red, info_ptr->int_y_red,
+ info_ptr->int_x_green, info_ptr->int_y_green,
+ info_ptr->int_x_blue, info_ptr->int_y_blue);
+# endif
+#endif
+ }
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+ if (info_ptr->unknown_chunks_num)
+ {
+ png_unknown_chunk *up;
+
+ png_debug(5, "writing extra chunks\n");
+
+ for (up = info_ptr->unknown_chunks;
+ up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
+ up++)
+ {
+ int keep=png_handle_as_unknown(png_ptr, up->name);
+ if (keep != PNG_HANDLE_CHUNK_NEVER &&
+ up->location && !(up->location & PNG_HAVE_PLTE) &&
+ !(up->location & PNG_HAVE_IDAT) &&
+ ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
+ (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+ {
+ png_write_chunk(png_ptr, up->name, up->data, up->size);
+ }
+ }
+ }
+#endif
+ png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
+ }
+}
+
+void PNGAPI
+png_write_info(png_structp png_ptr, png_infop info_ptr)
+{
+#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
+ int i;
+#endif
+
+ png_debug(1, "in png_write_info\n");
+
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+
+ png_write_info_before_PLTE(png_ptr, info_ptr);
+
+ if (info_ptr->valid & PNG_INFO_PLTE)
+ png_write_PLTE(png_ptr, info_ptr->palette,
+ (png_uint_32)info_ptr->num_palette);
+ else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ png_error(png_ptr, "Valid palette required for paletted images");
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_tRNS)
+ {
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+ /* invert the alpha channel (in tRNS) */
+ if ((png_ptr->transformations & PNG_INVERT_ALPHA) &&
+ info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ int j;
+ for (j=0; j<(int)info_ptr->num_trans; j++)
+ info_ptr->trans[j] = (png_byte)(255 - info_ptr->trans[j]);
+ }
+#endif
+ png_write_tRNS(png_ptr, info_ptr->trans, &(info_ptr->trans_values),
+ info_ptr->num_trans, info_ptr->color_type);
+ }
+#endif
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_bKGD)
+ png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type);
+#endif
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_hIST)
+ png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette);
+#endif
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_oFFs)
+ png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset,
+ info_ptr->offset_unit_type);
+#endif
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pCAL)
+ png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0,
+ info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams,
+ info_ptr->pcal_units, info_ptr->pcal_params);
+#endif
+#if defined(PNG_WRITE_sCAL_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sCAL)
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
+ png_write_sCAL(png_ptr, (int)info_ptr->scal_unit,
+ info_ptr->scal_pixel_width, info_ptr->scal_pixel_height);
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+ png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit,
+ info_ptr->scal_s_width, info_ptr->scal_s_height);
+#else
+ png_warning(png_ptr,
+ "png_write_sCAL not supported; sCAL chunk not written.");
+#endif
+#endif
+#endif
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_pHYs)
+ png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit,
+ info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type);
+#endif
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_tIME)
+ {
+ png_write_tIME(png_ptr, &(info_ptr->mod_time));
+ png_ptr->mode |= PNG_WROTE_tIME;
+ }
+#endif
+#if defined(PNG_WRITE_sPLT_SUPPORTED)
+ if (info_ptr->valid & PNG_INFO_sPLT)
+ for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
+ png_write_sPLT(png_ptr, info_ptr->splt_palettes + i);
+#endif
+#if defined(PNG_WRITE_TEXT_SUPPORTED)
+ /* Check to see if we need to write text chunks */
+ for (i = 0; i < info_ptr->num_text; i++)
+ {
+ png_debug2(2, "Writing header text chunk %d, type %d\n", i,
+ info_ptr->text[i].compression);
+ /* an internationalized chunk? */
+ if (info_ptr->text[i].compression > 0)
+ {
+#if defined(PNG_WRITE_iTXt_SUPPORTED)
+ /* write international chunk */
+ png_write_iTXt(png_ptr,
+ info_ptr->text[i].compression,
+ info_ptr->text[i].key,
+ info_ptr->text[i].lang,
+ info_ptr->text[i].lang_key,
+ info_ptr->text[i].text);
+#else
+ png_warning(png_ptr, "Unable to write international text");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ /* If we want a compressed text chunk */
+ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_zTXt)
+ {
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* write compressed chunk */
+ png_write_zTXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, 0,
+ info_ptr->text[i].compression);
+#else
+ png_warning(png_ptr, "Unable to write compressed text");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
+ }
+ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ {
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+ /* write uncompressed chunk */
+ png_write_tEXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text,
+ 0);
+#else
+ png_warning(png_ptr, "Unable to write uncompressed text");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ }
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+ if (info_ptr->unknown_chunks_num)
+ {
+ png_unknown_chunk *up;
+
+ png_debug(5, "writing extra chunks\n");
+
+ for (up = info_ptr->unknown_chunks;
+ up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
+ up++)
+ {
+ int keep=png_handle_as_unknown(png_ptr, up->name);
+ if (keep != PNG_HANDLE_CHUNK_NEVER &&
+ up->location && (up->location & PNG_HAVE_PLTE) &&
+ !(up->location & PNG_HAVE_IDAT) &&
+ ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
+ (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+ {
+ png_write_chunk(png_ptr, up->name, up->data, up->size);
+ }
+ }
+ }
+#endif
+}
+
+/* Writes the end of the PNG file. If you don't want to write comments or
+ * time information, you can pass NULL for info. If you already wrote these
+ * in png_write_info(), do not write them again here. If you have long
+ * comments, I suggest writing them here, and compressing them.
+ */
+void PNGAPI
+png_write_end(png_structp png_ptr, png_infop info_ptr)
+{
+ png_debug(1, "in png_write_end\n");
+ if (png_ptr == NULL)
+ return;
+ if (!(png_ptr->mode & PNG_HAVE_IDAT))
+ png_error(png_ptr, "No IDATs written into file");
+
+ /* see if user wants us to write information chunks */
+ if (info_ptr != NULL)
+ {
+#if defined(PNG_WRITE_TEXT_SUPPORTED)
+ int i; /* local index variable */
+#endif
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+ /* check to see if user has supplied a time chunk */
+ if ((info_ptr->valid & PNG_INFO_tIME) &&
+ !(png_ptr->mode & PNG_WROTE_tIME))
+ png_write_tIME(png_ptr, &(info_ptr->mod_time));
+#endif
+#if defined(PNG_WRITE_TEXT_SUPPORTED)
+ /* loop through comment chunks */
+ for (i = 0; i < info_ptr->num_text; i++)
+ {
+ png_debug2(2, "Writing trailer text chunk %d, type %d\n", i,
+ info_ptr->text[i].compression);
+ /* an internationalized chunk? */
+ if (info_ptr->text[i].compression > 0)
+ {
+#if defined(PNG_WRITE_iTXt_SUPPORTED)
+ /* write international chunk */
+ png_write_iTXt(png_ptr,
+ info_ptr->text[i].compression,
+ info_ptr->text[i].key,
+ info_ptr->text[i].lang,
+ info_ptr->text[i].lang_key,
+ info_ptr->text[i].text);
+#else
+ png_warning(png_ptr, "Unable to write international text");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
+ {
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+ /* write compressed chunk */
+ png_write_zTXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, 0,
+ info_ptr->text[i].compression);
+#else
+ png_warning(png_ptr, "Unable to write compressed text");
+#endif
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
+ }
+ else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ {
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+ /* write uncompressed chunk */
+ png_write_tEXt(png_ptr, info_ptr->text[i].key,
+ info_ptr->text[i].text, 0);
+#else
+ png_warning(png_ptr, "Unable to write uncompressed text");
+#endif
+
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ }
+ }
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+ if (info_ptr->unknown_chunks_num)
+ {
+ png_unknown_chunk *up;
+
+ png_debug(5, "writing extra chunks\n");
+
+ for (up = info_ptr->unknown_chunks;
+ up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
+ up++)
+ {
+ int keep=png_handle_as_unknown(png_ptr, up->name);
+ if (keep != PNG_HANDLE_CHUNK_NEVER &&
+ up->location && (up->location & PNG_AFTER_IDAT) &&
+ ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
+ (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+ {
+ png_write_chunk(png_ptr, up->name, up->data, up->size);
+ }
+ }
+ }
+#endif
+ }
+
+ png_ptr->mode |= PNG_AFTER_IDAT;
+
+ /* write end of PNG file */
+ png_write_IEND(png_ptr);
+}
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+#if !defined(_WIN32_WCE)
+/* "time.h" functions are not supported on WindowsCE */
+void PNGAPI
+png_convert_from_struct_tm(png_timep ptime, struct tm FAR * ttime)
+{
+ png_debug(1, "in png_convert_from_struct_tm\n");
+ ptime->year = (png_uint_16)(1900 + ttime->tm_year);
+ ptime->month = (png_byte)(ttime->tm_mon + 1);
+ ptime->day = (png_byte)ttime->tm_mday;
+ ptime->hour = (png_byte)ttime->tm_hour;
+ ptime->minute = (png_byte)ttime->tm_min;
+ ptime->second = (png_byte)ttime->tm_sec;
+}
+
+void PNGAPI
+png_convert_from_time_t(png_timep ptime, time_t ttime)
+{
+ struct tm *tbuf;
+
+ png_debug(1, "in png_convert_from_time_t\n");
+ tbuf = gmtime(&ttime);
+ png_convert_from_struct_tm(ptime, tbuf);
+}
+#endif
+#endif
+
+/* Initialize png_ptr structure, and allocate any memory needed */
+png_structp PNGAPI
+png_create_write_struct(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn)
+{
+#ifdef PNG_USER_MEM_SUPPORTED
+ return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn,
+ warn_fn, png_voidp_NULL, png_malloc_ptr_NULL, png_free_ptr_NULL));
+}
+
+/* Alternate initialize png_ptr structure, and allocate any memory needed */
+png_structp PNGAPI
+png_create_write_struct_2(png_const_charp user_png_ver, png_voidp error_ptr,
+ png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
+ png_malloc_ptr malloc_fn, png_free_ptr free_fn)
+{
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_structp png_ptr;
+#ifdef PNG_SETJMP_SUPPORTED
+#ifdef USE_FAR_KEYWORD
+ jmp_buf jmpbuf;
+#endif
+#endif
+ int i;
+ png_debug(1, "in png_create_write_struct\n");
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG,
+ (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr);
+#else
+ png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
+#endif /* PNG_USER_MEM_SUPPORTED */
+ if (png_ptr == NULL)
+ return (NULL);
+
+#if !defined(PNG_1_0_X)
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+#ifdef PNG_MMX_CODE_SUPPORTED
+ png_init_mmx_flags(png_ptr); /* 1.2.0 addition */
+#endif
+#endif
+#endif /* PNG_1_0_X */
+
+ /* added at libpng-1.2.6 */
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
+ png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+#else
+ if (setjmp(png_ptr->jmpbuf))
+#endif
+ {
+ png_free(png_ptr, png_ptr->zbuf);
+ png_ptr->zbuf=NULL;
+ png_destroy_struct(png_ptr);
+ return (NULL);
+ }
+#ifdef USE_FAR_KEYWORD
+ png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
+#endif
+#endif
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
+#endif /* PNG_USER_MEM_SUPPORTED */
+ png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn);
+
+ i=0;
+ do
+ {
+ if(user_png_ver[i] != png_libpng_ver[i])
+ png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+ } while (png_libpng_ver[i++]);
+
+ if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
+ {
+ /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
+ * we must recompile any applications that use any older library version.
+ * For versions after libpng 1.0, we will be compatible, so we need
+ * only check the first digit.
+ */
+ if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
+ (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
+ (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char msg[80];
+ if (user_png_ver)
+ {
+ png_snprintf(msg, 80,
+ "Application was compiled with png.h from libpng-%.20s",
+ user_png_ver);
+ png_warning(png_ptr, msg);
+ }
+ png_snprintf(msg, 80,
+ "Application is running with png.c from libpng-%.20s",
+ png_libpng_ver);
+ png_warning(png_ptr, msg);
+#endif
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "Incompatible libpng version in application and library");
+ }
+ }
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+
+ png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
+ png_flush_ptr_NULL);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
+ 1, png_doublep_NULL, png_doublep_NULL);
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+/* Applications that neglect to set up their own setjmp() and then encounter
+ a png_error() will longjmp here. Since the jmpbuf is then meaningless we
+ abort instead of returning. */
+#ifdef USE_FAR_KEYWORD
+ if (setjmp(jmpbuf))
+ PNG_ABORT();
+ png_memcpy(png_ptr->jmpbuf,jmpbuf,png_sizeof(jmp_buf));
+#else
+ if (setjmp(png_ptr->jmpbuf))
+ PNG_ABORT();
+#endif
+#endif
+ return (png_ptr);
+}
+
+/* Initialize png_ptr structure, and allocate any memory needed */
+#if defined(PNG_1_0_X) || defined(PNG_1_2_X)
+/* Deprecated. */
+#undef png_write_init
+void PNGAPI
+png_write_init(png_structp png_ptr)
+{
+ /* We only come here via pre-1.0.7-compiled applications */
+ png_write_init_2(png_ptr, "1.0.6 or earlier", 0, 0);
+}
+
+void PNGAPI
+png_write_init_2(png_structp png_ptr, png_const_charp user_png_ver,
+ png_size_t png_struct_size, png_size_t png_info_size)
+{
+ /* We only come here via pre-1.0.12-compiled applications */
+ if(png_ptr == NULL) return;
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ if(png_sizeof(png_struct) > png_struct_size ||
+ png_sizeof(png_info) > png_info_size)
+ {
+ char msg[80];
+ png_ptr->warning_fn=NULL;
+ if (user_png_ver)
+ {
+ png_snprintf(msg, 80,
+ "Application was compiled with png.h from libpng-%.20s",
+ user_png_ver);
+ png_warning(png_ptr, msg);
+ }
+ png_snprintf(msg, 80,
+ "Application is running with png.c from libpng-%.20s",
+ png_libpng_ver);
+ png_warning(png_ptr, msg);
+ }
+#endif
+ if(png_sizeof(png_struct) > png_struct_size)
+ {
+ png_ptr->error_fn=NULL;
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "The png struct allocated by the application for writing is too small.");
+ }
+ if(png_sizeof(png_info) > png_info_size)
+ {
+ png_ptr->error_fn=NULL;
+#ifdef PNG_ERROR_NUMBERS_SUPPORTED
+ png_ptr->flags=0;
+#endif
+ png_error(png_ptr,
+ "The info struct allocated by the application for writing is too small.");
+ }
+ png_write_init_3(&png_ptr, user_png_ver, png_struct_size);
+}
+#endif /* PNG_1_0_X || PNG_1_2_X */
+
+
+void PNGAPI
+png_write_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver,
+ png_size_t png_struct_size)
+{
+ png_structp png_ptr=*ptr_ptr;
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf tmp_jmp; /* to save current jump buffer */
+#endif
+
+ int i = 0;
+
+ if (png_ptr == NULL)
+ return;
+
+ do
+ {
+ if (user_png_ver[i] != png_libpng_ver[i])
+ {
+#ifdef PNG_LEGACY_SUPPORTED
+ png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
+#else
+ png_ptr->warning_fn=NULL;
+ png_warning(png_ptr,
+ "Application uses deprecated png_write_init() and should be recompiled.");
+ break;
+#endif
+ }
+ } while (png_libpng_ver[i++]);
+
+ png_debug(1, "in png_write_init_3\n");
+
+#ifdef PNG_SETJMP_SUPPORTED
+ /* save jump buffer and error functions */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
+#endif
+
+ if (png_sizeof(png_struct) > png_struct_size)
+ {
+ png_destroy_struct(png_ptr);
+ png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG);
+ *ptr_ptr = png_ptr;
+ }
+
+ /* reset all variables to 0 */
+ png_memset(png_ptr, 0, png_sizeof (png_struct));
+
+ /* added at libpng-1.2.6 */
+#ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ png_ptr->user_width_max=PNG_USER_WIDTH_MAX;
+ png_ptr->user_height_max=PNG_USER_HEIGHT_MAX;
+#endif
+
+#if !defined(PNG_1_0_X)
+#ifdef PNG_ASSEMBLER_CODE_SUPPORTED
+#ifdef PNG_MMX_CODE_SUPPORTED
+ png_init_mmx_flags(png_ptr); /* 1.2.0 addition */
+#endif
+#endif
+#endif /* PNG_1_0_X */
+
+#ifdef PNG_SETJMP_SUPPORTED
+ /* restore jump buffer */
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
+#endif
+
+ png_set_write_fn(png_ptr, png_voidp_NULL, png_rw_ptr_NULL,
+ png_flush_ptr_NULL);
+
+ /* initialize zbuf - compression buffer */
+ png_ptr->zbuf_size = PNG_ZBUF_SIZE;
+ png_ptr->zbuf = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_set_filter_heuristics(png_ptr, PNG_FILTER_HEURISTIC_DEFAULT,
+ 1, png_doublep_NULL, png_doublep_NULL);
+#endif
+}
+
+/* Write a few rows of image data. If the image is interlaced,
+ * either you will have to write the 7 sub images, or, if you
+ * have called png_set_interlace_handling(), you will have to
+ * "write" the image seven times.
+ */
+void PNGAPI
+png_write_rows(png_structp png_ptr, png_bytepp row,
+ png_uint_32 num_rows)
+{
+ png_uint_32 i; /* row counter */
+ png_bytepp rp; /* row pointer */
+
+ png_debug(1, "in png_write_rows\n");
+
+ if (png_ptr == NULL)
+ return;
+
+ /* loop through the rows */
+ for (i = 0, rp = row; i < num_rows; i++, rp++)
+ {
+ png_write_row(png_ptr, *rp);
+ }
+}
+
+/* Write the image. You only need to call this function once, even
+ * if you are writing an interlaced image.
+ */
+void PNGAPI
+png_write_image(png_structp png_ptr, png_bytepp image)
+{
+ png_uint_32 i; /* row index */
+ int pass, num_pass; /* pass variables */
+ png_bytepp rp; /* points to current row */
+
+ if (png_ptr == NULL)
+ return;
+
+ png_debug(1, "in png_write_image\n");
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* intialize interlace handling. If image is not interlaced,
+ this will set pass to 1 */
+ num_pass = png_set_interlace_handling(png_ptr);
+#else
+ num_pass = 1;
+#endif
+ /* loop through passes */
+ for (pass = 0; pass < num_pass; pass++)
+ {
+ /* loop through image */
+ for (i = 0, rp = image; i < png_ptr->height; i++, rp++)
+ {
+ png_write_row(png_ptr, *rp);
+ }
+ }
+}
+
+/* called by user to write a row of image data */
+void PNGAPI
+png_write_row(png_structp png_ptr, png_bytep row)
+{
+ if (png_ptr == NULL)
+ return;
+ png_debug2(1, "in png_write_row (row %ld, pass %d)\n",
+ png_ptr->row_number, png_ptr->pass);
+
+ /* initialize transformations and other stuff if first time */
+ if (png_ptr->row_number == 0 && png_ptr->pass == 0)
+ {
+ /* make sure we wrote the header info */
+ if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
+ png_error(png_ptr,
+ "png_write_info was never called before png_write_row.");
+
+ /* check for transforms that have been set but were defined out */
+#if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && defined(PNG_READ_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined.");
+#endif
+#if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined.");
+#endif
+
+ png_write_start_row(png_ptr);
+ }
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* if interlaced and not interested in row, return */
+ if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE))
+ {
+ switch (png_ptr->pass)
+ {
+ case 0:
+ if (png_ptr->row_number & 0x07)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 1:
+ if ((png_ptr->row_number & 0x07) || png_ptr->width < 5)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 2:
+ if ((png_ptr->row_number & 0x07) != 4)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 3:
+ if ((png_ptr->row_number & 0x03) || png_ptr->width < 3)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 4:
+ if ((png_ptr->row_number & 0x03) != 2)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 5:
+ if ((png_ptr->row_number & 0x01) || png_ptr->width < 2)
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ case 6:
+ if (!(png_ptr->row_number & 0x01))
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ break;
+ }
+ }
+#endif
+
+ /* set up row info for transformations */
+ png_ptr->row_info.color_type = png_ptr->color_type;
+ png_ptr->row_info.width = png_ptr->usr_width;
+ png_ptr->row_info.channels = png_ptr->usr_channels;
+ png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth;
+ png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth *
+ png_ptr->row_info.channels);
+
+ png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth,
+ png_ptr->row_info.width);
+
+ png_debug1(3, "row_info->color_type = %d\n", png_ptr->row_info.color_type);
+ png_debug1(3, "row_info->width = %lu\n", png_ptr->row_info.width);
+ png_debug1(3, "row_info->channels = %d\n", png_ptr->row_info.channels);
+ png_debug1(3, "row_info->bit_depth = %d\n", png_ptr->row_info.bit_depth);
+ png_debug1(3, "row_info->pixel_depth = %d\n", png_ptr->row_info.pixel_depth);
+ png_debug1(3, "row_info->rowbytes = %lu\n", png_ptr->row_info.rowbytes);
+
+ /* Copy user's row into buffer, leaving room for filter byte. */
+ png_memcpy_check(png_ptr, png_ptr->row_buf + 1, row,
+ png_ptr->row_info.rowbytes);
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+ /* handle interlacing */
+ if (png_ptr->interlaced && png_ptr->pass < 6 &&
+ (png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_do_write_interlace(&(png_ptr->row_info),
+ png_ptr->row_buf + 1, png_ptr->pass);
+ /* this should always get caught above, but still ... */
+ if (!(png_ptr->row_info.width))
+ {
+ png_write_finish_row(png_ptr);
+ return;
+ }
+ }
+#endif
+
+ /* handle other transformations */
+ if (png_ptr->transformations)
+ png_do_write_transformations(png_ptr);
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ /* Write filter_method 64 (intrapixel differencing) only if
+ * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
+ * 2. Libpng did not write a PNG signature (this filter_method is only
+ * used in PNG datastreams that are embedded in MNG datastreams) and
+ * 3. The application called png_permit_mng_features with a mask that
+ * included PNG_FLAG_MNG_FILTER_64 and
+ * 4. The filter_method is 64 and
+ * 5. The color_type is RGB or RGBA
+ */
+ if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
+ (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING))
+ {
+ /* Intrapixel differencing */
+ png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1);
+ }
+#endif
+
+ /* Find a filter if necessary, filter the row and write it out. */
+ png_write_find_filter(png_ptr, &(png_ptr->row_info));
+
+ if (png_ptr->write_row_fn != NULL)
+ (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass);
+}
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+/* Set the automatic flush interval or 0 to turn flushing off */
+void PNGAPI
+png_set_flush(png_structp png_ptr, int nrows)
+{
+ png_debug(1, "in png_set_flush\n");
+ if (png_ptr == NULL)
+ return;
+ png_ptr->flush_dist = (nrows < 0 ? 0 : nrows);
+}
+
+/* flush the current output buffers now */
+void PNGAPI
+png_write_flush(png_structp png_ptr)
+{
+ int wrote_IDAT;
+
+ png_debug(1, "in png_write_flush\n");
+ if (png_ptr == NULL)
+ return;
+ /* We have already written out all of the data */
+ if (png_ptr->row_number >= png_ptr->num_rows)
+ return;
+
+ do
+ {
+ int ret;
+
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH);
+ wrote_IDAT = 0;
+
+ /* check for compression errors */
+ if (ret != Z_OK)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ wrote_IDAT = 1;
+ }
+ } while(wrote_IDAT == 1);
+
+ /* If there is any data left to be output, write it into a new IDAT */
+ if (png_ptr->zbuf_size != png_ptr->zstream.avail_out)
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ png_ptr->flush_rows = 0;
+ png_flush(png_ptr);
+}
+#endif /* PNG_WRITE_FLUSH_SUPPORTED */
+
+/* free all memory used by the write */
+void PNGAPI
+png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)
+{
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn = NULL;
+ png_voidp mem_ptr = NULL;
+#endif
+
+ png_debug(1, "in png_destroy_write_struct\n");
+ if (png_ptr_ptr != NULL)
+ {
+ png_ptr = *png_ptr_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+ mem_ptr = png_ptr->mem_ptr;
+#endif
+ }
+
+ if (info_ptr_ptr != NULL)
+ info_ptr = *info_ptr_ptr;
+
+ if (info_ptr != NULL)
+ {
+ png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1);
+
+#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
+ if (png_ptr->num_chunk_list)
+ {
+ png_free(png_ptr, png_ptr->chunk_list);
+ png_ptr->chunk_list=NULL;
+ png_ptr->num_chunk_list=0;
+ }
+#endif
+
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn,
+ (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)info_ptr);
+#endif
+ *info_ptr_ptr = NULL;
+ }
+
+ if (png_ptr != NULL)
+ {
+ png_write_destroy(png_ptr);
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn,
+ (png_voidp)mem_ptr);
+#else
+ png_destroy_struct((png_voidp)png_ptr);
+#endif
+ *png_ptr_ptr = NULL;
+ }
+}
+
+
+/* Free any memory used in png_ptr struct (old method) */
+void /* PRIVATE */
+png_write_destroy(png_structp png_ptr)
+{
+#ifdef PNG_SETJMP_SUPPORTED
+ jmp_buf tmp_jmp; /* save jump buffer */
+#endif
+ png_error_ptr error_fn;
+ png_error_ptr warning_fn;
+ png_voidp error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_free_ptr free_fn;
+#endif
+
+ png_debug(1, "in png_write_destroy\n");
+ /* free any memory zlib uses */
+ deflateEnd(&png_ptr->zstream);
+
+ /* free our memory. png_free checks NULL for us. */
+ png_free(png_ptr, png_ptr->zbuf);
+ png_free(png_ptr, png_ptr->row_buf);
+ png_free(png_ptr, png_ptr->prev_row);
+ png_free(png_ptr, png_ptr->sub_row);
+ png_free(png_ptr, png_ptr->up_row);
+ png_free(png_ptr, png_ptr->avg_row);
+ png_free(png_ptr, png_ptr->paeth_row);
+
+#if defined(PNG_TIME_RFC1123_SUPPORTED)
+ png_free(png_ptr, png_ptr->time_buffer);
+#endif
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ png_free(png_ptr, png_ptr->prev_filters);
+ png_free(png_ptr, png_ptr->filter_weights);
+ png_free(png_ptr, png_ptr->inv_filter_weights);
+ png_free(png_ptr, png_ptr->filter_costs);
+ png_free(png_ptr, png_ptr->inv_filter_costs);
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+ /* reset structure */
+ png_memcpy(tmp_jmp, png_ptr->jmpbuf, png_sizeof (jmp_buf));
+#endif
+
+ error_fn = png_ptr->error_fn;
+ warning_fn = png_ptr->warning_fn;
+ error_ptr = png_ptr->error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ free_fn = png_ptr->free_fn;
+#endif
+
+ png_memset(png_ptr, 0, png_sizeof (png_struct));
+
+ png_ptr->error_fn = error_fn;
+ png_ptr->warning_fn = warning_fn;
+ png_ptr->error_ptr = error_ptr;
+#ifdef PNG_USER_MEM_SUPPORTED
+ png_ptr->free_fn = free_fn;
+#endif
+
+#ifdef PNG_SETJMP_SUPPORTED
+ png_memcpy(png_ptr->jmpbuf, tmp_jmp, png_sizeof (jmp_buf));
+#endif
+}
+
+/* Allow the application to select one or more row filters to use. */
+void PNGAPI
+png_set_filter(png_structp png_ptr, int method, int filters)
+{
+ png_debug(1, "in png_set_filter\n");
+ if (png_ptr == NULL)
+ return;
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ if((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
+ (method == PNG_INTRAPIXEL_DIFFERENCING))
+ method = PNG_FILTER_TYPE_BASE;
+#endif
+ if (method == PNG_FILTER_TYPE_BASE)
+ {
+ switch (filters & (PNG_ALL_FILTERS | 0x07))
+ {
+#ifndef PNG_NO_WRITE_FILTER
+ case 5:
+ case 6:
+ case 7: png_warning(png_ptr, "Unknown row filter for method 0");
+#endif /* PNG_NO_WRITE_FILTER */
+ case PNG_FILTER_VALUE_NONE:
+ png_ptr->do_filter=PNG_FILTER_NONE; break;
+#ifndef PNG_NO_WRITE_FILTER
+ case PNG_FILTER_VALUE_SUB:
+ png_ptr->do_filter=PNG_FILTER_SUB; break;
+ case PNG_FILTER_VALUE_UP:
+ png_ptr->do_filter=PNG_FILTER_UP; break;
+ case PNG_FILTER_VALUE_AVG:
+ png_ptr->do_filter=PNG_FILTER_AVG; break;
+ case PNG_FILTER_VALUE_PAETH:
+ png_ptr->do_filter=PNG_FILTER_PAETH; break;
+ default: png_ptr->do_filter = (png_byte)filters; break;
+#else
+ default: png_warning(png_ptr, "Unknown row filter for method 0");
+#endif /* PNG_NO_WRITE_FILTER */
+ }
+
+ /* If we have allocated the row_buf, this means we have already started
+ * with the image and we should have allocated all of the filter buffers
+ * that have been selected. If prev_row isn't already allocated, then
+ * it is too late to start using the filters that need it, since we
+ * will be missing the data in the previous row. If an application
+ * wants to start and stop using particular filters during compression,
+ * it should start out with all of the filters, and then add and
+ * remove them after the start of compression.
+ */
+ if (png_ptr->row_buf != NULL)
+ {
+#ifndef PNG_NO_WRITE_FILTER
+ if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
+ {
+ png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
+ }
+
+ if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Up filter after starting");
+ png_ptr->do_filter &= ~PNG_FILTER_UP;
+ }
+ else
+ {
+ png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
+ }
+ }
+
+ if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Average filter after starting");
+ png_ptr->do_filter &= ~PNG_FILTER_AVG;
+ }
+ else
+ {
+ png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
+ }
+ }
+
+ if ((png_ptr->do_filter & PNG_FILTER_PAETH) &&
+ png_ptr->paeth_row == NULL)
+ {
+ if (png_ptr->prev_row == NULL)
+ {
+ png_warning(png_ptr, "Can't add Paeth filter after starting");
+ png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH);
+ }
+ else
+ {
+ png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
+ }
+ }
+
+ if (png_ptr->do_filter == PNG_NO_FILTERS)
+#endif /* PNG_NO_WRITE_FILTER */
+ png_ptr->do_filter = PNG_FILTER_NONE;
+ }
+ }
+ else
+ png_error(png_ptr, "Unknown custom filter method");
+}
+
+/* This allows us to influence the way in which libpng chooses the "best"
+ * filter for the current scanline. While the "minimum-sum-of-absolute-
+ * differences metric is relatively fast and effective, there is some
+ * question as to whether it can be improved upon by trying to keep the
+ * filtered data going to zlib more consistent, hopefully resulting in
+ * better compression.
+ */
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED) /* GRR 970116 */
+void PNGAPI
+png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
+ int num_weights, png_doublep filter_weights,
+ png_doublep filter_costs)
+{
+ int i;
+
+ png_debug(1, "in png_set_filter_heuristics\n");
+ if (png_ptr == NULL)
+ return;
+ if (heuristic_method >= PNG_FILTER_HEURISTIC_LAST)
+ {
+ png_warning(png_ptr, "Unknown filter heuristic method");
+ return;
+ }
+
+ if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT)
+ {
+ heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
+ }
+
+ if (num_weights < 0 || filter_weights == NULL ||
+ heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
+ {
+ num_weights = 0;
+ }
+
+ png_ptr->num_prev_filters = (png_byte)num_weights;
+ png_ptr->heuristic_method = (png_byte)heuristic_method;
+
+ if (num_weights > 0)
+ {
+ if (png_ptr->prev_filters == NULL)
+ {
+ png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
+ (png_uint_32)(png_sizeof(png_byte) * num_weights));
+
+ /* To make sure that the weighting starts out fairly */
+ for (i = 0; i < num_weights; i++)
+ {
+ png_ptr->prev_filters[i] = 255;
+ }
+ }
+
+ if (png_ptr->filter_weights == NULL)
+ {
+ png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
+
+ png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
+ for (i = 0; i < num_weights; i++)
+ {
+ png_ptr->inv_filter_weights[i] =
+ png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
+ }
+ }
+
+ for (i = 0; i < num_weights; i++)
+ {
+ if (filter_weights[i] < 0.0)
+ {
+ png_ptr->inv_filter_weights[i] =
+ png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
+ }
+ else
+ {
+ png_ptr->inv_filter_weights[i] =
+ (png_uint_16)((double)PNG_WEIGHT_FACTOR*filter_weights[i]+0.5);
+ png_ptr->filter_weights[i] =
+ (png_uint_16)((double)PNG_WEIGHT_FACTOR/filter_weights[i]+0.5);
+ }
+ }
+ }
+
+ /* If, in the future, there are other filter methods, this would
+ * need to be based on png_ptr->filter.
+ */
+ if (png_ptr->filter_costs == NULL)
+ {
+ png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
+
+ png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
+ (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
+
+ for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
+ {
+ png_ptr->inv_filter_costs[i] =
+ png_ptr->filter_costs[i] = PNG_COST_FACTOR;
+ }
+ }
+
+ /* Here is where we set the relative costs of the different filters. We
+ * should take the desired compression level into account when setting
+ * the costs, so that Paeth, for instance, has a high relative cost at low
+ * compression levels, while it has a lower relative cost at higher
+ * compression settings. The filter types are in order of increasing
+ * relative cost, so it would be possible to do this with an algorithm.
+ */
+ for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
+ {
+ if (filter_costs == NULL || filter_costs[i] < 0.0)
+ {
+ png_ptr->inv_filter_costs[i] =
+ png_ptr->filter_costs[i] = PNG_COST_FACTOR;
+ }
+ else if (filter_costs[i] >= 1.0)
+ {
+ png_ptr->inv_filter_costs[i] =
+ (png_uint_16)((double)PNG_COST_FACTOR / filter_costs[i] + 0.5);
+ png_ptr->filter_costs[i] =
+ (png_uint_16)((double)PNG_COST_FACTOR * filter_costs[i] + 0.5);
+ }
+ }
+}
+#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+
+void PNGAPI
+png_set_compression_level(png_structp png_ptr, int level)
+{
+ png_debug(1, "in png_set_compression_level\n");
+ if (png_ptr == NULL)
+ return;
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL;
+ png_ptr->zlib_level = level;
+}
+
+void PNGAPI
+png_set_compression_mem_level(png_structp png_ptr, int mem_level)
+{
+ png_debug(1, "in png_set_compression_mem_level\n");
+ if (png_ptr == NULL)
+ return;
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL;
+ png_ptr->zlib_mem_level = mem_level;
+}
+
+void PNGAPI
+png_set_compression_strategy(png_structp png_ptr, int strategy)
+{
+ png_debug(1, "in png_set_compression_strategy\n");
+ if (png_ptr == NULL)
+ return;
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY;
+ png_ptr->zlib_strategy = strategy;
+}
+
+void PNGAPI
+png_set_compression_window_bits(png_structp png_ptr, int window_bits)
+{
+ if (png_ptr == NULL)
+ return;
+ if (window_bits > 15)
+ png_warning(png_ptr, "Only compression windows <= 32k supported by PNG");
+ else if (window_bits < 8)
+ png_warning(png_ptr, "Only compression windows >= 256 supported by PNG");
+#ifndef WBITS_8_OK
+ /* avoid libpng bug with 256-byte windows */
+ if (window_bits == 8)
+ {
+ png_warning(png_ptr, "Compression window is being reset to 512");
+ window_bits=9;
+ }
+#endif
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS;
+ png_ptr->zlib_window_bits = window_bits;
+}
+
+void PNGAPI
+png_set_compression_method(png_structp png_ptr, int method)
+{
+ png_debug(1, "in png_set_compression_method\n");
+ if (png_ptr == NULL)
+ return;
+ if (method != 8)
+ png_warning(png_ptr, "Only compression method 8 is supported by PNG");
+ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
+ png_ptr->zlib_method = method;
+}
+
+void PNGAPI
+png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn)
+{
+ if (png_ptr == NULL)
+ return;
+ png_ptr->write_row_fn = write_row_fn;
+}
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+void PNGAPI
+png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr
+ write_user_transform_fn)
+{
+ png_debug(1, "in png_set_write_user_transform_fn\n");
+ if (png_ptr == NULL)
+ return;
+ png_ptr->transformations |= PNG_USER_TRANSFORM;
+ png_ptr->write_user_transform_fn = write_user_transform_fn;
+}
+#endif
+
+
+#if defined(PNG_INFO_IMAGE_SUPPORTED)
+void PNGAPI
+png_write_png(png_structp png_ptr, png_infop info_ptr,
+ int transforms, voidp params)
+{
+ if (png_ptr == NULL || info_ptr == NULL)
+ return;
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+ /* invert the alpha channel from opacity to transparency */
+ if (transforms & PNG_TRANSFORM_INVERT_ALPHA)
+ png_set_invert_alpha(png_ptr);
+#endif
+
+ /* Write the file header information. */
+ png_write_info(png_ptr, info_ptr);
+
+ /* ------ these transformations don't touch the info structure ------- */
+
+#if defined(PNG_WRITE_INVERT_SUPPORTED)
+ /* invert monochrome pixels */
+ if (transforms & PNG_TRANSFORM_INVERT_MONO)
+ png_set_invert_mono(png_ptr);
+#endif
+
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+ /* Shift the pixels up to a legal bit depth and fill in
+ * as appropriate to correctly scale the image.
+ */
+ if ((transforms & PNG_TRANSFORM_SHIFT)
+ && (info_ptr->valid & PNG_INFO_sBIT))
+ png_set_shift(png_ptr, &info_ptr->sig_bit);
+#endif
+
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+ /* pack pixels into bytes */
+ if (transforms & PNG_TRANSFORM_PACKING)
+ png_set_packing(png_ptr);
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+ /* swap location of alpha bytes from ARGB to RGBA */
+ if (transforms & PNG_TRANSFORM_SWAP_ALPHA)
+ png_set_swap_alpha(png_ptr);
+#endif
+
+#if defined(PNG_WRITE_FILLER_SUPPORTED)
+ /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into
+ * RGB (4 channels -> 3 channels). The second parameter is not used.
+ */
+ if (transforms & PNG_TRANSFORM_STRIP_FILLER)
+ png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
+#endif
+
+#if defined(PNG_WRITE_BGR_SUPPORTED)
+ /* flip BGR pixels to RGB */
+ if (transforms & PNG_TRANSFORM_BGR)
+ png_set_bgr(png_ptr);
+#endif
+
+#if defined(PNG_WRITE_SWAP_SUPPORTED)
+ /* swap bytes of 16-bit files to most significant byte first */
+ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN)
+ png_set_swap(png_ptr);
+#endif
+
+#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+ /* swap bits of 1, 2, 4 bit packed pixel formats */
+ if (transforms & PNG_TRANSFORM_PACKSWAP)
+ png_set_packswap(png_ptr);
+#endif
+
+ /* ----------------------- end of transformations ------------------- */
+
+ /* write the bits */
+ if (info_ptr->valid & PNG_INFO_IDAT)
+ png_write_image(png_ptr, info_ptr->row_pointers);
+
+ /* It is REQUIRED to call this to finish writing the rest of the file */
+ png_write_end(png_ptr, info_ptr);
+
+ transforms = transforms; /* quiet compiler warnings */
+ params = params;
+}
+#endif
+#endif /* PNG_WRITE_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngwtran.c b/distrib/libpng-1.2.19/pngwtran.c
new file mode 100644
index 0000000..0372fe6
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngwtran.c
@@ -0,0 +1,572 @@
+
+/* pngwtran.c - transforms the data in a row for PNG writers
+ *
+ * Last changed in libpng 1.2.9 April 14, 2006
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2006 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+#ifdef PNG_WRITE_SUPPORTED
+
+/* Transform the data according to the user's wishes. The order of
+ * transformations is significant.
+ */
+void /* PRIVATE */
+png_do_write_transformations(png_structp png_ptr)
+{
+ png_debug(1, "in png_do_write_transformations\n");
+
+ if (png_ptr == NULL)
+ return;
+
+#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
+ if (png_ptr->transformations & PNG_USER_TRANSFORM)
+ if(png_ptr->write_user_transform_fn != NULL)
+ (*(png_ptr->write_user_transform_fn)) /* user write transform function */
+ (png_ptr, /* png_ptr */
+ &(png_ptr->row_info), /* row_info: */
+ /* png_uint_32 width; width of row */
+ /* png_uint_32 rowbytes; number of bytes in row */
+ /* png_byte color_type; color type of pixels */
+ /* png_byte bit_depth; bit depth of samples */
+ /* png_byte channels; number of channels (1-4) */
+ /* png_byte pixel_depth; bits per pixel (depth*channels) */
+ png_ptr->row_buf + 1); /* start of pixel data for row */
+#endif
+#if defined(PNG_WRITE_FILLER_SUPPORTED)
+ if (png_ptr->transformations & PNG_FILLER)
+ png_do_strip_filler(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ png_ptr->flags);
+#endif
+#if defined(PNG_WRITE_PACKSWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACKSWAP)
+ png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+ if (png_ptr->transformations & PNG_PACK)
+ png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ (png_uint_32)png_ptr->bit_depth);
+#endif
+#if defined(PNG_WRITE_SWAP_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_BYTES)
+ png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+ if (png_ptr->transformations & PNG_SHIFT)
+ png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1,
+ &(png_ptr->shift));
+#endif
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_SWAP_ALPHA)
+ png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_ALPHA)
+ png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_BGR_SUPPORTED)
+ if (png_ptr->transformations & PNG_BGR)
+ png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+#if defined(PNG_WRITE_INVERT_SUPPORTED)
+ if (png_ptr->transformations & PNG_INVERT_MONO)
+ png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1);
+#endif
+}
+
+#if defined(PNG_WRITE_PACK_SUPPORTED)
+/* Pack pixels into bytes. Pass the true bit depth in bit_depth. The
+ * row_info bit depth should be 8 (one pixel per byte). The channels
+ * should be 1 (this only happens on grayscale and paletted images).
+ */
+void /* PRIVATE */
+png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth)
+{
+ png_debug(1, "in png_do_pack\n");
+ if (row_info->bit_depth == 8 &&
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ row_info->channels == 1)
+ {
+ switch ((int)bit_depth)
+ {
+ case 1:
+ {
+ png_bytep sp, dp;
+ int mask, v;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ sp = row;
+ dp = row;
+ mask = 0x80;
+ v = 0;
+
+ for (i = 0; i < row_width; i++)
+ {
+ if (*sp != 0)
+ v |= mask;
+ sp++;
+ if (mask > 1)
+ mask >>= 1;
+ else
+ {
+ mask = 0x80;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ }
+ if (mask != 0x80)
+ *dp = (png_byte)v;
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp, dp;
+ int shift, v;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ sp = row;
+ dp = row;
+ shift = 6;
+ v = 0;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte value;
+
+ value = (png_byte)(*sp & 0x03);
+ v |= (value << shift);
+ if (shift == 0)
+ {
+ shift = 6;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ else
+ shift -= 2;
+ sp++;
+ }
+ if (shift != 6)
+ *dp = (png_byte)v;
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp, dp;
+ int shift, v;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ sp = row;
+ dp = row;
+ shift = 4;
+ v = 0;
+ for (i = 0; i < row_width; i++)
+ {
+ png_byte value;
+
+ value = (png_byte)(*sp & 0x0f);
+ v |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 4;
+ *dp = (png_byte)v;
+ dp++;
+ v = 0;
+ }
+ else
+ shift -= 4;
+
+ sp++;
+ }
+ if (shift != 4)
+ *dp = (png_byte)v;
+ break;
+ }
+ }
+ row_info->bit_depth = (png_byte)bit_depth;
+ row_info->pixel_depth = (png_byte)(bit_depth * row_info->channels);
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
+ row_info->width);
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_SHIFT_SUPPORTED)
+/* Shift pixel values to take advantage of whole range. Pass the
+ * true number of bits in bit_depth. The row should be packed
+ * according to row_info->bit_depth. Thus, if you had a row of
+ * bit depth 4, but the pixels only had values from 0 to 7, you
+ * would pass 3 as bit_depth, and this routine would translate the
+ * data to 0 to 15.
+ */
+void /* PRIVATE */
+png_do_shift(png_row_infop row_info, png_bytep row, png_color_8p bit_depth)
+{
+ png_debug(1, "in png_do_shift\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL &&
+#else
+ if (
+#endif
+ row_info->color_type != PNG_COLOR_TYPE_PALETTE)
+ {
+ int shift_start[4], shift_dec[4];
+ int channels = 0;
+
+ if (row_info->color_type & PNG_COLOR_MASK_COLOR)
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->red;
+ shift_dec[channels] = bit_depth->red;
+ channels++;
+ shift_start[channels] = row_info->bit_depth - bit_depth->green;
+ shift_dec[channels] = bit_depth->green;
+ channels++;
+ shift_start[channels] = row_info->bit_depth - bit_depth->blue;
+ shift_dec[channels] = bit_depth->blue;
+ channels++;
+ }
+ else
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->gray;
+ shift_dec[channels] = bit_depth->gray;
+ channels++;
+ }
+ if (row_info->color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ shift_start[channels] = row_info->bit_depth - bit_depth->alpha;
+ shift_dec[channels] = bit_depth->alpha;
+ channels++;
+ }
+
+ /* with low row depths, could only be grayscale, so one channel */
+ if (row_info->bit_depth < 8)
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_byte mask;
+ png_uint_32 row_bytes = row_info->rowbytes;
+
+ if (bit_depth->gray == 1 && row_info->bit_depth == 2)
+ mask = 0x55;
+ else if (row_info->bit_depth == 4 && bit_depth->gray == 3)
+ mask = 0x11;
+ else
+ mask = 0xff;
+
+ for (i = 0; i < row_bytes; i++, bp++)
+ {
+ png_uint_16 v;
+ int j;
+
+ v = *bp;
+ *bp = 0;
+ for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0])
+ {
+ if (j > 0)
+ *bp |= (png_byte)((v << j) & 0xff);
+ else
+ *bp |= (png_byte)((v >> (-j)) & mask);
+ }
+ }
+ }
+ else if (row_info->bit_depth == 8)
+ {
+ png_bytep bp = row;
+ png_uint_32 i;
+ png_uint_32 istop = channels * row_info->width;
+
+ for (i = 0; i < istop; i++, bp++)
+ {
+
+ png_uint_16 v;
+ int j;
+ int c = (int)(i%channels);
+
+ v = *bp;
+ *bp = 0;
+ for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
+ {
+ if (j > 0)
+ *bp |= (png_byte)((v << j) & 0xff);
+ else
+ *bp |= (png_byte)((v >> (-j)) & 0xff);
+ }
+ }
+ }
+ else
+ {
+ png_bytep bp;
+ png_uint_32 i;
+ png_uint_32 istop = channels * row_info->width;
+
+ for (bp = row, i = 0; i < istop; i++)
+ {
+ int c = (int)(i%channels);
+ png_uint_16 value, v;
+ int j;
+
+ v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1));
+ value = 0;
+ for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c])
+ {
+ if (j > 0)
+ value |= (png_uint_16)((v << j) & (png_uint_16)0xffff);
+ else
+ value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff);
+ }
+ *bp++ = (png_byte)(value >> 8);
+ *bp++ = (png_byte)(value & 0xff);
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED)
+void /* PRIVATE */
+png_do_write_swap_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_write_swap_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This converts from ARGB to RGBA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save;
+ }
+ }
+ /* This converts from AARRGGBB to RRGGBBAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save[2];
+ save[0] = *(sp++);
+ save[1] = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save[0];
+ *(dp++) = save[1];
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This converts from AG to GA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save;
+ }
+ }
+ /* This converts from AAGG to GGAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ png_byte save[2];
+ save[0] = *(sp++);
+ save[1] = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = save[0];
+ *(dp++) = save[1];
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED)
+void /* PRIVATE */
+png_do_write_invert_alpha(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_write_invert_alpha\n");
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL)
+#endif
+ {
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ {
+ /* This inverts the alpha channel in RGBA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ /* does nothing
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ */
+ sp+=3; dp = sp;
+ *(dp++) = (png_byte)(255 - *(sp++));
+ }
+ }
+ /* This inverts the alpha channel in RRGGBBAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ /* does nothing
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ */
+ sp+=6; dp = sp;
+ *(dp++) = (png_byte)(255 - *(sp++));
+ *(dp++) = (png_byte)(255 - *(sp++));
+ }
+ }
+ }
+ else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
+ {
+ /* This inverts the alpha channel in GA */
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ *(dp++) = *(sp++);
+ *(dp++) = (png_byte)(255 - *(sp++));
+ }
+ }
+ /* This inverts the alpha channel in GGAA */
+ else
+ {
+ png_bytep sp, dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ for (i = 0, sp = dp = row; i < row_width; i++)
+ {
+ /* does nothing
+ *(dp++) = *(sp++);
+ *(dp++) = *(sp++);
+ */
+ sp+=2; dp = sp;
+ *(dp++) = (png_byte)(255 - *(sp++));
+ *(dp++) = (png_byte)(255 - *(sp++));
+ }
+ }
+ }
+ }
+}
+#endif
+
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+/* undoes intrapixel differencing */
+void /* PRIVATE */
+png_do_write_intrapixel(png_row_infop row_info, png_bytep row)
+{
+ png_debug(1, "in png_do_write_intrapixel\n");
+ if (
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ row != NULL && row_info != NULL &&
+#endif
+ (row_info->color_type & PNG_COLOR_MASK_COLOR))
+ {
+ int bytes_per_pixel;
+ png_uint_32 row_width = row_info->width;
+ if (row_info->bit_depth == 8)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 3;
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 4;
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ *(rp) = (png_byte)((*rp - *(rp+1))&0xff);
+ *(rp+2) = (png_byte)((*(rp+2) - *(rp+1))&0xff);
+ }
+ }
+ else if (row_info->bit_depth == 16)
+ {
+ png_bytep rp;
+ png_uint_32 i;
+
+ if (row_info->color_type == PNG_COLOR_TYPE_RGB)
+ bytes_per_pixel = 6;
+ else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA)
+ bytes_per_pixel = 8;
+ else
+ return;
+
+ for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel)
+ {
+ png_uint_32 s0 = (*(rp ) << 8) | *(rp+1);
+ png_uint_32 s1 = (*(rp+2) << 8) | *(rp+3);
+ png_uint_32 s2 = (*(rp+4) << 8) | *(rp+5);
+ png_uint_32 red = (png_uint_32)((s0-s1) & 0xffffL);
+ png_uint_32 blue = (png_uint_32)((s2-s1) & 0xffffL);
+ *(rp ) = (png_byte)((red >> 8) & 0xff);
+ *(rp+1) = (png_byte)(red & 0xff);
+ *(rp+4) = (png_byte)((blue >> 8) & 0xff);
+ *(rp+5) = (png_byte)(blue & 0xff);
+ }
+ }
+ }
+}
+#endif /* PNG_MNG_FEATURES_SUPPORTED */
+#endif /* PNG_WRITE_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/pngwutil.c b/distrib/libpng-1.2.19/pngwutil.c
new file mode 100644
index 0000000..849ee7d
--- /dev/null
+++ b/distrib/libpng-1.2.19/pngwutil.c
@@ -0,0 +1,2782 @@
+
+/* pngwutil.c - utilities to write a PNG file
+ *
+ * Last changed in libpng 1.2.19 August 18, 2007
+ * For conditions of distribution and use, see copyright notice in png.h
+ * Copyright (c) 1998-2007 Glenn Randers-Pehrson
+ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
+ * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
+ */
+
+#define PNG_INTERNAL
+#include "png.h"
+#ifdef PNG_WRITE_SUPPORTED
+
+/* Place a 32-bit number into a buffer in PNG byte order. We work
+ * with unsigned numbers for convenience, although one supported
+ * ancillary chunk uses signed (two's complement) numbers.
+ */
+void PNGAPI
+png_save_uint_32(png_bytep buf, png_uint_32 i)
+{
+ buf[0] = (png_byte)((i >> 24) & 0xff);
+ buf[1] = (png_byte)((i >> 16) & 0xff);
+ buf[2] = (png_byte)((i >> 8) & 0xff);
+ buf[3] = (png_byte)(i & 0xff);
+}
+
+/* The png_save_int_32 function assumes integers are stored in two's
+ * complement format. If this isn't the case, then this routine needs to
+ * be modified to write data in two's complement format.
+ */
+void PNGAPI
+png_save_int_32(png_bytep buf, png_int_32 i)
+{
+ buf[0] = (png_byte)((i >> 24) & 0xff);
+ buf[1] = (png_byte)((i >> 16) & 0xff);
+ buf[2] = (png_byte)((i >> 8) & 0xff);
+ buf[3] = (png_byte)(i & 0xff);
+}
+
+/* Place a 16-bit number into a buffer in PNG byte order.
+ * The parameter is declared unsigned int, not png_uint_16,
+ * just to avoid potential problems on pre-ANSI C compilers.
+ */
+void PNGAPI
+png_save_uint_16(png_bytep buf, unsigned int i)
+{
+ buf[0] = (png_byte)((i >> 8) & 0xff);
+ buf[1] = (png_byte)(i & 0xff);
+}
+
+/* Write a PNG chunk all at once. The type is an array of ASCII characters
+ * representing the chunk name. The array must be at least 4 bytes in
+ * length, and does not need to be null terminated. To be safe, pass the
+ * pre-defined chunk names here, and if you need a new one, define it
+ * where the others are defined. The length is the length of the data.
+ * All the data must be present. If that is not possible, use the
+ * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end()
+ * functions instead.
+ */
+void PNGAPI
+png_write_chunk(png_structp png_ptr, png_bytep chunk_name,
+ png_bytep data, png_size_t length)
+{
+ if(png_ptr == NULL) return;
+ png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length);
+ png_write_chunk_data(png_ptr, data, length);
+ png_write_chunk_end(png_ptr);
+}
+
+/* Write the start of a PNG chunk. The type is the chunk type.
+ * The total_length is the sum of the lengths of all the data you will be
+ * passing in png_write_chunk_data().
+ */
+void PNGAPI
+png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name,
+ png_uint_32 length)
+{
+ png_byte buf[4];
+ png_debug2(0, "Writing %s chunk (%lu bytes)\n", chunk_name, length);
+ if(png_ptr == NULL) return;
+
+ /* write the length */
+ png_save_uint_32(buf, length);
+ png_write_data(png_ptr, buf, (png_size_t)4);
+
+ /* write the chunk name */
+ png_write_data(png_ptr, chunk_name, (png_size_t)4);
+ /* reset the crc and run it over the chunk name */
+ png_reset_crc(png_ptr);
+ png_calculate_crc(png_ptr, chunk_name, (png_size_t)4);
+}
+
+/* Write the data of a PNG chunk started with png_write_chunk_start().
+ * Note that multiple calls to this function are allowed, and that the
+ * sum of the lengths from these calls *must* add up to the total_length
+ * given to png_write_chunk_start().
+ */
+void PNGAPI
+png_write_chunk_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+ /* write the data, and run the CRC over it */
+ if(png_ptr == NULL) return;
+ if (data != NULL && length > 0)
+ {
+ png_calculate_crc(png_ptr, data, length);
+ png_write_data(png_ptr, data, length);
+ }
+}
+
+/* Finish a chunk started with png_write_chunk_start(). */
+void PNGAPI
+png_write_chunk_end(png_structp png_ptr)
+{
+ png_byte buf[4];
+
+ if(png_ptr == NULL) return;
+
+ /* write the crc */
+ png_save_uint_32(buf, png_ptr->crc);
+
+ png_write_data(png_ptr, buf, (png_size_t)4);
+}
+
+/* Simple function to write the signature. If we have already written
+ * the magic bytes of the signature, or more likely, the PNG stream is
+ * being embedded into another stream and doesn't need its own signature,
+ * we should call png_set_sig_bytes() to tell libpng how many of the
+ * bytes have already been written.
+ */
+void /* PRIVATE */
+png_write_sig(png_structp png_ptr)
+{
+ png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10};
+ /* write the rest of the 8 byte signature */
+ png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
+ (png_size_t)8 - png_ptr->sig_bytes);
+ if(png_ptr->sig_bytes < 3)
+ png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
+}
+
+#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED)
+/*
+ * This pair of functions encapsulates the operation of (a) compressing a
+ * text string, and (b) issuing it later as a series of chunk data writes.
+ * The compression_state structure is shared context for these functions
+ * set up by the caller in order to make the whole mess thread-safe.
+ */
+
+typedef struct
+{
+ char *input; /* the uncompressed input data */
+ int input_len; /* its length */
+ int num_output_ptr; /* number of output pointers used */
+ int max_output_ptr; /* size of output_ptr */
+ png_charpp output_ptr; /* array of pointers to output */
+} compression_state;
+
+/* compress given text into storage in the png_ptr structure */
+static int /* PRIVATE */
+png_text_compress(png_structp png_ptr,
+ png_charp text, png_size_t text_len, int compression,
+ compression_state *comp)
+{
+ int ret;
+
+ comp->num_output_ptr = 0;
+ comp->max_output_ptr = 0;
+ comp->output_ptr = NULL;
+ comp->input = NULL;
+ comp->input_len = 0;
+
+ /* we may just want to pass the text right through */
+ if (compression == PNG_TEXT_COMPRESSION_NONE)
+ {
+ comp->input = text;
+ comp->input_len = text_len;
+ return((int)text_len);
+ }
+
+ if (compression >= PNG_TEXT_COMPRESSION_LAST)
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char msg[50];
+ png_snprintf(msg, 50, "Unknown compression type %d", compression);
+ png_warning(png_ptr, msg);
+#else
+ png_warning(png_ptr, "Unknown compression type");
+#endif
+ }
+
+ /* We can't write the chunk until we find out how much data we have,
+ * which means we need to run the compressor first and save the
+ * output. This shouldn't be a problem, as the vast majority of
+ * comments should be reasonable, but we will set up an array of
+ * malloc'd pointers to be sure.
+ *
+ * If we knew the application was well behaved, we could simplify this
+ * greatly by assuming we can always malloc an output buffer large
+ * enough to hold the compressed text ((1001 * text_len / 1000) + 12)
+ * and malloc this directly. The only time this would be a bad idea is
+ * if we can't malloc more than 64K and we have 64K of random input
+ * data, or if the input string is incredibly large (although this
+ * wouldn't cause a failure, just a slowdown due to swapping).
+ */
+
+ /* set up the compression buffers */
+ png_ptr->zstream.avail_in = (uInt)text_len;
+ png_ptr->zstream.next_in = (Bytef *)text;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = (Bytef *)png_ptr->zbuf;
+
+ /* this is the same compression loop as in png_write_row() */
+ do
+ {
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
+ if (ret != Z_OK)
+ {
+ /* error */
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+ /* check to see if we need more room */
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* make sure the output array has room */
+ if (comp->num_output_ptr >= comp->max_output_ptr)
+ {
+ int old_max;
+
+ old_max = comp->max_output_ptr;
+ comp->max_output_ptr = comp->num_output_ptr + 4;
+ if (comp->output_ptr != NULL)
+ {
+ png_charpp old_ptr;
+
+ old_ptr = comp->output_ptr;
+ comp->output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(comp->max_output_ptr *
+ png_sizeof (png_charpp)));
+ png_memcpy(comp->output_ptr, old_ptr, old_max
+ * png_sizeof (png_charp));
+ png_free(png_ptr, old_ptr);
+ }
+ else
+ comp->output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(comp->max_output_ptr *
+ png_sizeof (png_charp)));
+ }
+
+ /* save the data */
+ comp->output_ptr[comp->num_output_ptr] = (png_charp)png_malloc(png_ptr,
+ (png_uint_32)png_ptr->zbuf_size);
+ png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ comp->num_output_ptr++;
+
+ /* and reset the buffer */
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ }
+ /* continue until we don't have any more to compress */
+ } while (png_ptr->zstream.avail_in);
+
+ /* finish the compression */
+ do
+ {
+ /* tell zlib we are finished */
+ ret = deflate(&png_ptr->zstream, Z_FINISH);
+
+ if (ret == Z_OK)
+ {
+ /* check to see if we need more room */
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* check to make sure our output array has room */
+ if (comp->num_output_ptr >= comp->max_output_ptr)
+ {
+ int old_max;
+
+ old_max = comp->max_output_ptr;
+ comp->max_output_ptr = comp->num_output_ptr + 4;
+ if (comp->output_ptr != NULL)
+ {
+ png_charpp old_ptr;
+
+ old_ptr = comp->output_ptr;
+ /* This could be optimized to realloc() */
+ comp->output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(comp->max_output_ptr *
+ png_sizeof (png_charpp)));
+ png_memcpy(comp->output_ptr, old_ptr,
+ old_max * png_sizeof (png_charp));
+ png_free(png_ptr, old_ptr);
+ }
+ else
+ comp->output_ptr = (png_charpp)png_malloc(png_ptr,
+ (png_uint_32)(comp->max_output_ptr *
+ png_sizeof (png_charp)));
+ }
+
+ /* save off the data */
+ comp->output_ptr[comp->num_output_ptr] =
+ (png_charp)png_malloc(png_ptr, (png_uint_32)png_ptr->zbuf_size);
+ png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
+ png_ptr->zbuf_size);
+ comp->num_output_ptr++;
+
+ /* and reset the buffer pointers */
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ }
+ }
+ else if (ret != Z_STREAM_END)
+ {
+ /* we got an error */
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+ } while (ret != Z_STREAM_END);
+
+ /* text length is number of buffers plus last buffer */
+ text_len = png_ptr->zbuf_size * comp->num_output_ptr;
+ if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
+ text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out;
+
+ return((int)text_len);
+}
+
+/* ship the compressed text out via chunk writes */
+static void /* PRIVATE */
+png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
+{
+ int i;
+
+ /* handle the no-compression case */
+ if (comp->input)
+ {
+ png_write_chunk_data(png_ptr, (png_bytep)comp->input,
+ (png_size_t)comp->input_len);
+ return;
+ }
+
+ /* write saved output buffers, if any */
+ for (i = 0; i < comp->num_output_ptr; i++)
+ {
+ png_write_chunk_data(png_ptr,(png_bytep)comp->output_ptr[i],
+ png_ptr->zbuf_size);
+ png_free(png_ptr, comp->output_ptr[i]);
+ comp->output_ptr[i]=NULL;
+ }
+ if (comp->max_output_ptr != 0)
+ png_free(png_ptr, comp->output_ptr);
+ comp->output_ptr=NULL;
+ /* write anything left in zbuf */
+ if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size)
+ png_write_chunk_data(png_ptr, png_ptr->zbuf,
+ png_ptr->zbuf_size - png_ptr->zstream.avail_out);
+
+ /* reset zlib for another zTXt/iTXt or image data */
+ deflateReset(&png_ptr->zstream);
+ png_ptr->zstream.data_type = Z_BINARY;
+}
+#endif
+
+/* Write the IHDR chunk, and update the png_struct with the necessary
+ * information. Note that the rest of this code depends upon this
+ * information being correct.
+ */
+void /* PRIVATE */
+png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
+ int bit_depth, int color_type, int compression_type, int filter_type,
+ int interlace_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IHDR;
+#endif
+ png_byte buf[13]; /* buffer to store the IHDR info */
+
+ png_debug(1, "in png_write_IHDR\n");
+ /* Check that we have valid input data from the application info */
+ switch (color_type)
+ {
+ case PNG_COLOR_TYPE_GRAY:
+ switch (bit_depth)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16: png_ptr->channels = 1; break;
+ default: png_error(png_ptr,"Invalid bit depth for grayscale image");
+ }
+ break;
+ case PNG_COLOR_TYPE_RGB:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for RGB image");
+ png_ptr->channels = 3;
+ break;
+ case PNG_COLOR_TYPE_PALETTE:
+ switch (bit_depth)
+ {
+ case 1:
+ case 2:
+ case 4:
+ case 8: png_ptr->channels = 1; break;
+ default: png_error(png_ptr, "Invalid bit depth for paletted image");
+ }
+ break;
+ case PNG_COLOR_TYPE_GRAY_ALPHA:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
+ png_ptr->channels = 2;
+ break;
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ if (bit_depth != 8 && bit_depth != 16)
+ png_error(png_ptr, "Invalid bit depth for RGBA image");
+ png_ptr->channels = 4;
+ break;
+ default:
+ png_error(png_ptr, "Invalid image color type specified");
+ }
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ {
+ png_warning(png_ptr, "Invalid compression type specified");
+ compression_type = PNG_COMPRESSION_TYPE_BASE;
+ }
+
+ /* Write filter_method 64 (intrapixel differencing) only if
+ * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and
+ * 2. Libpng did not write a PNG signature (this filter_method is only
+ * used in PNG datastreams that are embedded in MNG datastreams) and
+ * 3. The application called png_permit_mng_features with a mask that
+ * included PNG_FLAG_MNG_FILTER_64 and
+ * 4. The filter_method is 64 and
+ * 5. The color_type is RGB or RGBA
+ */
+ if (
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) &&
+ ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) &&
+ (color_type == PNG_COLOR_TYPE_RGB ||
+ color_type == PNG_COLOR_TYPE_RGB_ALPHA) &&
+ (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) &&
+#endif
+ filter_type != PNG_FILTER_TYPE_BASE)
+ {
+ png_warning(png_ptr, "Invalid filter type specified");
+ filter_type = PNG_FILTER_TYPE_BASE;
+ }
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ if (interlace_type != PNG_INTERLACE_NONE &&
+ interlace_type != PNG_INTERLACE_ADAM7)
+ {
+ png_warning(png_ptr, "Invalid interlace type specified");
+ interlace_type = PNG_INTERLACE_ADAM7;
+ }
+#else
+ interlace_type=PNG_INTERLACE_NONE;
+#endif
+
+ /* save off the relevent information */
+ png_ptr->bit_depth = (png_byte)bit_depth;
+ png_ptr->color_type = (png_byte)color_type;
+ png_ptr->interlaced = (png_byte)interlace_type;
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ png_ptr->filter_type = (png_byte)filter_type;
+#endif
+ png_ptr->compression_type = (png_byte)compression_type;
+ png_ptr->width = width;
+ png_ptr->height = height;
+
+ png_ptr->pixel_depth = (png_byte)(bit_depth * png_ptr->channels);
+ png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, width);
+ /* set the usr info, so any transformations can modify it */
+ png_ptr->usr_width = png_ptr->width;
+ png_ptr->usr_bit_depth = png_ptr->bit_depth;
+ png_ptr->usr_channels = png_ptr->channels;
+
+ /* pack the header information into the buffer */
+ png_save_uint_32(buf, width);
+ png_save_uint_32(buf + 4, height);
+ buf[8] = (png_byte)bit_depth;
+ buf[9] = (png_byte)color_type;
+ buf[10] = (png_byte)compression_type;
+ buf[11] = (png_byte)filter_type;
+ buf[12] = (png_byte)interlace_type;
+
+ /* write the chunk */
+ png_write_chunk(png_ptr, (png_bytep)png_IHDR, buf, (png_size_t)13);
+
+ /* initialize zlib with PNG info */
+ png_ptr->zstream.zalloc = png_zalloc;
+ png_ptr->zstream.zfree = png_zfree;
+ png_ptr->zstream.opaque = (voidpf)png_ptr;
+ if (!(png_ptr->do_filter))
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
+ png_ptr->bit_depth < 8)
+ png_ptr->do_filter = PNG_FILTER_NONE;
+ else
+ png_ptr->do_filter = PNG_ALL_FILTERS;
+ }
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY))
+ {
+ if (png_ptr->do_filter != PNG_FILTER_NONE)
+ png_ptr->zlib_strategy = Z_FILTERED;
+ else
+ png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY;
+ }
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL))
+ png_ptr->zlib_level = Z_DEFAULT_COMPRESSION;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL))
+ png_ptr->zlib_mem_level = 8;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS))
+ png_ptr->zlib_window_bits = 15;
+ if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD))
+ png_ptr->zlib_method = 8;
+ if (deflateInit2(&png_ptr->zstream, png_ptr->zlib_level,
+ png_ptr->zlib_method, png_ptr->zlib_window_bits,
+ png_ptr->zlib_mem_level, png_ptr->zlib_strategy) != Z_OK)
+ png_error(png_ptr, "zlib failed to initialize compressor");
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ /* libpng is not interested in zstream.data_type */
+ /* set it to a predefined value, to avoid its evaluation inside zlib */
+ png_ptr->zstream.data_type = Z_BINARY;
+
+ png_ptr->mode = PNG_HAVE_IHDR;
+}
+
+/* write the palette. We are careful not to trust png_color to be in the
+ * correct order for PNG, so people can redefine it to any convenient
+ * structure.
+ */
+void /* PRIVATE */
+png_write_PLTE(png_structp png_ptr, png_colorp palette, png_uint_32 num_pal)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_PLTE;
+#endif
+ png_uint_32 i;
+ png_colorp pal_ptr;
+ png_byte buf[3];
+
+ png_debug(1, "in png_write_PLTE\n");
+ if ((
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
+#endif
+ num_pal == 0) || num_pal > 256)
+ {
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ png_error(png_ptr, "Invalid number of colors in palette");
+ }
+ else
+ {
+ png_warning(png_ptr, "Invalid number of colors in palette");
+ return;
+ }
+ }
+
+ if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR))
+ {
+ png_warning(png_ptr,
+ "Ignoring request to write a PLTE chunk in grayscale PNG");
+ return;
+ }
+
+ png_ptr->num_palette = (png_uint_16)num_pal;
+ png_debug1(3, "num_palette = %d\n", png_ptr->num_palette);
+
+ png_write_chunk_start(png_ptr, png_PLTE, num_pal * 3);
+#ifndef PNG_NO_POINTER_INDEXING
+ for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++)
+ {
+ buf[0] = pal_ptr->red;
+ buf[1] = pal_ptr->green;
+ buf[2] = pal_ptr->blue;
+ png_write_chunk_data(png_ptr, buf, (png_size_t)3);
+ }
+#else
+ /* This is a little slower but some buggy compilers need to do this instead */
+ pal_ptr=palette;
+ for (i = 0; i < num_pal; i++)
+ {
+ buf[0] = pal_ptr[i].red;
+ buf[1] = pal_ptr[i].green;
+ buf[2] = pal_ptr[i].blue;
+ png_write_chunk_data(png_ptr, buf, (png_size_t)3);
+ }
+#endif
+ png_write_chunk_end(png_ptr);
+ png_ptr->mode |= PNG_HAVE_PLTE;
+}
+
+/* write an IDAT chunk */
+void /* PRIVATE */
+png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IDAT;
+#endif
+ png_debug(1, "in png_write_IDAT\n");
+
+ /* Optimize the CMF field in the zlib stream. */
+ /* This hack of the zlib stream is compliant to the stream specification. */
+ if (!(png_ptr->mode & PNG_HAVE_IDAT) &&
+ png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE)
+ {
+ unsigned int z_cmf = data[0]; /* zlib compression method and flags */
+ if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70)
+ {
+ /* Avoid memory underflows and multiplication overflows. */
+ /* The conditions below are practically always satisfied;
+ however, they still must be checked. */
+ if (length >= 2 &&
+ png_ptr->height < 16384 && png_ptr->width < 16384)
+ {
+ png_uint_32 uncompressed_idat_size = png_ptr->height *
+ ((png_ptr->width *
+ png_ptr->channels * png_ptr->bit_depth + 15) >> 3);
+ unsigned int z_cinfo = z_cmf >> 4;
+ unsigned int half_z_window_size = 1 << (z_cinfo + 7);
+ while (uncompressed_idat_size <= half_z_window_size &&
+ half_z_window_size >= 256)
+ {
+ z_cinfo--;
+ half_z_window_size >>= 1;
+ }
+ z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4);
+ if (data[0] != (png_byte)z_cmf)
+ {
+ data[0] = (png_byte)z_cmf;
+ data[1] &= 0xe0;
+ data[1] += (png_byte)(0x1f - ((z_cmf << 8) + data[1]) % 0x1f);
+ }
+ }
+ }
+ else
+ png_error(png_ptr,
+ "Invalid zlib compression method or flags in IDAT");
+ }
+
+ png_write_chunk(png_ptr, (png_bytep)png_IDAT, data, length);
+ png_ptr->mode |= PNG_HAVE_IDAT;
+}
+
+/* write an IEND chunk */
+void /* PRIVATE */
+png_write_IEND(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_IEND;
+#endif
+ png_debug(1, "in png_write_IEND\n");
+ png_write_chunk(png_ptr, (png_bytep)png_IEND, png_bytep_NULL,
+ (png_size_t)0);
+ png_ptr->mode |= PNG_HAVE_IEND;
+}
+
+#if defined(PNG_WRITE_gAMA_SUPPORTED)
+/* write a gAMA chunk */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+void /* PRIVATE */
+png_write_gAMA(png_structp png_ptr, double file_gamma)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_gAMA;
+#endif
+ png_uint_32 igamma;
+ png_byte buf[4];
+
+ png_debug(1, "in png_write_gAMA\n");
+ /* file_gamma is saved in 1/100,000ths */
+ igamma = (png_uint_32)(file_gamma * 100000.0 + 0.5);
+ png_save_uint_32(buf, igamma);
+ png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
+}
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+void /* PRIVATE */
+png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_gAMA;
+#endif
+ png_byte buf[4];
+
+ png_debug(1, "in png_write_gAMA\n");
+ /* file_gamma is saved in 1/100,000ths */
+ png_save_uint_32(buf, (png_uint_32)file_gamma);
+ png_write_chunk(png_ptr, (png_bytep)png_gAMA, buf, (png_size_t)4);
+}
+#endif
+#endif
+
+#if defined(PNG_WRITE_sRGB_SUPPORTED)
+/* write a sRGB chunk */
+void /* PRIVATE */
+png_write_sRGB(png_structp png_ptr, int srgb_intent)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_sRGB;
+#endif
+ png_byte buf[1];
+
+ png_debug(1, "in png_write_sRGB\n");
+ if(srgb_intent >= PNG_sRGB_INTENT_LAST)
+ png_warning(png_ptr,
+ "Invalid sRGB rendering intent specified");
+ buf[0]=(png_byte)srgb_intent;
+ png_write_chunk(png_ptr, (png_bytep)png_sRGB, buf, (png_size_t)1);
+}
+#endif
+
+#if defined(PNG_WRITE_iCCP_SUPPORTED)
+/* write an iCCP chunk */
+void /* PRIVATE */
+png_write_iCCP(png_structp png_ptr, png_charp name, int compression_type,
+ png_charp profile, int profile_len)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_iCCP;
+#endif
+ png_size_t name_len;
+ png_charp new_name;
+ compression_state comp;
+ int embedded_profile_len = 0;
+
+ png_debug(1, "in png_write_iCCP\n");
+
+ comp.num_output_ptr = 0;
+ comp.max_output_ptr = 0;
+ comp.output_ptr = NULL;
+ comp.input = NULL;
+ comp.input_len = 0;
+
+ if (name == NULL || (name_len = png_check_keyword(png_ptr, name,
+ &new_name)) == 0)
+ {
+ png_warning(png_ptr, "Empty keyword in iCCP chunk");
+ return;
+ }
+
+ if (compression_type != PNG_COMPRESSION_TYPE_BASE)
+ png_warning(png_ptr, "Unknown compression type in iCCP chunk");
+
+ if (profile == NULL)
+ profile_len = 0;
+
+ if (profile_len > 3)
+ embedded_profile_len =
+ ((*( (png_bytep)profile ))<<24) |
+ ((*( (png_bytep)profile+1))<<16) |
+ ((*( (png_bytep)profile+2))<< 8) |
+ ((*( (png_bytep)profile+3)) );
+
+ if (profile_len < embedded_profile_len)
+ {
+ png_warning(png_ptr,
+ "Embedded profile length too large in iCCP chunk");
+ return;
+ }
+
+ if (profile_len > embedded_profile_len)
+ {
+ png_warning(png_ptr,
+ "Truncating profile to actual length in iCCP chunk");
+ profile_len = embedded_profile_len;
+ }
+
+ if (profile_len)
+ profile_len = png_text_compress(png_ptr, profile, (png_size_t)profile_len,
+ PNG_COMPRESSION_TYPE_BASE, &comp);
+
+ /* make sure we include the NULL after the name and the compression type */
+ png_write_chunk_start(png_ptr, png_iCCP,
+ (png_uint_32)name_len+profile_len+2);
+ new_name[name_len+1]=0x00;
+ png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 2);
+
+ if (profile_len)
+ png_write_compressed_data_out(png_ptr, &comp);
+
+ png_write_chunk_end(png_ptr);
+ png_free(png_ptr, new_name);
+}
+#endif
+
+#if defined(PNG_WRITE_sPLT_SUPPORTED)
+/* write a sPLT chunk */
+void /* PRIVATE */
+png_write_sPLT(png_structp png_ptr, png_sPLT_tp spalette)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_sPLT;
+#endif
+ png_size_t name_len;
+ png_charp new_name;
+ png_byte entrybuf[10];
+ int entry_size = (spalette->depth == 8 ? 6 : 10);
+ int palette_size = entry_size * spalette->nentries;
+ png_sPLT_entryp ep;
+#ifdef PNG_NO_POINTER_INDEXING
+ int i;
+#endif
+
+ png_debug(1, "in png_write_sPLT\n");
+ if (spalette->name == NULL || (name_len = png_check_keyword(png_ptr,
+ spalette->name, &new_name))==0)
+ {
+ png_warning(png_ptr, "Empty keyword in sPLT chunk");
+ return;
+ }
+
+ /* make sure we include the NULL after the name */
+ png_write_chunk_start(png_ptr, png_sPLT,
+ (png_uint_32)(name_len + 2 + palette_size));
+ png_write_chunk_data(png_ptr, (png_bytep)new_name, name_len + 1);
+ png_write_chunk_data(png_ptr, (png_bytep)&spalette->depth, 1);
+
+ /* loop through each palette entry, writing appropriately */
+#ifndef PNG_NO_POINTER_INDEXING
+ for (ep = spalette->entries; ep<spalette->entries+spalette->nentries; ep++)
+ {
+ if (spalette->depth == 8)
+ {
+ entrybuf[0] = (png_byte)ep->red;
+ entrybuf[1] = (png_byte)ep->green;
+ entrybuf[2] = (png_byte)ep->blue;
+ entrybuf[3] = (png_byte)ep->alpha;
+ png_save_uint_16(entrybuf + 4, ep->frequency);
+ }
+ else
+ {
+ png_save_uint_16(entrybuf + 0, ep->red);
+ png_save_uint_16(entrybuf + 2, ep->green);
+ png_save_uint_16(entrybuf + 4, ep->blue);
+ png_save_uint_16(entrybuf + 6, ep->alpha);
+ png_save_uint_16(entrybuf + 8, ep->frequency);
+ }
+ png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size);
+ }
+#else
+ ep=spalette->entries;
+ for (i=0; i>spalette->nentries; i++)
+ {
+ if (spalette->depth == 8)
+ {
+ entrybuf[0] = (png_byte)ep[i].red;
+ entrybuf[1] = (png_byte)ep[i].green;
+ entrybuf[2] = (png_byte)ep[i].blue;
+ entrybuf[3] = (png_byte)ep[i].alpha;
+ png_save_uint_16(entrybuf + 4, ep[i].frequency);
+ }
+ else
+ {
+ png_save_uint_16(entrybuf + 0, ep[i].red);
+ png_save_uint_16(entrybuf + 2, ep[i].green);
+ png_save_uint_16(entrybuf + 4, ep[i].blue);
+ png_save_uint_16(entrybuf + 6, ep[i].alpha);
+ png_save_uint_16(entrybuf + 8, ep[i].frequency);
+ }
+ png_write_chunk_data(png_ptr, entrybuf, entry_size);
+ }
+#endif
+
+ png_write_chunk_end(png_ptr);
+ png_free(png_ptr, new_name);
+}
+#endif
+
+#if defined(PNG_WRITE_sBIT_SUPPORTED)
+/* write the sBIT chunk */
+void /* PRIVATE */
+png_write_sBIT(png_structp png_ptr, png_color_8p sbit, int color_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_sBIT;
+#endif
+ png_byte buf[4];
+ png_size_t size;
+
+ png_debug(1, "in png_write_sBIT\n");
+ /* make sure we don't depend upon the order of PNG_COLOR_8 */
+ if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_byte maxbits;
+
+ maxbits = (png_byte)(color_type==PNG_COLOR_TYPE_PALETTE ? 8 :
+ png_ptr->usr_bit_depth);
+ if (sbit->red == 0 || sbit->red > maxbits ||
+ sbit->green == 0 || sbit->green > maxbits ||
+ sbit->blue == 0 || sbit->blue > maxbits)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[0] = sbit->red;
+ buf[1] = sbit->green;
+ buf[2] = sbit->blue;
+ size = 3;
+ }
+ else
+ {
+ if (sbit->gray == 0 || sbit->gray > png_ptr->usr_bit_depth)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[0] = sbit->gray;
+ size = 1;
+ }
+
+ if (color_type & PNG_COLOR_MASK_ALPHA)
+ {
+ if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth)
+ {
+ png_warning(png_ptr, "Invalid sBIT depth specified");
+ return;
+ }
+ buf[size++] = sbit->alpha;
+ }
+
+ png_write_chunk(png_ptr, (png_bytep)png_sBIT, buf, size);
+}
+#endif
+
+#if defined(PNG_WRITE_cHRM_SUPPORTED)
+/* write the cHRM chunk */
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+void /* PRIVATE */
+png_write_cHRM(png_structp png_ptr, double white_x, double white_y,
+ double red_x, double red_y, double green_x, double green_y,
+ double blue_x, double blue_y)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_cHRM;
+#endif
+ png_byte buf[32];
+ png_uint_32 itemp;
+
+ png_debug(1, "in png_write_cHRM\n");
+ /* each value is saved in 1/100,000ths */
+ if (white_x < 0 || white_x > 0.8 || white_y < 0 || white_y > 0.8 ||
+ white_x + white_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM white point specified");
+#if !defined(PNG_NO_CONSOLE_IO)
+ fprintf(stderr,"white_x=%f, white_y=%f\n",white_x, white_y);
+#endif
+ return;
+ }
+ itemp = (png_uint_32)(white_x * 100000.0 + 0.5);
+ png_save_uint_32(buf, itemp);
+ itemp = (png_uint_32)(white_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 4, itemp);
+
+ if (red_x < 0 || red_y < 0 || red_x + red_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM red point specified");
+ return;
+ }
+ itemp = (png_uint_32)(red_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 8, itemp);
+ itemp = (png_uint_32)(red_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 12, itemp);
+
+ if (green_x < 0 || green_y < 0 || green_x + green_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM green point specified");
+ return;
+ }
+ itemp = (png_uint_32)(green_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 16, itemp);
+ itemp = (png_uint_32)(green_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 20, itemp);
+
+ if (blue_x < 0 || blue_y < 0 || blue_x + blue_y > 1.0)
+ {
+ png_warning(png_ptr, "Invalid cHRM blue point specified");
+ return;
+ }
+ itemp = (png_uint_32)(blue_x * 100000.0 + 0.5);
+ png_save_uint_32(buf + 24, itemp);
+ itemp = (png_uint_32)(blue_y * 100000.0 + 0.5);
+ png_save_uint_32(buf + 28, itemp);
+
+ png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
+}
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+void /* PRIVATE */
+png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x,
+ png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y,
+ png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x,
+ png_fixed_point blue_y)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_cHRM;
+#endif
+ png_byte buf[32];
+
+ png_debug(1, "in png_write_cHRM\n");
+ /* each value is saved in 1/100,000ths */
+ if (white_x > 80000L || white_y > 80000L || white_x + white_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid fixed cHRM white point specified");
+#if !defined(PNG_NO_CONSOLE_IO)
+ fprintf(stderr,"white_x=%ld, white_y=%ld\n",white_x, white_y);
+#endif
+ return;
+ }
+ png_save_uint_32(buf, (png_uint_32)white_x);
+ png_save_uint_32(buf + 4, (png_uint_32)white_y);
+
+ if (red_x + red_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid cHRM fixed red point specified");
+ return;
+ }
+ png_save_uint_32(buf + 8, (png_uint_32)red_x);
+ png_save_uint_32(buf + 12, (png_uint_32)red_y);
+
+ if (green_x + green_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid fixed cHRM green point specified");
+ return;
+ }
+ png_save_uint_32(buf + 16, (png_uint_32)green_x);
+ png_save_uint_32(buf + 20, (png_uint_32)green_y);
+
+ if (blue_x + blue_y > 100000L)
+ {
+ png_warning(png_ptr, "Invalid fixed cHRM blue point specified");
+ return;
+ }
+ png_save_uint_32(buf + 24, (png_uint_32)blue_x);
+ png_save_uint_32(buf + 28, (png_uint_32)blue_y);
+
+ png_write_chunk(png_ptr, (png_bytep)png_cHRM, buf, (png_size_t)32);
+}
+#endif
+#endif
+
+#if defined(PNG_WRITE_tRNS_SUPPORTED)
+/* write the tRNS chunk */
+void /* PRIVATE */
+png_write_tRNS(png_structp png_ptr, png_bytep trans, png_color_16p tran,
+ int num_trans, int color_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_tRNS;
+#endif
+ png_byte buf[6];
+
+ png_debug(1, "in png_write_tRNS\n");
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette)
+ {
+ png_warning(png_ptr,"Invalid number of transparent colors specified");
+ return;
+ }
+ /* write the chunk out as it is */
+ png_write_chunk(png_ptr, (png_bytep)png_tRNS, trans, (png_size_t)num_trans);
+ }
+ else if (color_type == PNG_COLOR_TYPE_GRAY)
+ {
+ /* one 16 bit value */
+ if(tran->gray >= (1 << png_ptr->bit_depth))
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to write tRNS chunk out-of-range for bit_depth");
+ return;
+ }
+ png_save_uint_16(buf, tran->gray);
+ png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)2);
+ }
+ else if (color_type == PNG_COLOR_TYPE_RGB)
+ {
+ /* three 16 bit values */
+ png_save_uint_16(buf, tran->red);
+ png_save_uint_16(buf + 2, tran->green);
+ png_save_uint_16(buf + 4, tran->blue);
+ if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
+ return;
+ }
+ png_write_chunk(png_ptr, (png_bytep)png_tRNS, buf, (png_size_t)6);
+ }
+ else
+ {
+ png_warning(png_ptr, "Can't write tRNS with an alpha channel");
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_bKGD_SUPPORTED)
+/* write the background chunk */
+void /* PRIVATE */
+png_write_bKGD(png_structp png_ptr, png_color_16p back, int color_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_bKGD;
+#endif
+ png_byte buf[6];
+
+ png_debug(1, "in png_write_bKGD\n");
+ if (color_type == PNG_COLOR_TYPE_PALETTE)
+ {
+ if (
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
+ (png_ptr->num_palette ||
+ (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) &&
+#endif
+ back->index > png_ptr->num_palette)
+ {
+ png_warning(png_ptr, "Invalid background palette index");
+ return;
+ }
+ buf[0] = back->index;
+ png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)1);
+ }
+ else if (color_type & PNG_COLOR_MASK_COLOR)
+ {
+ png_save_uint_16(buf, back->red);
+ png_save_uint_16(buf + 2, back->green);
+ png_save_uint_16(buf + 4, back->blue);
+ if(png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]))
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
+ return;
+ }
+ png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)6);
+ }
+ else
+ {
+ if(back->gray >= (1 << png_ptr->bit_depth))
+ {
+ png_warning(png_ptr,
+ "Ignoring attempt to write bKGD chunk out-of-range for bit_depth");
+ return;
+ }
+ png_save_uint_16(buf, back->gray);
+ png_write_chunk(png_ptr, (png_bytep)png_bKGD, buf, (png_size_t)2);
+ }
+}
+#endif
+
+#if defined(PNG_WRITE_hIST_SUPPORTED)
+/* write the histogram */
+void /* PRIVATE */
+png_write_hIST(png_structp png_ptr, png_uint_16p hist, int num_hist)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_hIST;
+#endif
+ int i;
+ png_byte buf[3];
+
+ png_debug(1, "in png_write_hIST\n");
+ if (num_hist > (int)png_ptr->num_palette)
+ {
+ png_debug2(3, "num_hist = %d, num_palette = %d\n", num_hist,
+ png_ptr->num_palette);
+ png_warning(png_ptr, "Invalid number of histogram entries specified");
+ return;
+ }
+
+ png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(num_hist * 2));
+ for (i = 0; i < num_hist; i++)
+ {
+ png_save_uint_16(buf, hist[i]);
+ png_write_chunk_data(png_ptr, buf, (png_size_t)2);
+ }
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
+ defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
+/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
+ * and if invalid, correct the keyword rather than discarding the entire
+ * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
+ * length, forbids leading or trailing whitespace, multiple internal spaces,
+ * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
+ *
+ * The new_key is allocated to hold the corrected keyword and must be freed
+ * by the calling routine. This avoids problems with trying to write to
+ * static keywords without having to have duplicate copies of the strings.
+ */
+png_size_t /* PRIVATE */
+png_check_keyword(png_structp png_ptr, png_charp key, png_charpp new_key)
+{
+ png_size_t key_len;
+ png_charp kp, dp;
+ int kflag;
+ int kwarn=0;
+
+ png_debug(1, "in png_check_keyword\n");
+ *new_key = NULL;
+
+ if (key == NULL || (key_len = png_strlen(key)) == 0)
+ {
+ png_warning(png_ptr, "zero length keyword");
+ return ((png_size_t)0);
+ }
+
+ png_debug1(2, "Keyword to be checked is '%s'\n", key);
+
+ *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
+ if (*new_key == NULL)
+ {
+ png_warning(png_ptr, "Out of memory while procesing keyword");
+ return ((png_size_t)0);
+ }
+
+ /* Replace non-printing characters with a blank and print a warning */
+ for (kp = key, dp = *new_key; *kp != '\0'; kp++, dp++)
+ {
+ if ((png_byte)*kp < 0x20 ||
+ ((png_byte)*kp > 0x7E && (png_byte)*kp < 0xA1))
+ {
+#if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE)
+ char msg[40];
+
+ png_snprintf(msg, 40,
+ "invalid keyword character 0x%02X", (png_byte)*kp);
+ png_warning(png_ptr, msg);
+#else
+ png_warning(png_ptr, "invalid character in keyword");
+#endif
+ *dp = ' ';
+ }
+ else
+ {
+ *dp = *kp;
+ }
+ }
+ *dp = '\0';
+
+ /* Remove any trailing white space. */
+ kp = *new_key + key_len - 1;
+ if (*kp == ' ')
+ {
+ png_warning(png_ptr, "trailing spaces removed from keyword");
+
+ while (*kp == ' ')
+ {
+ *(kp--) = '\0';
+ key_len--;
+ }
+ }
+
+ /* Remove any leading white space. */
+ kp = *new_key;
+ if (*kp == ' ')
+ {
+ png_warning(png_ptr, "leading spaces removed from keyword");
+
+ while (*kp == ' ')
+ {
+ kp++;
+ key_len--;
+ }
+ }
+
+ png_debug1(2, "Checking for multiple internal spaces in '%s'\n", kp);
+
+ /* Remove multiple internal spaces. */
+ for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
+ {
+ if (*kp == ' ' && kflag == 0)
+ {
+ *(dp++) = *kp;
+ kflag = 1;
+ }
+ else if (*kp == ' ')
+ {
+ key_len--;
+ kwarn=1;
+ }
+ else
+ {
+ *(dp++) = *kp;
+ kflag = 0;
+ }
+ }
+ *dp = '\0';
+ if(kwarn)
+ png_warning(png_ptr, "extra interior spaces removed from keyword");
+
+ if (key_len == 0)
+ {
+ png_free(png_ptr, *new_key);
+ *new_key=NULL;
+ png_warning(png_ptr, "Zero length keyword");
+ }
+
+ if (key_len > 79)
+ {
+ png_warning(png_ptr, "keyword length must be 1 - 79 characters");
+ new_key[79] = '\0';
+ key_len = 79;
+ }
+
+ return (key_len);
+}
+#endif
+
+#if defined(PNG_WRITE_tEXt_SUPPORTED)
+/* write a tEXt chunk */
+void /* PRIVATE */
+png_write_tEXt(png_structp png_ptr, png_charp key, png_charp text,
+ png_size_t text_len)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_tEXt;
+#endif
+ png_size_t key_len;
+ png_charp new_key;
+
+ png_debug(1, "in png_write_tEXt\n");
+ if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ {
+ png_warning(png_ptr, "Empty keyword in tEXt chunk");
+ return;
+ }
+
+ if (text == NULL || *text == '\0')
+ text_len = 0;
+ else
+ text_len = png_strlen(text);
+
+ /* make sure we include the 0 after the key */
+ png_write_chunk_start(png_ptr, (png_bytep)png_tEXt, (png_uint_32)key_len+text_len+1);
+ /*
+ * We leave it to the application to meet PNG-1.0 requirements on the
+ * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
+ * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
+ * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
+ */
+ png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
+ if (text_len)
+ png_write_chunk_data(png_ptr, (png_bytep)text, text_len);
+
+ png_write_chunk_end(png_ptr);
+ png_free(png_ptr, new_key);
+}
+#endif
+
+#if defined(PNG_WRITE_zTXt_SUPPORTED)
+/* write a compressed text chunk */
+void /* PRIVATE */
+png_write_zTXt(png_structp png_ptr, png_charp key, png_charp text,
+ png_size_t text_len, int compression)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_zTXt;
+#endif
+ png_size_t key_len;
+ char buf[1];
+ png_charp new_key;
+ compression_state comp;
+
+ png_debug(1, "in png_write_zTXt\n");
+
+ comp.num_output_ptr = 0;
+ comp.max_output_ptr = 0;
+ comp.output_ptr = NULL;
+ comp.input = NULL;
+ comp.input_len = 0;
+
+ if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ {
+ png_warning(png_ptr, "Empty keyword in zTXt chunk");
+ return;
+ }
+
+ if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
+ {
+ png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
+ png_free(png_ptr, new_key);
+ return;
+ }
+
+ text_len = png_strlen(text);
+
+ /* compute the compressed data; do it now for the length */
+ text_len = png_text_compress(png_ptr, text, text_len, compression,
+ &comp);
+
+ /* write start of chunk */
+ png_write_chunk_start(png_ptr, (png_bytep)png_zTXt, (png_uint_32)
+ (key_len+text_len+2));
+ /* write key */
+ png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
+ png_free(png_ptr, new_key);
+
+ buf[0] = (png_byte)compression;
+ /* write compression */
+ png_write_chunk_data(png_ptr, (png_bytep)buf, (png_size_t)1);
+ /* write the compressed data */
+ png_write_compressed_data_out(png_ptr, &comp);
+
+ /* close the chunk */
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#if defined(PNG_WRITE_iTXt_SUPPORTED)
+/* write an iTXt chunk */
+void /* PRIVATE */
+png_write_iTXt(png_structp png_ptr, int compression, png_charp key,
+ png_charp lang, png_charp lang_key, png_charp text)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_iTXt;
+#endif
+ png_size_t lang_len, key_len, lang_key_len, text_len;
+ png_charp new_lang, new_key;
+ png_byte cbuf[2];
+ compression_state comp;
+
+ png_debug(1, "in png_write_iTXt\n");
+
+ comp.num_output_ptr = 0;
+ comp.max_output_ptr = 0;
+ comp.output_ptr = NULL;
+ comp.input = NULL;
+
+ if (key == NULL || (key_len = png_check_keyword(png_ptr, key, &new_key))==0)
+ {
+ png_warning(png_ptr, "Empty keyword in iTXt chunk");
+ return;
+ }
+ if (lang == NULL || (lang_len = png_check_keyword(png_ptr, lang, &new_lang))==0)
+ {
+ png_warning(png_ptr, "Empty language field in iTXt chunk");
+ new_lang = NULL;
+ lang_len = 0;
+ }
+
+ if (lang_key == NULL)
+ lang_key_len = 0;
+ else
+ lang_key_len = png_strlen(lang_key);
+
+ if (text == NULL)
+ text_len = 0;
+ else
+ text_len = png_strlen(text);
+
+ /* compute the compressed data; do it now for the length */
+ text_len = png_text_compress(png_ptr, text, text_len, compression-2,
+ &comp);
+
+
+ /* make sure we include the compression flag, the compression byte,
+ * and the NULs after the key, lang, and lang_key parts */
+
+ png_write_chunk_start(png_ptr, (png_bytep)png_iTXt,
+ (png_uint_32)(
+ 5 /* comp byte, comp flag, terminators for key, lang and lang_key */
+ + key_len
+ + lang_len
+ + lang_key_len
+ + text_len));
+
+ /*
+ * We leave it to the application to meet PNG-1.0 requirements on the
+ * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of
+ * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
+ * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
+ */
+ png_write_chunk_data(png_ptr, (png_bytep)new_key, key_len + 1);
+
+ /* set the compression flag */
+ if (compression == PNG_ITXT_COMPRESSION_NONE || \
+ compression == PNG_TEXT_COMPRESSION_NONE)
+ cbuf[0] = 0;
+ else /* compression == PNG_ITXT_COMPRESSION_zTXt */
+ cbuf[0] = 1;
+ /* set the compression method */
+ cbuf[1] = 0;
+ png_write_chunk_data(png_ptr, cbuf, 2);
+
+ cbuf[0] = 0;
+ png_write_chunk_data(png_ptr, (new_lang ? (png_bytep)new_lang : cbuf), lang_len + 1);
+ png_write_chunk_data(png_ptr, (lang_key ? (png_bytep)lang_key : cbuf), lang_key_len + 1);
+ png_write_compressed_data_out(png_ptr, &comp);
+
+ png_write_chunk_end(png_ptr);
+ png_free(png_ptr, new_key);
+ if (new_lang)
+ png_free(png_ptr, new_lang);
+}
+#endif
+
+#if defined(PNG_WRITE_oFFs_SUPPORTED)
+/* write the oFFs chunk */
+void /* PRIVATE */
+png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset,
+ int unit_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_oFFs;
+#endif
+ png_byte buf[9];
+
+ png_debug(1, "in png_write_oFFs\n");
+ if (unit_type >= PNG_OFFSET_LAST)
+ png_warning(png_ptr, "Unrecognized unit type for oFFs chunk");
+
+ png_save_int_32(buf, x_offset);
+ png_save_int_32(buf + 4, y_offset);
+ buf[8] = (png_byte)unit_type;
+
+ png_write_chunk(png_ptr, png_oFFs, buf, (png_size_t)9);
+}
+#endif
+#if defined(PNG_WRITE_pCAL_SUPPORTED)
+/* write the pCAL chunk (described in the PNG extensions document) */
+void /* PRIVATE */
+png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
+ png_int_32 X1, int type, int nparams, png_charp units, png_charpp params)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_pCAL;
+#endif
+ png_size_t purpose_len, units_len, total_len;
+ png_uint_32p params_len;
+ png_byte buf[10];
+ png_charp new_purpose;
+ int i;
+
+ png_debug1(1, "in png_write_pCAL (%d parameters)\n", nparams);
+ if (type >= PNG_EQUATION_LAST)
+ png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
+
+ purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
+ png_debug1(3, "pCAL purpose length = %d\n", (int)purpose_len);
+ units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
+ png_debug1(3, "pCAL units length = %d\n", (int)units_len);
+ total_len = purpose_len + units_len + 10;
+
+ params_len = (png_uint_32p)png_malloc(png_ptr, (png_uint_32)(nparams
+ *png_sizeof(png_uint_32)));
+
+ /* Find the length of each parameter, making sure we don't count the
+ null terminator for the last parameter. */
+ for (i = 0; i < nparams; i++)
+ {
+ params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1);
+ png_debug2(3, "pCAL parameter %d length = %lu\n", i, params_len[i]);
+ total_len += (png_size_t)params_len[i];
+ }
+
+ png_debug1(3, "pCAL total length = %d\n", (int)total_len);
+ png_write_chunk_start(png_ptr, png_pCAL, (png_uint_32)total_len);
+ png_write_chunk_data(png_ptr, (png_bytep)new_purpose, purpose_len);
+ png_save_int_32(buf, X0);
+ png_save_int_32(buf + 4, X1);
+ buf[8] = (png_byte)type;
+ buf[9] = (png_byte)nparams;
+ png_write_chunk_data(png_ptr, buf, (png_size_t)10);
+ png_write_chunk_data(png_ptr, (png_bytep)units, (png_size_t)units_len);
+
+ png_free(png_ptr, new_purpose);
+
+ for (i = 0; i < nparams; i++)
+ {
+ png_write_chunk_data(png_ptr, (png_bytep)params[i],
+ (png_size_t)params_len[i]);
+ }
+
+ png_free(png_ptr, params_len);
+ png_write_chunk_end(png_ptr);
+}
+#endif
+
+#if defined(PNG_WRITE_sCAL_SUPPORTED)
+/* write the sCAL chunk */
+#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO)
+void /* PRIVATE */
+png_write_sCAL(png_structp png_ptr, int unit, double width, double height)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_sCAL;
+#endif
+ char buf[64];
+ png_size_t total_len;
+
+ png_debug(1, "in png_write_sCAL\n");
+
+ buf[0] = (char)unit;
+#if defined(_WIN32_WCE)
+/* sprintf() function is not supported on WindowsCE */
+ {
+ wchar_t wc_buf[32];
+ size_t wc_len;
+ swprintf(wc_buf, TEXT("%12.12e"), width);
+ wc_len = wcslen(wc_buf);
+ WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + 1, wc_len, NULL, NULL);
+ total_len = wc_len + 2;
+ swprintf(wc_buf, TEXT("%12.12e"), height);
+ wc_len = wcslen(wc_buf);
+ WideCharToMultiByte(CP_ACP, 0, wc_buf, -1, buf + total_len, wc_len,
+ NULL, NULL);
+ total_len += wc_len;
+ }
+#else
+ png_snprintf(buf + 1, 63, "%12.12e", width);
+ total_len = 1 + png_strlen(buf + 1) + 1;
+ png_snprintf(buf + total_len, 64-total_len, "%12.12e", height);
+ total_len += png_strlen(buf + total_len);
+#endif
+
+ png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len);
+ png_write_chunk(png_ptr, png_sCAL, (png_bytep)buf, total_len);
+}
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+void /* PRIVATE */
+png_write_sCAL_s(png_structp png_ptr, int unit, png_charp width,
+ png_charp height)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_sCAL;
+#endif
+ png_byte buf[64];
+ png_size_t wlen, hlen, total_len;
+
+ png_debug(1, "in png_write_sCAL_s\n");
+
+ wlen = png_strlen(width);
+ hlen = png_strlen(height);
+ total_len = wlen + hlen + 2;
+ if (total_len > 64)
+ {
+ png_warning(png_ptr, "Can't write sCAL (buffer too small)");
+ return;
+ }
+
+ buf[0] = (png_byte)unit;
+ png_memcpy(buf + 1, width, wlen + 1); /* append the '\0' here */
+ png_memcpy(buf + wlen + 2, height, hlen); /* do NOT append the '\0' here */
+
+ png_debug1(3, "sCAL total length = %u\n", (unsigned int)total_len);
+ png_write_chunk(png_ptr, png_sCAL, buf, total_len);
+}
+#endif
+#endif
+#endif
+
+#if defined(PNG_WRITE_pHYs_SUPPORTED)
+/* write the pHYs chunk */
+void /* PRIVATE */
+png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit,
+ png_uint_32 y_pixels_per_unit,
+ int unit_type)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_pHYs;
+#endif
+ png_byte buf[9];
+
+ png_debug(1, "in png_write_pHYs\n");
+ if (unit_type >= PNG_RESOLUTION_LAST)
+ png_warning(png_ptr, "Unrecognized unit type for pHYs chunk");
+
+ png_save_uint_32(buf, x_pixels_per_unit);
+ png_save_uint_32(buf + 4, y_pixels_per_unit);
+ buf[8] = (png_byte)unit_type;
+
+ png_write_chunk(png_ptr, png_pHYs, buf, (png_size_t)9);
+}
+#endif
+
+#if defined(PNG_WRITE_tIME_SUPPORTED)
+/* Write the tIME chunk. Use either png_convert_from_struct_tm()
+ * or png_convert_from_time_t(), or fill in the structure yourself.
+ */
+void /* PRIVATE */
+png_write_tIME(png_structp png_ptr, png_timep mod_time)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ PNG_tIME;
+#endif
+ png_byte buf[7];
+
+ png_debug(1, "in png_write_tIME\n");
+ if (mod_time->month > 12 || mod_time->month < 1 ||
+ mod_time->day > 31 || mod_time->day < 1 ||
+ mod_time->hour > 23 || mod_time->second > 60)
+ {
+ png_warning(png_ptr, "Invalid time specified for tIME chunk");
+ return;
+ }
+
+ png_save_uint_16(buf, mod_time->year);
+ buf[2] = mod_time->month;
+ buf[3] = mod_time->day;
+ buf[4] = mod_time->hour;
+ buf[5] = mod_time->minute;
+ buf[6] = mod_time->second;
+
+ png_write_chunk(png_ptr, png_tIME, buf, (png_size_t)7);
+}
+#endif
+
+/* initializes the row writing capability of libpng */
+void /* PRIVATE */
+png_write_start_row(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* start of interlace block in the y direction */
+ int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* offset to next interlace block in the y direction */
+ int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+#endif
+
+ png_size_t buf_size;
+
+ png_debug(1, "in png_write_start_row\n");
+ buf_size = (png_size_t)(PNG_ROWBYTES(
+ png_ptr->usr_channels*png_ptr->usr_bit_depth,png_ptr->width)+1);
+
+ /* set up row buffer */
+ png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
+ png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
+
+#ifndef PNG_NO_WRITE_FILTERING
+ /* set up filtering buffer, if using this filter */
+ if (png_ptr->do_filter & PNG_FILTER_SUB)
+ {
+ png_ptr->sub_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
+ }
+
+ /* We only need to keep the previous row if we are using one of these. */
+ if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH))
+ {
+ /* set up previous row buffer */
+ png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, (png_uint_32)buf_size);
+ png_memset(png_ptr->prev_row, 0, buf_size);
+
+ if (png_ptr->do_filter & PNG_FILTER_UP)
+ {
+ png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_AVG)
+ {
+ png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
+ }
+
+ if (png_ptr->do_filter & PNG_FILTER_PAETH)
+ {
+ png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
+ (png_ptr->rowbytes + 1));
+ png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
+ }
+#endif /* PNG_NO_WRITE_FILTERING */
+ }
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* if interlaced, we need to set up width and height of pass */
+ if (png_ptr->interlaced)
+ {
+ if (!(png_ptr->transformations & PNG_INTERLACE))
+ {
+ png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 -
+ png_pass_ystart[0]) / png_pass_yinc[0];
+ png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 -
+ png_pass_start[0]) / png_pass_inc[0];
+ }
+ else
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->usr_width = png_ptr->width;
+ }
+ }
+ else
+#endif
+ {
+ png_ptr->num_rows = png_ptr->height;
+ png_ptr->usr_width = png_ptr->width;
+ }
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+}
+
+/* Internal use only. Called when finished processing a row of data. */
+void /* PRIVATE */
+png_write_finish_row(png_structp png_ptr)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+
+ /* start of interlace block in the y direction */
+ int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1};
+
+ /* offset to next interlace block in the y direction */
+ int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};
+#endif
+
+ int ret;
+
+ png_debug(1, "in png_write_finish_row\n");
+ /* next row */
+ png_ptr->row_number++;
+
+ /* see if we are done */
+ if (png_ptr->row_number < png_ptr->num_rows)
+ return;
+
+#ifdef PNG_WRITE_INTERLACING_SUPPORTED
+ /* if interlaced, go to next pass */
+ if (png_ptr->interlaced)
+ {
+ png_ptr->row_number = 0;
+ if (png_ptr->transformations & PNG_INTERLACE)
+ {
+ png_ptr->pass++;
+ }
+ else
+ {
+ /* loop until we find a non-zero width or height pass */
+ do
+ {
+ png_ptr->pass++;
+ if (png_ptr->pass >= 7)
+ break;
+ png_ptr->usr_width = (png_ptr->width +
+ png_pass_inc[png_ptr->pass] - 1 -
+ png_pass_start[png_ptr->pass]) /
+ png_pass_inc[png_ptr->pass];
+ png_ptr->num_rows = (png_ptr->height +
+ png_pass_yinc[png_ptr->pass] - 1 -
+ png_pass_ystart[png_ptr->pass]) /
+ png_pass_yinc[png_ptr->pass];
+ if (png_ptr->transformations & PNG_INTERLACE)
+ break;
+ } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
+
+ }
+
+ /* reset the row above the image for the next pass */
+ if (png_ptr->pass < 7)
+ {
+ if (png_ptr->prev_row != NULL)
+ png_memset(png_ptr->prev_row, 0,
+ (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels*
+ png_ptr->usr_bit_depth,png_ptr->width))+1);
+ return;
+ }
+ }
+#endif
+
+ /* if we get here, we've just written the last row, so we need
+ to flush the compressor */
+ do
+ {
+ /* tell the compressor we are done */
+ ret = deflate(&png_ptr->zstream, Z_FINISH);
+ /* check for an error */
+ if (ret == Z_OK)
+ {
+ /* check to see if we need more room */
+ if (!(png_ptr->zstream.avail_out))
+ {
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ }
+ else if (ret != Z_STREAM_END)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+ } while (ret != Z_STREAM_END);
+
+ /* write any extra space */
+ if (png_ptr->zstream.avail_out < png_ptr->zbuf_size)
+ {
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
+ png_ptr->zstream.avail_out);
+ }
+
+ deflateReset(&png_ptr->zstream);
+ png_ptr->zstream.data_type = Z_BINARY;
+}
+
+#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
+/* Pick out the correct pixels for the interlace pass.
+ * The basic idea here is to go through the row with a source
+ * pointer and a destination pointer (sp and dp), and copy the
+ * correct pixels for the pass. As the row gets compacted,
+ * sp will always be >= dp, so we should never overwrite anything.
+ * See the default: case for the easiest code to understand.
+ */
+void /* PRIVATE */
+png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
+{
+#ifdef PNG_USE_LOCAL_ARRAYS
+ /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+ /* start of interlace block */
+ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0};
+
+ /* offset to next interlace block */
+ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};
+#endif
+
+ png_debug(1, "in png_do_write_interlace\n");
+ /* we don't have to do anything on the last pass (6) */
+#if defined(PNG_USELESS_TESTS_SUPPORTED)
+ if (row != NULL && row_info != NULL && pass < 6)
+#else
+ if (pass < 6)
+#endif
+ {
+ /* each pixel depth is handled separately */
+ switch (row_info->pixel_depth)
+ {
+ case 1:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ dp = row;
+ d = 0;
+ shift = 7;
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 3);
+ value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 7;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift--;
+
+ }
+ if (shift != 7)
+ *dp = (png_byte)d;
+ break;
+ }
+ case 2:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ dp = row;
+ shift = 6;
+ d = 0;
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 2);
+ value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 6;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift -= 2;
+ }
+ if (shift != 6)
+ *dp = (png_byte)d;
+ break;
+ }
+ case 4:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ int shift;
+ int d;
+ int value;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+
+ dp = row;
+ shift = 4;
+ d = 0;
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ sp = row + (png_size_t)(i >> 1);
+ value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f;
+ d |= (value << shift);
+
+ if (shift == 0)
+ {
+ shift = 4;
+ *dp++ = (png_byte)d;
+ d = 0;
+ }
+ else
+ shift -= 4;
+ }
+ if (shift != 4)
+ *dp = (png_byte)d;
+ break;
+ }
+ default:
+ {
+ png_bytep sp;
+ png_bytep dp;
+ png_uint_32 i;
+ png_uint_32 row_width = row_info->width;
+ png_size_t pixel_bytes;
+
+ /* start at the beginning */
+ dp = row;
+ /* find out how many bytes each pixel takes up */
+ pixel_bytes = (row_info->pixel_depth >> 3);
+ /* loop through the row, only looking at the pixels that
+ matter */
+ for (i = png_pass_start[pass]; i < row_width;
+ i += png_pass_inc[pass])
+ {
+ /* find out where the original pixel is */
+ sp = row + (png_size_t)i * pixel_bytes;
+ /* move the pixel */
+ if (dp != sp)
+ png_memcpy(dp, sp, pixel_bytes);
+ /* next pixel */
+ dp += pixel_bytes;
+ }
+ break;
+ }
+ }
+ /* set new row width */
+ row_info->width = (row_info->width +
+ png_pass_inc[pass] - 1 -
+ png_pass_start[pass]) /
+ png_pass_inc[pass];
+ row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth,
+ row_info->width);
+ }
+}
+#endif
+
+/* This filters the row, chooses which filter to use, if it has not already
+ * been specified by the application, and then writes the row out with the
+ * chosen filter.
+ */
+#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
+#define PNG_HISHIFT 10
+#define PNG_LOMASK ((png_uint_32)0xffffL)
+#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
+void /* PRIVATE */
+png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
+{
+ png_bytep prev_row, best_row, row_buf;
+ png_uint_32 mins, bpp;
+ png_byte filter_to_do = png_ptr->do_filter;
+ png_uint_32 row_bytes = row_info->rowbytes;
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ int num_p_filters = (int)png_ptr->num_prev_filters;
+#endif
+
+ png_debug(1, "in png_write_find_filter\n");
+ /* find out how many bytes offset each pixel is */
+ bpp = (row_info->pixel_depth + 7) >> 3;
+
+ prev_row = png_ptr->prev_row;
+ best_row = row_buf = png_ptr->row_buf;
+#ifndef PNG_NO_WRITE_FILTER
+ mins = PNG_MAXSUM;
+
+ /* The prediction method we use is to find which method provides the
+ * smallest value when summing the absolute values of the distances
+ * from zero, using anything >= 128 as negative numbers. This is known
+ * as the "minimum sum of absolute differences" heuristic. Other
+ * heuristics are the "weighted minimum sum of absolute differences"
+ * (experimental and can in theory improve compression), and the "zlib
+ * predictive" method (not implemented yet), which does test compressions
+ * of lines using different filter methods, and then chooses the
+ * (series of) filter(s) that give minimum compressed data size (VERY
+ * computationally expensive).
+ *
+ * GRR 980525: consider also
+ * (1) minimum sum of absolute differences from running average (i.e.,
+ * keep running sum of non-absolute differences & count of bytes)
+ * [track dispersion, too? restart average if dispersion too large?]
+ * (1b) minimum sum of absolute differences from sliding average, probably
+ * with window size <= deflate window (usually 32K)
+ * (2) minimum sum of squared differences from zero or running average
+ * (i.e., ~ root-mean-square approach)
+ */
+
+
+ /* We don't need to test the 'no filter' case if this is the only filter
+ * that has been chosen, as it doesn't actually do anything to the data.
+ */
+ if ((filter_to_do & PNG_FILTER_NONE) &&
+ filter_to_do != PNG_FILTER_NONE)
+ {
+ png_bytep rp;
+ png_uint_32 sum = 0;
+ png_uint_32 i;
+ int v;
+
+ for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
+ {
+ v = *rp;
+ sum += (v < 128) ? v : 256 - v;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ png_uint_32 sumhi, sumlo;
+ int j;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
+
+ /* Reduce the sum if we match any of the previous rows */
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ /* Factor in the cost of this filter (this is here for completeness,
+ * but it makes no sense to have a "cost" for the NONE filter, as
+ * it has the minimum possible computational cost - none).
+ */
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+ mins = sum;
+ }
+
+ /* sub filter */
+ if (filter_to_do == PNG_FILTER_SUB)
+ /* it's the only filter so no testing is needed */
+ {
+ png_bytep rp, lp, dp;
+ png_uint_32 i;
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
+ i++, rp++, dp++)
+ {
+ *dp = *rp;
+ }
+ for (lp = row_buf + 1; i < row_bytes;
+ i++, rp++, lp++, dp++)
+ {
+ *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+ }
+ best_row = png_ptr->sub_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_SUB)
+ {
+ png_bytep rp, dp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ /* We temporarily increase the "minimum sum" by the factor we
+ * would reduce the sum of this filter, so that we can do the
+ * early exit comparison without scaling the sum each time.
+ */
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
+ i++, rp++, dp++)
+ {
+ v = *dp = *rp;
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+ for (lp = row_buf + 1; i < row_bytes;
+ i++, rp++, lp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
+ {
+ sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->sub_row;
+ }
+ }
+
+ /* up filter */
+ if (filter_to_do == PNG_FILTER_UP)
+ {
+ png_bytep rp, dp, pp;
+ png_uint_32 i;
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
+ pp = prev_row + 1; i < row_bytes;
+ i++, rp++, pp++, dp++)
+ {
+ *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+ }
+ best_row = png_ptr->up_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_UP)
+ {
+ png_bytep rp, dp, pp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
+ pp = prev_row + 1; i < row_bytes; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->up_row;
+ }
+ }
+
+ /* avg filter */
+ if (filter_to_do == PNG_FILTER_AVG)
+ {
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 i;
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
+ }
+ for (lp = row_buf + 1; i < row_bytes; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
+ & 0xff);
+ }
+ best_row = png_ptr->avg_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_AVG)
+ {
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+ for (lp = row_buf + 1; i < row_bytes; i++)
+ {
+ v = *dp++ =
+ (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->avg_row;
+ }
+ }
+
+ /* Paeth filter */
+ if (filter_to_do == PNG_FILTER_PAETH)
+ {
+ png_bytep rp, dp, pp, cp, lp;
+ png_uint_32 i;
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+ }
+
+ for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp++;
+ c = *cp++;
+ a = *lp++;
+
+ p = b - c;
+ pc = a - c;
+
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+
+ *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
+ }
+ best_row = png_ptr->paeth_row;
+ }
+
+ else if (filter_to_do & PNG_FILTER_PAETH)
+ {
+ png_bytep rp, dp, pp, cp, lp;
+ png_uint_32 sum = 0, lmins = mins;
+ png_uint_32 i;
+ int v;
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 lmhi, lmlo;
+ lmlo = lmins & PNG_LOMASK;
+ lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
+ {
+ lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+ lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+
+ if (lmhi > PNG_HIMASK)
+ lmins = PNG_MAXSUM;
+ else
+ lmins = (lmhi << PNG_HISHIFT) + lmlo;
+ }
+#endif
+
+ for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
+ pp = prev_row + 1; i < bpp; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+ }
+
+ for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
+ {
+ int a, b, c, pa, pb, pc, p;
+
+ b = *pp++;
+ c = *cp++;
+ a = *lp++;
+
+#ifndef PNG_SLOW_PAETH
+ p = b - c;
+ pc = a - c;
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+#else /* PNG_SLOW_PAETH */
+ p = a + b - c;
+ pa = abs(p - a);
+ pb = abs(p - b);
+ pc = abs(p - c);
+ if (pa <= pb && pa <= pc)
+ p = a;
+ else if (pb <= pc)
+ p = b;
+ else
+ p = c;
+#endif /* PNG_SLOW_PAETH */
+
+ v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
+
+ sum += (v < 128) ? v : 256 - v;
+
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ {
+ int j;
+ png_uint_32 sumhi, sumlo;
+ sumlo = sum & PNG_LOMASK;
+ sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+
+ for (j = 0; j < num_p_filters; j++)
+ {
+ if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
+ {
+ sumlo = (sumlo * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_weights[j]) >>
+ PNG_WEIGHT_SHIFT;
+ }
+ }
+
+ sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+ sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
+ PNG_COST_SHIFT;
+
+ if (sumhi > PNG_HIMASK)
+ sum = PNG_MAXSUM;
+ else
+ sum = (sumhi << PNG_HISHIFT) + sumlo;
+ }
+#endif
+
+ if (sum < mins)
+ {
+ best_row = png_ptr->paeth_row;
+ }
+ }
+#endif /* PNG_NO_WRITE_FILTER */
+ /* Do the actual writing of the filtered row data from the chosen filter. */
+
+ png_write_filtered_row(png_ptr, best_row);
+
+#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
+ /* Save the type of filter we picked this time for future calculations */
+ if (png_ptr->num_prev_filters > 0)
+ {
+ int j;
+ for (j = 1; j < num_p_filters; j++)
+ {
+ png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
+ }
+ png_ptr->prev_filters[j] = best_row[0];
+ }
+#endif
+}
+
+
+/* Do the actual writing of a previously filtered row. */
+void /* PRIVATE */
+png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
+{
+ png_debug(1, "in png_write_filtered_row\n");
+ png_debug1(2, "filter = %d\n", filtered_row[0]);
+ /* set up the zlib input buffer */
+
+ png_ptr->zstream.next_in = filtered_row;
+ png_ptr->zstream.avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
+ /* repeat until we have compressed all the data */
+ do
+ {
+ int ret; /* return of zlib */
+
+ /* compress the data */
+ ret = deflate(&png_ptr->zstream, Z_NO_FLUSH);
+ /* check for compression errors */
+ if (ret != Z_OK)
+ {
+ if (png_ptr->zstream.msg != NULL)
+ png_error(png_ptr, png_ptr->zstream.msg);
+ else
+ png_error(png_ptr, "zlib error");
+ }
+
+ /* see if it is time to write another IDAT */
+ if (!(png_ptr->zstream.avail_out))
+ {
+ /* write the IDAT and reset the zlib output buffer */
+ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+ png_ptr->zstream.next_out = png_ptr->zbuf;
+ png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
+ }
+ /* repeat until all data has been compressed */
+ } while (png_ptr->zstream.avail_in);
+
+ /* swap the current and previous rows */
+ if (png_ptr->prev_row != NULL)
+ {
+ png_bytep tptr;
+
+ tptr = png_ptr->prev_row;
+ png_ptr->prev_row = png_ptr->row_buf;
+ png_ptr->row_buf = tptr;
+ }
+
+ /* finish row - updates counters and flushes zlib if last row */
+ png_write_finish_row(png_ptr);
+
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+ png_ptr->flush_rows++;
+
+ if (png_ptr->flush_dist > 0 &&
+ png_ptr->flush_rows >= png_ptr->flush_dist)
+ {
+ png_write_flush(png_ptr);
+ }
+#endif
+}
+#endif /* PNG_WRITE_SUPPORTED */
diff --git a/distrib/libpng-1.2.19/sources.make b/distrib/libpng-1.2.19/sources.make
new file mode 100644
index 0000000..d8088c7
--- /dev/null
+++ b/distrib/libpng-1.2.19/sources.make
@@ -0,0 +1,14 @@
+# this file is included by various Makefiles and defines the set of sources used by our version of LibPng
+#
+LIBPNG_SOURCES := png.c pngerror.c pngget.c pngmem.c pngpread.c pngread.c \
+ pngrio.c pngrtran.c pngrutil.c pngset.c pngtrans.c pngvcrd.c pngwio.c \
+ pngwrite.c pngwtran.c pngwutil.c
+
+ifeq ($(HOST_OS),darwin)
+ LIBPNG_CFLAGS += -DPNG_NO_MMX_CODE
+else
+ LIBPNG_SOURCES += pnggccrd.c
+endif
+
+LIBPNG_SOURCES := $(LIBPNG_SOURCES:%=$(LIBPNG_DIR)/%)
+
diff --git a/distrib/make-distrib.sh b/distrib/make-distrib.sh
new file mode 100755
index 0000000..537bc2c
--- /dev/null
+++ b/distrib/make-distrib.sh
@@ -0,0 +1,112 @@
+#!/bin/bash
+#
+# this script is used to build a source distribution package for the Android emulator
+# the package includes:
+# - the sources of our patched SDL library
+# - the sources of our patched QEMU emulator
+# - appropriate scripts to rebuild the emulator binary
+#
+
+# create temporary directory
+TMPROOT=/tmp/android-package
+DATE=$(date +%Y%m%d)
+PACKAGE=android-emulator-$DATE
+TMPDIR=$TMPROOT/$PACKAGE
+if ! ( rm -rf $TMPROOT && mkdir -p $TMPDIR ) then
+ echo "could not create temporary directory $TMPDIR"
+ exit 3
+fi
+
+locate_qemu_viewpath ()
+{
+ viewpath=$(p4 files $0 | sed -e "s/\(.*\)#.*/\\1/g")
+ # assumes that this program is in the 'distrib' directory of the QEMU sources
+ echo $(dirname $(dirname $viewpath))
+}
+
+locate_depot_files ()
+{
+ root=$(p4 where $1) || (
+ echo "you need to map $1 into your workspace to build an emulator source release package"
+ exit 3
+ )
+ root=$(echo $root | cut -d" " -f3 | sed -e "s%/\.\.\.%%")
+ echo $root
+}
+
+locate_source_files ()
+{
+ files=$(p4 files $1/... | grep -v "delete change" | sed -e "s/\(.*\)#.*/\\1/g")
+ files=$(echo $files | sed -e "s%$1/%%g")
+ echo $files
+}
+
+# locate SDL root directory in client workspace
+if [ -z "$SDLROOT" ] ; then
+ SDLROOT=$(locate_depot_files //toolchain/sdl/...)
+ echo "SDLROOT is $SDLROOT"
+fi
+
+if [ ! -x "$SDLROOT" ] ; then
+ if [ -z "$TOP" ] ; then
+ echo "please define the TOP variable"
+ exit 3
+ fi
+ echo "unable to find $SDLROOT as the SDL root directory"
+ echo "please define SDLROOT to point to the correct location"
+ exit 3
+fi
+
+# locate QEMU root directory
+if [ -z "$QEMUROOT" ] ; then
+ QEMUVIEW=$(locate_qemu_viewpath)
+ echo "QEMUVIEW is $QEMUVIEW"
+ QEMUROOT=$(locate_depot_files $QEMUVIEW/...)
+ echo "QEMUROOT is $QEMUROOT"
+fi
+
+if [ ! -x "$QEMUROOT" ] ; then
+ if [ -z "$TOP" ] ; then
+ echo "please define the TOP variable"
+ exit 3
+ fi
+ echo "unable to find $QEMUROOT as the QEMU root directory"
+ echo "please define QEMUROOT to point to the correct location"
+ exit 3
+fi
+
+copy_source_files ()
+{
+ DSTDIR=$1
+ SRCDIR=$2
+ files=$(locate_source_files $3)
+ mkdir $DSTDIR && for f in $files; do
+ mkdir -p $(dirname $DSTDIR/$f);
+ cp $SRCDIR/$f $DSTDIR/$f
+ done
+}
+
+# copy and cleanup the SDL sources
+echo "copying SDL sources"
+SDLDIR=$TMPDIR/sdl
+copy_source_files $SDLDIR $SDLROOT //toolchain/sdl
+
+# copy and cleanup the QEMU sources
+echo "copying QEMU sources"
+QEMUDIR=$TMPDIR/qemu
+copy_source_files $QEMUDIR $QEMUROOT $QEMUVIEW
+
+echo "copying control scripts"
+cp -f $QEMUDIR/Makefile.qemu $QEMUDIR/Makefile
+rm -f $QEMUDIR/Makefile.android
+cp $QEMUDIR/distrib/build-emulator.sh $TMPDIR/build-emulator.sh
+cp $QEMUDIR/distrib/README $TMPDIR/README
+
+echo "packaging release into a tarball"
+cd $TMPROOT
+tar cjf $PACKAGE.tar.bz2 $PACKAGE
+
+echo "cleaning up"
+rm -rf $TMPDIR
+
+echo "please grab $TMPROOT/$PACKAGE.tar.bz2"
diff --git a/distrib/update-audio.sh b/distrib/update-audio.sh
new file mode 100755
index 0000000..8afd3c4
--- /dev/null
+++ b/distrib/update-audio.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+#
+# this script is used to update the prebuilt libqemu-audio.a file in the Android source tree
+# we use a prebuilt package because we don't want to force the installation of the ALSA / EsounD / Whatever
+# development packages on every developer machine, or every build server.
+#
+
+# assumes this script is located in the 'distrib' sub-directory
+cd `dirname $0`
+cd ..
+
+locate_depot_files ()
+{
+ root=$(p4 where $1) || (
+ echo "you need to map $1 into your workspace to build an emulator source release package"
+ exit 3
+ )
+ root=$(echo $root | cut -d" " -f3 | sed -e "s%/\.\.\.%%")
+ echo $root
+}
+
+# find the prebuilt directory
+OS=`uname -s`
+EXE=""
+case "$OS" in
+ Darwin)
+ CPU=`uname -p`
+ if [ "$CPU" == "i386" ] ; then
+ OS=darwin-x86
+ else
+ OS=darwin-ppc
+ fi
+ ;;
+ *_NT-5.1)
+ OS=windows
+ EXE=.exe
+ ;;
+esac
+
+PREBUILT=$(locate_depot_files //device/prebuilt/$OS)
+
+# find the GNU Make program
+is_gnu_make ()
+{
+ version=$($1 -v | grep GNU)
+ if test -n "$version"; then
+ echo "$1"
+ else
+ echo ""
+ fi
+}
+
+if test -z "$GNUMAKE"; then
+ GNUMAKE=`which make` && GNUMAKE=$(is_gnu_make $GNUMAKE)
+fi
+
+if test -z "$GNUMAKE"; then
+ GNUMAKE=`which gmake` && GNUMAKE=$(is_gnu_make $GNUMAKE)
+fi
+
+if test -z "$GNUMAKE"; then
+ echo "could not find GNU Make on this machine. please define GNUMAKE to point to it"
+ exit 3
+fi
+
+TEST=$(is_gnu_make $GNUMAKE)
+if test -z "$TEST"; then
+ echo "it seems that '$GNUMAKE' is not a working GNU Make binary. please check the definition of GNUMAKE"
+ exit 3
+fi
+
+# ensure we have a recent audio library built
+#
+#echo "GNUMAKE is $GNUMAKE"
+source=arm-softmmu/libqemu-audio.a
+$GNUMAKE $source || (echo "could not build the audio library. Aborting" && exit 1)
+
+# now do a p4 edit, a copy and ask for submission
+#
+TARGET=$PREBUILT/qemu/libqemu-audio.a
+
+p4 edit $TARGET || (echo "could not p4 edit $TARGET" && exit 3)
+cp -f $source $TARGET
+echo "please do: p4 submit $TARGET"
+
diff --git a/distrib/zlib-1.2.3/Makefile b/distrib/zlib-1.2.3/Makefile
new file mode 100644
index 0000000..9cf80c9
--- /dev/null
+++ b/distrib/zlib-1.2.3/Makefile
@@ -0,0 +1,15 @@
+# Makefile used to compile zlib statically
+#
+ZLIB_LIB := $(SRC_PATH)/libz.a
+ZLIB_CFLAGS := -I$(ZLIB_DIR)
+
+include $(ZLIB_DIR)/sources.make
+ZLIB_OBJS := $(ZLIB_SOURCES:%.c=%.o)
+
+$(ZLIB_LIB): $(ZLIB_OBJS)
+ ar ru $(ZLIB_LIB) $(ZLIB_OBJS)
+
+$(ZLIB_OBJS): CFLAGS += $(ZLIB_CFLAGS)
+
+clean-zlib:
+ rm -f $(ZLIB_OBJS) $(zlib_lib)
diff --git a/distrib/zlib-1.2.3/adler32.c b/distrib/zlib-1.2.3/adler32.c
new file mode 100644
index 0000000..007ba26
--- /dev/null
+++ b/distrib/zlib-1.2.3/adler32.c
@@ -0,0 +1,149 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD4(a) \
+ do { \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD4(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ rem = (unsigned)(len2 % BASE);
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 > BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
diff --git a/distrib/zlib-1.2.3/compress.c b/distrib/zlib-1.2.3/compress.c
new file mode 100644
index 0000000..df04f01
--- /dev/null
+++ b/distrib/zlib-1.2.3/compress.c
@@ -0,0 +1,79 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
diff --git a/distrib/zlib-1.2.3/configure b/distrib/zlib-1.2.3/configure
new file mode 100755
index 0000000..d7ffdc3
--- /dev/null
+++ b/distrib/zlib-1.2.3/configure
@@ -0,0 +1,459 @@
+#!/bin/sh
+# configure script for zlib. This script is needed only if
+# you wish to build a shared library and your system supports them,
+# of if you need special compiler, flags or install directory.
+# Otherwise, you can just use directly "make test; make install"
+#
+# To create a shared library, use "configure --shared"; by default a static
+# library is created. If the primitive shared library support provided here
+# does not work, use ftp://prep.ai.mit.edu/pub/gnu/libtool-*.tar.gz
+#
+# To impose specific compiler or flags or install directory, use for example:
+# prefix=$HOME CC=cc CFLAGS="-O4" ./configure
+# or for csh/tcsh users:
+# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure)
+# LDSHARED is the command to be used to create a shared library
+
+# Incorrect settings of CC or CFLAGS may prevent creating a shared library.
+# If you have problems, try without defining CC and CFLAGS before reporting
+# an error.
+
+LIBS=libz.a
+LDFLAGS="-L. ${LIBS}"
+VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`
+VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h`
+VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h`
+AR=${AR-"ar rc"}
+RANLIB=${RANLIB-"ranlib"}
+prefix=${prefix-/usr/local}
+exec_prefix=${exec_prefix-'${prefix}'}
+libdir=${libdir-'${exec_prefix}/lib'}
+includedir=${includedir-'${prefix}/include'}
+mandir=${mandir-'${prefix}/share/man'}
+shared_ext='.so'
+shared=0
+gcc=0
+old_cc="$CC"
+old_cflags="$CFLAGS"
+
+while test $# -ge 1
+do
+case "$1" in
+ -h* | --h*)
+ echo 'usage:'
+ echo ' configure [--shared] [--prefix=PREFIX] [--exec_prefix=EXPREFIX]'
+ echo ' [--libdir=LIBDIR] [--includedir=INCLUDEDIR]'
+ exit 0;;
+ -p*=* | --p*=*) prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -e*=* | --e*=*) exec_prefix=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -l*=* | --libdir=*) libdir=`echo $1 | sed 's/[-a-z_]*=//'`; shift;;
+ -i*=* | --includedir=*) includedir=`echo $1 | sed 's/[-a-z_]*=//'`;shift;;
+ -p* | --p*) prefix="$2"; shift; shift;;
+ -e* | --e*) exec_prefix="$2"; shift; shift;;
+ -l* | --l*) libdir="$2"; shift; shift;;
+ -i* | --i*) includedir="$2"; shift; shift;;
+ -s* | --s*) shared=1; shift;;
+ *) echo "unknown option: $1"; echo "$0 --help for help"; exit 1;;
+ esac
+done
+
+test=ztest$$
+cat > $test.c <<EOF
+extern int getchar();
+int hello() {return getchar();}
+EOF
+
+test -z "$CC" && echo Checking for gcc...
+cc=${CC-gcc}
+cflags=${CFLAGS-"-O3"}
+# to force the asm version use: CFLAGS="-O3 -DASMV" ./configure
+case "$cc" in
+ *gcc*) gcc=1;;
+esac
+
+if test "$gcc" -eq 1 && ($cc -c $cflags $test.c) 2>/dev/null; then
+ CC="$cc"
+ SFLAGS=${CFLAGS-"-fPIC -O3"}
+ CFLAGS="$cflags"
+ case `(uname -s || echo unknown) 2>/dev/null` in
+ Linux | linux | GNU | GNU/*) LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1"};;
+ CYGWIN* | Cygwin* | cygwin* | OS/2* )
+ EXE='.exe';;
+ QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4
+ # (alain.bonnefoy@icbt.com)
+ LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"};;
+ HP-UX*)
+ LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"}
+ case `(uname -m || echo unknown) 2>/dev/null` in
+ ia64)
+ shared_ext='.so'
+ SHAREDLIB='libz.so';;
+ *)
+ shared_ext='.sl'
+ SHAREDLIB='libz.sl';;
+ esac;;
+ Darwin*) shared_ext='.dylib'
+ SHAREDLIB=libz$shared_ext
+ SHAREDLIBV=libz.$VER$shared_ext
+ SHAREDLIBM=libz.$VER1$shared_ext
+ LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER"};;
+ *) LDSHARED=${LDSHARED-"$cc -shared"};;
+ esac
+else
+ # find system name and corresponding cc options
+ CC=${CC-cc}
+ case `(uname -sr || echo unknown) 2>/dev/null` in
+ HP-UX*) SFLAGS=${CFLAGS-"-O +z"}
+ CFLAGS=${CFLAGS-"-O"}
+# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"}
+ LDSHARED=${LDSHARED-"ld -b"}
+ case `(uname -m || echo unknown) 2>/dev/null` in
+ ia64)
+ shared_ext='.so'
+ SHAREDLIB='libz.so';;
+ *)
+ shared_ext='.sl'
+ SHAREDLIB='libz.sl';;
+ esac;;
+ IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."}
+ CFLAGS=${CFLAGS-"-ansi -O2"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"}
+ CFLAGS=${CFLAGS-"-O -std1"}
+ LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"};;
+ OSF1*) SFLAGS=${CFLAGS-"-O -std1"}
+ CFLAGS=${CFLAGS-"-O -std1"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ QNX*) SFLAGS=${CFLAGS-"-4 -O"}
+ CFLAGS=${CFLAGS-"-4 -O"}
+ LDSHARED=${LDSHARED-"cc"}
+ RANLIB=${RANLIB-"true"}
+ AR="cc -A";;
+ SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "}
+ CFLAGS=${CFLAGS-"-O3"}
+ LDSHARED=${LDSHARED-"cc -dy -KPIC -G"};;
+ SunOS\ 5*) SFLAGS=${CFLAGS-"-fast -xcg89 -KPIC -R."}
+ CFLAGS=${CFLAGS-"-fast -xcg89"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"}
+ CFLAGS=${CFLAGS-"-O2"}
+ LDSHARED=${LDSHARED-"ld"};;
+ SunStudio\ 9*) SFLAGS=${CFLAGS-"-DUSE_MMAP -fast -xcode=pic32 -xtarget=ultra3 -xarch=v9b"}
+ CFLAGS=${CFLAGS-"-DUSE_MMAP -fast -xtarget=ultra3 -xarch=v9b"}
+ LDSHARED=${LDSHARED-"cc -xarch=v9b"};;
+ UNIX_System_V\ 4.2.0)
+ SFLAGS=${CFLAGS-"-KPIC -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ UNIX_SV\ 4.2MP)
+ SFLAGS=${CFLAGS-"-Kconform_pic -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ OpenUNIX\ 5)
+ SFLAGS=${CFLAGS-"-KPIC -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;
+ AIX*) # Courtesy of dbakker@arrayasolutions.com
+ SFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
+ CFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
+ LDSHARED=${LDSHARED-"xlc -G"};;
+ # send working options for other systems to support@gzip.org
+ *) SFLAGS=${CFLAGS-"-O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -shared"};;
+ esac
+fi
+
+SHAREDLIB=${SHAREDLIB-"libz$shared_ext"}
+SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"}
+SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"}
+
+if test $shared -eq 1; then
+ echo Checking for shared library support...
+ # we must test in two steps (cc then ld), required at least on SunOS 4.x
+ if test "`($CC -c $SFLAGS $test.c) 2>&1`" = "" &&
+ test "`($LDSHARED -o $test$shared_ext $test.o) 2>&1`" = ""; then
+ CFLAGS="$SFLAGS"
+ LIBS="$SHAREDLIBV"
+ echo Building shared library $SHAREDLIBV with $CC.
+ elif test -z "$old_cc" -a -z "$old_cflags"; then
+ echo No shared library support.
+ shared=0;
+ else
+ echo 'No shared library support; try without defining CC and CFLAGS'
+ shared=0;
+ fi
+fi
+if test $shared -eq 0; then
+ LDSHARED="$CC"
+ echo Building static library $LIBS version $VER with $CC.
+else
+ LDFLAGS="-L. ${SHAREDLIBV}"
+fi
+
+cat > $test.c <<EOF
+#include <unistd.h>
+int main() { return 0; }
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ sed < zconf.in.h "/HAVE_UNISTD_H/s%0%1%" > zconf.h
+ echo "Checking for unistd.h... Yes."
+else
+ cp -p zconf.in.h zconf.h
+ echo "Checking for unistd.h... No."
+fi
+
+cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+#include "zconf.h"
+
+int main()
+{
+#ifndef STDC
+ choke me
+#endif
+
+ return 0;
+}
+EOF
+
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()"
+
+ cat > $test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...)
+{
+ char buf[20];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return 0;
+}
+
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then
+ echo "Checking for vsnprintf() in stdio.h... Yes."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...)
+{
+ int n;
+ char buf[20];
+ va_list ap;
+
+ va_start(ap, fmt);
+ n = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return n;
+}
+
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of vsnprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_vsnprintf_void"
+ echo "Checking for return value of vsnprintf()... No."
+ echo " WARNING: apparently vsnprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ else
+ CFLAGS="$CFLAGS -DNO_vsnprintf"
+ echo "Checking for vsnprintf() in stdio.h... No."
+ echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib"
+ echo " can build but will be open to possible buffer-overflow security"
+ echo " vulnerabilities."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+#include <stdarg.h>
+
+int mytest(char *fmt, ...)
+{
+ int n;
+ char buf[20];
+ va_list ap;
+
+ va_start(ap, fmt);
+ n = vsprintf(buf, fmt, ap);
+ va_end(ap);
+ return n;
+}
+
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of vsprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_vsprintf_void"
+ echo "Checking for return value of vsprintf()... No."
+ echo " WARNING: apparently vsprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ fi
+else
+ echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()"
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+
+int mytest()
+{
+ char buf[20];
+
+ snprintf(buf, sizeof(buf), "%s", "foo");
+ return 0;
+}
+
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if test "`($CC $CFLAGS -o $test $test.c) 2>&1`" = ""; then
+ echo "Checking for snprintf() in stdio.h... Yes."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+
+int mytest()
+{
+ char buf[20];
+
+ return snprintf(buf, sizeof(buf), "%s", "foo");
+}
+
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of snprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_snprintf_void"
+ echo "Checking for return value of snprintf()... No."
+ echo " WARNING: apparently snprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ else
+ CFLAGS="$CFLAGS -DNO_snprintf"
+ echo "Checking for snprintf() in stdio.h... No."
+ echo " WARNING: snprintf() not found, falling back to sprintf(). zlib"
+ echo " can build but will be open to possible buffer-overflow security"
+ echo " vulnerabilities."
+
+ cat >$test.c <<EOF
+#include <stdio.h>
+
+int mytest()
+{
+ char buf[20];
+
+ return sprintf(buf, "%s", "foo");
+}
+
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for return value of sprintf()... Yes."
+ else
+ CFLAGS="$CFLAGS -DHAS_sprintf_void"
+ echo "Checking for return value of sprintf()... No."
+ echo " WARNING: apparently sprintf() does not return a value. zlib"
+ echo " can build but will be open to possible string-format security"
+ echo " vulnerabilities."
+ fi
+ fi
+fi
+
+cat >$test.c <<EOF
+#include <errno.h>
+int main() { return 0; }
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ echo "Checking for errno.h... Yes."
+else
+ echo "Checking for errno.h... No."
+ CFLAGS="$CFLAGS -DNO_ERRNO_H"
+fi
+
+cat > $test.c <<EOF
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+caddr_t hello() {
+ return mmap((caddr_t)0, (off_t)0, PROT_READ, MAP_SHARED, 0, (off_t)0);
+}
+EOF
+if test "`($CC -c $CFLAGS $test.c) 2>&1`" = ""; then
+ CFLAGS="$CFLAGS -DUSE_MMAP"
+ echo Checking for mmap support... Yes.
+else
+ echo Checking for mmap support... No.
+fi
+
+CPP=${CPP-"$CC -E"}
+case $CFLAGS in
+ *ASMV*)
+ if test "`nm $test.o | grep _hello`" = ""; then
+ CPP="$CPP -DNO_UNDERLINE"
+ echo Checking for underline in external names... No.
+ else
+ echo Checking for underline in external names... Yes.
+ fi;;
+esac
+
+rm -f $test.[co] $test $test$shared_ext
+
+# udpate Makefile
+sed < Makefile.in "
+/^CC *=/s#=.*#=$CC#
+/^CFLAGS *=/s#=.*#=$CFLAGS#
+/^CPP *=/s#=.*#=$CPP#
+/^LDSHARED *=/s#=.*#=$LDSHARED#
+/^LIBS *=/s#=.*#=$LIBS#
+/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
+/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#
+/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM#
+/^AR *=/s#=.*#=$AR#
+/^RANLIB *=/s#=.*#=$RANLIB#
+/^EXE *=/s#=.*#=$EXE#
+/^prefix *=/s#=.*#=$prefix#
+/^exec_prefix *=/s#=.*#=$exec_prefix#
+/^libdir *=/s#=.*#=$libdir#
+/^includedir *=/s#=.*#=$includedir#
+/^mandir *=/s#=.*#=$mandir#
+/^LDFLAGS *=/s#=.*#=$LDFLAGS#
+" > Makefile
diff --git a/distrib/zlib-1.2.3/crc32.c b/distrib/zlib-1.2.3/crc32.c
new file mode 100644
index 0000000..f658a9e
--- /dev/null
+++ b/distrib/zlib-1.2.3/crc32.c
@@ -0,0 +1,423 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# ifdef STDC /* need ANSI C limits.h to determine sizes */
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+# endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ unsigned long c;
+ int n, k;
+ unsigned long poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0UL;
+ for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ poly |= 1UL << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = REV(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = REV(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const unsigned long FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const unsigned long FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case */
+ if (len2 == 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320L; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
diff --git a/distrib/zlib-1.2.3/crc32.h b/distrib/zlib-1.2.3/crc32.h
new file mode 100644
index 0000000..8053b61
--- /dev/null
+++ b/distrib/zlib-1.2.3/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/distrib/zlib-1.2.3/deflate.c b/distrib/zlib-1.2.3/deflate.c
new file mode 100644
index 0000000..29ce1f6
--- /dev/null
+++ b/distrib/zlib-1.2.3/deflate.c
@@ -0,0 +1,1736 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->wrap == 2 ||
+ (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+ return Z_STREAM_ERROR;
+
+ s = strm->state;
+ if (s->wrap)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ strm->state->bi_valid = bits;
+ strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong destLen;
+
+ /* conservative upper bound */
+ destLen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+ /* if can't get parameters, return conservative bound */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return destLen;
+
+ /* if not default parameters, return conservative bound */
+ s = strm->state;
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return destLen;
+
+ /* default settings: return tight bound for that case */
+ return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy(dest, source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy(ds, ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, strm->next_in, len);
+ }
+#endif
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ /* %%% avoid this when Z_RLE */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+#ifdef FASTEST
+ if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) ||
+ (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#else
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#endif
+ /* longest_match() or longest_match_fast() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+ /* longest_match() or longest_match_fast() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+#if 0
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt run; /* length of run */
+ uInt max; /* maximum length of run */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan; /* scan for end of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest encodable run.
+ */
+ if (s->lookahead < MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ run = 0;
+ if (s->strstart > 0) { /* if there is a previous byte, that is */
+ max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH;
+ scan = s->window + s->strstart - 1;
+ prev = *scan++;
+ do {
+ if (*scan++ != prev)
+ break;
+ } while (++run < max);
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (run >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, run);
+ _tr_tally_dist(s, 1, run - MIN_MATCH, bflush);
+ s->lookahead -= run;
+ s->strstart += run;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif
diff --git a/distrib/zlib-1.2.3/deflate.h b/distrib/zlib-1.2.3/deflate.h
new file mode 100644
index 0000000..05a5ab3
--- /dev/null
+++ b/distrib/zlib-1.2.3/deflate.h
@@ -0,0 +1,331 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2004 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch _length_code[];
+ extern uch _dist_code[];
+#else
+ extern const uch _length_code[];
+ extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/distrib/zlib-1.2.3/gzio.c b/distrib/zlib-1.2.3/gzio.c
new file mode 100644
index 0000000..7e90f49
--- /dev/null
+++ b/distrib/zlib-1.2.3/gzio.c
@@ -0,0 +1,1026 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+#ifdef NO_DEFLATE /* for compatibility with old definition */
+# define NO_GZCOMPRESS
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef Z_BUFSIZE
+# ifdef MAXSEG_64K
+# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+# else
+# define Z_BUFSIZE 16384
+# endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+# define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#ifdef __MVS__
+# pragma map (fdopen , "\174\174FDOPEN")
+ FILE *fdopen(int, const char *);
+#endif
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+ z_off_t start; /* start of compressed data in file (header skipped) */
+ z_off_t in; /* bytes into deflate or inflate */
+ z_off_t out; /* bytes out of deflate or inflate */
+ int back; /* one character push-back */
+ int last; /* true if push-back is last character */
+} gz_stream;
+
+
+local gzFile gz_open OF((const char *path, const char *mode, int fd));
+local int do_flush OF((gzFile file, int flush));
+local int get_byte OF((gz_stream *s));
+local void check_header OF((gz_stream *s));
+local int destroy OF((gz_stream *s));
+local void putLong OF((FILE *file, uLong x));
+local uLong getLong OF((gz_stream *s));
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+ or path name (if fd == -1).
+ gz_open returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+ const char *path;
+ const char *mode;
+ int fd;
+{
+ int err;
+ int level = Z_DEFAULT_COMPRESSION; /* compression level */
+ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+ char *p = (char*)mode;
+ gz_stream *s;
+ char fmode[80]; /* copy of mode, without the compression level */
+ char *m = fmode;
+
+ if (!path || !mode) return Z_NULL;
+
+ s = (gz_stream *)ALLOC(sizeof(gz_stream));
+ if (!s) return Z_NULL;
+
+ s->stream.zalloc = (alloc_func)0;
+ s->stream.zfree = (free_func)0;
+ s->stream.opaque = (voidpf)0;
+ s->stream.next_in = s->inbuf = Z_NULL;
+ s->stream.next_out = s->outbuf = Z_NULL;
+ s->stream.avail_in = s->stream.avail_out = 0;
+ s->file = NULL;
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->in = 0;
+ s->out = 0;
+ s->back = EOF;
+ s->crc = crc32(0L, Z_NULL, 0);
+ s->msg = NULL;
+ s->transparent = 0;
+
+ s->path = (char*)ALLOC(strlen(path)+1);
+ if (s->path == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ strcpy(s->path, path); /* do this early for debugging */
+
+ s->mode = '\0';
+ do {
+ if (*p == 'r') s->mode = 'r';
+ if (*p == 'w' || *p == 'a') s->mode = 'w';
+ if (*p >= '0' && *p <= '9') {
+ level = *p - '0';
+ } else if (*p == 'f') {
+ strategy = Z_FILTERED;
+ } else if (*p == 'h') {
+ strategy = Z_HUFFMAN_ONLY;
+ } else if (*p == 'R') {
+ strategy = Z_RLE;
+ } else {
+ *m++ = *p; /* copy the mode */
+ }
+ } while (*p++ && m != fmode + sizeof(fmode));
+ if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateInit2(&(s->stream), level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+ /* windowBits is passed < 0 to suppress zlib header */
+
+ s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+ if (err != Z_OK || s->outbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ } else {
+ s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+ err = inflateInit2(&(s->stream), -MAX_WBITS);
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+ * present after the compressed stream.
+ */
+ if (err != Z_OK || s->inbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+
+ errno = 0;
+ s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+ if (s->file == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ if (s->mode == 'w') {
+ /* Write a very simple .gz header:
+ */
+ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+ Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+ s->start = 10L;
+ /* We use 10L instead of ftell(s->file) to because ftell causes an
+ * fflush on some systems. This version of the library doesn't use
+ * start anyway in write mode, so this initialization is not
+ * necessary.
+ */
+ } else {
+ check_header(s); /* skip the .gz header */
+ s->start = ftell(s->file) - s->stream.avail_in;
+ }
+
+ return (gzFile)s;
+}
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+ Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+ to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+ int fd;
+ const char *mode;
+{
+ char name[46]; /* allow for up to 128-bit integers */
+
+ if (fd < 0) return (gzFile)Z_NULL;
+ sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+ return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ /* Make room to allow flushing */
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+
+ return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+ gz_stream *s;
+{
+ if (s->z_eof) return EOF;
+ if (s->stream.avail_in == 0) {
+ errno = 0;
+ s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) s->z_err = Z_ERRNO;
+ return EOF;
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->stream.avail_in--;
+ return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+ Check the gzip header of a gz_stream opened for reading. Set the stream
+ mode to transparent if the gzip magic header is not present; set s->err
+ to Z_DATA_ERROR if the magic header is present but the rest of the header
+ is incorrect.
+ IN assertion: the stream s has already been created sucessfully;
+ s->stream.avail_in is zero for the first time, but may be non-zero
+ for concatenated .gz files.
+*/
+local void check_header(s)
+ gz_stream *s;
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ int c;
+
+ /* Assure two bytes in the buffer so we can peek ahead -- handle case
+ where first byte of header is at the end of the buffer after the last
+ gzip segment */
+ len = s->stream.avail_in;
+ if (len < 2) {
+ if (len) s->inbuf[0] = s->stream.next_in[0];
+ errno = 0;
+ len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
+ if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
+ s->stream.avail_in += len;
+ s->stream.next_in = s->inbuf;
+ if (s->stream.avail_in < 2) {
+ s->transparent = s->stream.avail_in;
+ return;
+ }
+ }
+
+ /* Peek ahead to check the gzip magic header */
+ if (s->stream.next_in[0] != gz_magic[0] ||
+ s->stream.next_in[1] != gz_magic[1]) {
+ s->transparent = 1;
+ return;
+ }
+ s->stream.avail_in -= 2;
+ s->stream.next_in += 2;
+
+ /* Check the rest of the gzip header */
+ method = get_byte(s);
+ flags = get_byte(s);
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ s->z_err = Z_DATA_ERROR;
+ return;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte(s);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte(s);
+ len += ((uInt)get_byte(s))<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte(s) != EOF) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte(s);
+ }
+ s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+ gz_stream *s;
+{
+ int err = Z_OK;
+
+ if (!s) return Z_STREAM_ERROR;
+
+ TRYFREE(s->msg);
+
+ if (s->stream.state != NULL) {
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateEnd(&(s->stream));
+#endif
+ } else if (s->mode == 'r') {
+ err = inflateEnd(&(s->stream));
+ }
+ }
+ if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+ if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+ err = Z_ERRNO;
+ }
+ if (s->z_err < 0) err = s->z_err;
+
+ TRYFREE(s->inbuf);
+ TRYFREE(s->outbuf);
+ TRYFREE(s->path);
+ TRYFREE(s);
+ return err;
+}
+
+/* ===========================================================================
+ Reads the given number of uncompressed bytes from the compressed file.
+ gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+ Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+ if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+ if (s->z_err == Z_STREAM_END) return 0; /* EOF */
+
+ next_out = (Byte*)buf;
+ s->stream.next_out = (Bytef*)buf;
+ s->stream.avail_out = len;
+
+ if (s->stream.avail_out && s->back != EOF) {
+ *next_out++ = s->back;
+ s->stream.next_out++;
+ s->stream.avail_out--;
+ s->back = EOF;
+ s->out++;
+ start++;
+ if (s->last) {
+ s->z_err = Z_STREAM_END;
+ return 1;
+ }
+ }
+
+ while (s->stream.avail_out != 0) {
+
+ if (s->transparent) {
+ /* Copy first the lookahead bytes: */
+ uInt n = s->stream.avail_in;
+ if (n > s->stream.avail_out) n = s->stream.avail_out;
+ if (n > 0) {
+ zmemcpy(s->stream.next_out, s->stream.next_in, n);
+ next_out += n;
+ s->stream.next_out = next_out;
+ s->stream.next_in += n;
+ s->stream.avail_out -= n;
+ s->stream.avail_in -= n;
+ }
+ if (s->stream.avail_out > 0) {
+ s->stream.avail_out -=
+ (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
+ }
+ len -= s->stream.avail_out;
+ s->in += len;
+ s->out += len;
+ if (len == 0) s->z_eof = 1;
+ return (int)len;
+ }
+ if (s->stream.avail_in == 0 && !s->z_eof) {
+
+ errno = 0;
+ s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+
+ if (s->z_err == Z_STREAM_END) {
+ /* Check CRC and original size */
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+ start = s->stream.next_out;
+
+ if (getLong(s) != s->crc) {
+ s->z_err = Z_DATA_ERROR;
+ } else {
+ (void)getLong(s);
+ /* The uncompressed length returned by above getlong() may be
+ * different from s->out in case of concatenated .gz files.
+ * Check for such files:
+ */
+ check_header(s);
+ if (s->z_err == Z_OK) {
+ inflateReset(&(s->stream));
+ s->crc = crc32(0L, Z_NULL, 0);
+ }
+ }
+ }
+ if (s->z_err != Z_OK || s->z_eof) break;
+ }
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+ if (len == s->stream.avail_out &&
+ (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
+ return -1;
+ return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ unsigned char c;
+
+ return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+ Push one byte back onto the stream.
+*/
+int ZEXPORT gzungetc(c, file)
+ int c;
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
+ s->back = c;
+ s->out--;
+ s->last = (s->z_err == Z_STREAM_END);
+ if (s->last) s->z_err = Z_OK;
+ s->z_eof = 0;
+ return c;
+}
+
+
+/* ===========================================================================
+ Reads bytes from the compressed file until len-1 characters are
+ read, or a newline character is read and transferred to buf, or an
+ end-of-file condition is encountered. The string is then terminated
+ with a null character.
+ gzgets returns buf, or Z_NULL in case of error.
+
+ The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ char *b = buf;
+ if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+ while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+ *buf = '\0';
+ return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_GZCOMPRESS
+/* ===========================================================================
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+ gzFile file;
+ voidpc buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.next_in = (Bytef*)buf;
+ s->stream.avail_in = len;
+
+ while (s->stream.avail_in != 0) {
+
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+ if (s->z_err != Z_OK) break;
+ }
+ s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+ return (int)(len - s->stream.avail_in);
+}
+
+
+/* ===========================================================================
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ va_list va;
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+ va_start(va, format);
+#ifdef NO_vsnprintf
+# ifdef HAS_vsprintf_void
+ (void)vsprintf(buf, format, va);
+ va_end(va);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = vsprintf(buf, format, va);
+ va_end(va);
+# endif
+#else
+# ifdef HAS_vsnprintf_void
+ (void)vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+ len = strlen(buf);
+# else
+ len = vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+# endif
+#endif
+ if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+#ifdef NO_snprintf
+# ifdef HAS_sprintf_void
+ sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#else
+# ifdef HAS_snprintf_void
+ snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ len = strlen(buf);
+# else
+ len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#endif
+ if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+ return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+ gzFile file;
+ const char *s;
+{
+ return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+ gzFile file;
+ int flush;
+{
+ uInt len;
+ int done = 0;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.avail_in = 0; /* should be zero already anyway */
+
+ for (;;) {
+ len = Z_BUFSIZE - s->stream.avail_out;
+
+ if (len != 0) {
+ if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+ s->z_err = Z_ERRNO;
+ return Z_ERRNO;
+ }
+ s->stream.next_out = s->outbuf;
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ if (done) break;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), flush);
+ s->out -= s->stream.avail_out;
+
+ /* Ignore the second of two consecutive flushes: */
+ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+ /* deflate has finished flushing only when it hasn't used up
+ * all the available space in the output buffer:
+ */
+ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+ if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+ }
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_stream *s = (gz_stream*)file;
+ int err = do_flush (file, flush);
+
+ if (err) return err;
+ fflush(s->file);
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_GZCOMPRESS */
+
+/* ===========================================================================
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error.
+ SEEK_END is not implemented, returns error.
+ In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || whence == SEEK_END ||
+ s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+ return -1L;
+ }
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return -1L;
+#else
+ if (whence == SEEK_SET) {
+ offset -= s->in;
+ }
+ if (offset < 0) return -1L;
+
+ /* At this point, offset is the number of zero bytes to write. */
+ if (s->inbuf == Z_NULL) {
+ s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+ if (s->inbuf == Z_NULL) return -1L;
+ zmemzero(s->inbuf, Z_BUFSIZE);
+ }
+ while (offset > 0) {
+ uInt size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+ size = gzwrite(file, s->inbuf, size);
+ if (size == 0) return -1L;
+
+ offset -= size;
+ }
+ return s->in;
+#endif
+ }
+ /* Rest of function is for reading only */
+
+ /* compute absolute position */
+ if (whence == SEEK_CUR) {
+ offset += s->out;
+ }
+ if (offset < 0) return -1L;
+
+ if (s->transparent) {
+ /* map to fseek */
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+ s->in = s->out = offset;
+ return offset;
+ }
+
+ /* For a negative seek, rewind and use positive seek */
+ if (offset >= s->out) {
+ offset -= s->out;
+ } else if (gzrewind(file) < 0) {
+ return -1L;
+ }
+ /* offset is now the number of bytes to skip. */
+
+ if (offset != 0 && s->outbuf == Z_NULL) {
+ s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+ if (s->outbuf == Z_NULL) return -1L;
+ }
+ if (offset && s->back != EOF) {
+ s->back = EOF;
+ s->out++;
+ offset--;
+ if (s->last) s->z_err = Z_STREAM_END;
+ }
+ while (offset > 0) {
+ int size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (int)offset;
+
+ size = gzread(file, s->outbuf, (uInt)size);
+ if (size <= 0) return -1L;
+ offset -= size;
+ }
+ return s->out;
+}
+
+/* ===========================================================================
+ Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return -1;
+
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ s->crc = crc32(0L, Z_NULL, 0);
+ if (!s->transparent) (void)inflateReset(&s->stream);
+ s->in = 0;
+ s->out = 0;
+ return fseek(s->file, s->start, SEEK_SET);
+}
+
+/* ===========================================================================
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+ gzFile file;
+{
+ return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ /* With concatenated compressed files that can have embedded
+ * crc trailers, z_eof is no longer the only/best indicator of EOF
+ * on a gz_stream. Handle end-of-stream error explicitly here.
+ */
+ if (s == NULL || s->mode != 'r') return 0;
+ if (s->z_eof) return 1;
+ return s->z_err == Z_STREAM_END;
+}
+
+/* ===========================================================================
+ Returns 1 if reading and doing so transparently, otherwise zero.
+*/
+int ZEXPORT gzdirect (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return 0;
+ return s->transparent;
+}
+
+/* ===========================================================================
+ Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+ FILE *file;
+ uLong x;
+{
+ int n;
+ for (n = 0; n < 4; n++) {
+ fputc((int)(x & 0xff), file);
+ x >>= 8;
+ }
+}
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets z_err in case
+ of error.
+*/
+local uLong getLong (s)
+ gz_stream *s;
+{
+ uLong x = (uLong)get_byte(s);
+ int c;
+
+ x += ((uLong)get_byte(s))<<8;
+ x += ((uLong)get_byte(s))<<16;
+ c = get_byte(s);
+ if (c == EOF) s->z_err = Z_DATA_ERROR;
+ x += ((uLong)c)<<24;
+ return x;
+}
+
+/* ===========================================================================
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return Z_STREAM_ERROR;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return Z_STREAM_ERROR;
+#else
+ if (do_flush (file, Z_FINISH) != Z_OK)
+ return destroy((gz_stream*)file);
+
+ putLong (s->file, s->crc);
+ putLong (s->file, (uLong)(s->in & 0xffffffff));
+#endif
+ }
+ return destroy((gz_stream*)file);
+}
+
+#ifdef STDC
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+/* ===========================================================================
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+const char * ZEXPORT gzerror (file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ char *m;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) {
+ *errnum = Z_STREAM_ERROR;
+ return (const char*)ERR_MSG(Z_STREAM_ERROR);
+ }
+ *errnum = s->z_err;
+ if (*errnum == Z_OK) return (const char*)"";
+
+ m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+ if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+ TRYFREE(s->msg);
+ s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+ if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
+ strcpy(s->msg, s->path);
+ strcat(s->msg, ": ");
+ strcat(s->msg, m);
+ return (const char*)s->msg;
+}
+
+/* ===========================================================================
+ Clear the error and end-of-file flags, and do the same for the real file.
+*/
+void ZEXPORT gzclearerr (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return;
+ if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
+ s->z_eof = 0;
+ clearerr(s->file);
+}
diff --git a/distrib/zlib-1.2.3/infback.c b/distrib/zlib-1.2.3/infback.c
new file mode 100644
index 0000000..455dbc9
--- /dev/null
+++ b/distrib/zlib-1.2.3/infback.c
@@ -0,0 +1,623 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ This code is largely copied from inflate.c. Normally either infback.o or
+ inflate.o would be linked into an application--not both. The interface
+ with inffast.c is retained so that optimized assembler-coded versions of
+ inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ windowBits is in the range 8..15, and window is a user-supplied
+ window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL ||
+ windowBits < 8 || windowBits > 15)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->dmax = 32768U;
+ state->wbits = windowBits;
+ state->wsize = 1U << windowBits;
+ state->window = window;
+ state->write = 0;
+ state->whave = 0;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = state->window; \
+ left = state->wsize; \
+ state->whave = left; \
+ if (out(out_desc, put, left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ state->mode = TYPE;
+ state->last = 0;
+ state->whave = 0;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = state->window;
+ left = state->wsize;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (state->mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (state->last) {
+ BYTEBITS();
+ state->mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (state->length != 0) {
+ copy = state->length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+
+ case LEN:
+ /* use inflate_fast() if we have enough input and output */
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ if (state->whave < state->wsize)
+ state->whave = state->wsize - left;
+ inflate_fast(strm, state->wsize);
+ LOAD();
+ break;
+ }
+
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+
+ /* process literal */
+ if (this.op == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ ROOM();
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+
+ /* get distance code */
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+
+ /* get distance extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ if (state->offset > state->wsize - (state->whave < state->wsize ?
+ left : 0)) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = state->wsize - state->offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - state->offset;
+ copy = left;
+ }
+ if (copy > state->length) copy = state->length;
+ state->length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (state->length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < state->wsize) {
+ if (out(out_desc, state->window, state->wsize - left))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
diff --git a/distrib/zlib-1.2.3/inffast.c b/distrib/zlib-1.2.3/inffast.c
new file mode 100644
index 0000000..bbee92e
--- /dev/null
+++ b/distrib/zlib-1.2.3/inffast.c
@@ -0,0 +1,318 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *in; /* local strm->next_in */
+ unsigned char FAR *last; /* while in < last, enough input available */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code this; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ write = state->write;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ PUP(out) = (unsigned char)(this.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ from = window - OFF;
+ if (write == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (write < op) { /* wrap around window */
+ from += wsize + write - op;
+ op -= write;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (write < len) { /* some from start of window */
+ op = write;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += write - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ this = dcode[this.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ this = lcode[this.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and write == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/distrib/zlib-1.2.3/inffast.h b/distrib/zlib-1.2.3/inffast.h
new file mode 100644
index 0000000..1e88d2d
--- /dev/null
+++ b/distrib/zlib-1.2.3/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/distrib/zlib-1.2.3/inffixed.h b/distrib/zlib-1.2.3/inffixed.h
new file mode 100644
index 0000000..75ed4b5
--- /dev/null
+++ b/distrib/zlib-1.2.3/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications. It
+ is part of the implementation of the compression library and
+ is subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/distrib/zlib-1.2.3/inflate.c b/distrib/zlib-1.2.3/inflate.c
new file mode 100644
index 0000000..792fdee
--- /dev/null
+++ b/distrib/zlib-1.2.3/inflate.c
@@ -0,0 +1,1368 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ strm->adler = 1; /* to support ill-conceived Java test suite */
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->wsize = 0;
+ state->whave = 0;
+ state->write = 0;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ if (windowBits < 0) {
+ state->wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48) windowBits &= 15;
+#endif
+ }
+ if (windowBits < 8 || windowBits > 15) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ return Z_STREAM_ERROR;
+ }
+ state->wbits = (unsigned)windowBits;
+ state->window = Z_NULL;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+ state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+ struct inflate_state FAR *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->write = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->write = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->write;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, strm->next_out - copy, copy);
+ state->write = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->write += dist;
+ if (state->write == state->wsize) state->write = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ break;
+ }
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+ if ((int)(this.op) == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ state->mode = LIT;
+ break;
+ }
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ if (state->offset > state->whave + out - left) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->write) {
+ copy -= state->write;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->write - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ if (updatewindow(strm, out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ if (state->mode == DICT) {
+ id = adler32(0L, Z_NULL, 0);
+ id = adler32(id, dictionary, dictLength);
+ if (id != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window */
+ if (updatewindow(strm, strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ if (dictLength > state->wsize) {
+ zmemcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ zmemcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy(dest, source, sizeof(z_stream));
+ zmemcpy(copy, state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
diff --git a/distrib/zlib-1.2.3/inflate.h b/distrib/zlib-1.2.3/inflate.h
new file mode 100644
index 0000000..07bd3e7
--- /dev/null
+++ b/distrib/zlib-1.2.3/inflate.h
@@ -0,0 +1,115 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN, /* i: waiting for length/lit code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+ NAME -> COMMENT -> HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or CHECK
+ STORED -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
diff --git a/distrib/zlib-1.2.3/inftrees.c b/distrib/zlib-1.2.3/inftrees.c
new file mode 100644
index 0000000..8a9c13f
--- /dev/null
+++ b/distrib/zlib-1.2.3/inftrees.c
@@ -0,0 +1,329 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)1;
+ this.val = (unsigned short)0;
+ *(*table)++ = this; /* make a table to force an error */
+ *(*table)++ = this;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked when a LENS table is being made
+ against the space in *table, ENOUGH, minus the maximum space needed by
+ the worst case distance code, MAXD. This should never happen, but the
+ sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+ This assumes that when type == LENS, bits == 9.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ this.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/distrib/zlib-1.2.3/inftrees.h b/distrib/zlib-1.2.3/inftrees.h
new file mode 100644
index 0000000..b1104c8
--- /dev/null
+++ b/distrib/zlib-1.2.3/inftrees.h
@@ -0,0 +1,55 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1444 code structures (852 for length/literals
+ and 592 for distances, the latter actually the result of an
+ exhaustive search). The true maximum is not known, but the value
+ below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/distrib/zlib-1.2.3/sources.make b/distrib/zlib-1.2.3/sources.make
new file mode 100644
index 0000000..c15fd78
--- /dev/null
+++ b/distrib/zlib-1.2.3/sources.make
@@ -0,0 +1,4 @@
+# this is included by various Makefiles
+ZLIB_SOURCES := adler32.c compress.c crc32.c deflate.c gzio.c infback.c inffast.c inflate.c inftrees.c trees.c uncompr.c zutil.c
+ZLIB_SOURCES := $(ZLIB_SOURCES:%=$(ZLIB_DIR)/%)
+
diff --git a/distrib/zlib-1.2.3/trees.c b/distrib/zlib-1.2.3/trees.c
new file mode 100644
index 0000000..395e4e1
--- /dev/null
+++ b/distrib/zlib-1.2.3/trees.c
@@ -0,0 +1,1219 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2005 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN)
+ set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to BINARY or TEXT, using a crude approximation:
+ * set it to Z_TEXT if all symbols are either printable characters (33 to 255)
+ * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise.
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n;
+
+ for (n = 0; n < 9; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ if (n == 9)
+ for (n = 14; n < 32; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/distrib/zlib-1.2.3/trees.h b/distrib/zlib-1.2.3/trees.h
new file mode 100644
index 0000000..72facf9
--- /dev/null
+++ b/distrib/zlib-1.2.3/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/distrib/zlib-1.2.3/uncompr.c b/distrib/zlib-1.2.3/uncompr.c
new file mode 100644
index 0000000..b59e3d0
--- /dev/null
+++ b/distrib/zlib-1.2.3/uncompr.c
@@ -0,0 +1,61 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/distrib/zlib-1.2.3/zconf.h b/distrib/zlib-1.2.3/zconf.h
new file mode 100644
index 0000000..03a9431
--- /dev/null
+++ b/distrib/zlib-1.2.3/zconf.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define deflateBound z_deflateBound
+# define deflatePrime z_deflatePrime
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateCopy z_inflateCopy
+# define inflateReset z_inflateReset
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+# define zError z_zError
+
+# define alloc_func z_alloc_func
+# define free_func z_free_func
+# define in_func z_in_func
+# define out_func z_out_func
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(__OS400__)
+# define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+# ifdef FAR
+# undef FAR
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(deflateBound,"DEBND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(compressBound,"CMBND")
+# pragma map(inflate_table,"INTABL")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/distrib/zlib-1.2.3/zlib.h b/distrib/zlib-1.2.3/zlib.h
new file mode 100644
index 0000000..0228179
--- /dev/null
+++ b/distrib/zlib-1.2.3/zlib.h
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.3, July 18th, 2005
+
+ Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumualte before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ the value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+ Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+ if and when it gets to the next deflate block boundary. When decoding the
+ zlib or gzip format, this will cause inflate() to return immediately after
+ the header and before the first block. When doing a raw inflate, inflate()
+ will go ahead and process the first block, and will return when it gets to
+ the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64
+ if inflate() is currently decoding the last block in the deflate stream,
+ plus 128 if inflate() returned immediately after decoding an end-of-block
+ code or decoding the complete header up to just before the first byte of the
+ deflate stream. The end-of-block will not be indicated until all of the
+ uncompressed data from that block has been written to strm->next_out. The
+ number of unused bits may in general be greater than seven, except when
+ bit 7 of data_type is set, in which case the number of unused bits will be
+ less than eight.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster approach
+ may be used for the single inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically. Any information
+ contained in the gzip header is not retained, so applications that need that
+ information should instead use raw inflate, see inflateInit2() below, or
+ inflateBack() and perform their own processing of the gzip header and
+ trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may then
+ call inflateSync() to look for a good compression block if a partial recovery
+ of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero),
+ no header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+ Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+ parameter only affects the compression ratio but not the correctness of the
+ compressed output even if it is not set appropriately. Z_FIXED prevents the
+ use of dynamic Huffman codes, allowing for a simpler decoder for special
+ applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front. In addition, the
+ current implementation of deflate will use at most the window size minus
+ 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit()
+ or deflateInit2(). This would be used to allocate an output buffer
+ for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the
+ bits leftover from a previous deflate stream when appending to it. As such,
+ this function can only be used for raw deflate, and must be used before the
+ first deflate() call after a deflateInit2() or deflateReset(). bits must be
+ less than or equal to 16, and that many of the least significant bits of
+ value will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is
+ a crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+ is set to null if there is no error message. inflateInit2 does not perform
+ any decompression apart from reading the zlib header if present: this will
+ be done by inflate(). (So next_in and avail_in may be modified, but next_out
+ and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK can be used to
+ force inflate() to return immediately after header processing is complete
+ and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When
+ any of extra, name, or comment are not Z_NULL and the respective field is
+ not present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+ be allocated, or Z_VERSION_ERROR if the version of the library does not
+ match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free
+ the allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects
+ only the raw deflate stream to decompress. This is different from the
+ normal behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format
+ error in the deflate stream (in which case strm->msg is set to indicate the
+ nature of the error), or Z_STREAM_ERROR if the stream was not properly
+ initialized. In the case of Z_BUF_ERROR, an input or output error can be
+ distinguished using strm->next_in which will be Z_NULL only if in() returned
+ an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+ out() returning non-zero. (in() will always be called before out(), so
+ strm->next_in is assured to be defined if out() returns non-zero.) Note
+ that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least the value returned
+ by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before
+ a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h", or 'R' for run-length encoding
+ as in "wb1R". (See the description of deflateInit2 for more information
+ about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error). The number of
+ uncompressed bytes written is limited to 4095. The caller should assure that
+ this limit is not exceeded. If it is exceeded, then gzprintf() will return
+ return an error (0) with nothing written. In this case, there may also be a
+ buffer overflow with unpredictable consequences, which is possible only if
+ zlib was compiled with the insecure functions sprintf() or vsprintf()
+ because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read again later.
+ Only one character of push-back is allowed. gzungetc() returns the
+ character pushed, or -1 on failure. gzungetc() will fail if a
+ character has been pushed but not read yet, or if c is -1. The pushed
+ character will be discarded if the stream is repositioned with gzseek()
+ or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns 1 if file is being read directly without decompression, otherwise
+ zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+/*
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is NULL, this function returns the required initial
+ value for the for the crc. Pre- and post-conditioning (one's complement) is
+ performed within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/distrib/zlib-1.2.3/zutil.c b/distrib/zlib-1.2.3/zutil.c
new file mode 100644
index 0000000..d55f594
--- /dev/null
+++ b/distrib/zlib-1.2.3/zutil.c
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch (sizeof(uInt)) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch (sizeof(uLong)) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch (sizeof(voidpf)) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch (sizeof(z_off_t)) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#ifdef STDC
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/distrib/zlib-1.2.3/zutil.h b/distrib/zlib-1.2.3/zutil.h
new file mode 100644
index 0000000..b7d5eff
--- /dev/null
+++ b/distrib/zlib-1.2.3/zutil.h
@@ -0,0 +1,269 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+# ifndef _WIN32_WCE
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+# ifdef _WIN32_WCE
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used. We rename it to
+ * avoid conflict with other libraries that use the same workaround.
+ */
+# define errno z_errno
+# endif
+ extern int errno;
+#else
+# ifndef _WIN32_WCE
+# include <errno.h>
+# endif
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# ifdef M_I86
+ #include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+ /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+ /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+#endif
+#ifdef VMS
+# define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */
diff --git a/dyngen-exec.h b/dyngen-exec.h
index 0c39228..acb5b55 100644
--- a/dyngen-exec.h
+++ b/dyngen-exec.h
@@ -35,15 +35,12 @@
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
-// Linux/Sparc64 defines uint64_t
-#if !(defined (__sparc_v9__) && defined(__linux__))
/* XXX may be done for all 64 bits targets ? */
#if defined (__x86_64__) || defined(__ia64)
typedef unsigned long uint64_t;
#else
typedef unsigned long long uint64_t;
#endif
-#endif
/* if Solaris/__sun__, don't typedef int8_t, as it will be typedef'd
prior to this and will cause an error in compliation, conflicting
@@ -53,14 +50,11 @@ typedef signed char int8_t;
#endif
typedef signed short int16_t;
typedef signed int int32_t;
-// Linux/Sparc64 defines int64_t
-#if !(defined (__sparc_v9__) && defined(__linux__))
#if defined (__x86_64__) || defined(__ia64)
typedef signed long int64_t;
#else
typedef signed long long int64_t;
#endif
-#endif
#define INT8_MIN (-128)
#define INT16_MIN (-32767-1)
@@ -134,12 +128,6 @@ extern int printf(const char *, ...);
#define AREG3 "g5"
#define AREG4 "g6"
#else
-#ifdef __sparc_v9__
-#define AREG0 "g1"
-#define AREG1 "g4"
-#define AREG2 "g5"
-#define AREG3 "g7"
-#else
#define AREG0 "g6"
#define AREG1 "g1"
#define AREG2 "g2"
@@ -153,7 +141,6 @@ extern int printf(const char *, ...);
#define AREG10 "l6"
#define AREG11 "l7"
#endif
-#endif
#define USE_FP_CONVERT
#endif
#ifdef __s390__
@@ -188,7 +175,12 @@ extern int printf(const char *, ...);
#endif
/* force GCC to generate only one epilog at the end of the function */
+#if defined(__i386__) || defined(__x86_64__)
+/* Also add 4 bytes of padding so that we can replace the ret with a jmp. */
+#define FORCE_RET() asm volatile ("nop;nop;nop;nop");
+#else
#define FORCE_RET() asm volatile ("");
+#endif
#ifndef OPPROTO
#define OPPROTO
@@ -238,12 +230,26 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#endif
#ifdef __i386__
-#define EXIT_TB() asm volatile ("ret")
-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
+/* Dyngen will replace hlt instructions with a ret instruction. Inserting a
+ ret directly would confuse dyngen. */
+#define EXIT_TB() asm volatile ("hlt")
+/* Dyngen will replace cli with 0x9e (jmp).
+ We generate the offset manually. */
+#if defined(__APPLE__)
+/* XXX Different relocations are generated for MacOS X for Intel
+ (please as from cctools). */
+#define GOTO_LABEL_PARAM(n) \
+ asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n)
+#else
+#define GOTO_LABEL_PARAM(n) \
+ asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:")
+#endif
#endif
#ifdef __x86_64__
-#define EXIT_TB() asm volatile ("ret")
-#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
+/* The same as i386. */
+#define EXIT_TB() asm volatile ("hlt")
+#define GOTO_LABEL_PARAM(n) \
+ asm volatile ("cli;.long " ASM_NAME(__op_gen_label) #n " - 1f;1:")
#endif
#ifdef __powerpc__
#define EXIT_TB() asm volatile ("blr")
@@ -273,4 +279,13 @@ extern int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
#define EXIT_TB() asm volatile ("rts")
#endif
+/* this definition to force inlining of all code that is used by op.c
+ * if we don't do that, some functions fail to properly inline with some
+ * GCC versions. and this results in erratic crashes that are hard to debug
+ *
+ * (that's because the non-inlined functions might clobber some "reserved"
+ * registers used by the translation block code
+ */
+#define inline __attribute__((always_inline)) __inline__
+
#endif /* !defined(__DYNGEN_EXEC_H__) */
diff --git a/dyngen.c b/dyngen.c
index 5fb921e..7425624 100644
--- a/dyngen.c
+++ b/dyngen.c
@@ -1,6 +1,6 @@
/*
* Generic Dynamic compiler generator
- *
+ *
* Copyright (c) 2003 Fabrice Bellard
*
* The COFF object format support was extracted from Kazu's QEMU port
@@ -32,6 +32,8 @@
#include "config-host.h"
+//#define DEBUG_OP
+
/* NOTE: we test CONFIG_WIN32 instead of _WIN32 to enabled cross
compilation */
#if defined(CONFIG_WIN32)
@@ -180,6 +182,20 @@ typedef struct coff_rel {
#include <mach-o/reloc.h>
#include <mach-o/ppc/reloc.h>
+#ifdef HOST_PPC
+
+#define MACH_CPU_TYPE CPU_TYPE_POWERPC
+#define mach_check_cputype(x) ((x) == CPU_TYPE_POWERPC)
+
+#elif defined(HOST_I386)
+
+#define MACH_CPU_TYPE CPU_TYPE_I386
+#define mach_check_cputype(x) ((x) == CPU_TYPE_I386)
+
+#else
+#error unsupported CPU - please update the code
+#endif
+
# define check_mach_header(x) (x.magic == MH_MAGIC)
typedef int32_t host_long;
typedef uint32_t host_ulong;
@@ -187,11 +203,11 @@ typedef uint32_t host_ulong;
struct nlist_extended
{
union {
- char *n_name;
- long n_strx;
+ char *n_name;
+ long n_strx;
} n_un;
- unsigned char n_type;
- unsigned char n_sect;
+ unsigned char n_type;
+ unsigned char n_sect;
short st_desc;
unsigned long st_value;
unsigned long st_size;
@@ -345,10 +361,10 @@ int elf_must_swap(struct elfhdr *h)
} swaptest;
swaptest.i = 1;
- return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
+ return (h->e_ident[EI_DATA] == ELFDATA2MSB) !=
(swaptest.b[0] == 0);
}
-
+
void elf_swap_ehdr(struct elfhdr *h)
{
swab16s(&h->e_type); /* Object file type */
@@ -401,7 +417,7 @@ void elf_swap_rel(ELF_RELOC *rel)
#endif
}
-struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr,
+struct elf_shdr *find_elf_section(struct elf_shdr *shdr, int shnum, const char *shstr,
const char *name)
{
int i;
@@ -426,7 +442,7 @@ int find_reloc(int sh_index)
for(i = 0; i < ehdr.e_shnum; i++) {
sec = &shdr[i];
- if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
+ if (sec->sh_type == SHT_RELOC && sec->sh_info == sh_index)
return i;
}
return 0;
@@ -456,11 +472,11 @@ int load_object(const char *filename)
ElfW(Sym) *sym;
char *shstr;
ELF_RELOC *rel;
-
+
fd = open(filename, O_RDONLY);
- if (fd < 0)
+ if (fd < 0)
error("can't open file '%s'", filename);
-
+
/* Read ELF header. */
if (read(fd, &ehdr, sizeof (ehdr)) != sizeof (ehdr))
error("unable to read file header");
@@ -478,13 +494,13 @@ int load_object(const char *filename)
if (do_swap)
elf_swap_ehdr(&ehdr);
if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
- error("Unsupported ELF class");
+ error("file %s: unsupported ELF class", filename);
if (ehdr.e_type != ET_REL)
- error("ELF object file expected");
+ error("file %s: ELF object file expected", filename);
if (ehdr.e_version != EV_CURRENT)
- error("Invalid ELF version");
+ error("file %s: invalid ELF version", filename);
if (!elf_check_arch(ehdr.e_machine))
- error("Unsupported CPU (e_machine=%d)", ehdr.e_machine);
+ error("file %s: unsupported CPU (e_machine=%d)", filename, ehdr.e_machine);
/* read section headers */
shdr = load_data(fd, ehdr.e_shoff, ehdr.e_shnum * sizeof(struct elf_shdr));
@@ -497,7 +513,7 @@ int load_object(const char *filename)
/* read all section data */
sdata = malloc(sizeof(void *) * ehdr.e_shnum);
memset(sdata, 0, sizeof(void *) * ehdr.e_shnum);
-
+
for(i = 0;i < ehdr.e_shnum; i++) {
sec = &shdr[i];
if (sec->sh_type != SHT_NOBITS)
@@ -505,7 +521,7 @@ int load_object(const char *filename)
}
sec = &shdr[ehdr.e_shstrndx];
- shstr = sdata[ehdr.e_shstrndx];
+ shstr = (char*) sdata[ehdr.e_shstrndx];
/* swap relocations */
for(i = 0; i < ehdr.e_shnum; i++) {
@@ -541,8 +557,8 @@ int load_object(const char *filename)
strtab_sec = &shdr[symtab_sec->sh_link];
symtab = (ElfW(Sym) *)sdata[symtab_sec - shdr];
- strtab = sdata[symtab_sec->sh_link];
-
+ strtab = (char*) sdata[symtab_sec->sh_link];
+
nb_syms = symtab_sec->sh_size / sizeof(ElfW(Sym));
if (do_swap) {
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
@@ -582,7 +598,7 @@ void sym_ent_name(struct external_syment *ext_sym, EXE_SYM *sym)
{
char *q;
int c, i, len;
-
+
if (ext_sym->e.e.e_zeroes != 0) {
q = sym->st_name;
for(i = 0; i < 8; i++) {
@@ -616,7 +632,7 @@ char *name_for_dotdata(struct coff_rel *rel)
if (sym->st_syment->e_scnum == data_shndx &&
text_data >= sym->st_value &&
text_data < sym->st_value + sym->st_size) {
-
+
return sym->st_name;
}
@@ -674,15 +690,15 @@ int load_object(const char *filename)
uint32_t *n_strtab;
EXE_SYM *sym;
EXE_RELOC *rel;
-
- fd = open(filename, O_RDONLY
+
+ fd = open(filename, O_RDONLY
#ifdef _WIN32
| O_BINARY
#endif
);
- if (fd < 0)
+ if (fd < 0)
error("can't open file '%s'", filename);
-
+
/* Read COFF header. */
if (read(fd, &fhdr, sizeof (fhdr)) != sizeof (fhdr))
error("unable to read file header");
@@ -695,11 +711,11 @@ int load_object(const char *filename)
/* read section headers */
shdr = load_data(fd, sizeof(struct external_filehdr) + fhdr.f_opthdr, fhdr.f_nscns * sizeof(struct external_scnhdr));
-
+
/* read all section data */
sdata = malloc(sizeof(void *) * fhdr.f_nscns);
memset(sdata, 0, sizeof(void *) * fhdr.f_nscns);
-
+
const char *p;
for(i = 0;i < fhdr.f_nscns; i++) {
sec = &shdr[i];
@@ -720,7 +736,7 @@ int load_object(const char *filename)
if (!data_sec)
error("could not find .data section");
coff_data_shndx = data_sec - shdr;
-
+
coff_symtab = load_data(fd, fhdr.f_symptr, fhdr.f_nsyms*SYMESZ);
for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
for(i=0;i<8;i++)
@@ -730,8 +746,8 @@ int load_object(const char *filename)
n_strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), STRTAB_SIZE);
- strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab);
-
+ strtab = load_data(fd, (fhdr.f_symptr + fhdr.f_nsyms*SYMESZ), *n_strtab);
+
nb_syms = fhdr.f_nsyms;
for (i = 0, ext_sym = coff_symtab; i < nb_syms; i++, ext_sym++) {
@@ -778,12 +794,12 @@ int load_object(const char *filename)
} else {
sym->st_size = 0;
}
-
+
sym->st_type = ext_sym->e_type;
sym->st_shndx = ext_sym->e_scnum;
}
-
+
/* find text relocations, if any */
sec = &shdr[coff_text_shndx];
coff_relocs = load_data(fd, sec->s_relptr, sec->s_nreloc*RELSZ);
@@ -791,7 +807,7 @@ int load_object(const char *filename)
/* set coff relocation */
relocs = malloc(sizeof(struct coff_rel) * nb_relocs);
- for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs;
+ for (i = 0, ext_rel = coff_relocs, rel = relocs; i < nb_relocs;
i++, ext_rel++, rel++) {
memset(rel, 0, sizeof(*rel));
rel->r_reloc = ext_rel;
@@ -820,7 +836,7 @@ uint8_t **sdata;
/* relocs */
struct relocation_info *relocs;
-
+
/* symbols */
EXE_SYM *symtab;
struct nlist *symtab_std;
@@ -840,10 +856,10 @@ static inline char *find_str_by_index(int index)
static char *get_sym_name(EXE_SYM *sym)
{
char *name = find_str_by_index(sym->n_un.n_strx);
-
+
if ( sym->n_type & N_STAB ) /* Debug symbols are ignored */
return "debug";
-
+
if(!name)
return name;
if(name[0]=='_')
@@ -853,7 +869,7 @@ static char *get_sym_name(EXE_SYM *sym)
}
/* find a section index given its segname, sectname */
-static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname,
+static int find_mach_sec_index(struct section *section_hdr, int shnum, const char *segname,
const char *sectname)
{
int i;
@@ -869,7 +885,7 @@ static int find_mach_sec_index(struct section *section_hdr, int shnum, const cha
}
/* find a section header given its segname, sectname */
-struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname,
+struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const char *segname,
const char *sectname)
{
int index = find_mach_sec_index(section_hdr, shnum, segname, sectname);
@@ -882,7 +898,7 @@ struct section *find_mach_sec_hdr(struct section *section_hdr, int shnum, const
static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned int *value)
{
struct scattered_relocation_info * scarel;
-
+
if(R_SCATTERED & rel->r_address) {
scarel = (struct scattered_relocation_info*)rel;
if(scarel->r_type != PPC_RELOC_PAIR)
@@ -895,58 +911,36 @@ static inline void fetch_next_pair_value(struct relocation_info * rel, unsigned
}
}
-/* find a sym name given its value, in a section number */
-static const char * find_sym_with_value_and_sec_number( int value, int sectnum, int * offset )
-{
- int i, ret = -1;
-
- for( i = 0 ; i < nb_syms; i++ )
- {
- if( !(symtab[i].n_type & N_STAB) && (symtab[i].n_type & N_SECT) &&
- (symtab[i].n_sect == sectnum) && (symtab[i].st_value <= value) )
- {
- if( (ret<0) || (symtab[i].st_value >= symtab[ret].st_value) )
- ret = i;
- }
- }
- if( ret < 0 ) {
- *offset = 0;
- return 0;
- } else {
- *offset = value - symtab[ret].st_value;
- return get_sym_name(&symtab[ret]);
- }
-}
-
-/*
- * Find symbol name given a (virtual) address, and a section which is of type
+/*
+ * Find symbol name given a (virtual) address, and a section which is of type
* S_NON_LAZY_SYMBOL_POINTERS or S_LAZY_SYMBOL_POINTERS or S_SYMBOL_STUBS
*/
static const char * find_reloc_name_in_sec_ptr(int address, struct section * sec_hdr)
{
unsigned int tocindex, symindex, size;
const char *name = 0;
-
+ int section_type;
+
/* Sanity check */
if(!( address >= sec_hdr->addr && address < (sec_hdr->addr + sec_hdr->size) ) )
return (char*)0;
-
- if( sec_hdr->flags & S_SYMBOL_STUBS ){
+
+ section_type = sec_hdr->flags & SECTION_TYPE;
+ if( section_type == S_SYMBOL_STUBS ){
size = sec_hdr->reserved2;
if(size == 0)
error("size = 0");
-
}
- else if( sec_hdr->flags & S_LAZY_SYMBOL_POINTERS ||
- sec_hdr->flags & S_NON_LAZY_SYMBOL_POINTERS)
+ else if( section_type == S_LAZY_SYMBOL_POINTERS ||
+ section_type == S_NON_LAZY_SYMBOL_POINTERS)
size = sizeof(unsigned long);
else
- return 0;
-
+ return NULL;
+
/* Compute our index in toc */
tocindex = (address - sec_hdr->addr)/size;
symindex = tocdylib[sec_hdr->reserved1 + tocindex];
-
+
name = get_sym_name(&symtab[symindex]);
return name;
@@ -958,12 +952,55 @@ static const char * find_reloc_name_given_its_address(int address)
for(i = 0; i < segment->nsects ; i++)
{
const char * name = find_reloc_name_in_sec_ptr(address, &section_hdr[i]);
- if((long)name != -1)
+ if((long)name != 0)
return name;
}
return 0;
}
+/* find a sym name given its value, in a section number */
+static const char * find_sym_with_value_and_sec_number( int value, int sectnum, int * offset )
+{
+ int i, ret = -1;
+
+ for( i = 0 ; i < nb_syms; i++ )
+ {
+ if( !(symtab[i].n_type & N_STAB) && (symtab[i].n_type & N_SECT) &&
+ (symtab[i].n_sect == sectnum) && (symtab[i].st_value <= value) )
+ {
+ if( (ret<0) || (symtab[i].st_value >= symtab[ret].st_value) )
+ ret = i;
+ }
+ }
+ if( ret < 0 ) {
+ /* look in indirect symbols if not found */
+ struct section* sec_hdr = &section_hdr[sectnum-1];
+ int section_type = sec_hdr->flags & SECTION_TYPE;
+
+ if (section_type == S_NON_LAZY_SYMBOL_POINTERS)
+ {
+ int tocindex = (int)(value - sec_hdr->addr)/sizeof(long);
+ int symindex = tocdylib[sec_hdr->reserved1 + tocindex];
+ const char* name = get_sym_name(&symtab[symindex]);
+ *offset = 0;
+ return name;
+ }
+ error("no symbol match for value=0x%04x in section %d with flags %02x", value, sectnum, sec_hdr->flags);
+ return NULL;
+ } else {
+ *offset = value - symtab[ret].st_value;
+ return get_sym_name(&symtab[ret]);
+ }
+}
+
+
+static int is_reloc_non_lazy(EXE_RELOC* rel)
+{
+ return ( rel->r_symbolnum >= 1 && rel->r_symbolnum <= segment->nsects &&
+ (section_hdr[rel->r_symbolnum-1].flags & SECTION_TYPE) == S_NON_LAZY_SYMBOL_POINTERS );
+}
+
+
static const char * get_reloc_name(EXE_RELOC * rel, int * sslide)
{
char * name = 0;
@@ -971,24 +1008,43 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide)
int sectnum = rel->r_symbolnum;
int sectoffset;
int other_half=0;
-
+
/* init the slide value */
*sslide = 0;
-
- if(R_SCATTERED & rel->r_address)
- return (char *)find_reloc_name_given_its_address(sca_rel->r_value);
+
+ if (R_SCATTERED & rel->r_address) {
+ char *name = (char *)find_reloc_name_given_its_address(sca_rel->r_value);
+
+ /* search it in the full symbol list, if not found */
+ if (!name) {
+ int i;
+ for (i = 0; i < nb_syms; i++) {
+ EXE_SYM *sym = &symtab[i];
+ if (sym->st_value == sca_rel->r_value) {
+ name = get_sym_name(sym);
+ switch (sca_rel->r_type) {
+ case GENERIC_RELOC_VANILLA:
+ *sslide = *(uint32_t *)(text + sca_rel->r_address) - sca_rel->r_value;
+ break;
+ }
+ break;
+ }
+ }
+ }
+ return name;
+ }
if(rel->r_extern)
{
/* ignore debug sym */
- if ( symtab[rel->r_symbolnum].n_type & N_STAB )
+ if ( symtab[rel->r_symbolnum].n_type & N_STAB )
return 0;
return get_sym_name(&symtab[rel->r_symbolnum]);
}
/* Intruction contains an offset to the symbols pointed to, in the rel->r_symbolnum section */
sectoffset = *(uint32_t *)(text + rel->r_address) & 0xffff;
-
+
if(sectnum==0xffffff)
return 0;
@@ -1008,20 +1064,27 @@ static const char * get_reloc_name(EXE_RELOC * rel, int * sslide)
sectoffset = ( *(uint32_t *)(text + rel->r_address) & 0x03fffffc );
if (sectoffset & 0x02000000) sectoffset |= 0xfc000000;
break;
+ case GENERIC_RELOC_VANILLA:
+ sectoffset = *(uint32_t *)(text + rel->r_address);
+ break;
default:
- error("switch(rel->type) not found");
+ error("switch(rel->type=%d) not found", rel->r_type);
}
- if(rel->r_pcrel)
+ if(rel->r_pcrel) {
sectoffset += rel->r_address;
-
- if (rel->r_type == PPC_RELOC_BR24)
+#ifdef HOST_I386
+ sectoffset += (1 << rel->r_length);
+#endif
+ }
+
+ if (rel->r_type == PPC_RELOC_BR24 || rel->r_pcrel)
name = (char *)find_reloc_name_in_sec_ptr((int)sectoffset, &section_hdr[sectnum-1]);
/* search it in the full symbol list, if not found */
if(!name)
name = (char *)find_sym_with_value_and_sec_number(sectoffset, sectnum, sslide);
-
+
return name;
}
@@ -1053,11 +1116,11 @@ int load_object(const char *filename)
unsigned int i, j;
EXE_SYM *sym;
struct nlist *syment;
-
+
fd = open(filename, O_RDONLY);
- if (fd < 0)
+ if (fd < 0)
error("can't open file '%s'", filename);
-
+
/* Read Mach header. */
if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
error("unable to read file header");
@@ -1066,13 +1129,13 @@ int load_object(const char *filename)
if (!check_mach_header(mach_hdr)) {
error("bad Mach header");
}
-
- if (mach_hdr.cputype != CPU_TYPE_POWERPC)
+
+ if (!mach_check_cputype(mach_hdr.cputype))
error("Unsupported CPU");
-
+
if (mach_hdr.filetype != MH_OBJECT)
error("Unsupported Mach Object");
-
+
/* read segment headers */
for(i=0, j=sizeof(mach_hdr); i<mach_hdr.ncmds ; i++)
{
@@ -1116,26 +1179,26 @@ int load_object(const char *filename)
/* read all section data */
sdata = (uint8_t **)malloc(sizeof(void *) * segment->nsects);
memset(sdata, 0, sizeof(void *) * segment->nsects);
-
+
/* Load the data in section data */
for(i = 0; i < segment->nsects; i++) {
sdata[i] = load_data(fd, section_hdr[i].offset, section_hdr[i].size);
}
-
+
/* text section */
text_sec_hdr = find_mach_sec_hdr(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
i = find_mach_sec_index(section_hdr, segment->nsects, SEG_TEXT, SECT_TEXT);
if (i == -1 || !text_sec_hdr)
error("could not find __TEXT,__text section");
text = sdata[i];
-
+
/* Make sure dysym was loaded */
if(!(int)dysymtabcmd)
error("could not find __DYSYMTAB segment");
-
+
/* read the table of content of the indirect sym */
tocdylib = load_data( fd, dysymtabcmd->indirectsymoff, dysymtabcmd->nindirectsyms * sizeof(uint32_t) );
-
+
/* Make sure symtab was loaded */
if(!(int)symtabcmd)
error("could not find __SYMTAB segment");
@@ -1143,20 +1206,20 @@ int load_object(const char *filename)
symtab_std = load_data(fd, symtabcmd->symoff, symtabcmd->nsyms * sizeof(struct nlist));
strtab = load_data(fd, symtabcmd->stroff, symtabcmd->strsize);
-
+
symtab = malloc(sizeof(EXE_SYM) * nb_syms);
-
+
/* Now transform the symtab, to an extended version, with the sym size, and the C name */
for(i = 0, sym = symtab, syment = symtab_std; i < nb_syms; i++, sym++, syment++) {
struct nlist *sym_follow, *sym_next = 0;
unsigned int j;
memset(sym, 0, sizeof(*sym));
-
+
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 < nb_syms; j++, sym_follow++) {
if ( sym_follow->n_sect != 1 || sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
@@ -1174,7 +1237,7 @@ int load_object(const char *filename)
else
sym->st_size = text_sec_hdr->size - sym->st_value;
}
-
+
/* Find Reloc */
relocs = load_data(fd, text_sec_hdr->reloff, text_sec_hdr->nreloc * sizeof(struct relocation_info));
nb_relocs = text_sec_hdr->nreloc;
@@ -1258,9 +1321,9 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset,
int offset, min_offset, pc_offset, data_size;
uint8_t data_allocated[1024];
unsigned int data_index;
-
+
memset(data_allocated, 0, sizeof(data_allocated));
-
+
p = p_start;
min_offset = p_end - p_start;
while (p < p_start + min_offset) {
@@ -1271,22 +1334,22 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset,
if (!(insn & 0x00800000))
offset = -offset;
if ((offset & 3) !=0)
- error("%s:%04x: ldr pc offset must be 32 bit aligned",
+ error("%s:%04x: ldr pc offset must be 32 bit aligned",
name, start_offset + p - p_start);
pc_offset = p - p_start + offset + 8;
- if (pc_offset <= (p - p_start) ||
+ if (pc_offset <= (p - p_start) ||
pc_offset >= (p_end - p_start))
- error("%s:%04x: ldr pc offset must point inside the function code",
+ error("%s:%04x: ldr pc offset must point inside the function code",
name, start_offset + p - p_start);
if (pc_offset < min_offset)
min_offset = pc_offset;
if (outfile) {
/* ldr position */
- fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
+ fprintf(outfile, " arm_ldr_ptr->ptr = gen_code_ptr + %d;\n",
p - p_start);
/* ldr data index */
data_index = ((p_end - p_start) - pc_offset - 4) >> 2;
- fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n",
+ fprintf(outfile, " arm_ldr_ptr->data_ptr = arm_data_ptr + %d;\n",
data_index);
fprintf(outfile, " arm_ldr_ptr++;\n");
if (data_index >= sizeof(data_allocated))
@@ -1338,15 +1401,653 @@ int arm_emit_ldr_info(const char *name, unsigned long start_offset,
if (!outfile)
printf("%s: invalid epilog\n", name);
}
- return p - p_start;
+ return p - p_start;
}
#endif
+#if defined(HOST_I386) || defined(HOST_X86_64)
+
+/* This byte is the first byte of an instruction. */
+#define FLAG_INSN (1 << 0)
+/* This byte has been processed as part of an instruction. */
+#define FLAG_SCANNED (1 << 1)
+/* This instruction is a return instruction. Gcc cometimes generates prefix
+ bytes, so may be more than one byte long. */
+#define FLAG_RET (1 << 2)
+/* This is either the target of a jump, or the preceeding instruction uses
+ a pc-relative offset. */
+#define FLAG_TARGET (1 << 3)
+/* This is a magic instruction that needs fixing up. */
+#define FLAG_EXIT (1 << 4)
+#define MAX_EXITS 5
+
+static void
+bad_opcode(const char *name, uint32_t op)
+{
+ error("Unsupported opcode %0*x in %s", (op > 0xff) ? 4 : 2, op, name);
+}
+
+/* Mark len bytes as scanned, Returns insn_size + len. Reports an error
+ if these bytes have already been scanned. */
+static int
+eat_bytes(const char *name, char *flags, int insn, int insn_size, int len)
+{
+ while (len > 0) {
+ /* This should never occur in sane code. */
+ if (flags[insn + insn_size] & FLAG_SCANNED)
+ error ("Overlapping instructions in %s", name);
+ flags[insn + insn_size] |= FLAG_SCANNED;
+ insn_size++;
+ len--;
+ }
+ return insn_size;
+}
+
+static void
+trace_i386_insn (const char *name, uint8_t *start_p, char *flags, int insn,
+ int len)
+{
+ uint8_t *ptr;
+ uint8_t op;
+ int modrm;
+ int is_prefix;
+ int op_size;
+ int addr_size;
+ int insn_size;
+ int is_ret;
+ int is_condjmp;
+ int is_jmp;
+ int is_exit;
+ int is_pcrel;
+ int immed;
+ int seen_rexw;
+ int32_t disp;
+
+ ptr = start_p + insn;
+ /* nonzero if this insn has a ModR/M byte. */
+ modrm = 1;
+ /* The size of the immediate value in this instruction. */
+ immed = 0;
+ /* The operand size. */
+ op_size = 4;
+ /* The address size */
+ addr_size = 4;
+ /* The total length of this instruction. */
+ insn_size = 0;
+ is_prefix = 1;
+ is_ret = 0;
+ is_condjmp = 0;
+ is_jmp = 0;
+ is_exit = 0;
+ seen_rexw = 0;
+ is_pcrel = 0;
+
+ while (is_prefix) {
+ op = ptr[insn_size];
+ insn_size = eat_bytes(name, flags, insn, insn_size, 1);
+ is_prefix = 0;
+ switch (op >> 4) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ if (op == 0x0f) {
+ /* two-byte opcode. */
+ op = ptr[insn_size];
+ insn_size = eat_bytes(name, flags, insn, insn_size, 1);
+ switch (op >> 4) {
+ case 0:
+ if ((op & 0xf) > 3)
+ modrm = 0;
+ break;
+ case 1: /* vector move or prefetch */
+ case 2: /* various moves and vector compares. */
+ case 4: /* cmov */
+ case 5: /* vector instructions */
+ case 6:
+ case 13:
+ case 14:
+ case 15:
+ break;
+ case 7: /* mmx */
+ if (op & 0x77) /* emms */
+ modrm = 0;
+ break;
+ case 3: /* wrmsr, rdtsc, rdmsr, rdpmc, sysenter, sysexit */
+ modrm = 0;
+ break;
+ case 8: /* long conditional jump */
+ is_condjmp = 1;
+ immed = op_size;
+ modrm = 0;
+ break;
+ case 9: /* setcc */
+ break;
+ case 10:
+ switch (op & 0x7) {
+ case 0: /* push fs/gs */
+ case 1: /* pop fs/gs */
+ case 2: /* cpuid/rsm */
+ modrm = 0;
+ break;
+ case 4: /* shld/shrd immediate */
+ immed = 1;
+ break;
+ default: /* Normal instructions with a ModR/M byte. */
+ break;
+ }
+ break;
+ case 11:
+ switch (op & 0xf) {
+ case 10: /* bt, bts, btr, btc */
+ immed = 1;
+ break;
+ default:
+ /* cmpxchg, lss, btr, lfs, lgs, movzx, btc, bsf, bsr
+ undefined, and movsx */
+ break;
+ }
+ break;
+ case 12:
+ if (op & 8) {
+ /* bswap */
+ modrm = 0;
+ } else {
+ switch (op & 0x7) {
+ case 2:
+ case 4:
+ case 5:
+ case 6:
+ immed = 1;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+ } else if ((op & 0x07) <= 0x3) {
+ /* General arithmentic ax. */
+ } else if ((op & 0x07) <= 0x5) {
+ /* General arithmetic ax, immediate. */
+ if (op & 0x01)
+ immed = op_size;
+ else
+ immed = 1;
+ modrm = 0;
+ } else if ((op & 0x23) == 0x22) {
+ /* Segment prefix. */
+ is_prefix = 1;
+ } else {
+ /* Segment register push/pop or DAA/AAA/DAS/AAS. */
+ modrm = 0;
+ }
+ break;
+
+#if defined(HOST_X86_64)
+ case 4: /* rex prefix. */
+ is_prefix = 1;
+ /* The address/operand size is actually 64-bit, but the immediate
+ values in the instruction are still 32-bit. */
+ op_size = 4;
+ addr_size = 4;
+ if (op & 8)
+ seen_rexw = 1;
+ break;
+#else
+ case 4: /* inc/dec register. */
+#endif
+ case 5: /* push/pop general register. */
+ modrm = 0;
+ break;
+
+ case 6:
+ switch (op & 0x0f) {
+ case 0: /* pusha */
+ case 1: /* popa */
+ modrm = 0;
+ break;
+ case 2: /* bound */
+ case 3: /* arpl */
+ break;
+ case 4: /* FS */
+ case 5: /* GS */
+ is_prefix = 1;
+ break;
+ case 6: /* opcode size prefix. */
+ op_size = 2;
+ is_prefix = 1;
+ break;
+ case 7: /* Address size prefix. */
+ addr_size = 2;
+ is_prefix = 1;
+ break;
+ case 8: /* push immediate */
+ immed = op_size;
+ modrm = 0;
+ break;
+ case 10: /* push 8-bit immediate */
+ immed = 1;
+ modrm = 0;
+ break;
+ case 9: /* imul immediate */
+ immed = op_size;
+ break;
+ case 11: /* imul 8-bit immediate */
+ immed = 1;
+ break;
+ case 12: /* insb */
+ case 13: /* insw */
+ case 14: /* outsb */
+ case 15: /* outsw */
+ modrm = 0;
+ break;
+ }
+ break;
+
+ case 7: /* Short conditional jump. */
+ is_condjmp = 1;
+ immed = 1;
+ modrm = 0;
+ break;
+
+ case 8:
+ if ((op & 0xf) <= 3) {
+ /* arithmetic immediate. */
+ if ((op & 3) == 1)
+ immed = op_size;
+ else
+ immed = 1;
+ }
+ /* else test, xchg, mov, lea or pop general. */
+ break;
+
+ case 9:
+ /* Various single-byte opcodes with no modrm byte. */
+ modrm = 0;
+ if (op == 10) {
+ /* Call */
+ immed = 4;
+ }
+ break;
+
+ case 10:
+ switch ((op & 0xe) >> 1) {
+ case 0: /* mov absoliute immediate. */
+ case 1:
+ if (seen_rexw)
+ immed = 8;
+ else
+ immed = addr_size;
+ break;
+ case 4: /* test immediate. */
+ if (op & 1)
+ immed = op_size;
+ else
+ immed = 1;
+ break;
+ default: /* Various string ops. */
+ break;
+ }
+ modrm = 0;
+ break;
+
+ case 11: /* move immediate to register */
+ if (op & 8) {
+ if (seen_rexw)
+ immed = 8;
+ else
+ immed = op_size;
+ } else {
+ immed = 1;
+ }
+ modrm = 0;
+ break;
+
+ case 12:
+ switch (op & 0xf) {
+ case 0: /* shift immediate */
+ case 1:
+ immed = 1;
+ break;
+ case 2: /* ret immediate */
+ immed = 2;
+ modrm = 0;
+ bad_opcode(name, op);
+ break;
+ case 3: /* ret */
+ modrm = 0;
+ is_ret = 1;
+ case 4: /* les */
+ case 5: /* lds */
+ break;
+ case 6: /* mov immediate byte */
+ immed = 1;
+ break;
+ case 7: /* mov immediate */
+ immed = op_size;
+ break;
+ case 8: /* enter */
+ /* TODO: Is this right? */
+ immed = 3;
+ modrm = 0;
+ break;
+ case 10: /* retf immediate */
+ immed = 2;
+ modrm = 0;
+ bad_opcode(name, op);
+ break;
+ case 13: /* int */
+ immed = 1;
+ modrm = 0;
+ break;
+ case 11: /* retf */
+ case 15: /* iret */
+ modrm = 0;
+ bad_opcode(name, op);
+ break;
+ default: /* leave, int3 or into */
+ modrm = 0;
+ break;
+ }
+ break;
+
+ case 13:
+ if ((op & 0xf) >= 8) {
+ /* Coprocessor escape. For our purposes this is just a normal
+ instruction with a ModR/M byte. */
+ } else if ((op & 0xf) >= 4) {
+ /* AAM, AAD or XLAT */
+ modrm = 0;
+ }
+ /* else shift instruction */
+ break;
+
+ case 14:
+ switch ((op & 0xc) >> 2) {
+ case 0: /* loop or jcxz */
+ is_condjmp = 1;
+ immed = 1;
+ break;
+ case 1: /* in/out immed */
+ immed = 1;
+ break;
+ case 2: /* call or jmp */
+ switch (op & 3) {
+ case 0: /* call */
+ immed = op_size;
+ break;
+ case 1: /* long jump */
+ immed = 4;
+ is_jmp = 1;
+ break;
+ case 2: /* far jmp */
+ bad_opcode(name, op);
+ break;
+ case 3: /* short jmp */
+ immed = 1;
+ is_jmp = 1;
+ break;
+ }
+ break;
+ case 3: /* in/out register */
+ break;
+ }
+ modrm = 0;
+ break;
+
+ case 15:
+ switch ((op & 0xe) >> 1) {
+ case 0:
+ case 1:
+ is_prefix = 1;
+ break;
+ case 2:
+ case 4:
+ case 5:
+ case 6:
+ modrm = 0;
+ /* Some privileged insns are used as markers. */
+ switch (op) {
+ case 0xf4: /* hlt: Exit translation block. */
+ is_exit = 1;
+ break;
+ case 0xfa: /* cli: Jump to label. */
+ is_exit = 1;
+ immed = 4;
+ break;
+ case 0xfb: /* sti: TB patch jump. */
+ /* Mark the insn for patching, but continue sscanning. */
+ flags[insn] |= FLAG_EXIT;
+ immed = 4;
+ break;
+ }
+ break;
+ case 3: /* unary grp3 */
+ if ((ptr[insn_size] & 0x38) == 0) {
+ if (op == 0xf7)
+ immed = op_size;
+ else
+ immed = 1; /* test immediate */
+ }
+ break;
+ case 7: /* inc/dec grp4/5 */
+ /* TODO: This includes indirect jumps. We should fail if we
+ encounter one of these. */
+ break;
+ }
+ break;
+ }
+ }
+
+ if (modrm) {
+ if (addr_size != 4)
+ error("16-bit addressing mode used in %s", name);
+
+ disp = 0;
+ modrm = ptr[insn_size];
+ insn_size = eat_bytes(name, flags, insn, insn_size, 1);
+ modrm &= 0xc7;
+ switch ((modrm & 0xc0) >> 6) {
+ case 0:
+ if (modrm == 5)
+ disp = 4;
+ break;
+ case 1:
+ disp = 1;
+ break;
+ case 2:
+ disp = 4;
+ break;
+ }
+ if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 4) {
+ /* SIB byte */
+ if (modrm == 4 && (ptr[insn_size] & 0x7) == 5) {
+ disp = 4;
+ is_pcrel = 1;
+ }
+ insn_size = eat_bytes(name, flags, insn, insn_size, 1);
+ }
+ insn_size = eat_bytes(name, flags, insn, insn_size, disp);
+ }
+ insn_size = eat_bytes(name, flags, insn, insn_size, immed);
+ if (is_condjmp || is_jmp) {
+ if (immed == 1) {
+ disp = (int8_t)*(ptr + insn_size - 1);
+ } else {
+ disp = (((int32_t)*(ptr + insn_size - 1)) << 24)
+ | (((int32_t)*(ptr + insn_size - 2)) << 16)
+ | (((int32_t)*(ptr + insn_size - 3)) << 8)
+ | *(ptr + insn_size - 4);
+ }
+ disp += insn_size;
+ /* Jumps to external symbols point to the address of the offset
+ before relocation. */
+ /* ??? These are probably a tailcall. We could fix them up by
+ replacing them with jmp to EOB + call, but it's easier to just
+ prevent the compiler generating them. */
+ if (disp == 1)
+ error("Unconditional jump (sibcall?) in %s", name);
+ disp += insn;
+ if (disp < 0 || disp > len)
+ error("Jump outside instruction in %s", name);
+
+ if ((flags[disp] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_SCANNED)
+ error("Overlapping instructions in %s", name);
+
+ flags[disp] |= (FLAG_INSN | FLAG_TARGET);
+ is_pcrel = 1;
+ }
+ if (is_pcrel) {
+ /* Mark the following insn as a jump target. This will stop
+ this instruction being moved. */
+ flags[insn + insn_size] |= FLAG_TARGET;
+ }
+ if (is_ret)
+ flags[insn] |= FLAG_RET;
+
+ if (is_exit)
+ flags[insn] |= FLAG_EXIT;
+
+ if (!(is_jmp || is_ret || is_exit))
+ flags[insn + insn_size] |= FLAG_INSN;
+}
+
+/* Scan a function body. Returns the position of the return sequence.
+ Sets *patch_bytes to the number of bytes that need to be copied from that
+ location. If no patching is required (ie. the return is the last insn)
+ *patch_bytes will be set to -1. *plen is the number of code bytes to copy.
+ */
+static int trace_i386_op(const char * name, uint8_t *start_p, int *plen,
+ int *patch_bytes, int *exit_addrs)
+{
+ char *flags;
+ int more;
+ int insn;
+ int retpos;
+ int bytes;
+ int num_exits;
+ int len;
+ int last_insn;
+
+ len = *plen;
+ flags = malloc(len + 1);
+ memset(flags, 0, len + 1);
+ flags[0] |= FLAG_INSN;
+ more = 1;
+ while (more) {
+ more = 0;
+ for (insn = 0; insn < len; insn++) {
+ if ((flags[insn] & (FLAG_INSN | FLAG_SCANNED)) == FLAG_INSN) {
+ trace_i386_insn(name, start_p, flags, insn, len);
+ more = 1;
+ }
+ }
+ }
+
+ /* Strip any unused code at the end of the function. */
+ while (len > 0 && flags[len - 1] == 0)
+ len--;
+
+ retpos = -1;
+ num_exits = 0;
+ last_insn = 0;
+ for (insn = 0; insn < len; insn++) {
+ if (flags[insn] & FLAG_RET) {
+ /* ??? In theory it should be possible to handle multiple return
+ points. In practice it's not worth the effort. */
+ if (retpos != -1)
+ error("Multiple return instructions in %s", name);
+ retpos = insn;
+ }
+ if (flags[insn] & FLAG_EXIT) {
+ if (num_exits == MAX_EXITS)
+ error("Too many block exits in %s", name);
+ exit_addrs[num_exits] = insn;
+ num_exits++;
+ }
+ if (flags[insn] & FLAG_INSN)
+ last_insn = insn;
+ }
+
+ exit_addrs[num_exits] = -1;
+ if (retpos == -1) {
+ if (num_exits == 0) {
+ error ("No return instruction found in %s", name);
+ } else {
+ retpos = len;
+ last_insn = len;
+ }
+ }
+
+ /* If the return instruction is the last instruction we can just
+ remove it. */
+ if (retpos == last_insn)
+ *patch_bytes = -1;
+ else
+ *patch_bytes = 0;
+
+ /* Back up over any nop instructions. */
+ while (retpos > 0
+ && (flags[retpos] & FLAG_TARGET) == 0
+ && (flags[retpos - 1] & FLAG_INSN) != 0
+ && start_p[retpos - 1] == 0x90) {
+ retpos--;
+ }
+
+ if (*patch_bytes == -1) {
+ *plen = retpos;
+ free (flags);
+ return retpos;
+ }
+ *plen = len;
+
+ /* The ret is in the middle of the function. Find four more bytes that
+ so the ret can be replaced by a jmp. */
+ /* ??? Use a short jump where possible. */
+ bytes = 4;
+ insn = retpos + 1;
+ /* We can clobber everything up to the next jump target. */
+ while (insn < len && bytes > 0 && (flags[insn] & FLAG_TARGET) == 0) {
+ insn++;
+ bytes--;
+ }
+ if (bytes > 0) {
+ /* ???: Strip out nop blocks. */
+ /* We can't do the replacement without clobbering anything important.
+ Copy preceeding instructions(s) to give us some space. */
+ while (retpos > 0) {
+ /* If this byte is the target of a jmp we can't move it. */
+ if (flags[retpos] & FLAG_TARGET)
+ break;
+
+ (*patch_bytes)++;
+ bytes--;
+ retpos--;
+
+ /* Break out of the loop if we have enough space and this is either
+ the first byte of an instruction or a pad byte. */
+ if ((flags[retpos] & (FLAG_INSN | FLAG_SCANNED)) != FLAG_SCANNED
+ && bytes <= 0) {
+ break;
+ }
+ }
+ }
+
+ if (bytes > 0)
+ error("Unable to replace ret with jmp in %s\n", name);
+
+ free(flags);
+ return retpos;
+}
+
+#endif
+
#define MAX_ARGS 3
/* generate op code */
-void gen_code(const char *name, host_ulong offset, host_ulong size,
+void gen_code(const char *name, host_ulong offset, host_ulong size,
FILE *outfile, int gen_switch)
{
int copy_size = 0;
@@ -1357,6 +2058,19 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
const char *sym_name, *p;
EXE_RELOC *rel;
+#if defined(CONFIG_FORMAT_MACH)
+ typedef struct { const char* name; int nonlazy; } SymRef;
+ int num_symrefs = 0;
+ int max_symrefs = 0;
+ SymRef* symrefs = NULL;
+#endif
+
+#if defined(HOST_I386) || defined(HOST_X86_64)
+ int patch_bytes;
+ int retpos;
+ int exit_addrs[MAX_EXITS];
+#endif
+
/* Compute exact size excluding prologue and epilogue instructions.
* Increment start_offset to skip epilogue instructions, then compute
* copy_size the indicate the size of the remaining instructions (in
@@ -1366,37 +2080,20 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
p_end = p_start + size;
start_offset = offset;
#if defined(HOST_I386) || defined(HOST_X86_64)
-#ifdef CONFIG_FORMAT_COFF
- {
- uint8_t *p;
- p = p_end - 1;
- if (p == p_start)
- error("empty code for %s", name);
- while (*p != 0xc3) {
- p--;
- if (p <= p_start)
- error("ret or jmp expected at the end of %s", name);
- }
- copy_size = p - p_start;
- }
-#else
{
int len;
len = p_end - p_start;
- if (len == 0)
- error("empty code for %s", name);
- if (p_end[-1] == 0xc3) {
- len--;
- } else {
- error("ret or jmp expected at the end of %s", name);
- }
+ retpos = trace_i386_op(name, p_start, &len, &patch_bytes, exit_addrs);
copy_size = len;
}
-#endif
#elif defined(HOST_PPC)
{
uint8_t *p;
p = (void *)(p_end - 4);
+ while (p > p_start && get32((uint32_t*)p) == 0x60000000) {
+ p_end = p;
+ p -= 4;
+ }
if (p == p_start)
error("empty code for %s", name);
if (get32((uint32_t *)p) != 0x4e800020)
@@ -1424,7 +2121,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
#endif
if (get32((uint32_t *)p) != 0x6bfa8001)
error("ret expected at the end of %s", name);
- copy_size = p - p_start;
+ copy_size = p - p_start;
}
#elif defined(HOST_IA64)
{
@@ -1442,12 +2139,9 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
{
#define INSN_SAVE 0x9de3a000
#define INSN_RET 0x81c7e008
-#define INSN_RETL 0x81c3e008
#define INSN_RESTORE 0x81e80000
#define INSN_RETURN 0x81cfe008
#define INSN_NOP 0x01000000
-#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
-#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
uint32_t start_insn, end_insn1, end_insn2;
uint8_t *p;
@@ -1457,21 +2151,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
start_insn = get32((uint32_t *)(p_start + 0x0));
end_insn1 = get32((uint32_t *)(p + 0x0));
end_insn2 = get32((uint32_t *)(p + 0x4));
- if (((start_insn & ~0x1fff) == INSN_SAVE) ||
- (start_insn & ~0x1fff) == INSN_ADD_SP) {
+ if ((start_insn & ~0x1fff) == INSN_SAVE) {
p_start += 0x4;
start_offset += 0x4;
+ if ((int)(start_insn | ~0x1fff) < -128)
+ error("Found bogus save at the start of %s", name);
if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
/* SPARC v7: ret; restore; */ ;
else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
/* SPARC v9: return; nop; */ ;
- else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
- /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
else
-
error("ret; restore; not found at end of %s", name);
- } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
- ;
} else {
error("No save at the beginning of %s", name);
}
@@ -1487,52 +2177,32 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
#elif defined(HOST_SPARC64)
{
-#define INSN_SAVE 0x9de3a000
-#define INSN_RET 0x81c7e008
-#define INSN_RETL 0x81c3e008
-#define INSN_RESTORE 0x81e80000
-#define INSN_RETURN 0x81cfe008
-#define INSN_NOP 0x01000000
-#define INSN_ADD_SP 0x9c03a000 // add %sp, nn, %sp
-#define INSN_SUB_SP 0x9c23a000 // sub %sp, nn, %sp
-
uint32_t start_insn, end_insn1, end_insn2, skip_insn;
uint8_t *p;
p = (void *)(p_end - 8);
-#if 0
- /* XXX: check why it occurs */
if (p <= p_start)
error("empty code for %s", name);
-#endif
start_insn = get32((uint32_t *)(p_start + 0x0));
end_insn1 = get32((uint32_t *)(p + 0x0));
end_insn2 = get32((uint32_t *)(p + 0x4));
- if (((start_insn & ~0x1fff) == INSN_SAVE) ||
- (start_insn & ~0x1fff) == INSN_ADD_SP) {
+ if ((start_insn & ~0x1fff) == 0x9de3a000) {
p_start += 0x4;
start_offset += 0x4;
- if (end_insn1 == INSN_RET && end_insn2 == INSN_RESTORE)
- /* SPARC v7: ret; restore; */ ;
- else if (end_insn1 == INSN_RETURN && end_insn2 == INSN_NOP)
- /* SPARC v9: return; nop; */ ;
- else if (end_insn1 == INSN_RETL && (end_insn2 & ~0x1fff) == INSN_SUB_SP)
- /* SPARC v7: retl; sub %sp, nn, %sp; */ ;
- else
-
+ if ((int)(start_insn | ~0x1fff) < -256)
+ error("Found bogus save at the start of %s", name);
+ if (end_insn1 != 0x81c7e008 || end_insn2 != 0x81e80000)
error("ret; restore; not found at end of %s", name);
- } else if (end_insn1 == INSN_RETL && end_insn2 == INSN_NOP) {
- ;
} else {
error("No save at the beginning of %s", name);
}
-
+
/* Skip a preceeding nop, if present. */
if (p > p_start) {
skip_insn = get32((uint32_t *)(p - 0x4));
if (skip_insn == 0x01000000)
p -= 4;
}
-
+
copy_size = p - p_start;
}
#elif defined(HOST_ARM)
@@ -1545,7 +2215,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
error("%s: invalid prolog", name);
p_start += 12;
start_offset += 12;
- copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
+ copy_size = arm_emit_ldr_info(name, start_offset, NULL, p_start, p_end,
relocs, nb_relocs);
}
#elif defined(HOST_M68K)
@@ -1556,7 +2226,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
error("empty code for %s", name);
// remove NOP's, probably added for alignment
while ((get16((uint16_t *)p) == 0x4e71) &&
- (p>p_start))
+ (p>p_start))
p -= 2;
if (get16((uint16_t *)p) != 0x4e75)
error("rts expected at the end of %s", name);
@@ -1586,7 +2256,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
}
}
-
+
nb_args = 0;
while (nb_args < MAX_ARGS && args_present[nb_args])
nb_args++;
@@ -1596,6 +2266,13 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
if (gen_switch == 2) {
+#if defined(HOST_I386) || defined(HOST_X86_64)
+ if (patch_bytes != -1)
+ copy_size += patch_bytes;
+#ifdef DEBUG_OP
+ copy_size += 2;
+#endif
+#endif
fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
} else if (gen_switch == 1) {
@@ -1610,11 +2287,30 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
fprintf(outfile, ";\n");
}
+
+#if 1
+ fprintf(outfile, " static const unsigned char %s[%d] = {\n", name, copy_size);
+ {
+ uint8_t* code = p_start + (start_offset - offset);
+ int nn;
+ const char* comma = " ";
+
+ for (nn = 0; nn < copy_size; nn++) {
+ fprintf(outfile, "%s0x%02x", comma, code[nn]);
+ comma = ", ";
+ if (((nn+1) & 15) == 0)
+ comma = ",\n ";
+ }
+ offset = start_offset;
+ }
+ fprintf(outfile, "\n };\n" );
+#else /* 0 */
#if defined(HOST_IA64)
fprintf(outfile, " extern char %s;\n", name);
#else
fprintf(outfile, " extern void %s();\n", name);
#endif
+#endif /* 0 */
for(i = 0, rel = relocs;i < nb_relocs; i++, rel++) {
host_ulong offset = get_rel_offset(rel);
@@ -1623,7 +2319,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
sym_name = get_rel_sym_name(rel);
if(!sym_name)
continue;
- if (*sym_name &&
+ if (*sym_name &&
!strstart(sym_name, "__op_param", NULL) &&
!strstart(sym_name, "__op_jmp", NULL) &&
!strstart(sym_name, "__op_gen_label", NULL)) {
@@ -1634,10 +2330,35 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
sym_name+1, sym_name);
continue;
}
-#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);
+#elif defined(CONFIG_FORMAT_MACH)
+ {
+ int nn;
+
+ for (nn = 0; nn < num_symrefs; nn++)
+ if ( !strcmp(sym_name, symrefs[nn].name) )
+ break;
+
+ if (nn >= num_symrefs)
+ {
+ if (num_symrefs >= max_symrefs) {
+ int new_max = max_symrefs + 16;
+ SymRef* new_refs = realloc( symrefs, new_max*sizeof(SymRef) );
+ symrefs = new_refs;
+ max_symrefs = new_max;
+ }
+
+ symrefs[nn].name = sym_name;
+ symrefs[nn].nonlazy = 0;
+
+ fprintf(outfile, " extern char %s __attribute__((unused));\n", sym_name);
+ num_symrefs++;
+ }
+
+ if ( !symrefs[nn].nonlazy && is_reloc_non_lazy(rel) ) {
+ symrefs[nn].nonlazy = 1;
+ fprintf(outfile, " static const void* __to_%s = &%s;\n", sym_name, sym_name );
+ }
+ }
#elif defined(HOST_IA64)
if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
/*
@@ -1669,7 +2390,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
if (strstart(sym_name, "__op_label", &p)) {
uint8_t *ptr;
unsigned long offset;
-
+
/* test if the variable refers to a label inside
the code we are generating */
#ifdef CONFIG_FORMAT_COFF
@@ -1701,7 +2422,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
/* try to find a matching relocation */
reloc_shndx = find_reloc(sym->st_shndx);
if (reloc_shndx) {
- nb_relocs1 = shdr[reloc_shndx].sh_size /
+ nb_relocs1 = shdr[reloc_shndx].sh_size /
shdr[reloc_shndx].sh_entsize;
rel = (ELF_RELOC *)sdata[reloc_shndx];
for(j = 0; j < nb_relocs1; j++) {
@@ -1713,7 +2434,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
}
}
-#endif
+#endif
if (val >= start_offset && val <= start_offset + copy_size) {
n = strtol(p, NULL, 10);
fprintf(outfile, " label_offsets[%d] = %ld + (gen_code_ptr - gen_code_buf);\n", n, (long)(val - start_offset));
@@ -1730,6 +2451,85 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
/* patch relocations */
#if defined(HOST_I386)
{
+#ifdef CONFIG_FORMAT_MACH
+ struct scattered_relocation_info *scarel;
+ struct relocation_info * rel;
+ char final_sym_name[256];
+ const char *sym_name;
+ const char *p;
+ int slide, sslide;
+ int i;
+
+ for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
+ unsigned int offset, length, value = 0;
+ unsigned int type, pcrel, isym = 0;
+ unsigned int usesym = 0;
+
+ if (R_SCATTERED & rel->r_address) {
+ scarel = (struct scattered_relocation_info*)rel;
+ offset = (unsigned int)scarel->r_address;
+ length = scarel->r_length;
+ pcrel = scarel->r_pcrel;
+ type = scarel->r_type;
+ value = scarel->r_value;
+ }
+ else {
+ value = isym = rel->r_symbolnum;
+ usesym = (rel->r_extern);
+ offset = rel->r_address;
+ length = rel->r_length;
+ pcrel = rel->r_pcrel;
+ type = rel->r_type;
+ }
+
+ slide = offset - start_offset;
+
+ if (!(offset >= start_offset && offset < start_offset + size))
+ continue; /* not in our range */
+
+ sym_name = get_reloc_name(rel, &sslide);
+
+ if (usesym && symtab[isym].n_type & N_STAB)
+ continue; /* don't handle STAB (debug sym) */
+
+ if (sym_name && strstart(sym_name, "__op_jmp", &p)) {
+ int n;
+ n = strtol(p, NULL, 10);
+ fprintf(outfile, " jmp_offsets[%d] = %d + (gen_code_ptr - gen_code_buf);\n", n, slide);
+ continue; /* Nothing more to do */
+ }
+
+ if (!sym_name) {
+ fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
+ name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type);
+ continue; /* dunno how to handle without final_sym_name */
+ }
+
+ get_reloc_expr(final_sym_name, sizeof(final_sym_name),
+ sym_name);
+
+ if (length != 2)
+ error("unsupported %d-bit relocation", 8 * (1 << length));
+
+ switch (type) {
+ case GENERIC_RELOC_VANILLA:
+ if (pcrel || strstart(sym_name,"__op_gen_label",&p)) {
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) - 4;\n",
+ slide, final_sym_name, slide);
+ }
+ else {
+ if ( is_reloc_non_lazy(rel) )
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)(void*)&__to_%s;\n", slide, sym_name);
+ else
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (%s + %d);\n",
+ slide, final_sym_name, sslide);
+ }
+ break;
+ default:
+ error("unsupported i386 relocation (%d)", type);
+ }
+ }
+#else
char name[256];
int type;
int addend;
@@ -1759,11 +2559,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
type = ELF32_R_TYPE(rel->r_info);
switch(type) {
case R_386_32:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
break;
case R_386_PC32:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
reloc_offset, name, reloc_offset, addend);
break;
default:
@@ -1786,11 +2586,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
type = rel->r_type;
switch(type) {
case DIR32:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
break;
case DISP32:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d -4;\n",
reloc_offset, name, reloc_offset, addend);
break;
default:
@@ -1801,6 +2601,43 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
#endif
}
}
+#endif
+ /* Replace the marker instructions with the actual opcodes. */
+ for (i = 0; exit_addrs[i] != -1; i++) {
+ int op;
+ switch (p_start[exit_addrs[i]])
+ {
+ case 0xf4: op = 0xc3; break; /* hlt -> ret */
+ case 0xfa: op = 0xe9; break; /* cli -> jmp */
+ case 0xfb: op = 0xe9; break; /* sti -> jmp */
+ default: error("Internal error");
+ }
+ fprintf(outfile,
+ " *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n",
+ exit_addrs[i], op);
+ }
+ /* Fix up the return instruction. */
+ if (patch_bytes != -1) {
+ if (patch_bytes) {
+ fprintf(outfile, " memcpy(gen_code_ptr + %d,"
+ "gen_code_ptr + %d, %d);\n",
+ copy_size, retpos, patch_bytes);
+ }
+ fprintf(outfile,
+ " *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n",
+ retpos);
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n",
+ retpos + 1, copy_size - (retpos + 5));
+
+ copy_size += patch_bytes;
+ }
+#ifdef DEBUG_OP
+ fprintf(outfile,
+ " *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n",
+ copy_size);
+ copy_size += 2;
+#endif
}
#elif defined(HOST_X86_64)
{
@@ -1818,15 +2655,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
reloc_offset = rel->r_offset - start_offset;
switch(type) {
case R_X86_64_32:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (uint32_t)%s + %d;\n",
reloc_offset, name, addend);
break;
case R_X86_64_32S:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (int32_t)%s + %d;\n",
reloc_offset, name, addend);
break;
case R_X86_64_PC32:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %d) + %d;\n",
reloc_offset, name, reloc_offset, addend);
break;
default:
@@ -1834,6 +2671,42 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
}
}
}
+ /* Replace the marker instructions with the actual opcodes. */
+ for (i = 0; exit_addrs[i] != -1; i++) {
+ int op;
+ switch (p_start[exit_addrs[i]])
+ {
+ case 0xf4: op = 0xc3; break; /* hlt -> ret */
+ case 0xfa: op = 0xe9; break; /* cli -> jmp */
+ case 0xfb: op = 0xe9; break; /* sti -> jmp */
+ default: error("Internal error");
+ }
+ fprintf(outfile,
+ " *(uint8_t *)(gen_code_ptr + %d) = 0x%x;\n",
+ exit_addrs[i], op);
+ }
+ /* Fix up the return instruction. */
+ if (patch_bytes != -1) {
+ if (patch_bytes) {
+ fprintf(outfile, " memcpy(gen_code_ptr + %d,"
+ "gen_code_ptr + %d, %d);\n",
+ copy_size, retpos, patch_bytes);
+ }
+ fprintf(outfile,
+ " *(uint8_t *)(gen_code_ptr + %d) = 0xe9;\n",
+ retpos);
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = 0x%x;\n",
+ retpos + 1, copy_size - (retpos + 5));
+
+ copy_size += patch_bytes;
+ }
+#ifdef DEBUG_OP
+ fprintf(outfile,
+ " *(uint16_t *)(gen_code_ptr + %d) = 0x9090;\n",
+ copy_size);
+ copy_size += 2;
+#endif
}
#elif defined(HOST_PPC)
{
@@ -1858,30 +2731,30 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
n, reloc_offset);
continue;
}
-
+
get_reloc_expr(name, sizeof(name), sym_name);
type = ELF32_R_TYPE(rel->r_info);
addend = rel->r_addend;
switch(type) {
case R_PPC_ADDR32:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
break;
case R_PPC_ADDR16_LO:
- fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d);\n",
reloc_offset, name, addend);
break;
case R_PPC_ADDR16_HI:
- fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d) >> 16;\n",
reloc_offset, name, addend);
break;
case R_PPC_ADDR16_HA:
- fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = (%s + %d + 0x8000) >> 16;\n",
reloc_offset, name, addend);
break;
case R_PPC_REL24:
/* warning: must be at 32 MB distancy */
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((%s - (long)(gen_code_ptr + %d) + %d) & 0x03fffffc);\n",
reloc_offset, reloc_offset, name, reloc_offset, addend);
break;
default:
@@ -1897,12 +2770,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
const char *p;
int slide, sslide;
int i;
-
+
for(i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
unsigned int offset, length, value = 0;
unsigned int type, pcrel, isym = 0;
unsigned int usesym = 0;
-
+
if(R_SCATTERED & rel->r_address) {
scarel = (struct scattered_relocation_info*)rel;
offset = (unsigned int)scarel->r_address;
@@ -1918,17 +2791,17 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
pcrel = rel->r_pcrel;
type = rel->r_type;
}
-
+
slide = offset - start_offset;
-
- if (!(offset >= start_offset && offset < start_offset + size))
+
+ if (!(offset >= start_offset && offset < start_offset + size))
continue; /* not in our range */
sym_name = get_reloc_name(rel, &sslide);
-
+
if(usesym && symtab[isym].n_type & N_STAB)
continue; /* don't handle STAB (debug sym) */
-
+
if (sym_name && strstart(sym_name, "__op_jmp", &p)) {
int n;
n = strtol(p, NULL, 10);
@@ -1936,40 +2809,52 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
n, slide);
continue; /* Nothing more to do */
}
-
+
if(!sym_name)
{
fprintf(outfile, "/* #warning relocation not handled in %s (value 0x%x, %s, offset 0x%x, length 0x%x, %s, type 0x%x) */\n",
name, value, usesym ? "use sym" : "don't use sym", offset, length, pcrel ? "pcrel":"", type);
continue; /* dunno how to handle without final_sym_name */
}
-
- get_reloc_expr(final_sym_name, sizeof(final_sym_name),
+
+ get_reloc_expr(final_sym_name, sizeof(final_sym_name),
sym_name);
switch(type) {
case PPC_RELOC_BR24:
if (!strstart(sym_name,"__op_gen_label",&p)) {
- fprintf(outfile, "{\n");
- fprintf(outfile, " uint32_t imm = *(uint32_t *)(gen_code_ptr + %d) & 0x3fffffc;\n", slide);
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm + ((long)%s - (long)gen_code_ptr) + %d) & 0x03fffffc);\n",
- slide, slide, name, sslide );
- fprintf(outfile, "}\n");
+ fprintf(outfile, " {\n");
+ fprintf(outfile, " uint32_t imm = (uint32_t) & %s;\n", get_rel_sym_name(rel));
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | ((imm - ((uint32_t)gen_code_ptr + %d)) & 0x03fffffc);\n",
+ slide, slide, slide );
+ fprintf(outfile, " }\n");
} else {
fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = (*(uint32_t *)(gen_code_ptr + %d) & ~0x03fffffc) | (((long)%s - (long)gen_code_ptr - %d) & 0x03fffffc);\n",
slide, slide, final_sym_name, slide);
}
break;
case PPC_RELOC_HI16:
- fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n",
- slide, final_sym_name, sslide);
+ if ( is_reloc_non_lazy(rel) )
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = ((uint32_t)(void*)&__to_%s + %d) >> 16;\n",
+ slide, sym_name, sslide);
+ else
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d) >> 16;\n",
+ slide, final_sym_name, sslide);
break;
case PPC_RELOC_LO16:
- fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n",
- slide, final_sym_name, sslide);
- break;
+ if ( is_reloc_non_lazy(rel) )
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = ((uint32_t)(void*)&__to_%s + %d);\n",
+ slide, sym_name, sslide);
+ else
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d);\n",
+ slide, final_sym_name, sslide);
+ break;
case PPC_RELOC_HA16:
- fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n",
- slide, final_sym_name, sslide);
+ if ( is_reloc_non_lazy(rel) )
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = ((uint32_t)(void*)&__to_%s + %d + 0x8000) >> 16;\n",
+ slide, sym_name, sslide);
+ else
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d + 2) = (%s + %d + 0x8000) >> 16;\n",
+ slide, final_sym_name, sslide);
break;
default:
error("unsupported powerpc relocation (%d)", type);
@@ -1995,15 +2880,15 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
reloc_offset = rel->r_offset - start_offset;
switch(type) {
case R_390_32:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
break;
case R_390_16:
- fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ fprintf(outfile, " *(uint16_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
break;
case R_390_8:
- fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ fprintf(outfile, " *(uint8_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
break;
default:
@@ -2159,7 +3044,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
reloc_offset = rel->r_offset - start_offset;
switch(type) {
case R_SPARC_32:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
break;
case R_SPARC_HI22:
@@ -2217,7 +3102,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
rel->r_offset < start_offset + copy_size) {
sym_name = strtab + symtab[ELF64_R_SYM(rel->r_info)].st_name;
get_reloc_expr(name, sizeof(name), sym_name);
- type = ELF32_R_TYPE(rel->r_info);
+ type = ELF64_R_TYPE(rel->r_info);
addend = rel->r_addend;
reloc_offset = rel->r_offset - start_offset;
switch(type) {
@@ -2241,15 +3126,6 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
" | ((%s + %d) & 0x3ff);\n",
reloc_offset, reloc_offset, name, addend);
break;
- case R_SPARC_OLO10:
- addend += ELF64_R_TYPE_DATA (rel->r_info);
- fprintf(outfile,
- " *(uint32_t *)(gen_code_ptr + %d) = "
- "((*(uint32_t *)(gen_code_ptr + %d)) "
- " & ~0x3ff) "
- " | ((%s + %d) & 0x3ff);\n",
- reloc_offset, reloc_offset, name, addend);
- break;
case R_SPARC_WDISP30:
fprintf(outfile,
" *(uint32_t *)(gen_code_ptr + %d) = "
@@ -2260,18 +3136,8 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
reloc_offset, reloc_offset, name, addend,
reloc_offset);
break;
- case R_SPARC_WDISP22:
- fprintf(outfile,
- " *(uint32_t *)(gen_code_ptr + %d) = "
- "((*(uint32_t *)(gen_code_ptr + %d)) "
- " & ~0x3fffff) "
- " | ((((%s + %d) - (long)(gen_code_ptr + %d))>>2) "
- " & 0x3fffff);\n",
- reloc_offset, reloc_offset, name, addend,
- reloc_offset);
- break;
default:
- error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
+ error("unsupported sparc64 relocation (%d)", type);
}
}
}
@@ -2299,11 +3165,11 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
reloc_offset = rel->r_offset - start_offset;
switch(type) {
case R_ARM_ABS32:
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %d;\n",
reloc_offset, name, addend);
break;
case R_ARM_PC24:
- fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
+ fprintf(outfile, " arm_reloc_pc24((uint32_t *)(gen_code_ptr + %d), 0x%x, %s);\n",
reloc_offset, addend, name);
break;
default:
@@ -2331,12 +3197,12 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
switch(type) {
case R_68K_32:
fprintf(outfile, " /* R_68K_32 RELOC, offset %x */\n", rel->r_offset) ;
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s + %#x;\n",
reloc_offset, name, addend );
break;
case R_68K_PC32:
fprintf(outfile, " /* R_68K_PC32 RELOC, offset %x */\n", rel->r_offset);
- fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
+ fprintf(outfile, " *(uint32_t *)(gen_code_ptr + %d) = %s - (long)(gen_code_ptr + %#x) + %#x;\n",
reloc_offset, name, reloc_offset, /*sym->st_value+*/ addend);
break;
default:
@@ -2404,7 +3270,7 @@ int gen_file(FILE *outfile, int out_type)
gen_code(name, sym->st_value, sym->st_size, outfile, 0);
}
}
-
+
} else {
/* generate big code generation switch */
fprintf(outfile,
@@ -2422,6 +3288,64 @@ fprintf(outfile,
" LDREntry *arm_ldr_ptr = arm_ldr_table;\n"
" uint32_t *arm_data_ptr = arm_data_table;\n");
#endif
+
+#if 0 && defined CONFIG_FORMAT_MACH
+ {
+ typedef struct { const char* name; int nonlazy; } SymRef;
+
+ EXE_RELOC* rel = relocs;
+ EXE_RELOC* rel_end = relocs + nb_relocs;
+ SymRef* symrefs = NULL;
+ int num_symrefs = 0;
+ int max_symrefs = 0;
+
+ for ( ; rel < rel_end; rel++ )
+ {
+ const char* sym_name = get_rel_sym_name(rel);
+ int nn;
+
+ if(!sym_name)
+ continue;
+
+ if ( !*sym_name ||
+ strstart(sym_name, "__op_param", NULL) ||
+ strstart(sym_name, "__op_jmp", NULL) ||
+ strstart(sym_name, "__op_gen_label", NULL))
+ continue;
+
+ for (nn = 0; nn < num_symrefs; nn++) {
+ if ( !strcmp( sym_name, symrefs[nn].name ) )
+ break;
+ }
+
+ if (nn >= num_symrefs)
+ {
+ if (num_symrefs >= max_symrefs) {
+ int new_max = max_symrefs + 16;
+ SymRef* new_refs = realloc( symrefs, new_max*sizeof(SymRef) );
+ if (new_refs == NULL) {
+ break;
+ }
+ symrefs = new_refs;
+ max_symrefs = new_max;
+ }
+
+ symrefs[nn].name = sym_name;
+ symrefs[nn].nonlazy = 0;
+
+ fprintf(outfile, " extern char %s __attribute__((unused));\n", sym_name);
+ num_symrefs++;
+ }
+
+ if ( !symrefs[nn].nonlazy && is_reloc_non_lazy(rel) ) {
+ symrefs[nn].nonlazy = 1;
+ fprintf(outfile, " static const void* __to_%s = &%s;\n", sym_name, sym_name );
+ }
+ }
+ free( symrefs );
+ }
+#endif
+
#ifdef HOST_IA64
{
long addend, not_first = 0;
@@ -2486,7 +3410,7 @@ fprintf(outfile,
" opc_ptr = opc_buf;\n"
" opparam_ptr = opparam_buf;\n");
- /* Generate prologue, if needed. */
+ /* Generate prologue, if needed. */
fprintf(outfile,
" for(;;) {\n"
@@ -2498,7 +3422,7 @@ fprintf(outfile,
name = get_sym_name(sym);
if (strstart(name, OP_PREFIX, NULL)) {
#if 0
- printf("%4d: %s pos=0x%08x len=%d\n",
+ printf("%4d: %s pos=0x%08x len=%d\n",
i, name, sym->st_value, sym->st_size);
#endif
#if defined(CONFIG_FORMAT_ELF) || defined(CONFIG_FORMAT_COFF)
@@ -2533,7 +3457,7 @@ fprintf(outfile,
" last_gen_code_ptr = gen_code_ptr;\n"
" arm_ldr_ptr = arm_ldr_table;\n"
" arm_data_ptr = arm_data_table;\n"
-" }\n");
+" }\n");
#endif
@@ -2551,7 +3475,7 @@ fprintf(outfile,
"plt_target, plt_offset);\n }\n");
#endif
-/* generate some code patching */
+/* generate some code patching */
#ifdef HOST_ARM
fprintf(outfile, "gen_code_ptr = arm_flush_ldr(gen_code_ptr, arm_ldr_table, arm_ldr_ptr, arm_data_table, arm_data_ptr, 0);\n");
#endif
diff --git a/elf.h b/elf.h
index 8ceb949..0dc82e7 100644
--- a/elf.h
+++ b/elf.h
@@ -227,7 +227,6 @@ typedef struct {
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
-#define ELF64_R_TYPE_DATA(i) (((ELF64_R_TYPE(i) >> 8) ^ 0x00800000) - 0x00800000)
#define R_386_NONE 0
#define R_386_32 1
@@ -327,7 +326,6 @@ typedef struct {
#define R_SPARC_10 30
#define R_SPARC_11 31
#define R_SPARC_64 32
-#define R_SPARC_OLO10 33
#define R_SPARC_WDISP16 40
#define R_SPARC_WDISP19 41
#define R_SPARC_7 43
diff --git a/exec-all.h b/exec-all.h
index b598948..366c972 100644
--- a/exec-all.h
+++ b/exec-all.h
@@ -194,6 +194,10 @@ typedef struct TranslationBlock {
jmp_first */
struct TranslationBlock *jmp_next[2];
struct TranslationBlock *jmp_first;
+#ifdef CONFIG_TRACE
+ struct BBRec *bb_rec;
+ uint64_t prev_time;
+#endif
} TranslationBlock;
static inline unsigned int tb_jmp_cache_hash_func(target_ulong pc)
@@ -316,16 +320,31 @@ do {\
#elif defined(__i386__) && defined(USE_DIRECT_JUMP)
-/* we patch the jump instruction directly */
+/* we patch the jump instruction directly. Use sti in place of the actual
+ jmp instruction so that dyngen can patch in the correct result. */
+#if defined(__APPLE__)
+/* XXX Different relocations are generated for MacOS X for Intel
+ (please as from cctools). */
#define GOTO_TB(opname, tbparam, n)\
do {\
- asm volatile (".section .data\n"\
+ asm volatile (ASM_DATA_SECTION\
ASM_OP_LABEL_NAME(n, opname) ":\n"\
".long 1f\n"\
ASM_PREVIOUS_SECTION \
- "jmp " ASM_NAME(__op_jmp) #n "\n"\
+ "sti;.long " ASM_NAME(__op_jmp) #n "\n"\
"1:\n");\
} while (0)
+#else
+#define GOTO_TB(opname, tbparam, n)\
+do {\
+ asm volatile (ASM_DATA_SECTION\
+ ASM_OP_LABEL_NAME(n, opname) ":\n"\
+ ".long 1f\n"\
+ ASM_PREVIOUS_SECTION \
+ "sti;.long " ASM_NAME(__op_jmp) #n " - 1f\n"\
+ "1:\n");\
+} while (0)
+#endif
#else
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 5e84620..75511c9 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -4911,7 +4911,7 @@ float128 float128_rem( float128 a, float128 b STATUS_PARAM )
sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
} while ( 0 <= (sbits64) aSig0 );
add128(
- aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 );
+ aSig0, aSig1, alternateASig0, alternateASig1, (bits64*)&sigMean0, &sigMean1 );
if ( ( sigMean0 < 0 )
|| ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
aSig0 = alternateASig0;
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index fdc80f3..44c29f1 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -46,8 +46,8 @@ these four paragraphs for those parts of this code that are retained.
typedef char flag;
typedef uint8_t uint8;
typedef int8_t int8;
-typedef int uint16;
-typedef int int16;
+typedef uint16_t uint16;
+typedef int16_t int16;
typedef unsigned int uint32;
typedef signed int int32;
typedef uint64_t uint64;
diff --git a/framebuffer.c b/framebuffer.c
new file mode 100644
index 0000000..e7c955f
--- /dev/null
+++ b/framebuffer.c
@@ -0,0 +1,243 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "framebuffer.h"
+#include <memory.h>
+#include <stdlib.h>
+
+typedef struct {
+ /* client fields, these correspond to code that waits for updates before displaying them */
+ /* at the moment, only one client is supported */
+ void* fb_opaque;
+ QFrameBufferUpdateFunc fb_update;
+ QFrameBufferRotateFunc fb_rotate;
+ QFrameBufferDoneFunc fb_done;
+
+ void* pr_opaque;
+ QFrameBufferCheckUpdateFunc pr_check;
+ QFrameBufferInvalidateFunc pr_invalidate;
+ QFrameBufferDetachFunc pr_detach;
+
+} QFrameBufferExtra;
+
+
+static int
+_get_pitch( int width, QFrameBufferFormat format )
+{
+
+ switch (format) {
+ case QFRAME_BUFFER_RGB565:
+ return width*2;
+ default:
+ return -1;
+ }
+}
+
+
+int
+qframebuffer_init( QFrameBuffer* qfbuff,
+ int width,
+ int height,
+ int rotation,
+ QFrameBufferFormat format )
+{
+ int pitch;
+
+ rotation &= 3;
+
+ if (!qfbuff || width < 0 || height < 0)
+ return -1;
+
+ pitch = _get_pitch( width, format );
+ if (pitch < 0)
+ return -1;
+
+ memset( qfbuff, 0, sizeof(*qfbuff) );
+
+ qfbuff->extra = calloc( 1, sizeof(QFrameBufferExtra) );
+ if (qfbuff->extra == NULL)
+ return -1;
+
+ qfbuff->pixels = calloc( pitch, height );
+ if (qfbuff->pixels == NULL && (height > 0 && pitch > 0)) {
+ free( qfbuff->extra );
+ return -1;
+ }
+
+ qfbuff->width = width;
+ qfbuff->height = height;
+ qfbuff->pitch = pitch;
+ qfbuff->format = format;
+
+ qframebuffer_set_dpi( qfbuff, DEFAULT_FRAMEBUFFER_DPI, DEFAULT_FRAMEBUFFER_DPI );
+ return 0;
+}
+
+
+void
+qframebuffer_set_dpi( QFrameBuffer* qfbuff,
+ int x_dpi,
+ int y_dpi )
+{
+ /* dpi = dots / inch
+ ** inch = dots / dpi
+ ** mm / 25.4 = dots / dpi
+ ** mm = (dots * 25.4)/dpi
+ */
+ qfbuff->phys_width_mm = 25.4 * qfbuff->width / x_dpi;
+ qfbuff->phys_height_mm = 25.4 * qfbuff->height / y_dpi;
+}
+
+/* alternative to qframebuffer_set_dpi where one can set the physical dimensions directly */
+/* in millimeters. for the record 1 inch = 25.4 mm */
+void
+qframebuffer_set_mm( QFrameBuffer* qfbuff,
+ int width_mm,
+ int height_mm )
+{
+ qfbuff->phys_width_mm = width_mm;
+ qfbuff->phys_height_mm = height_mm;
+}
+
+void
+qframebuffer_update( QFrameBuffer* qfbuff, int x, int y, int w, int h )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ if (extra->fb_update)
+ extra->fb_update( extra->fb_opaque, x, y, w, h );
+}
+
+
+void
+qframebuffer_add_client( QFrameBuffer* qfbuff,
+ void* fb_opaque,
+ QFrameBufferUpdateFunc fb_update,
+ QFrameBufferRotateFunc fb_rotate,
+ QFrameBufferDoneFunc fb_done )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ extra->fb_opaque = fb_opaque;
+ extra->fb_update = fb_update;
+ extra->fb_rotate = fb_rotate;
+ extra->fb_done = fb_done;
+}
+
+void
+qframebuffer_add_producer( QFrameBuffer* qfbuff,
+ void* opaque,
+ QFrameBufferCheckUpdateFunc pr_check,
+ QFrameBufferInvalidateFunc pr_invalidate,
+ QFrameBufferDetachFunc pr_detach )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ extra->pr_opaque = opaque;
+ extra->pr_check = pr_check;
+ extra->pr_invalidate = pr_invalidate;
+ extra->pr_detach = pr_detach;
+}
+
+
+void
+qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ if ((rotation ^ qfbuff->rotation) & 1) {
+ /* swap width and height if new rotation requires it */
+ int temp = qfbuff->width;
+ qfbuff->width = qfbuff->height;
+ qfbuff->height = temp;
+ qfbuff->pitch = _get_pitch( qfbuff->width, qfbuff->format );
+
+ temp = qfbuff->phys_width_mm;
+ qfbuff->phys_width_mm = qfbuff->phys_height_mm;
+ qfbuff->phys_height_mm = temp;
+ }
+ qfbuff->rotation = rotation;
+
+ if (extra->fb_rotate)
+ extra->fb_rotate( extra->fb_opaque, rotation );
+}
+
+
+extern void
+qframebuffer_done( QFrameBuffer* qfbuff )
+{
+ QFrameBufferExtra* extra = qfbuff->extra;
+
+ if (extra) {
+ if (extra->pr_detach)
+ extra->pr_detach( extra->pr_opaque );
+
+ if (extra->fb_done)
+ extra->fb_done( extra->fb_opaque );
+ }
+
+ free( qfbuff->pixels );
+ free( qfbuff->extra );
+ memset( qfbuff, 0, sizeof(*qfbuff) );
+}
+
+
+#define MAX_FRAME_BUFFERS 8
+
+static QFrameBuffer* framebuffer_fifo[ MAX_FRAME_BUFFERS ];
+static int framebuffer_fifo_rpos;
+static int framebuffer_fifo_count;
+
+void
+qframebuffer_fifo_add( QFrameBuffer* qfbuff )
+{
+ if (framebuffer_fifo_count >= MAX_FRAME_BUFFERS)
+ return;
+
+ framebuffer_fifo[ framebuffer_fifo_count++ ] = qfbuff;
+}
+
+
+QFrameBuffer*
+qframebuffer_fifo_get( void )
+{
+ if (framebuffer_fifo_rpos >= framebuffer_fifo_count)
+ return NULL;
+
+ return framebuffer_fifo[ framebuffer_fifo_rpos++ ];
+}
+
+
+void
+qframebuffer_check_updates( void )
+{
+ int nn;
+ for (nn = 0; nn < framebuffer_fifo_count; nn++) {
+ QFrameBuffer* q = framebuffer_fifo[nn];
+ QFrameBufferExtra* extra = q->extra;
+
+ if (extra->pr_check)
+ extra->pr_check( extra->pr_opaque );
+ }
+}
+
+void
+qframebuffer_invalidate_all( void )
+{
+ int nn;
+ for (nn = 0; nn < framebuffer_fifo_count; nn++) {
+ QFrameBuffer* q = framebuffer_fifo[nn];
+ QFrameBufferExtra* extra = q->extra;
+
+ if (extra->pr_invalidate)
+ extra->pr_invalidate( extra->pr_opaque );
+ }
+}
diff --git a/framebuffer.h b/framebuffer.h
new file mode 100644
index 0000000..46f9156
--- /dev/null
+++ b/framebuffer.h
@@ -0,0 +1,149 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _QEMU_FRAMEBUFFER_H_
+#define _QEMU_FRAMEBUFFER_H_
+
+/* a simple interface to a framebuffer display. this is to be used by the hardware framebuffer
+ * driver (e.g. hw/goldfish_fb.c) to send VRAM updates to the emulator.
+ *
+ * note the 'rotation' field: it can take values 0, 1, 2 or 3 and corresponds to a rotation
+ * that must be performed to the pixels stored in the framebuffer *before* displaying them
+ * a value of 1 corresponds to a rotation of 90 clockwise-degrees, when the framebuffer is
+ * rotated 90 or 270 degrees, its width/height are swapped automatically
+ *
+ * phys_width_mm and phys_height_mm are physical dimensions expressed in millimeters
+ *
+ * each QFrameBuffer can have one "client" that reacts to VRAM updates or the framebuffer
+ * rotations requested by the system.
+ */
+typedef struct QFrameBuffer QFrameBuffer;
+
+
+typedef enum {
+ QFRAME_BUFFER_NONE = 0,
+ QFRAME_BUFFER_RGB565 = 1,
+ QFRAME_BUFFER_MAX /* do not remove */
+} QFrameBufferFormat;
+
+struct QFrameBuffer {
+ int width; /* width in pixels */
+ int height; /* height in pixels */
+ int pitch; /* bytes per line */
+ int rotation; /* rotation to be applied when displaying */
+ QFrameBufferFormat format;
+ void* pixels; /* pixel buffer */
+
+ int phys_width_mm;
+ int phys_height_mm;
+
+ /* extra data that is handled by the framebuffer implementation */
+ void* extra;
+
+};
+
+/* the default dpi resolution of a typical framebuffer. this is an average between
+ * various prototypes being used during the development of the Android system...
+ */
+#define DEFAULT_FRAMEBUFFER_DPI 165
+
+
+/* initialize a framebuffer object and allocate its pixel buffer */
+/* this computes phys_width_mm and phys_height_mm assuming a 165 dpi screen */
+/* returns -1 in case of error, 0 otherwise */
+extern int
+qframebuffer_init( QFrameBuffer* qfbuff,
+ int width,
+ int height,
+ int rotation,
+ QFrameBufferFormat format );
+
+/* recompute phys_width_mm and phys_height_mm according to the emulated screen DPI settings */
+extern void
+qframebuffer_set_dpi( QFrameBuffer* qfbuff,
+ int x_dpi,
+ int y_dpi );
+
+/* alternative to qframebuffer_set_dpi where one can set the physical dimensions directly */
+/* in millimeters. for the record 1 inch = 25.4 mm */
+extern void
+qframebuffer_set_mm( QFrameBuffer* qfbuff,
+ int width_mm,
+ int height_mm );
+
+/* add one client to a given framebuffer */
+/* client functions */
+typedef void (*QFrameBufferUpdateFunc)( void* opaque, int x, int y, int w, int h );
+typedef void (*QFrameBufferRotateFunc)( void* opaque, int rotation );
+typedef void (*QFrameBufferDoneFunc) ( void* opaque );
+
+extern void
+qframebuffer_add_client( QFrameBuffer* qfbuff,
+ void* fb_opaque,
+ QFrameBufferUpdateFunc fb_update,
+ QFrameBufferRotateFunc fb_rotate,
+ QFrameBufferDoneFunc fb_done );
+
+/* add one producer to a given framebuffer */
+/* producer functions */
+typedef void (*QFrameBufferCheckUpdateFunc)( void* opaque );
+typedef void (*QFrameBufferInvalidateFunc) ( void* opaque );
+typedef void (*QFrameBufferDetachFunc) ( void* opaque );
+
+extern void
+qframebuffer_add_producer( QFrameBuffer* qfbuff,
+ void* opaque,
+ QFrameBufferCheckUpdateFunc fb_check,
+ QFrameBufferInvalidateFunc fb_invalidate,
+ QFrameBufferDetachFunc fb_detach );
+
+/* tell a client that a rectangle region has been updated in the framebuffer pixel buffer */
+extern void
+qframebuffer_update( QFrameBuffer* qfbuff, int x, int y, int w, int h );
+
+/* rotate the framebuffer (may swap width/height), and tell a client that we did */
+extern void
+qframebuffer_rotate( QFrameBuffer* qfbuff, int rotation );
+
+/* finalize a framebuffer, release its pixel buffer */
+extern void
+qframebuffer_done( QFrameBuffer* qfbuff );
+
+
+/*
+ * QFrameBuffer objects are created by the emulated system, its characteristics typically
+ * depend on the current device skin being used.
+ *
+ * there are also used by emulated framebuffer devices, who don't know much about all this
+ *
+ * use a simple fifo to bridge these together
+ */
+
+/* add a new constructed frame buffer object to our global list */
+extern void
+qframebuffer_fifo_add( QFrameBuffer* qfbuff );
+
+extern QFrameBuffer*
+qframebuffer_fifo_get( void );
+
+/*
+ * check all registered framebuffers for updates. tgus wukk cakk tge ckuebt's update
+ * functions in the end...
+ */
+
+extern void
+qframebuffer_check_updates( void );
+
+extern void
+qframebuffer_invalidate_all( void );
+
+#endif /* _QEMU_FRAMEBUFFER_H_ */
+
diff --git a/gdbstub.c b/gdbstub.c
index 6ad393f..a91dcd9 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -32,7 +32,7 @@
#include "vl.h"
#endif
-#include "qemu_socket.h"
+#include "sockets.h"
#ifdef _WIN32
/* XXX: these constants may be independent of the host ones even for Unix */
#ifndef SIGTRAP
@@ -886,7 +886,7 @@ static void gdb_accept(void *opaque)
GDBState *s;
struct sockaddr_in sockaddr;
socklen_t len;
- int val, fd;
+ int fd;
for(;;) {
len = sizeof(sockaddr);
@@ -900,8 +900,7 @@ static void gdb_accept(void *opaque)
}
/* set short latency */
- val = 1;
- setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+ socket_set_lowlatency(fd);
#ifdef CONFIG_USER_ONLY
s = &gdbserver_state;
@@ -916,9 +915,8 @@ static void gdb_accept(void *opaque)
s->env = first_cpu; /* XXX: allow to change CPU */
s->fd = fd;
-#ifdef CONFIG_USER_ONLY
- fcntl(fd, F_SETFL, O_NONBLOCK);
-#else
+ socket_set_nonblock(fd);
+#ifndef CONFIG_USER_ONLY
socket_set_nonblock(fd);
/* stop the VM */
@@ -934,7 +932,7 @@ static void gdb_accept(void *opaque)
static int gdbserver_open(int port)
{
struct sockaddr_in sockaddr;
- int fd, val, ret;
+ int fd, ret;
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0) {
@@ -943,8 +941,7 @@ static int gdbserver_open(int port)
}
/* allow fast reuse */
- val = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val));
+ socket_set_xreuseaddr(fd);
sockaddr.sin_family = AF_INET;
sockaddr.sin_port = htons(port);
diff --git a/gen-charmap.py b/gen-charmap.py
new file mode 100644
index 0000000..3c86350
--- /dev/null
+++ b/gen-charmap.py
@@ -0,0 +1,180 @@
+#!/usr/bin/python
+#
+# a python script used to generate some C constant tables from a key charmap file
+#
+# usage:
+# progname file.kcm > charmap-tab.h
+#
+import sys, os, string, re
+
+header = """\
+#include "android_charmap.h"
+
+/* the following is automatically generated by the 'gen-charmap.py' script
+ * do not touch. the generation command was:
+ * gen-charmap.py\
+"""
+
+header2 = """
+ */
+"""
+
+kmap_header = """\
+static const AKeyEntry _%(name)s_keys[] =
+{
+ /* keycode base caps fn caps+fn number */
+"""
+
+
+kmap_footer = """\
+};
+
+static const AKeyCharmap _%(name)s_charmap =
+{
+ _%(name)s_keys,
+ %(count)d,
+ "%(name)s"
+};
+"""
+
+
+re_mapname = re.compile( r".*/(\w+).kcm" )
+re_start = re.compile( r"(\w+)\s*(.*)" )
+re_char = re.compile( r"('.')\s*(.*)" )
+re_hex = re.compile( r"(0x\w+)\s*(.*)" )
+
+specials = { 'COMMA': 'Comma',
+ 'PERIOD': 'Period',
+ 'AT': 'At',
+ 'LEFT_BRACKET': 'LeftBracket',
+ 'RIGHT_BRACKET': 'RightBracket',
+ 'SLASH': 'Slash',
+ 'BACKSLASH': 'Backslash',
+ 'GRAVE': 'Grave',
+ 'MINUS': 'Minus',
+ 'EQUALS': 'Equals',
+ 'SEMICOLON': 'Semicolon',
+ 'APOSTROPHE': 'Apostrophe',
+ 'SPACE': 'Space',
+ 'ENTER': 'Enter',
+ 'TAB': 'Tab'
+ }
+
+entries = []
+
+def match_char_or_hex(line):
+ m = re_char.match(line)
+ if not m:
+ m = re_hex.match(line)
+ return m
+
+def quote(s):
+ if s == "'''":
+ s = "'\\''"
+ elif s == "'\\'":
+ s = "'\\\\'"
+ return s
+
+def process_line(line,result):
+ m = re_start.match(line)
+ if not m:
+ print "bad bad line: " + line
+ return -1
+ keycode = m.group(1)
+ line = m.group(2)
+ m = match_char_or_hex(line)
+ if not m:
+ print "character expected in: " + line
+ return -1
+ base = quote(m.group(1))
+ line = m.group(2)
+ m = match_char_or_hex(line)
+ if not m:
+ print "character expected in: " + line
+ return -1
+ caps = quote(m.group(1))
+ line = m.group(2)
+ m = match_char_or_hex(line)
+ if not m:
+ print "character expected in: " + line
+ return -1
+ fn = quote(m.group(1))
+ line = m.group(2)
+ m = match_char_or_hex(line)
+ if not m:
+ print "character expected in: " + line
+ return -1
+ caps_fn = quote(m.group(1))
+ line = m.group(2)
+ m = match_char_or_hex(line)
+ if not m:
+ print "character expected in: " + line
+ return -1
+ number = quote(m.group(1))
+
+ if specials.has_key(keycode):
+ keycode = specials[keycode]
+ keycode = "kKeyCode" + keycode
+
+ result.append( (keycode,base,caps,fn,caps_fn,number) )
+ return 0
+
+def process_file( file ):
+ result = []
+ fp = open(file,"rb")
+ for line in fp.xreadlines():
+ line = line.strip()
+ if not line: # skip empty lines
+ continue
+ if line[0] == '#' or line[0] == '[': # skip
+ continue
+ if process_line(line,result) < 0:
+ break
+ fp.close()
+ return result
+
+class KMap:
+ def __init__(self,name,results):
+ self.name = name
+ self.results = results
+
+ def dump(self):
+ t = { 'name': self.name, 'count':len(self.results) }
+ print kmap_header % t
+ for item in self.results:
+ print " { %-22s, %5s, %5s, %5s, %6s, %5s }," % item
+ print kmap_footer % t
+
+kmaps = []
+
+if len(sys.argv) < 2:
+ print "usage: progname charmap.kcm [charmap2.kcm ...] > charmap-tab.h"
+else:
+ genline = ""
+ for filepath in sys.argv[1:]:
+ m = re_mapname.match(filepath)
+ if not m:
+ print "%s is not a keyboard charmap name" % filepath
+ os.exit(1)
+
+ mapname = m.group(1)
+ genline = genline + " " + mapname + ".kcm"
+
+ for filepath in sys.argv[1:]:
+ m = re_mapname.match(filepath)
+ mapname = m.group(1)
+ result = process_file( filepath )
+ kmap = KMap(mapname,result)
+ kmaps.append(kmap)
+
+ print header + genline + header2
+ for kmap in kmaps:
+ kmap.dump()
+
+ print "const AKeyCharmap* android_charmaps[%d] = {" % len(kmaps),
+ comma = ""
+ for kmap in kmaps:
+ print "%s&_%s_charmap" % (comma, kmap.name),
+ comma = ", "
+ print "};"
+ print "const int android_charmap_count = %d;" % len(kmaps)
diff --git a/gen-skin.py b/gen-skin.py
new file mode 100755
index 0000000..f87bde7
--- /dev/null
+++ b/gen-skin.py
@@ -0,0 +1,78 @@
+#!/usr/bin/python
+#
+# a python script used to generate the "default-skin.h' header file
+# from a given skin directory
+#
+# usage:
+# progname skin-directory-path > default-skin.h
+#
+import sys, os, string, re
+
+header = """\
+/* automatically generated, do not touch */
+
+"""
+
+
+footer = """\
+
+static const FileEntry _file_entries[] =
+{
+"""
+
+footer2 = """\
+ { NULL, NULL, 0 }
+};
+"""
+
+
+entries = []
+
+def process_files( basepath, files ):
+ for file in files:
+ fp = open(basepath + "/" + file, "rb")
+ data = fp.read()
+ data_len = len(data)
+ data_add = 0
+ data_name = "_data_" + string.replace(file,".","_")
+
+ entries.append( (file, data_name, len(data)) )
+ print "static const unsigned char %s[%d] = {" % (data_name, data_len + data_add)
+ comma = " "
+ do_line = 0
+ do_comma = 0
+ count = 0
+ line = " "
+ for b in data:
+ d = ord(b)
+
+ if do_comma:
+ line = line + ","
+ do_comma = 0
+
+ if do_line:
+ print line
+ line = " "
+ do_line = 0
+
+ line = line + "%3d" % d
+ do_comma = 1
+ count += 1
+ if count == 16:
+ count = 0
+ do_line = 1
+
+ if len(line) > 0:
+ print line
+ print "};\n"
+
+if len(sys.argv) != 2:
+ print "usage: progname skindirpath > default-skin.h"
+else:
+ print header
+ skindir = sys.argv[1]
+ process_files( skindir, os.listdir(skindir) )
+ print footer
+ for e in entries:
+ print " { \"%s\", %s, %d }," % (e[0], e[1], e[2])
+ print footer2
diff --git a/hpet.h b/hpet.h
new file mode 100644
index 0000000..754051a
--- /dev/null
+++ b/hpet.h
@@ -0,0 +1,22 @@
+#ifndef __HPET__
+#define __HPET__ 1
+
+
+
+struct hpet_info {
+ unsigned long hi_ireqfreq; /* Hz */
+ unsigned long hi_flags; /* information */
+ unsigned short hi_hpet;
+ unsigned short hi_timer;
+};
+
+#define HPET_INFO_PERIODIC 0x0001 /* timer is periodic */
+
+#define HPET_IE_ON _IO('h', 0x01) /* interrupt on */
+#define HPET_IE_OFF _IO('h', 0x02) /* interrupt off */
+#define HPET_INFO _IOR('h', 0x03, struct hpet_info)
+#define HPET_EPI _IO('h', 0x04) /* enable periodic */
+#define HPET_DPI _IO('h', 0x05) /* disable periodic */
+#define HPET_IRQFREQ _IOW('h', 0x6, unsigned long) /* IRQFREQ usec */
+
+#endif /* !__HPET__ */
diff --git a/hw/acpi-dsdt.dsl b/hw/acpi-dsdt.dsl
deleted file mode 100644
index fc4081f..0000000
--- a/hw/acpi-dsdt.dsl
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * QEMU ACPI DSDT ASL definition
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * 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
- */
-DefinitionBlock (
- "acpi-dsdt.aml", // Output Filename
- "DSDT", // Signature
- 0x01, // DSDT Compliance Revision
- "QEMU", // OEMID
- "QEMUDSDT", // TABLE ID
- 0x1 // OEM Revision
- )
-{
- Scope (\)
- {
- /* CMOS memory access */
- OperationRegion (CMS, SystemIO, 0x70, 0x02)
- Field (CMS, ByteAcc, NoLock, Preserve)
- {
- CMSI, 8,
- CMSD, 8
- }
- Method (CMRD, 1, NotSerialized)
- {
- Store (Arg0, CMSI)
- Store (CMSD, Local0)
- Return (Local0)
- }
-
- /* Debug Output */
- OperationRegion (DBG, SystemIO, 0xb044, 0x04)
- Field (DBG, DWordAcc, NoLock, Preserve)
- {
- DBGL, 32,
- }
- }
-
-
- /* PCI Bus definition */
- Scope(\_SB) {
- Device(PCI0) {
- Name (_HID, EisaId ("PNP0A03"))
- Name (_ADR, 0x00)
- Name (_UID, 1)
- Name(_PRT, Package() {
- /* PCI IRQ routing table, example from ACPI 2.0a specification,
- section 6.2.8.1 */
- /* Note: we provide the same info as the PCI routing
- table of the Bochs BIOS */
-
- // PCI Slot 0
- Package() {0x0000ffff, 0, LNKD, 0},
- Package() {0x0000ffff, 1, LNKA, 0},
- Package() {0x0000ffff, 2, LNKB, 0},
- Package() {0x0000ffff, 3, LNKC, 0},
-
- // PCI Slot 1
- Package() {0x0001ffff, 0, LNKA, 0},
- Package() {0x0001ffff, 1, LNKB, 0},
- Package() {0x0001ffff, 2, LNKC, 0},
- Package() {0x0001ffff, 3, LNKD, 0},
-
- // PCI Slot 2
- Package() {0x0002ffff, 0, LNKB, 0},
- Package() {0x0002ffff, 1, LNKC, 0},
- Package() {0x0002ffff, 2, LNKD, 0},
- Package() {0x0002ffff, 3, LNKA, 0},
-
- // PCI Slot 3
- Package() {0x0003ffff, 0, LNKC, 0},
- Package() {0x0003ffff, 1, LNKD, 0},
- Package() {0x0003ffff, 2, LNKA, 0},
- Package() {0x0003ffff, 3, LNKB, 0},
-
- // PCI Slot 4
- Package() {0x0004ffff, 0, LNKD, 0},
- Package() {0x0004ffff, 1, LNKA, 0},
- Package() {0x0004ffff, 2, LNKB, 0},
- Package() {0x0004ffff, 3, LNKC, 0},
-
- // PCI Slot 5
- Package() {0x0005ffff, 0, LNKA, 0},
- Package() {0x0005ffff, 1, LNKB, 0},
- Package() {0x0005ffff, 2, LNKC, 0},
- Package() {0x0005ffff, 3, LNKD, 0},
- })
-
- Method (_CRS, 0, NotSerialized)
- {
- Name (MEMP, ResourceTemplate ()
- {
- WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
- 0x0000, // Address Space Granularity
- 0x0000, // Address Range Minimum
- 0x00FF, // Address Range Maximum
- 0x0000, // Address Translation Offset
- 0x0100, // Address Length
- ,, )
- IO (Decode16,
- 0x0CF8, // Address Range Minimum
- 0x0CF8, // Address Range Maximum
- 0x01, // Address Alignment
- 0x08, // Address Length
- )
- WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
- 0x0000, // Address Space Granularity
- 0x0000, // Address Range Minimum
- 0x0CF7, // Address Range Maximum
- 0x0000, // Address Translation Offset
- 0x0CF8, // Address Length
- ,, , TypeStatic)
- WordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
- 0x0000, // Address Space Granularity
- 0x0D00, // Address Range Minimum
- 0xFFFF, // Address Range Maximum
- 0x0000, // Address Translation Offset
- 0xF300, // Address Length
- ,, , TypeStatic)
- DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
- 0x00000000, // Address Space Granularity
- 0x000A0000, // Address Range Minimum
- 0x000BFFFF, // Address Range Maximum
- 0x00000000, // Address Translation Offset
- 0x00020000, // Address Length
- ,, , AddressRangeMemory, TypeStatic)
- DWordMemory (ResourceProducer, PosDecode, MinNotFixed, MaxFixed, NonCacheable, ReadWrite,
- 0x00000000, // Address Space Granularity
- 0x00000000, // Address Range Minimum
- 0xFEBFFFFF, // Address Range Maximum
- 0x00000000, // Address Translation Offset
- 0x00000000, // Address Length
- ,, MEMF, AddressRangeMemory, TypeStatic)
- })
- CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MIN, PMIN)
- CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._MAX, PMAX)
- CreateDWordField (MEMP, \_SB.PCI0._CRS.MEMF._LEN, PLEN)
- /* compute available RAM */
- Add(CMRD(0x34), ShiftLeft(CMRD(0x35), 8), Local0)
- ShiftLeft(Local0, 16, Local0)
- Add(Local0, 0x1000000, Local0)
- /* update field of last region */
- Store(Local0, PMIN)
- Subtract (PMAX, PMIN, PLEN)
- Increment (PLEN)
- Return (MEMP)
- }
- }
- }
-
- Scope(\_SB.PCI0) {
-
- /* PIIX3 ISA bridge */
- Device (ISA) {
- Name (_ADR, 0x00010000)
-
- /* PIIX PCI to ISA irq remapping */
- OperationRegion (P40C, PCI_Config, 0x60, 0x04)
-
-
- /* Keyboard seems to be important for WinXP install */
- Device (KBD)
- {
- Name (_HID, EisaId ("PNP0303"))
- Method (_STA, 0, NotSerialized)
- {
- Return (0x0f)
- }
-
- Method (_CRS, 0, NotSerialized)
- {
- Name (TMP, ResourceTemplate ()
- {
- IO (Decode16,
- 0x0060, // Address Range Minimum
- 0x0060, // Address Range Maximum
- 0x01, // Address Alignment
- 0x01, // Address Length
- )
- IO (Decode16,
- 0x0064, // Address Range Minimum
- 0x0064, // Address Range Maximum
- 0x01, // Address Alignment
- 0x01, // Address Length
- )
- IRQNoFlags ()
- {1}
- })
- Return (TMP)
- }
- }
-
- /* PS/2 mouse */
- Device (MOU)
- {
- Name (_HID, EisaId ("PNP0F13"))
- Method (_STA, 0, NotSerialized)
- {
- Return (0x0f)
- }
-
- Method (_CRS, 0, NotSerialized)
- {
- Name (TMP, ResourceTemplate ()
- {
- IRQNoFlags () {12}
- })
- Return (TMP)
- }
- }
-
- /* PS/2 floppy controller */
- Device (FDC0)
- {
- Name (_HID, EisaId ("PNP0700"))
- Method (_STA, 0, NotSerialized)
- {
- Return (0x0F)
- }
- Method (_CRS, 0, NotSerialized)
- {
- Name (BUF0, ResourceTemplate ()
- {
- IO (Decode16, 0x03F2, 0x03F2, 0x00, 0x04)
- IO (Decode16, 0x03F7, 0x03F7, 0x00, 0x01)
- IRQNoFlags () {6}
- DMA (Compatibility, NotBusMaster, Transfer8) {2}
- })
- Return (BUF0)
- }
- }
-
- /* Parallel port */
- Device (LPT)
- {
- Name (_HID, EisaId ("PNP0400"))
- Method (_STA, 0, NotSerialized)
- {
- Store (\_SB.PCI0.PX13.DRSA, Local0)
- And (Local0, 0x80000000, Local0)
- If (LEqual (Local0, 0))
- {
- Return (0x00)
- }
- Else
- {
- Return (0x0F)
- }
- }
- Method (_CRS, 0, NotSerialized)
- {
- Name (BUF0, ResourceTemplate ()
- {
- IO (Decode16, 0x0378, 0x0378, 0x08, 0x08)
- IRQNoFlags () {7}
- })
- Return (BUF0)
- }
- }
-
- /* Serial Ports */
- Device (COM1)
- {
- Name (_HID, EisaId ("PNP0501"))
- Name (_UID, 0x01)
- Method (_STA, 0, NotSerialized)
- {
- Store (\_SB.PCI0.PX13.DRSC, Local0)
- And (Local0, 0x08000000, Local0)
- If (LEqual (Local0, 0))
- {
- Return (0x00)
- }
- Else
- {
- Return (0x0F)
- }
- }
- Method (_CRS, 0, NotSerialized)
- {
- Name (BUF0, ResourceTemplate ()
- {
- IO (Decode16, 0x03F8, 0x03F8, 0x00, 0x08)
- IRQNoFlags () {4}
- })
- Return (BUF0)
- }
- }
-
- Device (COM2)
- {
- Name (_HID, EisaId ("PNP0501"))
- Name (_UID, 0x02)
- Method (_STA, 0, NotSerialized)
- {
- Store (\_SB.PCI0.PX13.DRSC, Local0)
- And (Local0, 0x80000000, Local0)
- If (LEqual (Local0, 0))
- {
- Return (0x00)
- }
- Else
- {
- Return (0x0F)
- }
- }
- Method (_CRS, 0, NotSerialized)
- {
- Name (BUF0, ResourceTemplate ()
- {
- IO (Decode16, 0x02F8, 0x02F8, 0x00, 0x08)
- IRQNoFlags () {3}
- })
- Return (BUF0)
- }
- }
- }
-
- /* PIIX4 PM */
- Device (PX13) {
- Name (_ADR, 0x00010003)
-
- OperationRegion (P13C, PCI_Config, 0x5c, 0x24)
- Field (P13C, DWordAcc, NoLock, Preserve)
- {
- DRSA, 32,
- DRSB, 32,
- DRSC, 32,
- DRSE, 32,
- DRSF, 32,
- DRSG, 32,
- DRSH, 32,
- DRSI, 32,
- DRSJ, 32
- }
- }
- }
-
- /* PCI IRQs */
- Scope(\_SB) {
- Field (\_SB.PCI0.ISA.P40C, ByteAcc, NoLock, Preserve)
- {
- PRQ0, 8,
- PRQ1, 8,
- PRQ2, 8,
- PRQ3, 8
- }
-
- Device(LNKA){
- Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
- Name(_UID, 1)
- Name(_PRS, ResourceTemplate(){
- IRQ (Level, ActiveLow, Shared)
- {3,4,5,6,7,9,10,11,12}
- })
- Method (_STA, 0, NotSerialized)
- {
- Store (0x0B, Local0)
- If (And (0x80, PRQ0, Local1))
- {
- Store (0x09, Local0)
- }
- Return (Local0)
- }
- Method (_DIS, 0, NotSerialized)
- {
- Or (PRQ0, 0x80, PRQ0)
- }
- Method (_CRS, 0, NotSerialized)
- {
- Name (PRR0, ResourceTemplate ()
- {
- IRQ (Level, ActiveLow, Shared)
- {1}
- })
- CreateWordField (PRR0, 0x01, TMP)
- Store (PRQ0, Local0)
- If (LLess (Local0, 0x80))
- {
- ShiftLeft (One, Local0, TMP)
- }
- Else
- {
- Store (Zero, TMP)
- }
- Return (PRR0)
- }
- Method (_SRS, 1, NotSerialized)
- {
- CreateWordField (Arg0, 0x01, TMP)
- FindSetRightBit (TMP, Local0)
- Decrement (Local0)
- Store (Local0, PRQ0)
- }
- }
- Device(LNKB){
- Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
- Name(_UID, 2)
- Name(_PRS, ResourceTemplate(){
- IRQ (Level, ActiveLow, Shared)
- {3,4,5,6,7,9,10,11,12}
- })
- Method (_STA, 0, NotSerialized)
- {
- Store (0x0B, Local0)
- If (And (0x80, PRQ1, Local1))
- {
- Store (0x09, Local0)
- }
- Return (Local0)
- }
- Method (_DIS, 0, NotSerialized)
- {
- Or (PRQ1, 0x80, PRQ1)
- }
- Method (_CRS, 0, NotSerialized)
- {
- Name (PRR0, ResourceTemplate ()
- {
- IRQ (Level, ActiveLow, Shared)
- {1}
- })
- CreateWordField (PRR0, 0x01, TMP)
- Store (PRQ1, Local0)
- If (LLess (Local0, 0x80))
- {
- ShiftLeft (One, Local0, TMP)
- }
- Else
- {
- Store (Zero, TMP)
- }
- Return (PRR0)
- }
- Method (_SRS, 1, NotSerialized)
- {
- CreateWordField (Arg0, 0x01, TMP)
- FindSetRightBit (TMP, Local0)
- Decrement (Local0)
- Store (Local0, PRQ1)
- }
- }
- Device(LNKC){
- Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
- Name(_UID, 3)
- Name(_PRS, ResourceTemplate(){
- IRQ (Level, ActiveLow, Shared)
- {3,4,5,6,7,9,10,11,12}
- })
- Method (_STA, 0, NotSerialized)
- {
- Store (0x0B, Local0)
- If (And (0x80, PRQ2, Local1))
- {
- Store (0x09, Local0)
- }
- Return (Local0)
- }
- Method (_DIS, 0, NotSerialized)
- {
- Or (PRQ2, 0x80, PRQ2)
- }
- Method (_CRS, 0, NotSerialized)
- {
- Name (PRR0, ResourceTemplate ()
- {
- IRQ (Level, ActiveLow, Shared)
- {1}
- })
- CreateWordField (PRR0, 0x01, TMP)
- Store (PRQ2, Local0)
- If (LLess (Local0, 0x80))
- {
- ShiftLeft (One, Local0, TMP)
- }
- Else
- {
- Store (Zero, TMP)
- }
- Return (PRR0)
- }
- Method (_SRS, 1, NotSerialized)
- {
- CreateWordField (Arg0, 0x01, TMP)
- FindSetRightBit (TMP, Local0)
- Decrement (Local0)
- Store (Local0, PRQ2)
- }
- }
- Device(LNKD){
- Name(_HID, EISAID("PNP0C0F")) // PCI interrupt link
- Name(_UID, 4)
- Name(_PRS, ResourceTemplate(){
- IRQ (Level, ActiveLow, Shared)
- {3,4,5,6,7,9,10,11,12}
- })
- Method (_STA, 0, NotSerialized)
- {
- Store (0x0B, Local0)
- If (And (0x80, PRQ3, Local1))
- {
- Store (0x09, Local0)
- }
- Return (Local0)
- }
- Method (_DIS, 0, NotSerialized)
- {
- Or (PRQ3, 0x80, PRQ3)
- }
- Method (_CRS, 0, NotSerialized)
- {
- Name (PRR0, ResourceTemplate ()
- {
- IRQ (Level, ActiveLow, Shared)
- {1}
- })
- CreateWordField (PRR0, 0x01, TMP)
- Store (PRQ3, Local0)
- If (LLess (Local0, 0x80))
- {
- ShiftLeft (One, Local0, TMP)
- }
- Else
- {
- Store (Zero, TMP)
- }
- Return (PRR0)
- }
- Method (_SRS, 1, NotSerialized)
- {
- CreateWordField (Arg0, 0x01, TMP)
- FindSetRightBit (TMP, Local0)
- Decrement (Local0)
- Store (Local0, PRQ3)
- }
- }
- }
-
- /* S5 = power off state */
- Name (_S5, Package (4) {
- 0x00, // PM1a_CNT.SLP_TYP
- 0x00, // PM2a_CNT.SLP_TYP
- 0x00, // reserved
- 0x00, // reserved
- })
-}
diff --git a/hw/acpi-dsdt.hex b/hw/acpi-dsdt.hex
deleted file mode 100644
index f4f50bd..0000000
--- a/hw/acpi-dsdt.hex
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- *
- * Intel ACPI Component Architecture
- * ASL Optimizing Compiler version 20060421 [Apr 29 2006]
- * Copyright (C) 2000 - 2006 Intel Corporation
- * Supports ACPI Specification Revision 3.0a
- *
- * Compilation of "/usr/local/home/bellard/qemu-current/hw/acpi-dsdt.dsl" - Wed Jun 14 20:09:53 2006
- *
- * C source code output
- *
- */
-unsigned char AmlCode[] =
-{
- 0x44,0x53,0x44,0x54,0x32,0x08,0x00,0x00, /* 00000000 "DSDT2..." */
- 0x01,0x5B,0x51,0x45,0x4D,0x55,0x00,0x00, /* 00000008 ".[QEMU.." */
- 0x51,0x45,0x4D,0x55,0x44,0x53,0x44,0x54, /* 00000010 "QEMUDSDT" */
- 0x01,0x00,0x00,0x00,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
- 0x21,0x04,0x06,0x20,0x10,0x4F,0x04,0x5C, /* 00000020 "!.. .O.\" */
- 0x00,0x5B,0x80,0x43,0x4D,0x53,0x5F,0x01, /* 00000028 ".[.CMS_." */
- 0x0A,0x70,0x0A,0x02,0x5B,0x81,0x10,0x43, /* 00000030 ".p..[..C" */
- 0x4D,0x53,0x5F,0x01,0x43,0x4D,0x53,0x49, /* 00000038 "MS_.CMSI" */
- 0x08,0x43,0x4D,0x53,0x44,0x08,0x14,0x14, /* 00000040 ".CMSD..." */
- 0x43,0x4D,0x52,0x44,0x01,0x70,0x68,0x43, /* 00000048 "CMRD.phC" */
- 0x4D,0x53,0x49,0x70,0x43,0x4D,0x53,0x44, /* 00000050 "MSIpCMSD" */
- 0x60,0xA4,0x60,0x5B,0x80,0x44,0x42,0x47, /* 00000058 "`.`[.DBG" */
- 0x5F,0x01,0x0B,0x44,0xB0,0x0A,0x04,0x5B, /* 00000060 "_..D...[" */
- 0x81,0x0B,0x44,0x42,0x47,0x5F,0x03,0x44, /* 00000068 "..DBG_.D" */
- 0x42,0x47,0x4C,0x20,0x10,0x4E,0x25,0x5F, /* 00000070 "BGL .N%_" */
- 0x53,0x42,0x5F,0x5B,0x82,0x46,0x25,0x50, /* 00000078 "SB_[.F%P" */
- 0x43,0x49,0x30,0x08,0x5F,0x48,0x49,0x44, /* 00000080 "CI0._HID" */
- 0x0C,0x41,0xD0,0x0A,0x03,0x08,0x5F,0x41, /* 00000088 ".A...._A" */
- 0x44,0x52,0x00,0x08,0x5F,0x55,0x49,0x44, /* 00000090 "DR.._UID" */
- 0x01,0x08,0x5F,0x50,0x52,0x54,0x12,0x47, /* 00000098 ".._PRT.G" */
- 0x15,0x18,0x12,0x0B,0x04,0x0B,0xFF,0xFF, /* 000000A0 "........" */
- 0x00,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0B, /* 000000A8 ".LNKD..." */
- 0x04,0x0B,0xFF,0xFF,0x01,0x4C,0x4E,0x4B, /* 000000B0 ".....LNK" */
- 0x41,0x00,0x12,0x0C,0x04,0x0B,0xFF,0xFF, /* 000000B8 "A......." */
- 0x0A,0x02,0x4C,0x4E,0x4B,0x42,0x00,0x12, /* 000000C0 "..LNKB.." */
- 0x0C,0x04,0x0B,0xFF,0xFF,0x0A,0x03,0x4C, /* 000000C8 ".......L" */
- 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000000D0 "NKC....." */
- 0xFF,0xFF,0x01,0x00,0x00,0x4C,0x4E,0x4B, /* 000000D8 ".....LNK" */
- 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000000E0 "A......." */
- 0x01,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000000E8 "...LNKB." */
- 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00, /* 000000F0 "........" */
- 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000000F8 "..LNKC.." */
- 0x0E,0x04,0x0C,0xFF,0xFF,0x01,0x00,0x0A, /* 00000100 "........" */
- 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x12,0x0D, /* 00000108 ".LNKD..." */
- 0x04,0x0C,0xFF,0xFF,0x02,0x00,0x00,0x4C, /* 00000110 ".......L" */
- 0x4E,0x4B,0x42,0x00,0x12,0x0D,0x04,0x0C, /* 00000118 "NKB....." */
- 0xFF,0xFF,0x02,0x00,0x01,0x4C,0x4E,0x4B, /* 00000120 ".....LNK" */
- 0x43,0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF, /* 00000128 "C......." */
- 0x02,0x00,0x0A,0x02,0x4C,0x4E,0x4B,0x44, /* 00000130 "....LNKD" */
- 0x00,0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x02, /* 00000138 "........" */
- 0x00,0x0A,0x03,0x4C,0x4E,0x4B,0x41,0x00, /* 00000140 "...LNKA." */
- 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x03,0x00, /* 00000148 "........" */
- 0x00,0x4C,0x4E,0x4B,0x43,0x00,0x12,0x0D, /* 00000150 ".LNKC..." */
- 0x04,0x0C,0xFF,0xFF,0x03,0x00,0x01,0x4C, /* 00000158 ".......L" */
- 0x4E,0x4B,0x44,0x00,0x12,0x0E,0x04,0x0C, /* 00000160 "NKD....." */
- 0xFF,0xFF,0x03,0x00,0x0A,0x02,0x4C,0x4E, /* 00000168 "......LN" */
- 0x4B,0x41,0x00,0x12,0x0E,0x04,0x0C,0xFF, /* 00000170 "KA......" */
- 0xFF,0x03,0x00,0x0A,0x03,0x4C,0x4E,0x4B, /* 00000178 ".....LNK" */
- 0x42,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 00000180 "B......." */
- 0x04,0x00,0x00,0x4C,0x4E,0x4B,0x44,0x00, /* 00000188 "...LNKD." */
- 0x12,0x0D,0x04,0x0C,0xFF,0xFF,0x04,0x00, /* 00000190 "........" */
- 0x01,0x4C,0x4E,0x4B,0x41,0x00,0x12,0x0E, /* 00000198 ".LNKA..." */
- 0x04,0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x02, /* 000001A0 "........" */
- 0x4C,0x4E,0x4B,0x42,0x00,0x12,0x0E,0x04, /* 000001A8 "LNKB...." */
- 0x0C,0xFF,0xFF,0x04,0x00,0x0A,0x03,0x4C, /* 000001B0 ".......L" */
- 0x4E,0x4B,0x43,0x00,0x12,0x0D,0x04,0x0C, /* 000001B8 "NKC....." */
- 0xFF,0xFF,0x05,0x00,0x00,0x4C,0x4E,0x4B, /* 000001C0 ".....LNK" */
- 0x41,0x00,0x12,0x0D,0x04,0x0C,0xFF,0xFF, /* 000001C8 "A......." */
- 0x05,0x00,0x01,0x4C,0x4E,0x4B,0x42,0x00, /* 000001D0 "...LNKB." */
- 0x12,0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00, /* 000001D8 "........" */
- 0x0A,0x02,0x4C,0x4E,0x4B,0x43,0x00,0x12, /* 000001E0 "..LNKC.." */
- 0x0E,0x04,0x0C,0xFF,0xFF,0x05,0x00,0x0A, /* 000001E8 "........" */
- 0x03,0x4C,0x4E,0x4B,0x44,0x00,0x14,0x4C, /* 000001F0 ".LNKD..L" */
- 0x0D,0x5F,0x43,0x52,0x53,0x00,0x08,0x4D, /* 000001F8 "._CRS..M" */
- 0x45,0x4D,0x50,0x11,0x42,0x07,0x0A,0x6E, /* 00000200 "EMP.B..n" */
- 0x88,0x0D,0x00,0x02,0x0C,0x00,0x00,0x00, /* 00000208 "........" */
- 0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x01, /* 00000210 "........" */
- 0x47,0x01,0xF8,0x0C,0xF8,0x0C,0x01,0x08, /* 00000218 "G......." */
- 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000220 "........" */
- 0x00,0x00,0xF7,0x0C,0x00,0x00,0xF8,0x0C, /* 00000228 "........" */
- 0x88,0x0D,0x00,0x01,0x0C,0x03,0x00,0x00, /* 00000230 "........" */
- 0x00,0x0D,0xFF,0xFF,0x00,0x00,0x00,0xF3, /* 00000238 "........" */
- 0x87,0x17,0x00,0x00,0x0C,0x03,0x00,0x00, /* 00000240 "........" */
- 0x00,0x00,0x00,0x00,0x0A,0x00,0xFF,0xFF, /* 00000248 "........" */
- 0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000250 "........" */
- 0x02,0x00,0x87,0x17,0x00,0x00,0x08,0x01, /* 00000258 "........" */
- 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* 00000260 "........" */
- 0xFF,0xFF,0xBF,0xFE,0x00,0x00,0x00,0x00, /* 00000268 "........" */
- 0x00,0x00,0x00,0x00,0x79,0x00,0x8A,0x4D, /* 00000270 "....y..M" */
- 0x45,0x4D,0x50,0x0A,0x5C,0x50,0x4D,0x49, /* 00000278 "EMP.\PMI" */
- 0x4E,0x8A,0x4D,0x45,0x4D,0x50,0x0A,0x60, /* 00000280 "N.MEMP.`" */
- 0x50,0x4D,0x41,0x58,0x8A,0x4D,0x45,0x4D, /* 00000288 "PMAX.MEM" */
- 0x50,0x0A,0x68,0x50,0x4C,0x45,0x4E,0x72, /* 00000290 "P.hPLENr" */
- 0x43,0x4D,0x52,0x44,0x0A,0x34,0x79,0x43, /* 00000298 "CMRD.4yC" */
- 0x4D,0x52,0x44,0x0A,0x35,0x0A,0x08,0x00, /* 000002A0 "MRD.5..." */
- 0x60,0x79,0x60,0x0A,0x10,0x60,0x72,0x60, /* 000002A8 "`y`..`r`" */
- 0x0C,0x00,0x00,0x00,0x01,0x60,0x70,0x60, /* 000002B0 ".....`p`" */
- 0x50,0x4D,0x49,0x4E,0x74,0x50,0x4D,0x41, /* 000002B8 "PMINtPMA" */
- 0x58,0x50,0x4D,0x49,0x4E,0x50,0x4C,0x45, /* 000002C0 "XPMINPLE" */
- 0x4E,0x75,0x50,0x4C,0x45,0x4E,0xA4,0x4D, /* 000002C8 "NuPLEN.M" */
- 0x45,0x4D,0x50,0x10,0x42,0x26,0x2E,0x5F, /* 000002D0 "EMP.B&._" */
- 0x53,0x42,0x5F,0x50,0x43,0x49,0x30,0x5B, /* 000002D8 "SB_PCI0[" */
- 0x82,0x43,0x20,0x49,0x53,0x41,0x5F,0x08, /* 000002E0 ".C ISA_." */
- 0x5F,0x41,0x44,0x52,0x0C,0x00,0x00,0x01, /* 000002E8 "_ADR...." */
- 0x00,0x5B,0x80,0x50,0x34,0x30,0x43,0x02, /* 000002F0 ".[.P40C." */
- 0x0A,0x60,0x0A,0x04,0x5B,0x82,0x44,0x04, /* 000002F8 ".`..[.D." */
- 0x4B,0x42,0x44,0x5F,0x08,0x5F,0x48,0x49, /* 00000300 "KBD_._HI" */
- 0x44,0x0C,0x41,0xD0,0x03,0x03,0x14,0x09, /* 00000308 "D.A....." */
- 0x5F,0x53,0x54,0x41,0x00,0xA4,0x0A,0x0F, /* 00000310 "_STA...." */
- 0x14,0x29,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000318 ".)_CRS.." */
- 0x54,0x4D,0x50,0x5F,0x11,0x18,0x0A,0x15, /* 00000320 "TMP_...." */
- 0x47,0x01,0x60,0x00,0x60,0x00,0x01,0x01, /* 00000328 "G.`.`..." */
- 0x47,0x01,0x64,0x00,0x64,0x00,0x01,0x01, /* 00000330 "G.d.d..." */
- 0x22,0x02,0x00,0x79,0x00,0xA4,0x54,0x4D, /* 00000338 ""..y..TM" */
- 0x50,0x5F,0x5B,0x82,0x33,0x4D,0x4F,0x55, /* 00000340 "P_[.3MOU" */
- 0x5F,0x08,0x5F,0x48,0x49,0x44,0x0C,0x41, /* 00000348 "_._HID.A" */
- 0xD0,0x0F,0x13,0x14,0x09,0x5F,0x53,0x54, /* 00000350 "....._ST" */
- 0x41,0x00,0xA4,0x0A,0x0F,0x14,0x19,0x5F, /* 00000358 "A......_" */
- 0x43,0x52,0x53,0x00,0x08,0x54,0x4D,0x50, /* 00000360 "CRS..TMP" */
- 0x5F,0x11,0x08,0x0A,0x05,0x22,0x00,0x10, /* 00000368 "_....".." */
- 0x79,0x00,0xA4,0x54,0x4D,0x50,0x5F,0x5B, /* 00000370 "y..TMP_[" */
- 0x82,0x47,0x04,0x46,0x44,0x43,0x30,0x08, /* 00000378 ".G.FDC0." */
- 0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0,0x07, /* 00000380 "_HID.A.." */
- 0x00,0x14,0x09,0x5F,0x53,0x54,0x41,0x00, /* 00000388 "..._STA." */
- 0xA4,0x0A,0x0F,0x14,0x2C,0x5F,0x43,0x52, /* 00000390 "....,_CR" */
- 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000398 "S..BUF0." */
- 0x1B,0x0A,0x18,0x47,0x01,0xF2,0x03,0xF2, /* 000003A0 "...G...." */
- 0x03,0x00,0x04,0x47,0x01,0xF7,0x03,0xF7, /* 000003A8 "...G...." */
- 0x03,0x00,0x01,0x22,0x40,0x00,0x2A,0x04, /* 000003B0 "..."@.*." */
- 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 000003B8 ".y..BUF0" */
- 0x5B,0x82,0x4B,0x05,0x4C,0x50,0x54,0x5F, /* 000003C0 "[.K.LPT_" */
- 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 000003C8 "._HID.A." */
- 0x04,0x00,0x14,0x28,0x5F,0x53,0x54,0x41, /* 000003D0 "...(_STA" */
- 0x00,0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58, /* 000003D8 ".p^^^.PX" */
- 0x31,0x33,0x44,0x52,0x53,0x41,0x60,0x7B, /* 000003E0 "13DRSA`{" */
- 0x60,0x0C,0x00,0x00,0x00,0x80,0x60,0xA0, /* 000003E8 "`.....`." */
- 0x06,0x93,0x60,0x00,0xA4,0x00,0xA1,0x04, /* 000003F0 "..`....." */
- 0xA4,0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52, /* 000003F8 "....!_CR" */
- 0x53,0x00,0x08,0x42,0x55,0x46,0x30,0x11, /* 00000400 "S..BUF0." */
- 0x10,0x0A,0x0D,0x47,0x01,0x78,0x03,0x78, /* 00000408 "...G.x.x" */
- 0x03,0x08,0x08,0x22,0x80,0x00,0x79,0x00, /* 00000410 "..."..y." */
- 0xA4,0x42,0x55,0x46,0x30,0x5B,0x82,0x41, /* 00000418 ".BUF0[.A" */
- 0x06,0x43,0x4F,0x4D,0x31,0x08,0x5F,0x48, /* 00000420 ".COM1._H" */
- 0x49,0x44,0x0C,0x41,0xD0,0x05,0x01,0x08, /* 00000428 "ID.A...." */
- 0x5F,0x55,0x49,0x44,0x01,0x14,0x28,0x5F, /* 00000430 "_UID..(_" */
- 0x53,0x54,0x41,0x00,0x70,0x5E,0x5E,0x5E, /* 00000438 "STA.p^^^" */
- 0x2E,0x50,0x58,0x31,0x33,0x44,0x52,0x53, /* 00000440 ".PX13DRS" */
- 0x43,0x60,0x7B,0x60,0x0C,0x00,0x00,0x00, /* 00000448 "C`{`...." */
- 0x08,0x60,0xA0,0x06,0x93,0x60,0x00,0xA4, /* 00000450 ".`...`.." */
- 0x00,0xA1,0x04,0xA4,0x0A,0x0F,0x14,0x21, /* 00000458 ".......!" */
- 0x5F,0x43,0x52,0x53,0x00,0x08,0x42,0x55, /* 00000460 "_CRS..BU" */
- 0x46,0x30,0x11,0x10,0x0A,0x0D,0x47,0x01, /* 00000468 "F0....G." */
- 0xF8,0x03,0xF8,0x03,0x00,0x08,0x22,0x10, /* 00000470 "......"." */
- 0x00,0x79,0x00,0xA4,0x42,0x55,0x46,0x30, /* 00000478 ".y..BUF0" */
- 0x5B,0x82,0x42,0x06,0x43,0x4F,0x4D,0x32, /* 00000480 "[.B.COM2" */
- 0x08,0x5F,0x48,0x49,0x44,0x0C,0x41,0xD0, /* 00000488 "._HID.A." */
- 0x05,0x01,0x08,0x5F,0x55,0x49,0x44,0x0A, /* 00000490 "..._UID." */
- 0x02,0x14,0x28,0x5F,0x53,0x54,0x41,0x00, /* 00000498 "..(_STA." */
- 0x70,0x5E,0x5E,0x5E,0x2E,0x50,0x58,0x31, /* 000004A0 "p^^^.PX1" */
- 0x33,0x44,0x52,0x53,0x43,0x60,0x7B,0x60, /* 000004A8 "3DRSC`{`" */
- 0x0C,0x00,0x00,0x00,0x80,0x60,0xA0,0x06, /* 000004B0 ".....`.." */
- 0x93,0x60,0x00,0xA4,0x00,0xA1,0x04,0xA4, /* 000004B8 ".`......" */
- 0x0A,0x0F,0x14,0x21,0x5F,0x43,0x52,0x53, /* 000004C0 "...!_CRS" */
- 0x00,0x08,0x42,0x55,0x46,0x30,0x11,0x10, /* 000004C8 "..BUF0.." */
- 0x0A,0x0D,0x47,0x01,0xF8,0x02,0xF8,0x02, /* 000004D0 "..G....." */
- 0x00,0x08,0x22,0x08,0x00,0x79,0x00,0xA4, /* 000004D8 ".."..y.." */
- 0x42,0x55,0x46,0x30,0x5B,0x82,0x40,0x05, /* 000004E0 "BUF0[.@." */
- 0x50,0x58,0x31,0x33,0x08,0x5F,0x41,0x44, /* 000004E8 "PX13._AD" */
- 0x52,0x0C,0x03,0x00,0x01,0x00,0x5B,0x80, /* 000004F0 "R.....[." */
- 0x50,0x31,0x33,0x43,0x02,0x0A,0x5C,0x0A, /* 000004F8 "P13C..\." */
- 0x24,0x5B,0x81,0x33,0x50,0x31,0x33,0x43, /* 00000500 "$[.3P13C" */
- 0x03,0x44,0x52,0x53,0x41,0x20,0x44,0x52, /* 00000508 ".DRSA DR" */
- 0x53,0x42,0x20,0x44,0x52,0x53,0x43,0x20, /* 00000510 "SB DRSC " */
- 0x44,0x52,0x53,0x45,0x20,0x44,0x52,0x53, /* 00000518 "DRSE DRS" */
- 0x46,0x20,0x44,0x52,0x53,0x47,0x20,0x44, /* 00000520 "F DRSG D" */
- 0x52,0x53,0x48,0x20,0x44,0x52,0x53,0x49, /* 00000528 "RSH DRSI" */
- 0x20,0x44,0x52,0x53,0x4A,0x20,0x10,0x4F, /* 00000530 " DRSJ .O" */
- 0x2E,0x5F,0x53,0x42,0x5F,0x5B,0x81,0x24, /* 00000538 "._SB_[.$" */
- 0x2F,0x03,0x50,0x43,0x49,0x30,0x49,0x53, /* 00000540 "/.PCI0IS" */
- 0x41,0x5F,0x50,0x34,0x30,0x43,0x01,0x50, /* 00000548 "A_P40C.P" */
- 0x52,0x51,0x30,0x08,0x50,0x52,0x51,0x31, /* 00000550 "RQ0.PRQ1" */
- 0x08,0x50,0x52,0x51,0x32,0x08,0x50,0x52, /* 00000558 ".PRQ2.PR" */
- 0x51,0x33,0x08,0x5B,0x82,0x4E,0x0A,0x4C, /* 00000560 "Q3.[.N.L" */
- 0x4E,0x4B,0x41,0x08,0x5F,0x48,0x49,0x44, /* 00000568 "NKA._HID" */
- 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000570 ".A...._U" */
- 0x49,0x44,0x01,0x08,0x5F,0x50,0x52,0x53, /* 00000578 "ID.._PRS" */
- 0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E,0x18, /* 00000580 "....#..." */
- 0x79,0x00,0x14,0x1A,0x5F,0x53,0x54,0x41, /* 00000588 "y..._STA" */
- 0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D,0x7B, /* 00000590 ".p..`..{" */
- 0x0A,0x80,0x50,0x52,0x51,0x30,0x61,0x70, /* 00000598 "..PRQ0ap" */
- 0x0A,0x09,0x60,0xA4,0x60,0x14,0x11,0x5F, /* 000005A0 "..`.`.._" */
- 0x44,0x49,0x53,0x00,0x7D,0x50,0x52,0x51, /* 000005A8 "DIS.}PRQ" */
- 0x30,0x0A,0x80,0x50,0x52,0x51,0x30,0x14, /* 000005B0 "0..PRQ0." */
- 0x3F,0x5F,0x43,0x52,0x53,0x00,0x08,0x50, /* 000005B8 "?_CRS..P" */
- 0x52,0x52,0x30,0x11,0x09,0x0A,0x06,0x23, /* 000005C0 "RR0....#" */
- 0x02,0x00,0x18,0x79,0x00,0x8B,0x50,0x52, /* 000005C8 "...y..PR" */
- 0x52,0x30,0x01,0x54,0x4D,0x50,0x5F,0x70, /* 000005D0 "R0.TMP_p" */
- 0x50,0x52,0x51,0x30,0x60,0xA0,0x0C,0x95, /* 000005D8 "PRQ0`..." */
- 0x60,0x0A,0x80,0x79,0x01,0x60,0x54,0x4D, /* 000005E0 "`..y.`TM" */
- 0x50,0x5F,0xA1,0x07,0x70,0x00,0x54,0x4D, /* 000005E8 "P_..p.TM" */
- 0x50,0x5F,0xA4,0x50,0x52,0x52,0x30,0x14, /* 000005F0 "P_.PRR0." */
- 0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B,0x68, /* 000005F8 "._SRS..h" */
- 0x01,0x54,0x4D,0x50,0x5F,0x82,0x54,0x4D, /* 00000600 ".TMP_.TM" */
- 0x50,0x5F,0x60,0x76,0x60,0x70,0x60,0x50, /* 00000608 "P_`v`p`P" */
- 0x52,0x51,0x30,0x5B,0x82,0x4F,0x0A,0x4C, /* 00000610 "RQ0[.O.L" */
- 0x4E,0x4B,0x42,0x08,0x5F,0x48,0x49,0x44, /* 00000618 "NKB._HID" */
- 0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F,0x55, /* 00000620 ".A...._U" */
- 0x49,0x44,0x0A,0x02,0x08,0x5F,0x50,0x52, /* 00000628 "ID..._PR" */
- 0x53,0x11,0x09,0x0A,0x06,0x23,0xF8,0x1E, /* 00000630 "S....#.." */
- 0x18,0x79,0x00,0x14,0x1A,0x5F,0x53,0x54, /* 00000638 ".y..._ST" */
- 0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0,0x0D, /* 00000640 "A.p..`.." */
- 0x7B,0x0A,0x80,0x50,0x52,0x51,0x31,0x61, /* 00000648 "{..PRQ1a" */
- 0x70,0x0A,0x09,0x60,0xA4,0x60,0x14,0x11, /* 00000650 "p..`.`.." */
- 0x5F,0x44,0x49,0x53,0x00,0x7D,0x50,0x52, /* 00000658 "_DIS.}PR" */
- 0x51,0x31,0x0A,0x80,0x50,0x52,0x51,0x31, /* 00000660 "Q1..PRQ1" */
- 0x14,0x3F,0x5F,0x43,0x52,0x53,0x00,0x08, /* 00000668 ".?_CRS.." */
- 0x50,0x52,0x52,0x30,0x11,0x09,0x0A,0x06, /* 00000670 "PRR0...." */
- 0x23,0x02,0x00,0x18,0x79,0x00,0x8B,0x50, /* 00000678 "#...y..P" */
- 0x52,0x52,0x30,0x01,0x54,0x4D,0x50,0x5F, /* 00000680 "RR0.TMP_" */
- 0x70,0x50,0x52,0x51,0x31,0x60,0xA0,0x0C, /* 00000688 "pPRQ1`.." */
- 0x95,0x60,0x0A,0x80,0x79,0x01,0x60,0x54, /* 00000690 ".`..y.`T" */
- 0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00,0x54, /* 00000698 "MP_..p.T" */
- 0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52,0x30, /* 000006A0 "MP_.PRR0" */
- 0x14,0x1B,0x5F,0x53,0x52,0x53,0x01,0x8B, /* 000006A8 ".._SRS.." */
- 0x68,0x01,0x54,0x4D,0x50,0x5F,0x82,0x54, /* 000006B0 "h.TMP_.T" */
- 0x4D,0x50,0x5F,0x60,0x76,0x60,0x70,0x60, /* 000006B8 "MP_`v`p`" */
- 0x50,0x52,0x51,0x31,0x5B,0x82,0x4F,0x0A, /* 000006C0 "PRQ1[.O." */
- 0x4C,0x4E,0x4B,0x43,0x08,0x5F,0x48,0x49, /* 000006C8 "LNKC._HI" */
- 0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08,0x5F, /* 000006D0 "D.A...._" */
- 0x55,0x49,0x44,0x0A,0x03,0x08,0x5F,0x50, /* 000006D8 "UID..._P" */
- 0x52,0x53,0x11,0x09,0x0A,0x06,0x23,0xF8, /* 000006E0 "RS....#." */
- 0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F,0x53, /* 000006E8 "..y..._S" */
- 0x54,0x41,0x00,0x70,0x0A,0x0B,0x60,0xA0, /* 000006F0 "TA.p..`." */
- 0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51,0x32, /* 000006F8 ".{..PRQ2" */
- 0x61,0x70,0x0A,0x09,0x60,0xA4,0x60,0x14, /* 00000700 "ap..`.`." */
- 0x11,0x5F,0x44,0x49,0x53,0x00,0x7D,0x50, /* 00000708 "._DIS.}P" */
- 0x52,0x51,0x32,0x0A,0x80,0x50,0x52,0x51, /* 00000710 "RQ2..PRQ" */
- 0x32,0x14,0x3F,0x5F,0x43,0x52,0x53,0x00, /* 00000718 "2.?_CRS." */
- 0x08,0x50,0x52,0x52,0x30,0x11,0x09,0x0A, /* 00000720 ".PRR0..." */
- 0x06,0x23,0x02,0x00,0x18,0x79,0x00,0x8B, /* 00000728 ".#...y.." */
- 0x50,0x52,0x52,0x30,0x01,0x54,0x4D,0x50, /* 00000730 "PRR0.TMP" */
- 0x5F,0x70,0x50,0x52,0x51,0x32,0x60,0xA0, /* 00000738 "_pPRQ2`." */
- 0x0C,0x95,0x60,0x0A,0x80,0x79,0x01,0x60, /* 00000740 "..`..y.`" */
- 0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70,0x00, /* 00000748 "TMP_..p." */
- 0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52,0x52, /* 00000750 "TMP_.PRR" */
- 0x30,0x14,0x1B,0x5F,0x53,0x52,0x53,0x01, /* 00000758 "0.._SRS." */
- 0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F,0x82, /* 00000760 ".h.TMP_." */
- 0x54,0x4D,0x50,0x5F,0x60,0x76,0x60,0x70, /* 00000768 "TMP_`v`p" */
- 0x60,0x50,0x52,0x51,0x32,0x5B,0x82,0x4F, /* 00000770 "`PRQ2[.O" */
- 0x0A,0x4C,0x4E,0x4B,0x44,0x08,0x5F,0x48, /* 00000778 ".LNKD._H" */
- 0x49,0x44,0x0C,0x41,0xD0,0x0C,0x0F,0x08, /* 00000780 "ID.A...." */
- 0x5F,0x55,0x49,0x44,0x0A,0x04,0x08,0x5F, /* 00000788 "_UID..._" */
- 0x50,0x52,0x53,0x11,0x09,0x0A,0x06,0x23, /* 00000790 "PRS....#" */
- 0xF8,0x1E,0x18,0x79,0x00,0x14,0x1A,0x5F, /* 00000798 "...y..._" */
- 0x53,0x54,0x41,0x00,0x70,0x0A,0x0B,0x60, /* 000007A0 "STA.p..`" */
- 0xA0,0x0D,0x7B,0x0A,0x80,0x50,0x52,0x51, /* 000007A8 "..{..PRQ" */
- 0x33,0x61,0x70,0x0A,0x09,0x60,0xA4,0x60, /* 000007B0 "3ap..`.`" */
- 0x14,0x11,0x5F,0x44,0x49,0x53,0x00,0x7D, /* 000007B8 ".._DIS.}" */
- 0x50,0x52,0x51,0x33,0x0A,0x80,0x50,0x52, /* 000007C0 "PRQ3..PR" */
- 0x51,0x33,0x14,0x3F,0x5F,0x43,0x52,0x53, /* 000007C8 "Q3.?_CRS" */
- 0x00,0x08,0x50,0x52,0x52,0x30,0x11,0x09, /* 000007D0 "..PRR0.." */
- 0x0A,0x06,0x23,0x02,0x00,0x18,0x79,0x00, /* 000007D8 "..#...y." */
- 0x8B,0x50,0x52,0x52,0x30,0x01,0x54,0x4D, /* 000007E0 ".PRR0.TM" */
- 0x50,0x5F,0x70,0x50,0x52,0x51,0x33,0x60, /* 000007E8 "P_pPRQ3`" */
- 0xA0,0x0C,0x95,0x60,0x0A,0x80,0x79,0x01, /* 000007F0 "...`..y." */
- 0x60,0x54,0x4D,0x50,0x5F,0xA1,0x07,0x70, /* 000007F8 "`TMP_..p" */
- 0x00,0x54,0x4D,0x50,0x5F,0xA4,0x50,0x52, /* 00000800 ".TMP_.PR" */
- 0x52,0x30,0x14,0x1B,0x5F,0x53,0x52,0x53, /* 00000808 "R0.._SRS" */
- 0x01,0x8B,0x68,0x01,0x54,0x4D,0x50,0x5F, /* 00000810 "..h.TMP_" */
- 0x82,0x54,0x4D,0x50,0x5F,0x60,0x76,0x60, /* 00000818 ".TMP_`v`" */
- 0x70,0x60,0x50,0x52,0x51,0x33,0x08,0x5F, /* 00000820 "p`PRQ3._" */
- 0x53,0x35,0x5F,0x12,0x06,0x04,0x00,0x00, /* 00000828 "S5_....." */
- 0x00,0x00,
-};
diff --git a/hw/acpi.c b/hw/acpi.c
deleted file mode 100644
index 6c20a4e..0000000
--- a/hw/acpi.c
+++ /dev/null
@@ -1,615 +0,0 @@
-/*
- * ACPI implementation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * 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 "vl.h"
-
-//#define DEBUG
-
-/* i82731AB (PIIX4) compatible power management function */
-#define PM_FREQ 3579545
-
-/* XXX: make them variable */
-#define PM_IO_BASE 0xb000
-#define SMI_CMD_IO_ADDR 0xb040
-#define ACPI_DBG_IO_ADDR 0xb044
-
-typedef struct PIIX4PMState {
- PCIDevice dev;
- uint16_t pmsts;
- uint16_t pmen;
- uint16_t pmcntrl;
- QEMUTimer *tmr_timer;
- int64_t tmr_overflow_time;
-} PIIX4PMState;
-
-#define RTC_EN (1 << 10)
-#define PWRBTN_EN (1 << 8)
-#define GBL_EN (1 << 5)
-#define TMROF_EN (1 << 0)
-
-#define SCI_EN (1 << 0)
-
-#define SUS_EN (1 << 13)
-
-/* Note: only used for ACPI bios init. Could be deleted when ACPI init
- is integrated in Bochs BIOS */
-static PIIX4PMState *piix4_pm_state;
-
-static uint32_t get_pmtmr(PIIX4PMState *s)
-{
- uint32_t d;
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
- return d & 0xffffff;
-}
-
-static int get_pmsts(PIIX4PMState *s)
-{
- int64_t d;
- int pmsts;
- pmsts = s->pmsts;
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
- if (d >= s->tmr_overflow_time)
- s->pmsts |= TMROF_EN;
- return pmsts;
-}
-
-static void pm_update_sci(PIIX4PMState *s)
-{
- int sci_level, pmsts;
- int64_t expire_time;
-
- 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);
- /* 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);
- qemu_mod_timer(s->tmr_timer, expire_time);
- } else {
- qemu_del_timer(s->tmr_timer);
- }
-}
-
-static void pm_tmr_timer(void *opaque)
-{
- PIIX4PMState *s = opaque;
- pm_update_sci(s);
-}
-
-static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- PIIX4PMState *s = opaque;
- addr &= 0x3f;
- switch(addr) {
- case 0x00:
- {
- int64_t d;
- int pmsts;
- pmsts = get_pmsts(s);
- if (pmsts & val & TMROF_EN) {
- /* if TMRSTS is reset, then compute the new overflow time */
- d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
- s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
- }
- s->pmsts &= ~val;
- pm_update_sci(s);
- }
- break;
- case 0x02:
- s->pmen = val;
- pm_update_sci(s);
- break;
- case 0x04:
- {
- int sus_typ;
- s->pmcntrl = val & ~(SUS_EN);
- if (val & SUS_EN) {
- /* change suspend type */
- sus_typ = (val >> 10) & 3;
- switch(sus_typ) {
- case 0: /* soft power off */
- qemu_system_shutdown_request();
- break;
- default:
- break;
- }
- }
- }
- break;
- default:
- break;
- }
-#ifdef DEBUG
- printf("PM writew port=0x%04x val=0x%04x\n", addr, val);
-#endif
-}
-
-static uint32_t pm_ioport_readw(void *opaque, uint32_t addr)
-{
- PIIX4PMState *s = opaque;
- uint32_t val;
-
- addr &= 0x3f;
- switch(addr) {
- case 0x00:
- val = get_pmsts(s);
- break;
- case 0x02:
- val = s->pmen;
- break;
- case 0x04:
- val = s->pmcntrl;
- break;
- default:
- val = 0;
- break;
- }
-#ifdef DEBUG
- printf("PM readw port=0x%04x val=0x%04x\n", addr, val);
-#endif
- return val;
-}
-
-static void pm_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- // PIIX4PMState *s = opaque;
- addr &= 0x3f;
-#ifdef DEBUG
- printf("PM writel port=0x%04x val=0x%08x\n", addr, val);
-#endif
-}
-
-static uint32_t pm_ioport_readl(void *opaque, uint32_t addr)
-{
- PIIX4PMState *s = opaque;
- uint32_t val;
-
- addr &= 0x3f;
- switch(addr) {
- case 0x08:
- val = get_pmtmr(s);
- break;
- default:
- val = 0;
- break;
- }
-#ifdef DEBUG
- printf("PM readl port=0x%04x val=0x%08x\n", addr, val);
-#endif
- return val;
-}
-
-static void smi_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- PIIX4PMState *s = opaque;
-#ifdef DEBUG
- printf("SMI cmd val=0x%02x\n", val);
-#endif
- switch(val) {
- case 0xf0: /* ACPI disable */
- s->pmcntrl &= ~SCI_EN;
- break;
- case 0xf1: /* ACPI enable */
- s->pmcntrl |= SCI_EN;
- break;
- }
-}
-
-static void acpi_dbg_writel(void *opaque, uint32_t addr, uint32_t val)
-{
-#if defined(DEBUG)
- printf("ACPI: DBG: 0x%08x\n", val);
-#endif
-}
-
-/* XXX: we still add it to the PIIX3 and we count on the fact that
- OSes are smart enough to accept this strange configuration */
-void piix4_pm_init(PCIBus *bus, int devfn)
-{
- PIIX4PMState *s;
- uint8_t *pci_conf;
- uint32_t pm_io_base;
-
- s = (PIIX4PMState *)pci_register_device(bus,
- "PM", sizeof(PIIX4PMState),
- devfn, NULL, NULL);
- pci_conf = s->dev.config;
- pci_conf[0x00] = 0x86;
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x13;
- pci_conf[0x03] = 0x71;
- pci_conf[0x08] = 0x00; // revision number
- pci_conf[0x09] = 0x00;
- pci_conf[0x0a] = 0x80; // other bridge device
- pci_conf[0x0b] = 0x06; // bridge device
- pci_conf[0x0e] = 0x00; // header_type
- pci_conf[0x3d] = 0x01; // interrupt pin 1
-
- pm_io_base = PM_IO_BASE;
- pci_conf[0x40] = pm_io_base | 1;
- pci_conf[0x41] = pm_io_base >> 8;
- register_ioport_write(pm_io_base, 64, 2, pm_ioport_writew, s);
- register_ioport_read(pm_io_base, 64, 2, pm_ioport_readw, s);
- register_ioport_write(pm_io_base, 64, 4, pm_ioport_writel, s);
- register_ioport_read(pm_io_base, 64, 4, pm_ioport_readl, s);
-
- register_ioport_write(SMI_CMD_IO_ADDR, 1, 1, smi_cmd_writeb, s);
- register_ioport_write(ACPI_DBG_IO_ADDR, 4, 4, acpi_dbg_writel, s);
-
- /* XXX: which specification is used ? The i82731AB has different
- mappings */
- pci_conf[0x5f] = (parallel_hds[0] != NULL ? 0x80 : 0) | 0x10;
- pci_conf[0x63] = 0x60;
- pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
- (serial_hds[1] != NULL ? 0x90 : 0);
-
- s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
- piix4_pm_state = s;
-}
-
-/* ACPI tables */
-/* XXX: move them in the Bochs BIOS ? */
-
-/*************************************************/
-
-/* Table structure from Linux kernel (the ACPI tables are under the
- BSD license) */
-
-#define ACPI_TABLE_HEADER_DEF /* ACPI common table header */ \
- uint8_t signature [4]; /* ACPI signature (4 ASCII characters) */\
- uint32_t length; /* Length of table, in bytes, including header */\
- uint8_t revision; /* ACPI Specification minor version # */\
- uint8_t checksum; /* To make sum of entire table == 0 */\
- uint8_t oem_id [6]; /* OEM identification */\
- uint8_t oem_table_id [8]; /* OEM table identification */\
- uint32_t oem_revision; /* OEM revision number */\
- uint8_t asl_compiler_id [4]; /* ASL compiler vendor ID */\
- uint32_t asl_compiler_revision; /* ASL compiler revision number */
-
-
-struct acpi_table_header /* ACPI common table header */
-{
- ACPI_TABLE_HEADER_DEF
-};
-
-struct rsdp_descriptor /* Root System Descriptor Pointer */
-{
- uint8_t signature [8]; /* ACPI signature, contains "RSD PTR " */
- uint8_t checksum; /* To make sum of struct == 0 */
- uint8_t oem_id [6]; /* OEM identification */
- uint8_t revision; /* Must be 0 for 1.0, 2 for 2.0 */
- uint32_t rsdt_physical_address; /* 32-bit physical address of RSDT */
- uint32_t length; /* XSDT Length in bytes including hdr */
- uint64_t xsdt_physical_address; /* 64-bit physical address of XSDT */
- uint8_t extended_checksum; /* Checksum of entire table */
- uint8_t reserved [3]; /* Reserved field must be 0 */
-};
-
-/*
- * ACPI 1.0 Root System Description Table (RSDT)
- */
-struct rsdt_descriptor_rev1
-{
- ACPI_TABLE_HEADER_DEF /* ACPI common table header */
- uint32_t table_offset_entry [2]; /* Array of pointers to other */
- /* ACPI tables */
-};
-
-/*
- * ACPI 1.0 Firmware ACPI Control Structure (FACS)
- */
-struct facs_descriptor_rev1
-{
- uint8_t signature[4]; /* ACPI Signature */
- uint32_t length; /* Length of structure, in bytes */
- uint32_t hardware_signature; /* Hardware configuration signature */
- uint32_t firmware_waking_vector; /* ACPI OS waking vector */
- uint32_t global_lock; /* Global Lock */
- uint32_t S4bios_f : 1; /* Indicates if S4BIOS support is present */
- uint32_t reserved1 : 31; /* Must be 0 */
- uint8_t resverved3 [40]; /* Reserved - must be zero */
-};
-
-
-/*
- * ACPI 1.0 Fixed ACPI Description Table (FADT)
- */
-struct fadt_descriptor_rev1
-{
- ACPI_TABLE_HEADER_DEF /* ACPI common table header */
- uint32_t firmware_ctrl; /* Physical address of FACS */
- uint32_t dsdt; /* Physical address of DSDT */
- uint8_t model; /* System Interrupt Model */
- uint8_t reserved1; /* Reserved */
- uint16_t sci_int; /* System vector of SCI interrupt */
- uint32_t smi_cmd; /* Port address of SMI command port */
- uint8_t acpi_enable; /* Value to write to smi_cmd to enable ACPI */
- uint8_t acpi_disable; /* Value to write to smi_cmd to disable ACPI */
- uint8_t S4bios_req; /* Value to write to SMI CMD to enter S4BIOS state */
- uint8_t reserved2; /* Reserved - must be zero */
- uint32_t pm1a_evt_blk; /* Port address of Power Mgt 1a acpi_event Reg Blk */
- uint32_t pm1b_evt_blk; /* Port address of Power Mgt 1b acpi_event Reg Blk */
- uint32_t pm1a_cnt_blk; /* Port address of Power Mgt 1a Control Reg Blk */
- uint32_t pm1b_cnt_blk; /* Port address of Power Mgt 1b Control Reg Blk */
- uint32_t pm2_cnt_blk; /* Port address of Power Mgt 2 Control Reg Blk */
- uint32_t pm_tmr_blk; /* Port address of Power Mgt Timer Ctrl Reg Blk */
- uint32_t gpe0_blk; /* Port addr of General Purpose acpi_event 0 Reg Blk */
- uint32_t gpe1_blk; /* Port addr of General Purpose acpi_event 1 Reg Blk */
- uint8_t pm1_evt_len; /* Byte length of ports at pm1_x_evt_blk */
- uint8_t pm1_cnt_len; /* Byte length of ports at pm1_x_cnt_blk */
- uint8_t pm2_cnt_len; /* Byte Length of ports at pm2_cnt_blk */
- uint8_t pm_tmr_len; /* Byte Length of ports at pm_tm_blk */
- uint8_t gpe0_blk_len; /* Byte Length of ports at gpe0_blk */
- uint8_t gpe1_blk_len; /* Byte Length of ports at gpe1_blk */
- uint8_t gpe1_base; /* Offset in gpe model where gpe1 events start */
- uint8_t reserved3; /* Reserved */
- uint16_t plvl2_lat; /* Worst case HW latency to enter/exit C2 state */
- uint16_t plvl3_lat; /* Worst case HW latency to enter/exit C3 state */
- uint16_t flush_size; /* Size of area read to flush caches */
- uint16_t flush_stride; /* Stride used in flushing caches */
- uint8_t duty_offset; /* Bit location of duty cycle field in p_cnt reg */
- uint8_t duty_width; /* Bit width of duty cycle field in p_cnt reg */
- uint8_t day_alrm; /* Index to day-of-month alarm in RTC CMOS RAM */
- uint8_t mon_alrm; /* Index to month-of-year alarm in RTC CMOS RAM */
- uint8_t century; /* Index to century in RTC CMOS RAM */
- uint8_t reserved4; /* Reserved */
- uint8_t reserved4a; /* Reserved */
- uint8_t reserved4b; /* Reserved */
-#if 0
- uint32_t wb_invd : 1; /* The wbinvd instruction works properly */
- uint32_t wb_invd_flush : 1; /* The wbinvd flushes but does not invalidate */
- uint32_t proc_c1 : 1; /* All processors support C1 state */
- uint32_t plvl2_up : 1; /* C2 state works on MP system */
- uint32_t pwr_button : 1; /* Power button is handled as a generic feature */
- uint32_t sleep_button : 1; /* Sleep button is handled as a generic feature, or not present */
- uint32_t fixed_rTC : 1; /* RTC wakeup stat not in fixed register space */
- uint32_t rtcs4 : 1; /* RTC wakeup stat not possible from S4 */
- uint32_t tmr_val_ext : 1; /* The tmr_val width is 32 bits (0 = 24 bits) */
- uint32_t reserved5 : 23; /* Reserved - must be zero */
-#else
- uint32_t flags;
-#endif
-};
-
-/*
- * MADT values and structures
- */
-
-/* Values for MADT PCATCompat */
-
-#define DUAL_PIC 0
-#define MULTIPLE_APIC 1
-
-
-/* Master MADT */
-
-struct multiple_apic_table
-{
- ACPI_TABLE_HEADER_DEF /* ACPI common table header */
- uint32_t local_apic_address; /* Physical address of local APIC */
-#if 0
- uint32_t PCATcompat : 1; /* A one indicates system also has dual 8259s */
- uint32_t reserved1 : 31;
-#else
- uint32_t flags;
-#endif
-};
-
-
-/* Values for Type in APIC_HEADER_DEF */
-
-#define APIC_PROCESSOR 0
-#define APIC_IO 1
-#define APIC_XRUPT_OVERRIDE 2
-#define APIC_NMI 3
-#define APIC_LOCAL_NMI 4
-#define APIC_ADDRESS_OVERRIDE 5
-#define APIC_IO_SAPIC 6
-#define APIC_LOCAL_SAPIC 7
-#define APIC_XRUPT_SOURCE 8
-#define APIC_RESERVED 9 /* 9 and greater are reserved */
-
-/*
- * MADT sub-structures (Follow MULTIPLE_APIC_DESCRIPTION_TABLE)
- */
-#define APIC_HEADER_DEF /* Common APIC sub-structure header */\
- uint8_t type; \
- uint8_t length;
-
-/* Sub-structures for MADT */
-
-struct madt_processor_apic
-{
- APIC_HEADER_DEF
- uint8_t processor_id; /* ACPI processor id */
- uint8_t local_apic_id; /* Processor's local APIC id */
-#if 0
- uint32_t processor_enabled: 1; /* Processor is usable if set */
- uint32_t reserved2 : 31; /* Reserved, must be zero */
-#else
- uint32_t flags;
-#endif
-};
-
-struct madt_io_apic
-{
- APIC_HEADER_DEF
- uint8_t io_apic_id; /* I/O APIC ID */
- uint8_t reserved; /* Reserved - must be zero */
- uint32_t address; /* APIC physical address */
- uint32_t interrupt; /* Global system interrupt where INTI
- * lines start */
-};
-
-#include "acpi-dsdt.hex"
-
-static int acpi_checksum(const uint8_t *data, int len)
-{
- int sum, i;
- sum = 0;
- for(i = 0; i < len; i++)
- sum += data[i];
- return (-sum) & 0xff;
-}
-
-static void acpi_build_table_header(struct acpi_table_header *h,
- char *sig, int len)
-{
- memcpy(h->signature, sig, 4);
- h->length = cpu_to_le32(len);
- h->revision = 0;
- memcpy(h->oem_id, "QEMU ", 6);
- memcpy(h->oem_table_id, "QEMU", 4);
- memcpy(h->oem_table_id + 4, sig, 4);
- h->oem_revision = cpu_to_le32(1);
- memcpy(h->asl_compiler_id, "QEMU", 4);
- h->asl_compiler_revision = cpu_to_le32(1);
- h->checksum = acpi_checksum((void *)h, len);
-}
-
-#define ACPI_TABLES_BASE 0x000e8000
-
-/* base_addr must be a multiple of 4KB */
-void acpi_bios_init(void)
-{
- struct rsdp_descriptor *rsdp;
- struct rsdt_descriptor_rev1 *rsdt;
- struct fadt_descriptor_rev1 *fadt;
- struct facs_descriptor_rev1 *facs;
- struct multiple_apic_table *madt;
- uint8_t *dsdt;
- uint32_t base_addr, rsdt_addr, fadt_addr, addr, facs_addr, dsdt_addr;
- uint32_t pm_io_base, acpi_tables_size, madt_addr, madt_size;
- int i;
-
- /* compute PCI I/O addresses */
- pm_io_base = (piix4_pm_state->dev.config[0x40] |
- (piix4_pm_state->dev.config[0x41] << 8)) & ~0x3f;
-
- base_addr = ACPI_TABLES_BASE;
-
- /* reserve memory space for tables */
- addr = base_addr;
- rsdp = (void *)(phys_ram_base + addr);
- addr += sizeof(*rsdp);
-
- rsdt_addr = addr;
- rsdt = (void *)(phys_ram_base + addr);
- addr += sizeof(*rsdt);
-
- fadt_addr = addr;
- fadt = (void *)(phys_ram_base + addr);
- addr += sizeof(*fadt);
-
- /* XXX: FACS should be in RAM */
- addr = (addr + 63) & ~63; /* 64 byte alignment for FACS */
- facs_addr = addr;
- facs = (void *)(phys_ram_base + addr);
- addr += sizeof(*facs);
-
- dsdt_addr = addr;
- dsdt = (void *)(phys_ram_base + addr);
- addr += sizeof(AmlCode);
-
- addr = (addr + 7) & ~7;
- madt_addr = addr;
- madt_size = sizeof(*madt) +
- sizeof(struct madt_processor_apic) * smp_cpus +
- sizeof(struct madt_io_apic);
- madt = (void *)(phys_ram_base + addr);
- addr += madt_size;
-
- acpi_tables_size = addr - base_addr;
-
- cpu_register_physical_memory(base_addr, acpi_tables_size,
- base_addr | IO_MEM_ROM);
-
- /* RSDP */
- memset(rsdp, 0, sizeof(*rsdp));
- memcpy(rsdp->signature, "RSD PTR ", 8);
- memcpy(rsdp->oem_id, "QEMU ", 6);
- rsdp->rsdt_physical_address = cpu_to_le32(rsdt_addr);
- rsdp->checksum = acpi_checksum((void *)rsdp, 20);
-
- /* RSDT */
- rsdt->table_offset_entry[0] = cpu_to_le32(fadt_addr);
- rsdt->table_offset_entry[1] = cpu_to_le32(madt_addr);
- acpi_build_table_header((struct acpi_table_header *)rsdt,
- "RSDT", sizeof(*rsdt));
-
- /* FADT */
- memset(fadt, 0, sizeof(*fadt));
- fadt->firmware_ctrl = cpu_to_le32(facs_addr);
- fadt->dsdt = cpu_to_le32(dsdt_addr);
- fadt->model = 1;
- fadt->reserved1 = 0;
- fadt->sci_int = cpu_to_le16(piix4_pm_state->dev.config[0x3c]);
- fadt->smi_cmd = cpu_to_le32(SMI_CMD_IO_ADDR);
- fadt->acpi_enable = 0xf1;
- fadt->acpi_disable = 0xf0;
- fadt->pm1a_evt_blk = cpu_to_le32(pm_io_base);
- fadt->pm1a_cnt_blk = cpu_to_le32(pm_io_base + 0x04);
- fadt->pm_tmr_blk = cpu_to_le32(pm_io_base + 0x08);
- fadt->pm1_evt_len = 4;
- fadt->pm1_cnt_len = 2;
- fadt->pm_tmr_len = 4;
- fadt->plvl2_lat = cpu_to_le16(50);
- fadt->plvl3_lat = cpu_to_le16(50);
- fadt->plvl3_lat = cpu_to_le16(50);
- /* WBINVD + PROC_C1 + PWR_BUTTON + SLP_BUTTON + FIX_RTC */
- fadt->flags = cpu_to_le32((1 << 0) | (1 << 2) | (1 << 4) | (1 << 5) | (1 << 6));
- acpi_build_table_header((struct acpi_table_header *)fadt, "FACP",
- sizeof(*fadt));
-
- /* FACS */
- memset(facs, 0, sizeof(*facs));
- memcpy(facs->signature, "FACS", 4);
- facs->length = cpu_to_le32(sizeof(*facs));
-
- /* DSDT */
- memcpy(dsdt, AmlCode, sizeof(AmlCode));
-
- /* MADT */
- {
- struct madt_processor_apic *apic;
- struct madt_io_apic *io_apic;
-
- memset(madt, 0, madt_size);
- madt->local_apic_address = cpu_to_le32(0xfee00000);
- madt->flags = cpu_to_le32(1);
- apic = (void *)(madt + 1);
- for(i=0;i<smp_cpus;i++) {
- apic->type = APIC_PROCESSOR;
- apic->length = sizeof(*apic);
- apic->processor_id = i;
- apic->local_apic_id = i;
- apic->flags = cpu_to_le32(1);
- apic++;
- }
- io_apic = (void *)apic;
- io_apic->type = APIC_IO;
- io_apic->length = sizeof(*io_apic);
- io_apic->io_apic_id = smp_cpus;
- io_apic->address = cpu_to_le32(0xfec00000);
- io_apic->interrupt = cpu_to_le32(0);
-
- acpi_build_table_header((struct acpi_table_header *)madt,
- "APIC", madt_size);
- }
-}
diff --git a/hw/adb.c b/hw/adb.c
deleted file mode 100644
index 8e08cb1..0000000
--- a/hw/adb.c
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * QEMU ADB support
- *
- * Copyright (c) 2004 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"
-
-/* ADB commands */
-#define ADB_BUSRESET 0x00
-#define ADB_FLUSH 0x01
-#define ADB_WRITEREG 0x08
-#define ADB_READREG 0x0c
-
-/* ADB device commands */
-#define ADB_CMD_SELF_TEST 0xff
-#define ADB_CMD_CHANGE_ID 0xfe
-#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd
-#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00
-
-/* ADB default device IDs (upper 4 bits of ADB command byte) */
-#define ADB_DONGLE 1
-#define ADB_KEYBOARD 2
-#define ADB_MOUSE 3
-#define ADB_TABLET 4
-#define ADB_MODEM 5
-#define ADB_MISC 7
-
-/* error codes */
-#define ADB_RET_NOTPRESENT (-2)
-
-int adb_request(ADBBusState *s, uint8_t *obuf, const uint8_t *buf, int len)
-{
- ADBDevice *d;
- int devaddr, cmd, i;
-
- cmd = buf[0] & 0xf;
- if (cmd == ADB_BUSRESET) {
- for(i = 0; i < s->nb_devices; i++) {
- d = &s->devices[i];
- if (d->devreset) {
- d->devreset(d);
- }
- }
- return 0;
- }
- devaddr = buf[0] >> 4;
- for(i = 0; i < s->nb_devices; i++) {
- d = &s->devices[i];
- if (d->devaddr == devaddr) {
- return d->devreq(d, obuf, buf, len);
- }
- }
- return ADB_RET_NOTPRESENT;
-}
-
-/* XXX: move that to cuda ? */
-int adb_poll(ADBBusState *s, uint8_t *obuf)
-{
- ADBDevice *d;
- int olen, i;
- uint8_t buf[1];
-
- olen = 0;
- for(i = 0; i < s->nb_devices; i++) {
- if (s->poll_index >= s->nb_devices)
- s->poll_index = 0;
- d = &s->devices[s->poll_index];
- buf[0] = ADB_READREG | (d->devaddr << 4);
- olen = adb_request(s, obuf + 1, buf, 1);
- /* if there is data, we poll again the same device */
- if (olen > 0) {
- obuf[0] = buf[0];
- olen++;
- break;
- }
- s->poll_index++;
- }
- return olen;
-}
-
-ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
- ADBDeviceRequest *devreq,
- ADBDeviceReset *devreset,
- void *opaque)
-{
- ADBDevice *d;
- if (s->nb_devices >= MAX_ADB_DEVICES)
- return NULL;
- d = &s->devices[s->nb_devices++];
- d->bus = s;
- d->devaddr = devaddr;
- d->devreq = devreq;
- d->devreset = devreset;
- d->opaque = opaque;
- return d;
-}
-
-/***************************************************************/
-/* Keyboard ADB device */
-
-typedef struct KBDState {
- uint8_t data[128];
- int rptr, wptr, count;
-} KBDState;
-
-static const uint8_t pc_to_adb_keycode[256] = {
- 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48,
- 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1,
- 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9,
- 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96,
- 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83,
- 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0,110, 81, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76,125, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 75, 0, 0,124, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0,115, 62,116, 0, 59, 0, 60, 0,119,
- 61,121,114,117, 0, 0, 0, 0, 0, 0, 0, 55,126, 0,127, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-static void adb_kbd_put_keycode(void *opaque, int keycode)
-{
- ADBDevice *d = opaque;
- KBDState *s = d->opaque;
-
- if (s->count < sizeof(s->data)) {
- s->data[s->wptr] = keycode;
- if (++s->wptr == sizeof(s->data))
- s->wptr = 0;
- s->count++;
- }
-}
-
-static int adb_kbd_poll(ADBDevice *d, uint8_t *obuf)
-{
- static int ext_keycode;
- KBDState *s = d->opaque;
- int adb_keycode, keycode;
- int olen;
-
- olen = 0;
- for(;;) {
- if (s->count == 0)
- break;
- keycode = s->data[s->rptr];
- if (++s->rptr == sizeof(s->data))
- s->rptr = 0;
- s->count--;
-
- if (keycode == 0xe0) {
- ext_keycode = 1;
- } else {
- if (ext_keycode)
- adb_keycode = pc_to_adb_keycode[keycode | 0x80];
- else
- adb_keycode = pc_to_adb_keycode[keycode & 0x7f];
- obuf[0] = adb_keycode | (keycode & 0x80);
- /* NOTE: could put a second keycode if needed */
- obuf[1] = 0xff;
- olen = 2;
- ext_keycode = 0;
- break;
- }
- }
- return olen;
-}
-
-static int adb_kbd_request(ADBDevice *d, uint8_t *obuf,
- const uint8_t *buf, int len)
-{
- KBDState *s = d->opaque;
- int cmd, reg, olen;
-
- if ((buf[0] & 0x0f) == ADB_FLUSH) {
- /* flush keyboard fifo */
- s->wptr = s->rptr = s->count = 0;
- return 0;
- }
-
- cmd = buf[0] & 0xc;
- reg = buf[0] & 0x3;
- olen = 0;
- switch(cmd) {
- case ADB_WRITEREG:
- switch(reg) {
- case 2:
- /* LED status */
- break;
- case 3:
- switch(buf[2]) {
- case ADB_CMD_SELF_TEST:
- break;
- case ADB_CMD_CHANGE_ID:
- case ADB_CMD_CHANGE_ID_AND_ACT:
- case ADB_CMD_CHANGE_ID_AND_ENABLE:
- d->devaddr = buf[1] & 0xf;
- break;
- default:
- /* XXX: check this */
- d->devaddr = buf[1] & 0xf;
- d->handler = buf[2];
- break;
- }
- }
- break;
- case ADB_READREG:
- switch(reg) {
- case 0:
- olen = adb_kbd_poll(d, obuf);
- break;
- case 1:
- break;
- case 2:
- obuf[0] = 0x00; /* XXX: check this */
- obuf[1] = 0x07; /* led status */
- olen = 2;
- break;
- case 3:
- obuf[0] = d->handler;
- obuf[1] = d->devaddr;
- olen = 2;
- break;
- }
- break;
- }
- return olen;
-}
-
-static int adb_kbd_reset(ADBDevice *d)
-{
- KBDState *s = d->opaque;
-
- d->handler = 1;
- d->devaddr = ADB_KEYBOARD;
- memset(s, 0, sizeof(KBDState));
-
- return 0;
-}
-
-void adb_kbd_init(ADBBusState *bus)
-{
- ADBDevice *d;
- KBDState *s;
- s = qemu_mallocz(sizeof(KBDState));
- d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_request,
- adb_kbd_reset, s);
- adb_kbd_reset(d);
- qemu_add_kbd_event_handler(adb_kbd_put_keycode, d);
-}
-
-/***************************************************************/
-/* Mouse ADB device */
-
-typedef struct MouseState {
- int buttons_state, last_buttons_state;
- int dx, dy, dz;
-} MouseState;
-
-static void adb_mouse_event(void *opaque,
- int dx1, int dy1, int dz1, int buttons_state)
-{
- ADBDevice *d = opaque;
- MouseState *s = d->opaque;
-
- s->dx += dx1;
- s->dy += dy1;
- s->dz += dz1;
- s->buttons_state = buttons_state;
-}
-
-
-static int adb_mouse_poll(ADBDevice *d, uint8_t *obuf)
-{
- MouseState *s = d->opaque;
- int dx, dy;
-
- if (s->last_buttons_state == s->buttons_state &&
- s->dx == 0 && s->dy == 0)
- return 0;
-
- dx = s->dx;
- if (dx < -63)
- dx = -63;
- else if (dx > 63)
- dx = 63;
-
- dy = s->dy;
- if (dy < -63)
- dy = -63;
- else if (dy > 63)
- dy = 63;
-
- s->dx -= dx;
- s->dy -= dy;
- s->last_buttons_state = s->buttons_state;
-
- dx &= 0x7f;
- dy &= 0x7f;
-
- if (!(s->buttons_state & MOUSE_EVENT_LBUTTON))
- dy |= 0x80;
- if (!(s->buttons_state & MOUSE_EVENT_RBUTTON))
- dx |= 0x80;
-
- obuf[0] = dy;
- obuf[1] = dx;
- return 2;
-}
-
-static int adb_mouse_request(ADBDevice *d, uint8_t *obuf,
- const uint8_t *buf, int len)
-{
- MouseState *s = d->opaque;
- int cmd, reg, olen;
-
- if ((buf[0] & 0x0f) == ADB_FLUSH) {
- /* flush mouse fifo */
- s->buttons_state = s->last_buttons_state;
- s->dx = 0;
- s->dy = 0;
- s->dz = 0;
- return 0;
- }
-
- cmd = buf[0] & 0xc;
- reg = buf[0] & 0x3;
- olen = 0;
- switch(cmd) {
- case ADB_WRITEREG:
- switch(reg) {
- case 2:
- break;
- case 3:
- switch(buf[2]) {
- case ADB_CMD_SELF_TEST:
- break;
- case ADB_CMD_CHANGE_ID:
- case ADB_CMD_CHANGE_ID_AND_ACT:
- case ADB_CMD_CHANGE_ID_AND_ENABLE:
- d->devaddr = buf[1] & 0xf;
- break;
- default:
- /* XXX: check this */
- d->devaddr = buf[1] & 0xf;
- break;
- }
- }
- break;
- case ADB_READREG:
- switch(reg) {
- case 0:
- olen = adb_mouse_poll(d, obuf);
- break;
- case 1:
- break;
- case 3:
- obuf[0] = d->handler;
- obuf[1] = d->devaddr;
- olen = 2;
- break;
- }
- break;
- }
- return olen;
-}
-
-static int adb_mouse_reset(ADBDevice *d)
-{
- MouseState *s = d->opaque;
-
- d->handler = 2;
- d->devaddr = ADB_MOUSE;
- memset(s, 0, sizeof(MouseState));
-
- return 0;
-}
-
-void adb_mouse_init(ADBBusState *bus)
-{
- ADBDevice *d;
- MouseState *s;
-
- s = qemu_mallocz(sizeof(MouseState));
- d = adb_register_device(bus, ADB_MOUSE, adb_mouse_request,
- adb_mouse_reset, s);
- adb_mouse_reset(d);
- qemu_add_mouse_event_handler(adb_mouse_event, d, 0);
-}
diff --git a/hw/adlib.c b/hw/adlib.c
deleted file mode 100644
index b47bc3e..0000000
--- a/hw/adlib.c
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * QEMU Proxy for OPL2/3 emulation by MAME team
- *
- * Copyright (c) 2004-2005 Vassili Karpov (malc)
- *
- * 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 <assert.h>
-#include "vl.h"
-
-#define ADLIB_KILL_TIMERS 1
-
-#define dolog(...) AUD_log ("adlib", __VA_ARGS__)
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
-
-#ifdef HAS_YMF262
-#include "ymf262.h"
-void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
-#define SHIFT 2
-#else
-#include "fmopl.h"
-#define SHIFT 1
-#endif
-
-#define IO_READ_PROTO(name) \
- uint32_t name (void *opaque, uint32_t nport)
-#define IO_WRITE_PROTO(name) \
- void name (void *opaque, uint32_t nport, uint32_t val)
-
-static struct {
- int port;
- int freq;
-} conf = {0x220, 44100};
-
-typedef struct {
- QEMUSoundCard card;
- int ticking[2];
- int enabled;
- int active;
- int bufpos;
-#ifdef DEBUG
- int64_t exp[2];
-#endif
- int16_t *mixbuf;
- uint64_t dexp[2];
- SWVoiceOut *voice;
- int left, pos, samples;
- QEMUAudioTimeStamp ats;
-#ifndef HAS_YMF262
- FM_OPL *opl;
-#endif
-} AdlibState;
-
-static AdlibState glob_adlib;
-
-static void adlib_stop_opl_timer (AdlibState *s, size_t n)
-{
-#ifdef HAS_YMF262
- YMF262TimerOver (0, n);
-#else
- OPLTimerOver (s->opl, n);
-#endif
- s->ticking[n] = 0;
-}
-
-static void adlib_kill_timers (AdlibState *s)
-{
- size_t i;
-
- for (i = 0; i < 2; ++i) {
- if (s->ticking[i]) {
- uint64_t delta;
-
- delta = AUD_get_elapsed_usec_out (s->voice, &s->ats);
- ldebug (
- "delta = %f dexp = %f expired => %d\n",
- delta / 1000000.0,
- s->dexp[i] / 1000000.0,
- delta >= s->dexp[i]
- );
- if (ADLIB_KILL_TIMERS || delta >= s->dexp[i]) {
- adlib_stop_opl_timer (s, i);
- AUD_init_time_stamp_out (s->voice, &s->ats);
- }
- }
- }
-}
-
-static IO_WRITE_PROTO(adlib_write)
-{
- AdlibState *s = opaque;
- int a = nport & 3;
- int status;
-
- s->active = 1;
- AUD_set_active_out (s->voice, 1);
-
- adlib_kill_timers (s);
-
-#ifdef HAS_YMF262
- status = YMF262Write (0, a, val);
-#else
- status = OPLWrite (s->opl, a, val);
-#endif
-}
-
-static IO_READ_PROTO(adlib_read)
-{
- AdlibState *s = opaque;
- uint8_t data;
- int a = nport & 3;
-
- adlib_kill_timers (s);
-
-#ifdef HAS_YMF262
- data = YMF262Read (0, a);
-#else
- data = OPLRead (s->opl, a);
-#endif
- return data;
-}
-
-static void timer_handler (int c, double interval_Sec)
-{
- AdlibState *s = &glob_adlib;
- unsigned n = c & 1;
-#ifdef DEBUG
- double interval;
- int64_t exp;
-#endif
-
- if (interval_Sec == 0.0) {
- s->ticking[n] = 0;
- return;
- }
-
- s->ticking[n] = 1;
-#ifdef DEBUG
- interval = ticks_per_sec * interval_Sec;
- exp = qemu_get_clock (vm_clock) + interval;
- s->exp[n] = exp;
-#endif
-
- s->dexp[n] = interval_Sec * 1000000.0;
- AUD_init_time_stamp_out (s->voice, &s->ats);
-}
-
-static int write_audio (AdlibState *s, int samples)
-{
- int net = 0;
- int pos = s->pos;
-
- while (samples) {
- int nbytes, wbytes, wsampl;
-
- nbytes = samples << SHIFT;
- wbytes = AUD_write (
- s->voice,
- s->mixbuf + (pos << (SHIFT - 1)),
- nbytes
- );
-
- if (wbytes) {
- wsampl = wbytes >> SHIFT;
-
- samples -= wsampl;
- pos = (pos + wsampl) % s->samples;
-
- net += wsampl;
- }
- else {
- break;
- }
- }
-
- return net;
-}
-
-static void adlib_callback (void *opaque, int free)
-{
- AdlibState *s = opaque;
- int samples, net = 0, to_play, written;
-
- samples = free >> SHIFT;
- if (!(s->active && s->enabled) || !samples) {
- return;
- }
-
- to_play = audio_MIN (s->left, samples);
- while (to_play) {
- written = write_audio (s, to_play);
-
- if (written) {
- s->left -= written;
- samples -= written;
- to_play -= written;
- s->pos = (s->pos + written) % s->samples;
- }
- else {
- return;
- }
- }
-
- samples = audio_MIN (samples, s->samples - s->pos);
- if (!samples) {
- return;
- }
-
-#ifdef HAS_YMF262
- YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
-#else
- YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
-#endif
-
- while (samples) {
- written = write_audio (s, samples);
-
- if (written) {
- net += written;
- samples -= written;
- s->pos = (s->pos + written) % s->samples;
- }
- else {
- s->left = samples;
- return;
- }
- }
-}
-
-static void Adlib_fini (AdlibState *s)
-{
-#ifdef HAS_YMF262
- YMF262Shutdown ();
-#else
- if (s->opl) {
- OPLDestroy (s->opl);
- s->opl = NULL;
- }
-#endif
-
- if (s->mixbuf) {
- qemu_free (s->mixbuf);
- }
-
- s->active = 0;
- s->enabled = 0;
- AUD_remove_card (&s->card);
-}
-
-int Adlib_init (AudioState *audio)
-{
- AdlibState *s = &glob_adlib;
- audsettings_t as;
-
- if (!audio) {
- dolog ("No audio state\n");
- return -1;
- }
-
-#ifdef HAS_YMF262
- if (YMF262Init (1, 14318180, conf.freq)) {
- dolog ("YMF262Init %d failed\n", conf.freq);
- return -1;
- }
- else {
- YMF262SetTimerHandler (0, timer_handler, 0);
- s->enabled = 1;
- }
-#else
- s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, conf.freq);
- if (!s->opl) {
- dolog ("OPLCreate %d failed\n", conf.freq);
- return -1;
- }
- else {
- OPLSetTimerHandler (s->opl, timer_handler, 0);
- s->enabled = 1;
- }
-#endif
-
- as.freq = conf.freq;
- as.nchannels = SHIFT;
- as.fmt = AUD_FMT_S16;
- as.endianness = AUDIO_HOST_ENDIANNESS;
-
- AUD_register_card (audio, "adlib", &s->card);
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "adlib",
- s,
- adlib_callback,
- &as
- );
- if (!s->voice) {
- Adlib_fini (s);
- return -1;
- }
-
- s->samples = AUD_get_buffer_size_out (s->voice) >> SHIFT;
- s->mixbuf = qemu_mallocz (s->samples << SHIFT);
-
- if (!s->mixbuf) {
- dolog ("Could not allocate mixing buffer, %d samples (each %d bytes)\n",
- s->samples, 1 << SHIFT);
- Adlib_fini (s);
- return -1;
- }
-
- register_ioport_read (0x388, 4, 1, adlib_read, s);
- register_ioport_write (0x388, 4, 1, adlib_write, s);
-
- register_ioport_read (conf.port, 4, 1, adlib_read, s);
- register_ioport_write (conf.port, 4, 1, adlib_write, s);
-
- register_ioport_read (conf.port + 8, 2, 1, adlib_read, s);
- register_ioport_write (conf.port + 8, 2, 1, adlib_write, s);
-
- return 0;
-}
diff --git a/hw/android_arm.c b/hw/android_arm.c
new file mode 100644
index 0000000..7b1d446
--- /dev/null
+++ b/hw/android_arm.c
@@ -0,0 +1,149 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "arm_pic.h"
+#include "goldfish_device.h"
+
+int android_audio_enabled;
+char* audio_input_source = NULL;
+
+void goldfish_memlog_init(uint32_t base);
+
+static struct goldfish_device event0_device = {
+ .name = "goldfish_events",
+ .id = 0,
+ .size = 0x1000,
+ .irq_count = 1
+};
+
+static struct goldfish_device nand_device = {
+ .name = "goldfish_nand",
+ .id = 0,
+ .size = 0x1000
+};
+
+static struct goldfish_device trace_device = {
+ .name = "qemu_trace",
+ .id = -1,
+ .size = 0x1000
+};
+
+/* Board init. */
+
+#define TEST_SWITCH 1
+#if TEST_SWITCH
+uint32_t switch_test_write(void *opaque, uint32_t state)
+{
+ goldfish_switch_set_state(opaque, state);
+ return state;
+}
+#endif
+
+static void android_arm_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)
+{
+ CPUState *env;
+ qemu_irq *cpu_pic;
+ qemu_irq *goldfish_pic;
+ int i;
+
+ env = cpu_init();
+ cpu_arm_set_model(env, ARM_CPUID_ARM926);
+
+ register_savevm( "cpu", 0, ARM_CPU_SAVE_VERSION, cpu_save, cpu_load, env );
+
+ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+
+ cpu_pic = arm_pic_init_cpu(env);
+ goldfish_pic = goldfish_interrupt_init(0xff000000, cpu_pic[ARM_PIC_CPU_IRQ], cpu_pic[ARM_PIC_CPU_FIQ]);
+ goldfish_device_init(goldfish_pic, 0xff010000, 0x7f0000, 10, 22);
+
+ goldfish_device_bus_init(0xff001000, 1);
+
+ goldfish_timer_and_rtc_init(0xff003000, 3);
+
+ goldfish_tty_add(serial_hds[0], 0, 0xff002000, 4);
+ for(i = 1; i < MAX_SERIAL_PORTS; i++) {
+ //printf("android_arm_init serial %d %x\n", i, serial_hds[i]);
+ if(serial_hds[i]) {
+ goldfish_tty_add(serial_hds[i], i, 0, 0);
+ }
+ }
+
+ for(i = 0; i < MAX_NICS; i++) {
+ if (nd_table[i].vlan) {
+ if (nd_table[i].model == NULL
+ || strcmp(nd_table[i].model, "smc91c111") == 0) {
+ struct goldfish_device *smc_device;
+ smc_device = qemu_mallocz(sizeof(*smc_device));
+ smc_device->name = "smc91x";
+ smc_device->id = i;
+ smc_device->size = 0x1000;
+ smc_device->irq_count = 1;
+ goldfish_add_device_no_io(smc_device);
+ smc91c111_init(&nd_table[i], smc_device->base, goldfish_pic[smc_device->irq]);
+ } else {
+ fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
+ exit (1);
+ }
+ }
+ }
+
+ goldfish_fb_init(ds, 0);
+#ifdef HAS_AUDIO
+ if (android_audio_enabled) {
+ AUD_init();
+ goldfish_audio_init(0xff004000, 0, audio_input_source);
+ }
+#endif
+ if (bs_table[0])
+ goldfish_mmc_init(0xff005000, 0, bs_table[0]);
+
+ goldfish_memlog_init(0xff006000);
+
+ goldfish_battery_init();
+
+ goldfish_add_device_no_io(&event0_device);
+ events_dev_init(event0_device.base, goldfish_pic[event0_device.irq]);
+
+#ifdef CONFIG_NAND
+ goldfish_add_device_no_io(&nand_device);
+ nand_dev_init(nand_device.base);
+#endif
+#ifdef CONFIG_TRACE
+ extern const char *trace_filename;
+ if(trace_filename != NULL) {
+ goldfish_add_device_no_io(&trace_device);
+ trace_dev_init(trace_device.base);
+ }
+#endif
+
+#if TEST_SWITCH
+ {
+ void *sw;
+ sw = goldfish_switch_add("test", NULL, NULL, 0);
+ goldfish_switch_set_state(sw, 1);
+ goldfish_switch_add("test2", switch_test_write, sw, 1);
+ }
+#endif
+
+ arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
+ initrd_filename, 1441);
+}
+
+QEMUMachine android_arm_machine = {
+ "android_arm",
+ "ARM Android Emulator",
+ android_arm_init,
+};
diff --git a/hw/apb_pci.c b/hw/apb_pci.c
deleted file mode 100644
index 02e9824..0000000
--- a/hw/apb_pci.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * QEMU Ultrasparc APB PCI host
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "vl.h"
-typedef target_phys_addr_t pci_addr_t;
-#include "pci_host.h"
-
-typedef PCIHostState APBState;
-
-static void pci_apb_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- APBState *s = opaque;
- int i;
-
- for (i = 11; i < 32; i++) {
- if ((val & (1 << i)) != 0)
- break;
- }
- s->config_reg = (1 << 16) | (val & 0x7FC) | (i << 11);
-}
-
-static uint32_t pci_apb_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- APBState *s = opaque;
- uint32_t val;
- int devfn;
-
- devfn = (s->config_reg >> 8) & 0xFF;
- val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_config_write[] = {
- &pci_apb_config_writel,
- &pci_apb_config_writel,
- &pci_apb_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_apb_config_read[] = {
- &pci_apb_config_readl,
- &pci_apb_config_readl,
- &pci_apb_config_readl,
-};
-
-static void apb_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- //PCIBus *s = opaque;
-
- switch (addr & 0x3f) {
- case 0x00: // Control/Status
- case 0x10: // AFSR
- case 0x18: // AFAR
- case 0x20: // Diagnostic
- case 0x28: // Target address space
- // XXX
- default:
- break;
- }
-}
-
-static uint32_t apb_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- //PCIBus *s = opaque;
- uint32_t val;
-
- switch (addr & 0x3f) {
- case 0x00: // Control/Status
- case 0x10: // AFSR
- case 0x18: // AFAR
- case 0x20: // Diagnostic
- case 0x28: // Target address space
- // XXX
- default:
- val = 0;
- break;
- }
- return val;
-}
-
-static CPUWriteMemoryFunc *apb_config_write[] = {
- &apb_config_writel,
- &apb_config_writel,
- &apb_config_writel,
-};
-
-static CPUReadMemoryFunc *apb_config_read[] = {
- &apb_config_readl,
- &apb_config_readl,
- &apb_config_readl,
-};
-
-static CPUWriteMemoryFunc *pci_apb_write[] = {
- &pci_host_data_writeb,
- &pci_host_data_writew,
- &pci_host_data_writel,
-};
-
-static CPUReadMemoryFunc *pci_apb_read[] = {
- &pci_host_data_readb,
- &pci_host_data_readw,
- &pci_host_data_readl,
-};
-
-static void pci_apb_iowriteb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- cpu_outb(NULL, addr & 0xffff, val);
-}
-
-static void pci_apb_iowritew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- cpu_outw(NULL, addr & 0xffff, val);
-}
-
-static void pci_apb_iowritel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- cpu_outl(NULL, addr & 0xffff, val);
-}
-
-static uint32_t pci_apb_ioreadb (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
-
- val = cpu_inb(NULL, addr & 0xffff);
- return val;
-}
-
-static uint32_t pci_apb_ioreadw (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
-
- val = cpu_inw(NULL, addr & 0xffff);
- return val;
-}
-
-static uint32_t pci_apb_ioreadl (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
-
- val = cpu_inl(NULL, addr & 0xffff);
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_apb_iowrite[] = {
- &pci_apb_iowriteb,
- &pci_apb_iowritew,
- &pci_apb_iowritel,
-};
-
-static CPUReadMemoryFunc *pci_apb_ioread[] = {
- &pci_apb_ioreadb,
- &pci_apb_ioreadw,
- &pci_apb_ioreadl,
-};
-
-/* ??? This is probably wrong. */
-static void pci_apb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
-{
- pic_set_irq_new(pic, d->config[PCI_INTERRUPT_LINE], level);
-}
-
-PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
- void *pic)
-{
- APBState *s;
- PCIDevice *d;
- int pci_mem_config, pci_mem_data, apb_config, pci_ioport;
-
- s = qemu_mallocz(sizeof(APBState));
- /* Ultrasparc APB main bus */
- s->bus = pci_register_bus(pci_apb_set_irq, pic, 0);
-
- pci_mem_config = cpu_register_io_memory(0, pci_apb_config_read,
- pci_apb_config_write, s);
- apb_config = cpu_register_io_memory(0, apb_config_read,
- apb_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_apb_read,
- pci_apb_write, s);
- pci_ioport = cpu_register_io_memory(0, pci_apb_ioread,
- pci_apb_iowrite, s);
-
- cpu_register_physical_memory(special_base + 0x2000ULL, 0x40, apb_config);
- cpu_register_physical_memory(special_base + 0x1000000ULL, 0x10, pci_mem_config);
- cpu_register_physical_memory(special_base + 0x2000000ULL, 0x10000, pci_ioport);
- cpu_register_physical_memory(mem_base, 0x10000000, pci_mem_data); // XXX size should be 4G-prom
-
- d = pci_register_device(s->bus, "Advanced PCI Bus", sizeof(PCIDevice),
- -1, NULL, NULL);
- d->config[0x00] = 0x8e; // vendor_id : Sun
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x00; // device_id
- d->config[0x03] = 0xa0;
- d->config[0x04] = 0x06; // command = bus master, pci mem
- d->config[0x05] = 0x00;
- d->config[0x06] = 0xa0; // status = fast back-to-back, 66MHz, no error
- d->config[0x07] = 0x03; // status = medium devsel
- d->config[0x08] = 0x00; // revision
- d->config[0x09] = 0x00; // programming i/f
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- return s->bus;
-}
-
-
diff --git a/hw/apic.c b/hw/apic.c
deleted file mode 100644
index 8f88cce..0000000
--- a/hw/apic.c
+++ /dev/null
@@ -1,1042 +0,0 @@
-/*
- * APIC support
- *
- * Copyright (c) 2004-2005 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include "vl.h"
-
-//#define DEBUG_APIC
-//#define DEBUG_IOAPIC
-
-/* APIC Local Vector Table */
-#define APIC_LVT_TIMER 0
-#define APIC_LVT_THERMAL 1
-#define APIC_LVT_PERFORM 2
-#define APIC_LVT_LINT0 3
-#define APIC_LVT_LINT1 4
-#define APIC_LVT_ERROR 5
-#define APIC_LVT_NB 6
-
-/* APIC delivery modes */
-#define APIC_DM_FIXED 0
-#define APIC_DM_LOWPRI 1
-#define APIC_DM_SMI 2
-#define APIC_DM_NMI 4
-#define APIC_DM_INIT 5
-#define APIC_DM_SIPI 6
-#define APIC_DM_EXTINT 7
-
-/* APIC destination mode */
-#define APIC_DESTMODE_FLAT 0xf
-#define APIC_DESTMODE_CLUSTER 1
-
-#define APIC_TRIGGER_EDGE 0
-#define APIC_TRIGGER_LEVEL 1
-
-#define APIC_LVT_TIMER_PERIODIC (1<<17)
-#define APIC_LVT_MASKED (1<<16)
-#define APIC_LVT_LEVEL_TRIGGER (1<<15)
-#define APIC_LVT_REMOTE_IRR (1<<14)
-#define APIC_INPUT_POLARITY (1<<13)
-#define APIC_SEND_PENDING (1<<12)
-
-#define IOAPIC_NUM_PINS 0x18
-
-#define ESR_ILLEGAL_ADDRESS (1 << 7)
-
-#define APIC_SV_ENABLE (1 << 8)
-
-#define MAX_APICS 255
-#define MAX_APIC_WORDS 8
-
-typedef struct APICState {
- CPUState *cpu_env;
- uint32_t apicbase;
- uint8_t id;
- uint8_t arb_id;
- uint8_t tpr;
- uint32_t spurious_vec;
- uint8_t log_dest;
- uint8_t dest_mode;
- uint32_t isr[8]; /* in service register */
- uint32_t tmr[8]; /* trigger mode register */
- uint32_t irr[8]; /* interrupt request register */
- uint32_t lvt[APIC_LVT_NB];
- uint32_t esr; /* error register */
- uint32_t icr[2];
-
- uint32_t divide_conf;
- int count_shift;
- uint32_t initial_count;
- int64_t initial_count_load_time, next_time;
- QEMUTimer *timer;
-} APICState;
-
-struct IOAPICState {
- uint8_t id;
- uint8_t ioregsel;
-
- uint32_t irr;
- uint64_t ioredtbl[IOAPIC_NUM_PINS];
-};
-
-static int apic_io_memory;
-static APICState *local_apics[MAX_APICS + 1];
-static int last_apic_id = 0;
-
-static void apic_init_ipi(APICState *s);
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
-static void apic_update_irq(APICState *s);
-
-/* Find first bit starting from msb. Return 0 if value = 0 */
-static int fls_bit(uint32_t value)
-{
- unsigned int ret = 0;
-
-#if defined(HOST_I386)
- __asm__ __volatile__ ("bsr %1, %0\n" : "+r" (ret) : "rm" (value));
- return ret;
-#else
- if (value > 0xffff)
- value >>= 16, ret = 16;
- if (value > 0xff)
- value >>= 8, ret += 8;
- if (value > 0xf)
- value >>= 4, ret += 4;
- if (value > 0x3)
- value >>= 2, ret += 2;
- return ret + (value >> 1);
-#endif
-}
-
-/* Find first bit starting from lsb. Return 0 if value = 0 */
-static int ffs_bit(uint32_t value)
-{
- unsigned int ret = 0;
-
-#if defined(HOST_I386)
- __asm__ __volatile__ ("bsf %1, %0\n" : "+r" (ret) : "rm" (value));
- return ret;
-#else
- if (!value)
- return 0;
- if (!(value & 0xffff))
- value >>= 16, ret = 16;
- if (!(value & 0xff))
- value >>= 8, ret += 8;
- if (!(value & 0xf))
- value >>= 4, ret += 4;
- if (!(value & 0x3))
- value >>= 2, ret += 2;
- if (!(value & 0x1))
- ret++;
- return ret;
-#endif
-}
-
-static inline void set_bit(uint32_t *tab, int index)
-{
- int i, mask;
- i = index >> 5;
- mask = 1 << (index & 0x1f);
- tab[i] |= mask;
-}
-
-static inline void reset_bit(uint32_t *tab, int index)
-{
- int i, mask;
- i = index >> 5;
- mask = 1 << (index & 0x1f);
- tab[i] &= ~mask;
-}
-
-#define foreach_apic(apic, deliver_bitmask, code) \
-{\
- int __i, __j, __mask;\
- for(__i = 0; __i < MAX_APIC_WORDS; __i++) {\
- __mask = deliver_bitmask[__i];\
- if (__mask) {\
- for(__j = 0; __j < 32; __j++) {\
- if (__mask & (1 << __j)) {\
- apic = local_apics[__i * 32 + __j];\
- if (apic) {\
- code;\
- }\
- }\
- }\
- }\
- }\
-}
-
-static void apic_bus_deliver(const uint32_t *deliver_bitmask,
- uint8_t delivery_mode,
- uint8_t vector_num, uint8_t polarity,
- uint8_t trigger_mode)
-{
- APICState *apic_iter;
-
- switch (delivery_mode) {
- case APIC_DM_LOWPRI:
- /* XXX: search for focus processor, arbitration */
- {
- int i, d;
- d = -1;
- for(i = 0; i < MAX_APIC_WORDS; i++) {
- if (deliver_bitmask[i]) {
- d = i * 32 + ffs_bit(deliver_bitmask[i]);
- break;
- }
- }
- if (d >= 0) {
- apic_iter = local_apics[d];
- if (apic_iter) {
- apic_set_irq(apic_iter, vector_num, trigger_mode);
- }
- }
- }
- return;
-
- case APIC_DM_FIXED:
- break;
-
- case APIC_DM_SMI:
- case APIC_DM_NMI:
- break;
-
- case APIC_DM_INIT:
- /* normal INIT IPI sent to processors */
- foreach_apic(apic_iter, deliver_bitmask,
- apic_init_ipi(apic_iter) );
- return;
-
- case APIC_DM_EXTINT:
- /* handled in I/O APIC code */
- break;
-
- default:
- return;
- }
-
- foreach_apic(apic_iter, deliver_bitmask,
- apic_set_irq(apic_iter, vector_num, trigger_mode) );
-}
-
-void cpu_set_apic_base(CPUState *env, uint64_t val)
-{
- APICState *s = env->apic_state;
-#ifdef DEBUG_APIC
- printf("cpu_set_apic_base: %016" PRIx64 "\n", val);
-#endif
- s->apicbase = (val & 0xfffff000) |
- (s->apicbase & (MSR_IA32_APICBASE_BSP | MSR_IA32_APICBASE_ENABLE));
- /* if disabled, cannot be enabled again */
- if (!(val & MSR_IA32_APICBASE_ENABLE)) {
- s->apicbase &= ~MSR_IA32_APICBASE_ENABLE;
- env->cpuid_features &= ~CPUID_APIC;
- s->spurious_vec &= ~APIC_SV_ENABLE;
- }
-}
-
-uint64_t cpu_get_apic_base(CPUState *env)
-{
- APICState *s = env->apic_state;
-#ifdef DEBUG_APIC
- printf("cpu_get_apic_base: %016" PRIx64 "\n", (uint64_t)s->apicbase);
-#endif
- return s->apicbase;
-}
-
-void cpu_set_apic_tpr(CPUX86State *env, uint8_t val)
-{
- APICState *s = env->apic_state;
- s->tpr = (val & 0x0f) << 4;
- apic_update_irq(s);
-}
-
-uint8_t cpu_get_apic_tpr(CPUX86State *env)
-{
- APICState *s = env->apic_state;
- return s->tpr >> 4;
-}
-
-/* return -1 if no bit is set */
-static int get_highest_priority_int(uint32_t *tab)
-{
- int i;
- for(i = 7; i >= 0; i--) {
- if (tab[i] != 0) {
- return i * 32 + fls_bit(tab[i]);
- }
- }
- return -1;
-}
-
-static int apic_get_ppr(APICState *s)
-{
- int tpr, isrv, ppr;
-
- tpr = (s->tpr >> 4);
- isrv = get_highest_priority_int(s->isr);
- if (isrv < 0)
- isrv = 0;
- isrv >>= 4;
- if (tpr >= isrv)
- ppr = s->tpr;
- else
- ppr = isrv << 4;
- return ppr;
-}
-
-static int apic_get_arb_pri(APICState *s)
-{
- /* XXX: arbitration */
- return 0;
-}
-
-/* signal the CPU if an irq is pending */
-static void apic_update_irq(APICState *s)
-{
- int irrv, ppr;
- if (!(s->spurious_vec & APIC_SV_ENABLE))
- return;
- irrv = get_highest_priority_int(s->irr);
- if (irrv < 0)
- return;
- ppr = apic_get_ppr(s);
- if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
- return;
- cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
-}
-
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
-{
- set_bit(s->irr, vector_num);
- if (trigger_mode)
- set_bit(s->tmr, vector_num);
- else
- reset_bit(s->tmr, vector_num);
- apic_update_irq(s);
-}
-
-static void apic_eoi(APICState *s)
-{
- int isrv;
- isrv = get_highest_priority_int(s->isr);
- if (isrv < 0)
- return;
- reset_bit(s->isr, isrv);
- /* XXX: send the EOI packet to the APIC bus to allow the I/O APIC to
- set the remote IRR bit for level triggered interrupts. */
- apic_update_irq(s);
-}
-
-static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
- uint8_t dest, uint8_t dest_mode)
-{
- APICState *apic_iter;
- int i;
-
- if (dest_mode == 0) {
- if (dest == 0xff) {
- memset(deliver_bitmask, 0xff, MAX_APIC_WORDS * sizeof(uint32_t));
- } else {
- memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
- set_bit(deliver_bitmask, dest);
- }
- } else {
- /* XXX: cluster mode */
- memset(deliver_bitmask, 0x00, MAX_APIC_WORDS * sizeof(uint32_t));
- for(i = 0; i < MAX_APICS; i++) {
- apic_iter = local_apics[i];
- if (apic_iter) {
- if (apic_iter->dest_mode == 0xf) {
- if (dest & apic_iter->log_dest)
- set_bit(deliver_bitmask, i);
- } else if (apic_iter->dest_mode == 0x0) {
- if ((dest & 0xf0) == (apic_iter->log_dest & 0xf0) &&
- (dest & apic_iter->log_dest & 0x0f)) {
- set_bit(deliver_bitmask, i);
- }
- }
- }
- }
- }
-}
-
-
-static void apic_init_ipi(APICState *s)
-{
- int i;
-
- for(i = 0; i < APIC_LVT_NB; i++)
- s->lvt[i] = 1 << 16; /* mask LVT */
- s->tpr = 0;
- s->spurious_vec = 0xff;
- s->log_dest = 0;
- s->dest_mode = 0xf;
- memset(s->isr, 0, sizeof(s->isr));
- memset(s->tmr, 0, sizeof(s->tmr));
- memset(s->irr, 0, sizeof(s->irr));
- memset(s->lvt, 0, sizeof(s->lvt));
- s->esr = 0;
- memset(s->icr, 0, sizeof(s->icr));
- s->divide_conf = 0;
- s->count_shift = 0;
- s->initial_count = 0;
- s->initial_count_load_time = 0;
- s->next_time = 0;
-}
-
-/* send a SIPI message to the CPU to start it */
-static void apic_startup(APICState *s, int vector_num)
-{
- CPUState *env = s->cpu_env;
- if (!(env->hflags & HF_HALTED_MASK))
- return;
- env->eip = 0;
- cpu_x86_load_seg_cache(env, R_CS, vector_num << 8, vector_num << 12,
- 0xffff, 0);
- env->hflags &= ~HF_HALTED_MASK;
-}
-
-static void apic_deliver(APICState *s, uint8_t dest, uint8_t dest_mode,
- uint8_t delivery_mode, uint8_t vector_num,
- uint8_t polarity, uint8_t trigger_mode)
-{
- uint32_t deliver_bitmask[MAX_APIC_WORDS];
- int dest_shorthand = (s->icr[0] >> 18) & 3;
- APICState *apic_iter;
-
- switch (dest_shorthand) {
- case 0:
- apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
- break;
- case 1:
- memset(deliver_bitmask, 0x00, sizeof(deliver_bitmask));
- set_bit(deliver_bitmask, s->id);
- break;
- case 2:
- memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
- break;
- case 3:
- memset(deliver_bitmask, 0xff, sizeof(deliver_bitmask));
- reset_bit(deliver_bitmask, s->id);
- break;
- }
-
- switch (delivery_mode) {
- case APIC_DM_INIT:
- {
- int trig_mode = (s->icr[0] >> 15) & 1;
- int level = (s->icr[0] >> 14) & 1;
- if (level == 0 && trig_mode == 1) {
- foreach_apic(apic_iter, deliver_bitmask,
- apic_iter->arb_id = apic_iter->id );
- return;
- }
- }
- break;
-
- case APIC_DM_SIPI:
- foreach_apic(apic_iter, deliver_bitmask,
- apic_startup(apic_iter, vector_num) );
- return;
- }
-
- apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
- trigger_mode);
-}
-
-int apic_get_interrupt(CPUState *env)
-{
- APICState *s = env->apic_state;
- int intno;
-
- /* if the APIC is installed or enabled, we let the 8259 handle the
- IRQs */
- if (!s)
- return -1;
- if (!(s->spurious_vec & APIC_SV_ENABLE))
- return -1;
-
- /* XXX: spurious IRQ handling */
- intno = get_highest_priority_int(s->irr);
- if (intno < 0)
- return -1;
- reset_bit(s->irr, intno);
- if (s->tpr && intno <= s->tpr)
- return s->spurious_vec & 0xff;
- set_bit(s->isr, intno);
- apic_update_irq(s);
- return intno;
-}
-
-static uint32_t apic_get_current_count(APICState *s)
-{
- int64_t d;
- uint32_t val;
- d = (qemu_get_clock(vm_clock) - s->initial_count_load_time) >>
- s->count_shift;
- if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
- /* periodic */
- val = s->initial_count - (d % ((uint64_t)s->initial_count + 1));
- } else {
- if (d >= s->initial_count)
- val = 0;
- else
- val = s->initial_count - d;
- }
- return val;
-}
-
-static void apic_timer_update(APICState *s, int64_t current_time)
-{
- int64_t next_time, d;
-
- if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
- d = (current_time - s->initial_count_load_time) >>
- s->count_shift;
- if (s->lvt[APIC_LVT_TIMER] & APIC_LVT_TIMER_PERIODIC) {
- d = ((d / ((uint64_t)s->initial_count + 1)) + 1) * ((uint64_t)s->initial_count + 1);
- } else {
- if (d >= s->initial_count)
- goto no_timer;
- d = (uint64_t)s->initial_count + 1;
- }
- next_time = s->initial_count_load_time + (d << s->count_shift);
- qemu_mod_timer(s->timer, next_time);
- s->next_time = next_time;
- } else {
- no_timer:
- qemu_del_timer(s->timer);
- }
-}
-
-static void apic_timer(void *opaque)
-{
- APICState *s = opaque;
-
- if (!(s->lvt[APIC_LVT_TIMER] & APIC_LVT_MASKED)) {
- apic_set_irq(s, s->lvt[APIC_LVT_TIMER] & 0xff, APIC_TRIGGER_EDGE);
- }
- apic_timer_update(s, s->next_time);
-}
-
-static uint32_t apic_mem_readb(void *opaque, target_phys_addr_t addr)
-{
- return 0;
-}
-
-static uint32_t apic_mem_readw(void *opaque, target_phys_addr_t addr)
-{
- return 0;
-}
-
-static void apic_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-}
-
-static void apic_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-}
-
-static uint32_t apic_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- CPUState *env;
- APICState *s;
- uint32_t val;
- int index;
-
- env = cpu_single_env;
- if (!env)
- return 0;
- s = env->apic_state;
-
- index = (addr >> 4) & 0xff;
- switch(index) {
- case 0x02: /* id */
- val = s->id << 24;
- break;
- case 0x03: /* version */
- val = 0x11 | ((APIC_LVT_NB - 1) << 16); /* version 0x11 */
- break;
- case 0x08:
- val = s->tpr;
- break;
- case 0x09:
- val = apic_get_arb_pri(s);
- break;
- case 0x0a:
- /* ppr */
- val = apic_get_ppr(s);
- break;
- case 0x0d:
- val = s->log_dest << 24;
- break;
- case 0x0e:
- val = s->dest_mode << 28;
- break;
- case 0x0f:
- val = s->spurious_vec;
- break;
- case 0x10 ... 0x17:
- val = s->isr[index & 7];
- break;
- case 0x18 ... 0x1f:
- val = s->tmr[index & 7];
- break;
- case 0x20 ... 0x27:
- val = s->irr[index & 7];
- break;
- case 0x28:
- val = s->esr;
- break;
- case 0x30:
- case 0x31:
- val = s->icr[index & 1];
- break;
- case 0x32 ... 0x37:
- val = s->lvt[index - 0x32];
- break;
- case 0x38:
- val = s->initial_count;
- break;
- case 0x39:
- val = apic_get_current_count(s);
- break;
- case 0x3e:
- val = s->divide_conf;
- break;
- default:
- s->esr |= ESR_ILLEGAL_ADDRESS;
- val = 0;
- break;
- }
-#ifdef DEBUG_APIC
- printf("APIC read: %08x = %08x\n", (uint32_t)addr, val);
-#endif
- return val;
-}
-
-static void apic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- CPUState *env;
- APICState *s;
- int index;
-
- env = cpu_single_env;
- if (!env)
- return;
- s = env->apic_state;
-
-#ifdef DEBUG_APIC
- printf("APIC write: %08x = %08x\n", (uint32_t)addr, val);
-#endif
-
- index = (addr >> 4) & 0xff;
- switch(index) {
- case 0x02:
- s->id = (val >> 24);
- break;
- case 0x03:
- break;
- case 0x08:
- s->tpr = val;
- apic_update_irq(s);
- break;
- case 0x09:
- case 0x0a:
- break;
- case 0x0b: /* EOI */
- apic_eoi(s);
- break;
- case 0x0d:
- s->log_dest = val >> 24;
- break;
- case 0x0e:
- s->dest_mode = val >> 28;
- break;
- case 0x0f:
- s->spurious_vec = val & 0x1ff;
- apic_update_irq(s);
- break;
- case 0x10 ... 0x17:
- case 0x18 ... 0x1f:
- case 0x20 ... 0x27:
- case 0x28:
- break;
- case 0x30:
- s->icr[0] = val;
- apic_deliver(s, (s->icr[1] >> 24) & 0xff, (s->icr[0] >> 11) & 1,
- (s->icr[0] >> 8) & 7, (s->icr[0] & 0xff),
- (s->icr[0] >> 14) & 1, (s->icr[0] >> 15) & 1);
- break;
- case 0x31:
- s->icr[1] = val;
- break;
- case 0x32 ... 0x37:
- {
- int n = index - 0x32;
- s->lvt[n] = val;
- if (n == APIC_LVT_TIMER)
- apic_timer_update(s, qemu_get_clock(vm_clock));
- }
- break;
- case 0x38:
- s->initial_count = val;
- s->initial_count_load_time = qemu_get_clock(vm_clock);
- apic_timer_update(s, s->initial_count_load_time);
- break;
- case 0x39:
- break;
- case 0x3e:
- {
- int v;
- s->divide_conf = val & 0xb;
- v = (s->divide_conf & 3) | ((s->divide_conf >> 1) & 4);
- s->count_shift = (v + 1) & 7;
- }
- break;
- default:
- s->esr |= ESR_ILLEGAL_ADDRESS;
- break;
- }
-}
-
-static void apic_save(QEMUFile *f, void *opaque)
-{
- APICState *s = opaque;
- int i;
-
- qemu_put_be32s(f, &s->apicbase);
- qemu_put_8s(f, &s->id);
- qemu_put_8s(f, &s->arb_id);
- qemu_put_8s(f, &s->tpr);
- qemu_put_be32s(f, &s->spurious_vec);
- qemu_put_8s(f, &s->log_dest);
- qemu_put_8s(f, &s->dest_mode);
- for (i = 0; i < 8; i++) {
- qemu_put_be32s(f, &s->isr[i]);
- qemu_put_be32s(f, &s->tmr[i]);
- qemu_put_be32s(f, &s->irr[i]);
- }
- for (i = 0; i < APIC_LVT_NB; i++) {
- qemu_put_be32s(f, &s->lvt[i]);
- }
- qemu_put_be32s(f, &s->esr);
- qemu_put_be32s(f, &s->icr[0]);
- qemu_put_be32s(f, &s->icr[1]);
- qemu_put_be32s(f, &s->divide_conf);
- qemu_put_be32s(f, &s->count_shift);
- qemu_put_be32s(f, &s->initial_count);
- qemu_put_be64s(f, &s->initial_count_load_time);
- qemu_put_be64s(f, &s->next_time);
-}
-
-static int apic_load(QEMUFile *f, void *opaque, int version_id)
-{
- APICState *s = opaque;
- int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- /* XXX: what if the base changes? (registered memory regions) */
- qemu_get_be32s(f, &s->apicbase);
- qemu_get_8s(f, &s->id);
- qemu_get_8s(f, &s->arb_id);
- qemu_get_8s(f, &s->tpr);
- qemu_get_be32s(f, &s->spurious_vec);
- qemu_get_8s(f, &s->log_dest);
- qemu_get_8s(f, &s->dest_mode);
- for (i = 0; i < 8; i++) {
- qemu_get_be32s(f, &s->isr[i]);
- qemu_get_be32s(f, &s->tmr[i]);
- qemu_get_be32s(f, &s->irr[i]);
- }
- for (i = 0; i < APIC_LVT_NB; i++) {
- qemu_get_be32s(f, &s->lvt[i]);
- }
- qemu_get_be32s(f, &s->esr);
- qemu_get_be32s(f, &s->icr[0]);
- qemu_get_be32s(f, &s->icr[1]);
- qemu_get_be32s(f, &s->divide_conf);
- qemu_get_be32s(f, &s->count_shift);
- qemu_get_be32s(f, &s->initial_count);
- qemu_get_be64s(f, &s->initial_count_load_time);
- qemu_get_be64s(f, &s->next_time);
- return 0;
-}
-
-static void apic_reset(void *opaque)
-{
- APICState *s = opaque;
- apic_init_ipi(s);
-}
-
-static CPUReadMemoryFunc *apic_mem_read[3] = {
- apic_mem_readb,
- apic_mem_readw,
- apic_mem_readl,
-};
-
-static CPUWriteMemoryFunc *apic_mem_write[3] = {
- apic_mem_writeb,
- apic_mem_writew,
- apic_mem_writel,
-};
-
-int apic_init(CPUState *env)
-{
- APICState *s;
-
- if (last_apic_id >= MAX_APICS)
- return -1;
- s = qemu_mallocz(sizeof(APICState));
- if (!s)
- return -1;
- env->apic_state = s;
- apic_init_ipi(s);
- s->id = last_apic_id++;
- s->cpu_env = env;
- s->apicbase = 0xfee00000 |
- (s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
-
- /* XXX: mapping more APICs at the same memory location */
- if (apic_io_memory == 0) {
- /* NOTE: the APIC is directly connected to the CPU - it is not
- on the global memory bus. */
- apic_io_memory = cpu_register_io_memory(0, apic_mem_read,
- apic_mem_write, NULL);
- cpu_register_physical_memory(s->apicbase & ~0xfff, 0x1000,
- apic_io_memory);
- }
- s->timer = qemu_new_timer(vm_clock, apic_timer, s);
-
- register_savevm("apic", 0, 1, apic_save, apic_load, s);
- qemu_register_reset(apic_reset, s);
-
- local_apics[s->id] = s;
- return 0;
-}
-
-static void ioapic_service(IOAPICState *s)
-{
- uint8_t i;
- uint8_t trig_mode;
- uint8_t vector;
- uint8_t delivery_mode;
- uint32_t mask;
- uint64_t entry;
- uint8_t dest;
- uint8_t dest_mode;
- uint8_t polarity;
- uint32_t deliver_bitmask[MAX_APIC_WORDS];
-
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- mask = 1 << i;
- if (s->irr & mask) {
- entry = s->ioredtbl[i];
- if (!(entry & APIC_LVT_MASKED)) {
- trig_mode = ((entry >> 15) & 1);
- dest = entry >> 56;
- dest_mode = (entry >> 11) & 1;
- delivery_mode = (entry >> 8) & 7;
- polarity = (entry >> 13) & 1;
- if (trig_mode == APIC_TRIGGER_EDGE)
- s->irr &= ~mask;
- if (delivery_mode == APIC_DM_EXTINT)
- vector = pic_read_irq(isa_pic);
- else
- vector = entry & 0xff;
-
- apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
- apic_bus_deliver(deliver_bitmask, delivery_mode,
- vector, polarity, trig_mode);
- }
- }
- }
-}
-
-void ioapic_set_irq(void *opaque, int vector, int level)
-{
- IOAPICState *s = opaque;
-
- if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
- uint32_t mask = 1 << vector;
- uint64_t entry = s->ioredtbl[vector];
-
- if ((entry >> 15) & 1) {
- /* level triggered */
- if (level) {
- s->irr |= mask;
- ioapic_service(s);
- } else {
- s->irr &= ~mask;
- }
- } else {
- /* edge triggered */
- if (level) {
- s->irr |= mask;
- ioapic_service(s);
- }
- }
- }
-}
-
-static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- IOAPICState *s = opaque;
- int index;
- uint32_t val = 0;
-
- addr &= 0xff;
- if (addr == 0x00) {
- val = s->ioregsel;
- } else if (addr == 0x10) {
- switch (s->ioregsel) {
- case 0x00:
- val = s->id << 24;
- break;
- case 0x01:
- val = 0x11 | ((IOAPIC_NUM_PINS - 1) << 16); /* version 0x11 */
- break;
- case 0x02:
- val = 0;
- break;
- default:
- index = (s->ioregsel - 0x10) >> 1;
- if (index >= 0 && index < IOAPIC_NUM_PINS) {
- if (s->ioregsel & 1)
- val = s->ioredtbl[index] >> 32;
- else
- val = s->ioredtbl[index] & 0xffffffff;
- }
- }
-#ifdef DEBUG_IOAPIC
- printf("I/O APIC read: %08x = %08x\n", s->ioregsel, val);
-#endif
- }
- return val;
-}
-
-static void ioapic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- IOAPICState *s = opaque;
- int index;
-
- addr &= 0xff;
- if (addr == 0x00) {
- s->ioregsel = val;
- return;
- } else if (addr == 0x10) {
-#ifdef DEBUG_IOAPIC
- printf("I/O APIC write: %08x = %08x\n", s->ioregsel, val);
-#endif
- switch (s->ioregsel) {
- case 0x00:
- s->id = (val >> 24) & 0xff;
- return;
- case 0x01:
- case 0x02:
- return;
- default:
- index = (s->ioregsel - 0x10) >> 1;
- if (index >= 0 && index < IOAPIC_NUM_PINS) {
- if (s->ioregsel & 1) {
- s->ioredtbl[index] &= 0xffffffff;
- s->ioredtbl[index] |= (uint64_t)val << 32;
- } else {
- s->ioredtbl[index] &= ~0xffffffffULL;
- s->ioredtbl[index] |= val;
- }
- ioapic_service(s);
- }
- }
- }
-}
-
-static void ioapic_save(QEMUFile *f, void *opaque)
-{
- IOAPICState *s = opaque;
- int i;
-
- qemu_put_8s(f, &s->id);
- qemu_put_8s(f, &s->ioregsel);
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- qemu_put_be64s(f, &s->ioredtbl[i]);
- }
-}
-
-static int ioapic_load(QEMUFile *f, void *opaque, int version_id)
-{
- IOAPICState *s = opaque;
- int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_8s(f, &s->id);
- qemu_get_8s(f, &s->ioregsel);
- for (i = 0; i < IOAPIC_NUM_PINS; i++) {
- qemu_get_be64s(f, &s->ioredtbl[i]);
- }
- return 0;
-}
-
-static void ioapic_reset(void *opaque)
-{
- IOAPICState *s = opaque;
- int i;
-
- memset(s, 0, sizeof(*s));
- for(i = 0; i < IOAPIC_NUM_PINS; i++)
- s->ioredtbl[i] = 1 << 16; /* mask LVT */
-}
-
-static CPUReadMemoryFunc *ioapic_mem_read[3] = {
- ioapic_mem_readl,
- ioapic_mem_readl,
- ioapic_mem_readl,
-};
-
-static CPUWriteMemoryFunc *ioapic_mem_write[3] = {
- ioapic_mem_writel,
- ioapic_mem_writel,
- ioapic_mem_writel,
-};
-
-IOAPICState *ioapic_init(void)
-{
- IOAPICState *s;
- int io_memory;
-
- s = qemu_mallocz(sizeof(IOAPICState));
- if (!s)
- return NULL;
- ioapic_reset(s);
- s->id = last_apic_id++;
-
- io_memory = cpu_register_io_memory(0, ioapic_mem_read,
- ioapic_mem_write, s);
- cpu_register_physical_memory(0xfec00000, 0x1000, io_memory);
-
- register_savevm("ioapic", 0, 1, ioapic_save, ioapic_load, s);
- qemu_register_reset(ioapic_reset, s);
-
- return s;
-}
diff --git a/hw/arm_pic.c b/hw/arm_pic.c
index fbc2d67..c228c04 100644
--- a/hw/arm_pic.c
+++ b/hw/arm_pic.c
@@ -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)
{
}
@@ -24,50 +19,30 @@ void irq_info(void)
{
}
-
-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",
+ 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);
}
diff --git a/hw/arm_pic.h b/hw/arm_pic.h
index b299149..7886bcf 100644
--- a/hw/arm_pic.h
+++ b/hw/arm_pic.h
@@ -14,14 +14,12 @@
#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);
+#include "irq.h"
/* 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 */
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
deleted file mode 100644
index a97d73e..0000000
--- a/hw/arm_timer.c
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * ARM PrimeCell Timer modules.
- *
- * Copyright (c) 2005-2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the GPL.
- */
-
-#include "vl.h"
-#include "arm_pic.h"
-
-/* Common timer implementation. */
-
-#define TIMER_CTRL_ONESHOT (1 << 0)
-#define TIMER_CTRL_32BIT (1 << 1)
-#define TIMER_CTRL_DIV1 (0 << 2)
-#define TIMER_CTRL_DIV16 (1 << 2)
-#define TIMER_CTRL_DIV256 (2 << 2)
-#define TIMER_CTRL_IE (1 << 5)
-#define TIMER_CTRL_PERIODIC (1 << 6)
-#define TIMER_CTRL_ENABLE (1 << 7)
-
-typedef struct {
- int64_t next_time;
- int64_t expires;
- int64_t loaded;
- QEMUTimer *timer;
- uint32_t control;
- uint32_t count;
- uint32_t limit;
- int raw_freq;
- int freq;
- int int_level;
- void *pic;
- int irq;
-} arm_timer_state;
-
-/* Calculate the new expiry time of the given timer. */
-
-static void arm_timer_reload(arm_timer_state *s)
-{
- int64_t delay;
-
- s->loaded = s->expires;
- delay = muldiv64(s->count, ticks_per_sec, s->freq);
- if (delay == 0)
- delay = 1;
- s->expires += delay;
-}
-
-/* Check all active timers, and schedule the next timer interrupt. */
-
-static void arm_timer_update(arm_timer_state *s, int64_t now)
-{
- int64_t next;
-
- /* Ignore disabled timers. */
- if ((s->control & TIMER_CTRL_ENABLE) == 0)
- return;
- /* Ignore expired one-shot timers. */
- if (s->count == 0 && (s->control & TIMER_CTRL_ONESHOT))
- return;
- if (s->expires - now <= 0) {
- /* Timer has expired. */
- s->int_level = 1;
- if (s->control & TIMER_CTRL_ONESHOT) {
- /* One-shot. */
- s->count = 0;
- } else {
- if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
- /* Free running. */
- if (s->control & TIMER_CTRL_32BIT)
- s->count = 0xffffffff;
- else
- s->count = 0xffff;
- } else {
- /* Periodic. */
- s->count = s->limit;
- }
- }
- }
- while (s->expires - now <= 0) {
- arm_timer_reload(s);
- }
- /* Update interrupts. */
- if (s->int_level && (s->control & TIMER_CTRL_IE)) {
- pic_set_irq_new(s->pic, s->irq, 1);
- } else {
- pic_set_irq_new(s->pic, s->irq, 0);
- }
-
- next = now;
- if (next - s->expires < 0)
- next = s->expires;
-
- /* Schedule the next timer interrupt. */
- if (next == now) {
- qemu_del_timer(s->timer);
- s->next_time = 0;
- } else if (next != s->next_time) {
- qemu_mod_timer(s->timer, next);
- s->next_time = next;
- }
-}
-
-/* Return the current value of the timer. */
-static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now)
-{
- int64_t elapsed;
- int64_t period;
-
- if (s->count == 0)
- return 0;
- if ((s->control & TIMER_CTRL_ENABLE) == 0)
- return s->count;
- elapsed = now - s->loaded;
- period = s->expires - s->loaded;
- /* If the timer should have expired then return 0. This can happen
- when the host timer signal doesnt occur immediately. It's better to
- have a timer appear to sit at zero for a while than have it wrap
- around before the guest interrupt is raised. */
- /* ??? Could we trigger the interrupt here? */
- if (elapsed > period)
- return 0;
- /* We need to calculate count * elapsed / period without overfowing.
- Scale both elapsed and period so they fit in a 32-bit int. */
- while (period != (int32_t)period) {
- period >>= 1;
- elapsed >>= 1;
- }
- return ((uint64_t)s->count * (uint64_t)(int32_t)elapsed)
- / (int32_t)period;
-}
-
-uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
-{
- arm_timer_state *s = (arm_timer_state *)opaque;
-
- switch (offset >> 2) {
- case 0: /* TimerLoad */
- case 6: /* TimerBGLoad */
- return s->limit;
- case 1: /* TimerValue */
- return arm_timer_getcount(s, qemu_get_clock(vm_clock));
- case 2: /* TimerControl */
- return s->control;
- case 4: /* TimerRIS */
- return s->int_level;
- case 5: /* TimerMIS */
- if ((s->control & TIMER_CTRL_IE) == 0)
- return 0;
- return s->int_level;
- default:
- cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", offset);
- return 0;
- }
-}
-
-static void arm_timer_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- arm_timer_state *s = (arm_timer_state *)opaque;
- int64_t now;
-
- now = qemu_get_clock(vm_clock);
- switch (offset >> 2) {
- case 0: /* TimerLoad */
- s->limit = value;
- s->count = value;
- s->expires = now;
- arm_timer_reload(s);
- break;
- case 1: /* TimerValue */
- /* ??? Linux seems to want to write to this readonly register.
- Ignore it. */
- break;
- case 2: /* TimerControl */
- if (s->control & TIMER_CTRL_ENABLE) {
- /* Pause the timer if it is running. This may cause some
- inaccuracy dure to rounding, but avoids a whole lot of other
- messyness. */
- s->count = arm_timer_getcount(s, now);
- }
- s->control = value;
- s->freq = s->raw_freq;
- /* ??? Need to recalculate expiry time after changing divisor. */
- switch ((value >> 2) & 3) {
- case 1: s->freq >>= 4; break;
- case 2: s->freq >>= 8; break;
- }
- if (s->control & TIMER_CTRL_ENABLE) {
- /* Restart the timer if still enabled. */
- s->expires = now;
- arm_timer_reload(s);
- }
- break;
- case 3: /* TimerIntClr */
- s->int_level = 0;
- break;
- case 6: /* TimerBGLoad */
- s->limit = value;
- break;
- default:
- cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", offset);
- }
- arm_timer_update(s, now);
-}
-
-static void arm_timer_tick(void *opaque)
-{
- int64_t now;
-
- now = qemu_get_clock(vm_clock);
- arm_timer_update((arm_timer_state *)opaque, now);
-}
-
-static void *arm_timer_init(uint32_t freq, void *pic, int 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;
- s->count = 0xffffffff;
-
- s->timer = qemu_new_timer(vm_clock, arm_timer_tick, s);
- /* ??? Save/restore. */
- return s;
-}
-
-/* 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
- 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;
-} sp804_state;
-
-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]);
-}
-
-static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
-{
- sp804_state *s = (sp804_state *)opaque;
-
- /* ??? Don't know the PrimeCell ID for this device. */
- offset -= s->base;
- if (offset < 0x20) {
- return arm_timer_read(s->timer[0], offset);
- } else {
- return arm_timer_read(s->timer[1], offset - 0x20);
- }
-}
-
-static void sp804_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- sp804_state *s = (sp804_state *)opaque;
-
- offset -= s->base;
- if (offset < 0x20) {
- arm_timer_write(s->timer[0], offset, value);
- } else {
- arm_timer_write(s->timer[1], offset - 0x20, value);
- }
-}
-
-static CPUReadMemoryFunc *sp804_readfn[] = {
- sp804_read,
- sp804_read,
- sp804_read
-};
-
-static CPUWriteMemoryFunc *sp804_writefn[] = {
- sp804_write,
- sp804_write,
- sp804_write
-};
-
-void sp804_init(uint32_t base, void *pic, int irq)
-{
- int iomemtype;
- sp804_state *s;
-
- s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
- s->handler = sp804_set_irq;
- 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);
- iomemtype = cpu_register_io_memory(0, sp804_readfn,
- sp804_writefn, s);
- cpu_register_physical_memory(base, 0x00000fff, iomemtype);
- /* ??? Save/restore. */
-}
-
-
-/* Integrator/CP timer module. */
-
-typedef struct {
- void *timer[3];
- uint32_t base;
-} icp_pit_state;
-
-static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
-{
- icp_pit_state *s = (icp_pit_state *)opaque;
- int n;
-
- /* ??? Don't know the PrimeCell ID for this device. */
- offset -= s->base;
- n = offset >> 8;
- if (n > 3)
- cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n);
-
- return arm_timer_read(s->timer[n], offset & 0xff);
-}
-
-static void icp_pit_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- icp_pit_state *s = (icp_pit_state *)opaque;
- int n;
-
- offset -= s->base;
- n = offset >> 8;
- if (n > 3)
- cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n);
-
- arm_timer_write(s->timer[n], offset & 0xff, value);
-}
-
-
-static CPUReadMemoryFunc *icp_pit_readfn[] = {
- icp_pit_read,
- icp_pit_read,
- icp_pit_read
-};
-
-static CPUWriteMemoryFunc *icp_pit_writefn[] = {
- icp_pit_write,
- icp_pit_write,
- icp_pit_write
-};
-
-void icp_pit_init(uint32_t base, void *pic, int irq)
-{
- int iomemtype;
- icp_pit_state *s;
-
- 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);
- /* 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);
-
- iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
- icp_pit_writefn, s);
- cpu_register_physical_memory(base, 0x00000fff, iomemtype);
- /* ??? Save/restore. */
-}
-
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
deleted file mode 100644
index d186d79..0000000
--- a/hw/cirrus_vga.c
+++ /dev/null
@@ -1,3193 +0,0 @@
-/*
- * QEMU Cirrus CLGD 54xx VGA Emulator.
- *
- * Copyright (c) 2004 Fabrice Bellard
- * Copyright (c) 2004 Makoto Suzuki (suzu)
- *
- * 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.
- */
-/*
- * Reference: Finn Thogersons' VGADOC4b
- * available at http://home.worldonline.dk/~finth/
- */
-#include "vl.h"
-#include "vga_int.h"
-
-/*
- * TODO:
- * - destination write mask support not complete (bits 5..7)
- * - optimize linear mappings
- * - optimize bitblt functions
- */
-
-//#define DEBUG_CIRRUS
-//#define DEBUG_BITBLT
-
-/***************************************
- *
- * definitions
- *
- ***************************************/
-
-#define qemu_MIN(a,b) ((a) < (b) ? (a) : (b))
-
-// ID
-#define CIRRUS_ID_CLGD5422 (0x23<<2)
-#define CIRRUS_ID_CLGD5426 (0x24<<2)
-#define CIRRUS_ID_CLGD5424 (0x25<<2)
-#define CIRRUS_ID_CLGD5428 (0x26<<2)
-#define CIRRUS_ID_CLGD5430 (0x28<<2)
-#define CIRRUS_ID_CLGD5434 (0x2A<<2)
-#define CIRRUS_ID_CLGD5436 (0x2B<<2)
-#define CIRRUS_ID_CLGD5446 (0x2E<<2)
-
-// sequencer 0x07
-#define CIRRUS_SR7_BPP_VGA 0x00
-#define CIRRUS_SR7_BPP_SVGA 0x01
-#define CIRRUS_SR7_BPP_MASK 0x0e
-#define CIRRUS_SR7_BPP_8 0x00
-#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02
-#define CIRRUS_SR7_BPP_24 0x04
-#define CIRRUS_SR7_BPP_16 0x06
-#define CIRRUS_SR7_BPP_32 0x08
-#define CIRRUS_SR7_ISAADDR_MASK 0xe0
-
-// sequencer 0x0f
-#define CIRRUS_MEMSIZE_512k 0x08
-#define CIRRUS_MEMSIZE_1M 0x10
-#define CIRRUS_MEMSIZE_2M 0x18
-#define CIRRUS_MEMFLAGS_BANKSWITCH 0x80 // bank switching is enabled.
-
-// sequencer 0x12
-#define CIRRUS_CURSOR_SHOW 0x01
-#define CIRRUS_CURSOR_HIDDENPEL 0x02
-#define CIRRUS_CURSOR_LARGE 0x04 // 64x64 if set, 32x32 if clear
-
-// sequencer 0x17
-#define CIRRUS_BUSTYPE_VLBFAST 0x10
-#define CIRRUS_BUSTYPE_PCI 0x20
-#define CIRRUS_BUSTYPE_VLBSLOW 0x30
-#define CIRRUS_BUSTYPE_ISA 0x38
-#define CIRRUS_MMIO_ENABLE 0x04
-#define CIRRUS_MMIO_USE_PCIADDR 0x40 // 0xb8000 if cleared.
-#define CIRRUS_MEMSIZEEXT_DOUBLE 0x80
-
-// control 0x0b
-#define CIRRUS_BANKING_DUAL 0x01
-#define CIRRUS_BANKING_GRANULARITY_16K 0x20 // set:16k, clear:4k
-
-// control 0x30
-#define CIRRUS_BLTMODE_BACKWARDS 0x01
-#define CIRRUS_BLTMODE_MEMSYSDEST 0x02
-#define CIRRUS_BLTMODE_MEMSYSSRC 0x04
-#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08
-#define CIRRUS_BLTMODE_PATTERNCOPY 0x40
-#define CIRRUS_BLTMODE_COLOREXPAND 0x80
-#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30
-#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00
-#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10
-#define CIRRUS_BLTMODE_PIXELWIDTH24 0x20
-#define CIRRUS_BLTMODE_PIXELWIDTH32 0x30
-
-// control 0x31
-#define CIRRUS_BLT_BUSY 0x01
-#define CIRRUS_BLT_START 0x02
-#define CIRRUS_BLT_RESET 0x04
-#define CIRRUS_BLT_FIFOUSED 0x10
-#define CIRRUS_BLT_AUTOSTART 0x80
-
-// control 0x32
-#define CIRRUS_ROP_0 0x00
-#define CIRRUS_ROP_SRC_AND_DST 0x05
-#define CIRRUS_ROP_NOP 0x06
-#define CIRRUS_ROP_SRC_AND_NOTDST 0x09
-#define CIRRUS_ROP_NOTDST 0x0b
-#define CIRRUS_ROP_SRC 0x0d
-#define CIRRUS_ROP_1 0x0e
-#define CIRRUS_ROP_NOTSRC_AND_DST 0x50
-#define CIRRUS_ROP_SRC_XOR_DST 0x59
-#define CIRRUS_ROP_SRC_OR_DST 0x6d
-#define CIRRUS_ROP_NOTSRC_OR_NOTDST 0x90
-#define CIRRUS_ROP_SRC_NOTXOR_DST 0x95
-#define CIRRUS_ROP_SRC_OR_NOTDST 0xad
-#define CIRRUS_ROP_NOTSRC 0xd0
-#define CIRRUS_ROP_NOTSRC_OR_DST 0xd6
-#define CIRRUS_ROP_NOTSRC_AND_NOTDST 0xda
-
-#define CIRRUS_ROP_NOP_INDEX 2
-#define CIRRUS_ROP_SRC_INDEX 5
-
-// control 0x33
-#define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04
-#define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02
-#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01
-
-// memory-mapped IO
-#define CIRRUS_MMIO_BLTBGCOLOR 0x00 // dword
-#define CIRRUS_MMIO_BLTFGCOLOR 0x04 // dword
-#define CIRRUS_MMIO_BLTWIDTH 0x08 // word
-#define CIRRUS_MMIO_BLTHEIGHT 0x0a // word
-#define CIRRUS_MMIO_BLTDESTPITCH 0x0c // word
-#define CIRRUS_MMIO_BLTSRCPITCH 0x0e // word
-#define CIRRUS_MMIO_BLTDESTADDR 0x10 // dword
-#define CIRRUS_MMIO_BLTSRCADDR 0x14 // dword
-#define CIRRUS_MMIO_BLTWRITEMASK 0x17 // byte
-#define CIRRUS_MMIO_BLTMODE 0x18 // byte
-#define CIRRUS_MMIO_BLTROP 0x1a // byte
-#define CIRRUS_MMIO_BLTMODEEXT 0x1b // byte
-#define CIRRUS_MMIO_BLTTRANSPARENTCOLOR 0x1c // word?
-#define CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK 0x20 // word?
-#define CIRRUS_MMIO_LINEARDRAW_START_X 0x24 // word
-#define CIRRUS_MMIO_LINEARDRAW_START_Y 0x26 // word
-#define CIRRUS_MMIO_LINEARDRAW_END_X 0x28 // word
-#define CIRRUS_MMIO_LINEARDRAW_END_Y 0x2a // word
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_INC 0x2c // byte
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ROLLOVER 0x2d // byte
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_MASK 0x2e // byte
-#define CIRRUS_MMIO_LINEARDRAW_LINESTYLE_ACCUM 0x2f // byte
-#define CIRRUS_MMIO_BRESENHAM_K1 0x30 // word
-#define CIRRUS_MMIO_BRESENHAM_K3 0x32 // word
-#define CIRRUS_MMIO_BRESENHAM_ERROR 0x34 // word
-#define CIRRUS_MMIO_BRESENHAM_DELTA_MAJOR 0x36 // word
-#define CIRRUS_MMIO_BRESENHAM_DIRECTION 0x38 // byte
-#define CIRRUS_MMIO_LINEDRAW_MODE 0x39 // byte
-#define CIRRUS_MMIO_BLTSTATUS 0x40 // byte
-
-// PCI 0x00: vendor, 0x02: device
-#define PCI_VENDOR_CIRRUS 0x1013
-#define PCI_DEVICE_CLGD5462 0x00d0
-#define PCI_DEVICE_CLGD5465 0x00d6
-
-// PCI 0x04: command(word), 0x06(word): status
-#define PCI_COMMAND_IOACCESS 0x0001
-#define PCI_COMMAND_MEMACCESS 0x0002
-#define PCI_COMMAND_BUSMASTER 0x0004
-#define PCI_COMMAND_SPECIALCYCLE 0x0008
-#define PCI_COMMAND_MEMWRITEINVALID 0x0010
-#define PCI_COMMAND_PALETTESNOOPING 0x0020
-#define PCI_COMMAND_PARITYDETECTION 0x0040
-#define PCI_COMMAND_ADDRESSDATASTEPPING 0x0080
-#define PCI_COMMAND_SERR 0x0100
-#define PCI_COMMAND_BACKTOBACKTRANS 0x0200
-// PCI 0x08, 0xff000000 (0x09-0x0b:class,0x08:rev)
-#define PCI_CLASS_BASE_DISPLAY 0x03
-// PCI 0x08, 0x00ff0000
-#define PCI_CLASS_SUB_VGA 0x00
-// PCI 0x0c, 0x00ff0000 (0x0c:cacheline,0x0d:latency,0x0e:headertype,0x0f:Built-in self test)
-#define PCI_CLASS_HEADERTYPE_00h 0x00
-// 0x10-0x3f (headertype 00h)
-// PCI 0x10,0x14,0x18,0x1c,0x20,0x24: base address mapping registers
-// 0x10: MEMBASE, 0x14: IOBASE(hard-coded in XFree86 3.x)
-#define PCI_MAP_MEM 0x0
-#define PCI_MAP_IO 0x1
-#define PCI_MAP_MEM_ADDR_MASK (~0xf)
-#define PCI_MAP_IO_ADDR_MASK (~0x3)
-#define PCI_MAP_MEMFLAGS_32BIT 0x0
-#define PCI_MAP_MEMFLAGS_32BIT_1M 0x1
-#define PCI_MAP_MEMFLAGS_64BIT 0x4
-#define PCI_MAP_MEMFLAGS_CACHEABLE 0x8
-// PCI 0x28: cardbus CIS pointer
-// PCI 0x2c: subsystem vendor id, 0x2e: subsystem id
-// PCI 0x30: expansion ROM base address
-#define PCI_ROMBIOS_ENABLED 0x1
-// PCI 0x34: 0xffffff00=reserved, 0x000000ff=capabilities pointer
-// PCI 0x38: reserved
-// PCI 0x3c: 0x3c=int-line, 0x3d=int-pin, 0x3e=min-gnt, 0x3f=maax-lat
-
-#define CIRRUS_PNPMMIO_SIZE 0x1000
-
-
-/* I/O and memory hook */
-#define CIRRUS_HOOK_NOT_HANDLED 0
-#define CIRRUS_HOOK_HANDLED 1
-
-struct CirrusVGAState;
-typedef void (*cirrus_bitblt_rop_t) (struct CirrusVGAState *s,
- uint8_t * dst, const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight);
-typedef void (*cirrus_fill_t)(struct CirrusVGAState *s,
- uint8_t *dst, int dst_pitch, int width, int height);
-
-typedef struct CirrusVGAState {
- VGA_STATE_COMMON
-
- int cirrus_linear_io_addr;
- int cirrus_linear_bitblt_io_addr;
- int cirrus_mmio_io_addr;
- uint32_t cirrus_addr_mask;
- uint32_t linear_mmio_mask;
- uint8_t cirrus_shadow_gr0;
- uint8_t cirrus_shadow_gr1;
- uint8_t cirrus_hidden_dac_lockindex;
- uint8_t cirrus_hidden_dac_data;
- uint32_t cirrus_bank_base[2];
- uint32_t cirrus_bank_limit[2];
- uint8_t cirrus_hidden_palette[48];
- uint32_t hw_cursor_x;
- uint32_t hw_cursor_y;
- int cirrus_blt_pixelwidth;
- int cirrus_blt_width;
- int cirrus_blt_height;
- int cirrus_blt_dstpitch;
- int cirrus_blt_srcpitch;
- uint32_t cirrus_blt_fgcol;
- uint32_t cirrus_blt_bgcol;
- uint32_t cirrus_blt_dstaddr;
- uint32_t cirrus_blt_srcaddr;
- uint8_t cirrus_blt_mode;
- uint8_t cirrus_blt_modeext;
- cirrus_bitblt_rop_t cirrus_rop;
-#define CIRRUS_BLTBUFSIZE (2048 * 4) /* one line width */
- uint8_t cirrus_bltbuf[CIRRUS_BLTBUFSIZE];
- uint8_t *cirrus_srcptr;
- uint8_t *cirrus_srcptr_end;
- uint32_t cirrus_srccounter;
- /* hwcursor display state */
- int last_hw_cursor_size;
- int last_hw_cursor_x;
- int last_hw_cursor_y;
- int last_hw_cursor_y_start;
- int last_hw_cursor_y_end;
- int real_vram_size; /* XXX: suppress that */
- CPUWriteMemoryFunc **cirrus_linear_write;
-} CirrusVGAState;
-
-typedef struct PCICirrusVGAState {
- PCIDevice dev;
- CirrusVGAState cirrus_vga;
-} PCICirrusVGAState;
-
-static uint8_t rop_to_index[256];
-
-/***************************************
- *
- * prototypes.
- *
- ***************************************/
-
-
-static void cirrus_bitblt_reset(CirrusVGAState *s);
-static void cirrus_update_memory_access(CirrusVGAState *s);
-
-/***************************************
- *
- * raster operations
- *
- ***************************************/
-
-static void cirrus_bitblt_rop_nop(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
- int dstpitch,int srcpitch,
- int bltwidth,int bltheight)
-{
-}
-
-static void cirrus_bitblt_fill_nop(CirrusVGAState *s,
- uint8_t *dst,
- int dstpitch, int bltwidth,int bltheight)
-{
-}
-
-#define ROP_NAME 0
-#define ROP_OP(d, s) d = 0
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_and_dst
-#define ROP_OP(d, s) d = (s) & (d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_and_notdst
-#define ROP_OP(d, s) d = (s) & (~(d))
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notdst
-#define ROP_OP(d, s) d = ~(d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src
-#define ROP_OP(d, s) d = s
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME 1
-#define ROP_OP(d, s) d = ~0
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_and_dst
-#define ROP_OP(d, s) d = (~(s)) & (d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_xor_dst
-#define ROP_OP(d, s) d = (s) ^ (d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_or_dst
-#define ROP_OP(d, s) d = (s) | (d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_or_notdst
-#define ROP_OP(d, s) d = (~(s)) | (~(d))
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_notxor_dst
-#define ROP_OP(d, s) d = ~((s) ^ (d))
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME src_or_notdst
-#define ROP_OP(d, s) d = (s) | (~(d))
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc
-#define ROP_OP(d, s) d = (~(s))
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_or_dst
-#define ROP_OP(d, s) d = (~(s)) | (d)
-#include "cirrus_vga_rop.h"
-
-#define ROP_NAME notsrc_and_notdst
-#define ROP_OP(d, s) d = (~(s)) & (~(d))
-#include "cirrus_vga_rop.h"
-
-static const cirrus_bitblt_rop_t cirrus_fwd_rop[16] = {
- cirrus_bitblt_rop_fwd_0,
- cirrus_bitblt_rop_fwd_src_and_dst,
- cirrus_bitblt_rop_nop,
- cirrus_bitblt_rop_fwd_src_and_notdst,
- cirrus_bitblt_rop_fwd_notdst,
- cirrus_bitblt_rop_fwd_src,
- cirrus_bitblt_rop_fwd_1,
- cirrus_bitblt_rop_fwd_notsrc_and_dst,
- cirrus_bitblt_rop_fwd_src_xor_dst,
- cirrus_bitblt_rop_fwd_src_or_dst,
- cirrus_bitblt_rop_fwd_notsrc_or_notdst,
- cirrus_bitblt_rop_fwd_src_notxor_dst,
- cirrus_bitblt_rop_fwd_src_or_notdst,
- cirrus_bitblt_rop_fwd_notsrc,
- cirrus_bitblt_rop_fwd_notsrc_or_dst,
- cirrus_bitblt_rop_fwd_notsrc_and_notdst,
-};
-
-static const cirrus_bitblt_rop_t cirrus_bkwd_rop[16] = {
- cirrus_bitblt_rop_bkwd_0,
- cirrus_bitblt_rop_bkwd_src_and_dst,
- cirrus_bitblt_rop_nop,
- cirrus_bitblt_rop_bkwd_src_and_notdst,
- cirrus_bitblt_rop_bkwd_notdst,
- cirrus_bitblt_rop_bkwd_src,
- cirrus_bitblt_rop_bkwd_1,
- cirrus_bitblt_rop_bkwd_notsrc_and_dst,
- cirrus_bitblt_rop_bkwd_src_xor_dst,
- cirrus_bitblt_rop_bkwd_src_or_dst,
- cirrus_bitblt_rop_bkwd_notsrc_or_notdst,
- cirrus_bitblt_rop_bkwd_src_notxor_dst,
- cirrus_bitblt_rop_bkwd_src_or_notdst,
- cirrus_bitblt_rop_bkwd_notsrc,
- cirrus_bitblt_rop_bkwd_notsrc_or_dst,
- cirrus_bitblt_rop_bkwd_notsrc_and_notdst,
-};
-
-#define ROP2(name) {\
- name ## _8,\
- name ## _16,\
- name ## _24,\
- name ## _32,\
- }
-
-#define ROP_NOP2(func) {\
- func,\
- func,\
- func,\
- func,\
- }
-
-static const cirrus_bitblt_rop_t cirrus_patternfill[16][4] = {
- ROP2(cirrus_patternfill_0),
- ROP2(cirrus_patternfill_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_patternfill_src_and_notdst),
- ROP2(cirrus_patternfill_notdst),
- ROP2(cirrus_patternfill_src),
- ROP2(cirrus_patternfill_1),
- ROP2(cirrus_patternfill_notsrc_and_dst),
- ROP2(cirrus_patternfill_src_xor_dst),
- ROP2(cirrus_patternfill_src_or_dst),
- ROP2(cirrus_patternfill_notsrc_or_notdst),
- ROP2(cirrus_patternfill_src_notxor_dst),
- ROP2(cirrus_patternfill_src_or_notdst),
- ROP2(cirrus_patternfill_notsrc),
- ROP2(cirrus_patternfill_notsrc_or_dst),
- ROP2(cirrus_patternfill_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand_transp[16][4] = {
- ROP2(cirrus_colorexpand_transp_0),
- ROP2(cirrus_colorexpand_transp_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_colorexpand_transp_src_and_notdst),
- ROP2(cirrus_colorexpand_transp_notdst),
- ROP2(cirrus_colorexpand_transp_src),
- ROP2(cirrus_colorexpand_transp_1),
- ROP2(cirrus_colorexpand_transp_notsrc_and_dst),
- ROP2(cirrus_colorexpand_transp_src_xor_dst),
- ROP2(cirrus_colorexpand_transp_src_or_dst),
- ROP2(cirrus_colorexpand_transp_notsrc_or_notdst),
- ROP2(cirrus_colorexpand_transp_src_notxor_dst),
- ROP2(cirrus_colorexpand_transp_src_or_notdst),
- ROP2(cirrus_colorexpand_transp_notsrc),
- ROP2(cirrus_colorexpand_transp_notsrc_or_dst),
- ROP2(cirrus_colorexpand_transp_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand[16][4] = {
- ROP2(cirrus_colorexpand_0),
- ROP2(cirrus_colorexpand_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_colorexpand_src_and_notdst),
- ROP2(cirrus_colorexpand_notdst),
- ROP2(cirrus_colorexpand_src),
- ROP2(cirrus_colorexpand_1),
- ROP2(cirrus_colorexpand_notsrc_and_dst),
- ROP2(cirrus_colorexpand_src_xor_dst),
- ROP2(cirrus_colorexpand_src_or_dst),
- ROP2(cirrus_colorexpand_notsrc_or_notdst),
- ROP2(cirrus_colorexpand_src_notxor_dst),
- ROP2(cirrus_colorexpand_src_or_notdst),
- ROP2(cirrus_colorexpand_notsrc),
- ROP2(cirrus_colorexpand_notsrc_or_dst),
- ROP2(cirrus_colorexpand_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern_transp[16][4] = {
- ROP2(cirrus_colorexpand_pattern_transp_0),
- ROP2(cirrus_colorexpand_pattern_transp_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_colorexpand_pattern_transp_src_and_notdst),
- ROP2(cirrus_colorexpand_pattern_transp_notdst),
- ROP2(cirrus_colorexpand_pattern_transp_src),
- ROP2(cirrus_colorexpand_pattern_transp_1),
- ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_dst),
- ROP2(cirrus_colorexpand_pattern_transp_src_xor_dst),
- ROP2(cirrus_colorexpand_pattern_transp_src_or_dst),
- ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_notdst),
- ROP2(cirrus_colorexpand_pattern_transp_src_notxor_dst),
- ROP2(cirrus_colorexpand_pattern_transp_src_or_notdst),
- ROP2(cirrus_colorexpand_pattern_transp_notsrc),
- ROP2(cirrus_colorexpand_pattern_transp_notsrc_or_dst),
- ROP2(cirrus_colorexpand_pattern_transp_notsrc_and_notdst),
-};
-
-static const cirrus_bitblt_rop_t cirrus_colorexpand_pattern[16][4] = {
- ROP2(cirrus_colorexpand_pattern_0),
- ROP2(cirrus_colorexpand_pattern_src_and_dst),
- ROP_NOP2(cirrus_bitblt_rop_nop),
- ROP2(cirrus_colorexpand_pattern_src_and_notdst),
- ROP2(cirrus_colorexpand_pattern_notdst),
- ROP2(cirrus_colorexpand_pattern_src),
- ROP2(cirrus_colorexpand_pattern_1),
- ROP2(cirrus_colorexpand_pattern_notsrc_and_dst),
- ROP2(cirrus_colorexpand_pattern_src_xor_dst),
- ROP2(cirrus_colorexpand_pattern_src_or_dst),
- ROP2(cirrus_colorexpand_pattern_notsrc_or_notdst),
- ROP2(cirrus_colorexpand_pattern_src_notxor_dst),
- ROP2(cirrus_colorexpand_pattern_src_or_notdst),
- ROP2(cirrus_colorexpand_pattern_notsrc),
- ROP2(cirrus_colorexpand_pattern_notsrc_or_dst),
- ROP2(cirrus_colorexpand_pattern_notsrc_and_notdst),
-};
-
-static const cirrus_fill_t cirrus_fill[16][4] = {
- ROP2(cirrus_fill_0),
- ROP2(cirrus_fill_src_and_dst),
- ROP_NOP2(cirrus_bitblt_fill_nop),
- ROP2(cirrus_fill_src_and_notdst),
- ROP2(cirrus_fill_notdst),
- ROP2(cirrus_fill_src),
- ROP2(cirrus_fill_1),
- ROP2(cirrus_fill_notsrc_and_dst),
- ROP2(cirrus_fill_src_xor_dst),
- ROP2(cirrus_fill_src_or_dst),
- ROP2(cirrus_fill_notsrc_or_notdst),
- ROP2(cirrus_fill_src_notxor_dst),
- ROP2(cirrus_fill_src_or_notdst),
- ROP2(cirrus_fill_notsrc),
- ROP2(cirrus_fill_notsrc_or_dst),
- ROP2(cirrus_fill_notsrc_and_notdst),
-};
-
-static inline void cirrus_bitblt_fgcol(CirrusVGAState *s)
-{
- unsigned int color;
- switch (s->cirrus_blt_pixelwidth) {
- case 1:
- s->cirrus_blt_fgcol = s->cirrus_shadow_gr1;
- break;
- case 2:
- color = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8);
- s->cirrus_blt_fgcol = le16_to_cpu(color);
- break;
- case 3:
- s->cirrus_blt_fgcol = s->cirrus_shadow_gr1 |
- (s->gr[0x11] << 8) | (s->gr[0x13] << 16);
- break;
- default:
- case 4:
- color = s->cirrus_shadow_gr1 | (s->gr[0x11] << 8) |
- (s->gr[0x13] << 16) | (s->gr[0x15] << 24);
- s->cirrus_blt_fgcol = le32_to_cpu(color);
- break;
- }
-}
-
-static inline void cirrus_bitblt_bgcol(CirrusVGAState *s)
-{
- unsigned int color;
- switch (s->cirrus_blt_pixelwidth) {
- case 1:
- s->cirrus_blt_bgcol = s->cirrus_shadow_gr0;
- break;
- case 2:
- color = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8);
- s->cirrus_blt_bgcol = le16_to_cpu(color);
- break;
- case 3:
- s->cirrus_blt_bgcol = s->cirrus_shadow_gr0 |
- (s->gr[0x10] << 8) | (s->gr[0x12] << 16);
- break;
- default:
- case 4:
- color = s->cirrus_shadow_gr0 | (s->gr[0x10] << 8) |
- (s->gr[0x12] << 16) | (s->gr[0x14] << 24);
- s->cirrus_blt_bgcol = le32_to_cpu(color);
- break;
- }
-}
-
-static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
- int off_pitch, int bytesperline,
- int lines)
-{
- int y;
- int off_cur;
- int off_cur_end;
-
- for (y = 0; y < lines; y++) {
- off_cur = off_begin;
- off_cur_end = off_cur + bytesperline;
- off_cur &= TARGET_PAGE_MASK;
- while (off_cur < off_cur_end) {
- cpu_physical_memory_set_dirty(s->vram_offset + off_cur);
- off_cur += TARGET_PAGE_SIZE;
- }
- off_begin += off_pitch;
- }
-}
-
-static int cirrus_bitblt_common_patterncopy(CirrusVGAState * s,
- const uint8_t * src)
-{
- uint8_t *dst;
-
- dst = s->vram_ptr + s->cirrus_blt_dstaddr;
- (*s->cirrus_rop) (s, dst, src,
- s->cirrus_blt_dstpitch, 0,
- s->cirrus_blt_width, s->cirrus_blt_height);
- cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
- s->cirrus_blt_dstpitch, s->cirrus_blt_width,
- s->cirrus_blt_height);
- return 1;
-}
-
-/* fill */
-
-static int cirrus_bitblt_solidfill(CirrusVGAState *s, int blt_rop)
-{
- cirrus_fill_t rop_func;
-
- rop_func = cirrus_fill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- rop_func(s, s->vram_ptr + s->cirrus_blt_dstaddr,
- s->cirrus_blt_dstpitch,
- s->cirrus_blt_width, s->cirrus_blt_height);
- cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
- s->cirrus_blt_dstpitch, s->cirrus_blt_width,
- s->cirrus_blt_height);
- cirrus_bitblt_reset(s);
- return 1;
-}
-
-/***************************************
- *
- * bitblt (video-to-video)
- *
- ***************************************/
-
-static int cirrus_bitblt_videotovideo_patterncopy(CirrusVGAState * s)
-{
- return cirrus_bitblt_common_patterncopy(s,
- s->vram_ptr +
- (s->cirrus_blt_srcaddr & ~7));
-}
-
-static void cirrus_do_copy(CirrusVGAState *s, int dst, int src, int w, int h)
-{
- int sx, sy;
- int dx, dy;
- int width, height;
- int depth;
- int notify = 0;
-
- depth = s->get_bpp((VGAState *)s) / 8;
- s->get_resolution((VGAState *)s, &width, &height);
-
- /* extra x, y */
- sx = (src % (width * depth)) / depth;
- sy = (src / (width * depth));
- dx = (dst % (width *depth)) / depth;
- dy = (dst / (width * depth));
-
- /* normalize width */
- w /= depth;
-
- /* if we're doing a backward copy, we have to adjust
- our x/y to be the upper left corner (instead of the lower
- right corner) */
- if (s->cirrus_blt_dstpitch < 0) {
- sx -= (s->cirrus_blt_width / depth) - 1;
- dx -= (s->cirrus_blt_width / depth) - 1;
- sy -= s->cirrus_blt_height - 1;
- dy -= s->cirrus_blt_height - 1;
- }
-
- /* are we in the visible portion of memory? */
- if (sx >= 0 && sy >= 0 && dx >= 0 && dy >= 0 &&
- (sx + w) <= width && (sy + h) <= height &&
- (dx + w) <= width && (dy + h) <= height) {
- notify = 1;
- }
-
- /* make to sure only copy if it's a plain copy ROP */
- if (*s->cirrus_rop != cirrus_bitblt_rop_fwd_src &&
- *s->cirrus_rop != cirrus_bitblt_rop_bkwd_src)
- notify = 0;
-
- /* we have to flush all pending changes so that the copy
- is generated at the appropriate moment in time */
- if (notify)
- vga_hw_update();
-
- (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
- s->vram_ptr + s->cirrus_blt_srcaddr,
- s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
- s->cirrus_blt_width, s->cirrus_blt_height);
-
- if (notify)
- s->ds->dpy_copy(s->ds,
- sx, sy, dx, dy,
- s->cirrus_blt_width / depth,
- s->cirrus_blt_height);
-
- /* we don't have to notify the display that this portion has
- changed since dpy_copy implies this */
-
- if (!notify)
- cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
- s->cirrus_blt_dstpitch, s->cirrus_blt_width,
- s->cirrus_blt_height);
-}
-
-static int cirrus_bitblt_videotovideo_copy(CirrusVGAState * s)
-{
- if (s->ds->dpy_copy) {
- cirrus_do_copy(s, s->cirrus_blt_dstaddr - s->start_addr,
- s->cirrus_blt_srcaddr - s->start_addr,
- s->cirrus_blt_width, s->cirrus_blt_height);
- } else {
- (*s->cirrus_rop) (s, s->vram_ptr + s->cirrus_blt_dstaddr,
- s->vram_ptr + s->cirrus_blt_srcaddr,
- s->cirrus_blt_dstpitch, s->cirrus_blt_srcpitch,
- s->cirrus_blt_width, s->cirrus_blt_height);
-
- cirrus_invalidate_region(s, s->cirrus_blt_dstaddr,
- s->cirrus_blt_dstpitch, s->cirrus_blt_width,
- s->cirrus_blt_height);
- }
-
- return 1;
-}
-
-/***************************************
- *
- * bitblt (cpu-to-video)
- *
- ***************************************/
-
-static void cirrus_bitblt_cputovideo_next(CirrusVGAState * s)
-{
- int copy_count;
- uint8_t *end_ptr;
-
- if (s->cirrus_srccounter > 0) {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- cirrus_bitblt_common_patterncopy(s, s->cirrus_bltbuf);
- the_end:
- s->cirrus_srccounter = 0;
- cirrus_bitblt_reset(s);
- } else {
- /* at least one scan line */
- do {
- (*s->cirrus_rop)(s, s->vram_ptr + s->cirrus_blt_dstaddr,
- s->cirrus_bltbuf, 0, 0, s->cirrus_blt_width, 1);
- cirrus_invalidate_region(s, s->cirrus_blt_dstaddr, 0,
- s->cirrus_blt_width, 1);
- s->cirrus_blt_dstaddr += s->cirrus_blt_dstpitch;
- s->cirrus_srccounter -= s->cirrus_blt_srcpitch;
- if (s->cirrus_srccounter <= 0)
- goto the_end;
- /* more bytes than needed can be transfered because of
- word alignment, so we keep them for the next line */
- /* XXX: keep alignment to speed up transfer */
- end_ptr = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
- copy_count = s->cirrus_srcptr_end - end_ptr;
- memmove(s->cirrus_bltbuf, end_ptr, copy_count);
- s->cirrus_srcptr = s->cirrus_bltbuf + copy_count;
- s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
- } while (s->cirrus_srcptr >= s->cirrus_srcptr_end);
- }
- }
-}
-
-/***************************************
- *
- * bitblt wrapper
- *
- ***************************************/
-
-static void cirrus_bitblt_reset(CirrusVGAState * s)
-{
- s->gr[0x31] &=
- ~(CIRRUS_BLT_START | CIRRUS_BLT_BUSY | CIRRUS_BLT_FIFOUSED);
- s->cirrus_srcptr = &s->cirrus_bltbuf[0];
- s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
- s->cirrus_srccounter = 0;
- cirrus_update_memory_access(s);
-}
-
-static int cirrus_bitblt_cputovideo(CirrusVGAState * s)
-{
- int w;
-
- s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_MEMSYSSRC;
- s->cirrus_srcptr = &s->cirrus_bltbuf[0];
- s->cirrus_srcptr_end = &s->cirrus_bltbuf[0];
-
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
- s->cirrus_blt_srcpitch = 8;
- } else {
- /* XXX: check for 24 bpp */
- s->cirrus_blt_srcpitch = 8 * 8 * s->cirrus_blt_pixelwidth;
- }
- s->cirrus_srccounter = s->cirrus_blt_srcpitch;
- } else {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
- w = s->cirrus_blt_width / s->cirrus_blt_pixelwidth;
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY)
- s->cirrus_blt_srcpitch = ((w + 31) >> 5);
- else
- s->cirrus_blt_srcpitch = ((w + 7) >> 3);
- } else {
- /* always align input size to 32 bits */
- s->cirrus_blt_srcpitch = (s->cirrus_blt_width + 3) & ~3;
- }
- s->cirrus_srccounter = s->cirrus_blt_srcpitch * s->cirrus_blt_height;
- }
- s->cirrus_srcptr = s->cirrus_bltbuf;
- s->cirrus_srcptr_end = s->cirrus_bltbuf + s->cirrus_blt_srcpitch;
- cirrus_update_memory_access(s);
- return 1;
-}
-
-static int cirrus_bitblt_videotocpu(CirrusVGAState * s)
-{
- /* XXX */
-#ifdef DEBUG_BITBLT
- printf("cirrus: bitblt (video to cpu) is not implemented yet\n");
-#endif
- return 0;
-}
-
-static int cirrus_bitblt_videotovideo(CirrusVGAState * s)
-{
- int ret;
-
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- ret = cirrus_bitblt_videotovideo_patterncopy(s);
- } else {
- ret = cirrus_bitblt_videotovideo_copy(s);
- }
- if (ret)
- cirrus_bitblt_reset(s);
- return ret;
-}
-
-static void cirrus_bitblt_start(CirrusVGAState * s)
-{
- uint8_t blt_rop;
-
- s->gr[0x31] |= CIRRUS_BLT_BUSY;
-
- s->cirrus_blt_width = (s->gr[0x20] | (s->gr[0x21] << 8)) + 1;
- s->cirrus_blt_height = (s->gr[0x22] | (s->gr[0x23] << 8)) + 1;
- s->cirrus_blt_dstpitch = (s->gr[0x24] | (s->gr[0x25] << 8));
- s->cirrus_blt_srcpitch = (s->gr[0x26] | (s->gr[0x27] << 8));
- s->cirrus_blt_dstaddr =
- (s->gr[0x28] | (s->gr[0x29] << 8) | (s->gr[0x2a] << 16));
- s->cirrus_blt_srcaddr =
- (s->gr[0x2c] | (s->gr[0x2d] << 8) | (s->gr[0x2e] << 16));
- s->cirrus_blt_mode = s->gr[0x30];
- s->cirrus_blt_modeext = s->gr[0x33];
- blt_rop = s->gr[0x32];
-
-#ifdef DEBUG_BITBLT
- printf("rop=0x%02x mode=0x%02x modeext=0x%02x w=%d h=%d dpitch=%d spitch=%d daddr=0x%08x saddr=0x%08x writemask=0x%02x\n",
- blt_rop,
- s->cirrus_blt_mode,
- s->cirrus_blt_modeext,
- s->cirrus_blt_width,
- s->cirrus_blt_height,
- s->cirrus_blt_dstpitch,
- s->cirrus_blt_srcpitch,
- s->cirrus_blt_dstaddr,
- s->cirrus_blt_srcaddr,
- s->gr[0x2f]);
-#endif
-
- switch (s->cirrus_blt_mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) {
- case CIRRUS_BLTMODE_PIXELWIDTH8:
- s->cirrus_blt_pixelwidth = 1;
- break;
- case CIRRUS_BLTMODE_PIXELWIDTH16:
- s->cirrus_blt_pixelwidth = 2;
- break;
- case CIRRUS_BLTMODE_PIXELWIDTH24:
- s->cirrus_blt_pixelwidth = 3;
- break;
- case CIRRUS_BLTMODE_PIXELWIDTH32:
- s->cirrus_blt_pixelwidth = 4;
- break;
- default:
-#ifdef DEBUG_BITBLT
- printf("cirrus: bitblt - pixel width is unknown\n");
-#endif
- goto bitblt_ignore;
- }
- s->cirrus_blt_mode &= ~CIRRUS_BLTMODE_PIXELWIDTHMASK;
-
- if ((s->
- cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSSRC |
- CIRRUS_BLTMODE_MEMSYSDEST))
- == (CIRRUS_BLTMODE_MEMSYSSRC | CIRRUS_BLTMODE_MEMSYSDEST)) {
-#ifdef DEBUG_BITBLT
- printf("cirrus: bitblt - memory-to-memory copy is requested\n");
-#endif
- goto bitblt_ignore;
- }
-
- if ((s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) &&
- (s->cirrus_blt_mode & (CIRRUS_BLTMODE_MEMSYSDEST |
- CIRRUS_BLTMODE_TRANSPARENTCOMP |
- CIRRUS_BLTMODE_PATTERNCOPY |
- CIRRUS_BLTMODE_COLOREXPAND)) ==
- (CIRRUS_BLTMODE_PATTERNCOPY | CIRRUS_BLTMODE_COLOREXPAND)) {
- cirrus_bitblt_fgcol(s);
- cirrus_bitblt_solidfill(s, blt_rop);
- } else {
- if ((s->cirrus_blt_mode & (CIRRUS_BLTMODE_COLOREXPAND |
- CIRRUS_BLTMODE_PATTERNCOPY)) ==
- CIRRUS_BLTMODE_COLOREXPAND) {
-
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
- cirrus_bitblt_bgcol(s);
- else
- cirrus_bitblt_fgcol(s);
- s->cirrus_rop = cirrus_colorexpand_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- } else {
- cirrus_bitblt_fgcol(s);
- cirrus_bitblt_bgcol(s);
- s->cirrus_rop = cirrus_colorexpand[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- }
- } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_PATTERNCOPY) {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_COLOREXPAND) {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) {
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV)
- cirrus_bitblt_bgcol(s);
- else
- cirrus_bitblt_fgcol(s);
- s->cirrus_rop = cirrus_colorexpand_pattern_transp[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- } else {
- cirrus_bitblt_fgcol(s);
- cirrus_bitblt_bgcol(s);
- s->cirrus_rop = cirrus_colorexpand_pattern[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- }
- } else {
- s->cirrus_rop = cirrus_patternfill[rop_to_index[blt_rop]][s->cirrus_blt_pixelwidth - 1];
- }
- } else {
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_BACKWARDS) {
- s->cirrus_blt_dstpitch = -s->cirrus_blt_dstpitch;
- s->cirrus_blt_srcpitch = -s->cirrus_blt_srcpitch;
- s->cirrus_rop = cirrus_bkwd_rop[rop_to_index[blt_rop]];
- } else {
- s->cirrus_rop = cirrus_fwd_rop[rop_to_index[blt_rop]];
- }
- }
-
- // setup bitblt engine.
- if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSSRC) {
- if (!cirrus_bitblt_cputovideo(s))
- goto bitblt_ignore;
- } else if (s->cirrus_blt_mode & CIRRUS_BLTMODE_MEMSYSDEST) {
- if (!cirrus_bitblt_videotocpu(s))
- goto bitblt_ignore;
- } else {
- if (!cirrus_bitblt_videotovideo(s))
- goto bitblt_ignore;
- }
- }
- return;
- bitblt_ignore:;
- cirrus_bitblt_reset(s);
-}
-
-static void cirrus_write_bitblt(CirrusVGAState * s, unsigned reg_value)
-{
- unsigned old_value;
-
- old_value = s->gr[0x31];
- s->gr[0x31] = reg_value;
-
- if (((old_value & CIRRUS_BLT_RESET) != 0) &&
- ((reg_value & CIRRUS_BLT_RESET) == 0)) {
- cirrus_bitblt_reset(s);
- } else if (((old_value & CIRRUS_BLT_START) == 0) &&
- ((reg_value & CIRRUS_BLT_START) != 0)) {
- cirrus_bitblt_start(s);
- }
-}
-
-
-/***************************************
- *
- * basic parameters
- *
- ***************************************/
-
-static void cirrus_get_offsets(VGAState *s1,
- uint32_t *pline_offset,
- uint32_t *pstart_addr)
-{
- CirrusVGAState * s = (CirrusVGAState *)s1;
- uint32_t start_addr;
- uint32_t line_offset;
-
- line_offset = s->cr[0x13]
- | ((s->cr[0x1b] & 0x10) << 4);
- line_offset <<= 3;
- *pline_offset = line_offset;
-
- start_addr = (s->cr[0x0c] << 8)
- | s->cr[0x0d]
- | ((s->cr[0x1b] & 0x01) << 16)
- | ((s->cr[0x1b] & 0x0c) << 15)
- | ((s->cr[0x1d] & 0x80) << 12);
- *pstart_addr = start_addr;
-}
-
-static uint32_t cirrus_get_bpp16_depth(CirrusVGAState * s)
-{
- uint32_t ret = 16;
-
- switch (s->cirrus_hidden_dac_data & 0xf) {
- case 0:
- ret = 15;
- break; /* Sierra HiColor */
- case 1:
- ret = 16;
- break; /* XGA HiColor */
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: invalid DAC value %x in 16bpp\n",
- (s->cirrus_hidden_dac_data & 0xf));
-#endif
- ret = 15; /* XXX */
- break;
- }
- return ret;
-}
-
-static int cirrus_get_bpp(VGAState *s1)
-{
- CirrusVGAState * s = (CirrusVGAState *)s1;
- uint32_t ret = 8;
-
- if ((s->sr[0x07] & 0x01) != 0) {
- /* Cirrus SVGA */
- switch (s->sr[0x07] & CIRRUS_SR7_BPP_MASK) {
- case CIRRUS_SR7_BPP_8:
- ret = 8;
- break;
- case CIRRUS_SR7_BPP_16_DOUBLEVCLK:
- ret = cirrus_get_bpp16_depth(s);
- break;
- case CIRRUS_SR7_BPP_24:
- ret = 24;
- break;
- case CIRRUS_SR7_BPP_16:
- ret = cirrus_get_bpp16_depth(s);
- break;
- case CIRRUS_SR7_BPP_32:
- ret = 32;
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: unknown bpp - sr7=%x\n", s->sr[0x7]);
-#endif
- ret = 8;
- break;
- }
- } else {
- /* VGA */
- ret = 0;
- }
-
- return ret;
-}
-
-static void cirrus_get_resolution(VGAState *s, int *pwidth, int *pheight)
-{
- int width, height;
-
- width = (s->cr[0x01] + 1) * 8;
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
- height = (height + 1);
- /* interlace support */
- if (s->cr[0x1a] & 0x01)
- height = height * 2;
- *pwidth = width;
- *pheight = height;
-}
-
-/***************************************
- *
- * bank memory
- *
- ***************************************/
-
-static void cirrus_update_bank_ptr(CirrusVGAState * s, unsigned bank_index)
-{
- unsigned offset;
- unsigned limit;
-
- if ((s->gr[0x0b] & 0x01) != 0) /* dual bank */
- offset = s->gr[0x09 + bank_index];
- else /* single bank */
- offset = s->gr[0x09];
-
- if ((s->gr[0x0b] & 0x20) != 0)
- offset <<= 14;
- else
- offset <<= 12;
-
- if (s->real_vram_size <= offset)
- limit = 0;
- else
- limit = s->real_vram_size - offset;
-
- if (((s->gr[0x0b] & 0x01) == 0) && (bank_index != 0)) {
- if (limit > 0x8000) {
- offset += 0x8000;
- limit -= 0x8000;
- } else {
- limit = 0;
- }
- }
-
- if (limit > 0) {
- s->cirrus_bank_base[bank_index] = offset;
- s->cirrus_bank_limit[bank_index] = limit;
- } else {
- s->cirrus_bank_base[bank_index] = 0;
- s->cirrus_bank_limit[bank_index] = 0;
- }
-}
-
-/***************************************
- *
- * I/O access between 0x3c4-0x3c5
- *
- ***************************************/
-
-static int
-cirrus_hook_read_sr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
-{
- switch (reg_index) {
- case 0x00: // Standard VGA
- case 0x01: // Standard VGA
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- return CIRRUS_HOOK_NOT_HANDLED;
- case 0x06: // Unlock Cirrus extensions
- *reg_value = s->sr[reg_index];
- break;
- case 0x10:
- case 0x30:
- case 0x50:
- case 0x70: // Graphics Cursor X
- case 0x90:
- case 0xb0:
- case 0xd0:
- case 0xf0: // Graphics Cursor X
- *reg_value = s->sr[0x10];
- break;
- case 0x11:
- case 0x31:
- case 0x51:
- case 0x71: // Graphics Cursor Y
- case 0x91:
- case 0xb1:
- case 0xd1:
- case 0xf1: // Graphics Cursor Y
- *reg_value = s->sr[0x11];
- break;
- case 0x05: // ???
- case 0x07: // Extended Sequencer Mode
- case 0x08: // EEPROM Control
- case 0x09: // Scratch Register 0
- case 0x0a: // Scratch Register 1
- case 0x0b: // VCLK 0
- case 0x0c: // VCLK 1
- case 0x0d: // VCLK 2
- case 0x0e: // VCLK 3
- case 0x0f: // DRAM Control
- case 0x12: // Graphics Cursor Attribute
- case 0x13: // Graphics Cursor Pattern Address
- case 0x14: // Scratch Register 2
- case 0x15: // Scratch Register 3
- case 0x16: // Performance Tuning Register
- case 0x17: // Configuration Readback and Extended Control
- case 0x18: // Signature Generator Control
- case 0x19: // Signal Generator Result
- case 0x1a: // Signal Generator Result
- case 0x1b: // VCLK 0 Denominator & Post
- case 0x1c: // VCLK 1 Denominator & Post
- case 0x1d: // VCLK 2 Denominator & Post
- case 0x1e: // VCLK 3 Denominator & Post
- case 0x1f: // BIOS Write Enable and MCLK select
-#ifdef DEBUG_CIRRUS
- printf("cirrus: handled inport sr_index %02x\n", reg_index);
-#endif
- *reg_value = s->sr[reg_index];
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: inport sr_index %02x\n", reg_index);
-#endif
- *reg_value = 0xff;
- break;
- }
-
- return CIRRUS_HOOK_HANDLED;
-}
-
-static int
-cirrus_hook_write_sr(CirrusVGAState * s, unsigned reg_index, int reg_value)
-{
- switch (reg_index) {
- case 0x00: // Standard VGA
- case 0x01: // Standard VGA
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- return CIRRUS_HOOK_NOT_HANDLED;
- case 0x06: // Unlock Cirrus extensions
- reg_value &= 0x17;
- if (reg_value == 0x12) {
- s->sr[reg_index] = 0x12;
- } else {
- s->sr[reg_index] = 0x0f;
- }
- break;
- case 0x10:
- case 0x30:
- case 0x50:
- case 0x70: // Graphics Cursor X
- case 0x90:
- case 0xb0:
- case 0xd0:
- case 0xf0: // Graphics Cursor X
- s->sr[0x10] = reg_value;
- s->hw_cursor_x = (reg_value << 3) | (reg_index >> 5);
- break;
- case 0x11:
- case 0x31:
- case 0x51:
- case 0x71: // Graphics Cursor Y
- case 0x91:
- case 0xb1:
- case 0xd1:
- case 0xf1: // Graphics Cursor Y
- s->sr[0x11] = reg_value;
- s->hw_cursor_y = (reg_value << 3) | (reg_index >> 5);
- break;
- case 0x07: // Extended Sequencer Mode
- case 0x08: // EEPROM Control
- case 0x09: // Scratch Register 0
- case 0x0a: // Scratch Register 1
- case 0x0b: // VCLK 0
- case 0x0c: // VCLK 1
- case 0x0d: // VCLK 2
- case 0x0e: // VCLK 3
- case 0x0f: // DRAM Control
- case 0x12: // Graphics Cursor Attribute
- case 0x13: // Graphics Cursor Pattern Address
- case 0x14: // Scratch Register 2
- case 0x15: // Scratch Register 3
- case 0x16: // Performance Tuning Register
- case 0x18: // Signature Generator Control
- case 0x19: // Signature Generator Result
- case 0x1a: // Signature Generator Result
- case 0x1b: // VCLK 0 Denominator & Post
- case 0x1c: // VCLK 1 Denominator & Post
- case 0x1d: // VCLK 2 Denominator & Post
- case 0x1e: // VCLK 3 Denominator & Post
- case 0x1f: // BIOS Write Enable and MCLK select
- s->sr[reg_index] = reg_value;
-#ifdef DEBUG_CIRRUS
- printf("cirrus: handled outport sr_index %02x, sr_value %02x\n",
- reg_index, reg_value);
-#endif
- break;
- case 0x17: // Configuration Readback and Extended Control
- s->sr[reg_index] = (s->sr[reg_index] & 0x38) | (reg_value & 0xc7);
- cirrus_update_memory_access(s);
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: outport sr_index %02x, sr_value %02x\n", reg_index,
- reg_value);
-#endif
- break;
- }
-
- return CIRRUS_HOOK_HANDLED;
-}
-
-/***************************************
- *
- * I/O access at 0x3c6
- *
- ***************************************/
-
-static void cirrus_read_hidden_dac(CirrusVGAState * s, int *reg_value)
-{
- *reg_value = 0xff;
- if (++s->cirrus_hidden_dac_lockindex == 5) {
- *reg_value = s->cirrus_hidden_dac_data;
- s->cirrus_hidden_dac_lockindex = 0;
- }
-}
-
-static void cirrus_write_hidden_dac(CirrusVGAState * s, int reg_value)
-{
- if (s->cirrus_hidden_dac_lockindex == 4) {
- s->cirrus_hidden_dac_data = reg_value;
-#if defined(DEBUG_CIRRUS)
- printf("cirrus: outport hidden DAC, value %02x\n", reg_value);
-#endif
- }
- s->cirrus_hidden_dac_lockindex = 0;
-}
-
-/***************************************
- *
- * I/O access at 0x3c9
- *
- ***************************************/
-
-static int cirrus_hook_read_palette(CirrusVGAState * s, int *reg_value)
-{
- if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL))
- return CIRRUS_HOOK_NOT_HANDLED;
- *reg_value =
- s->cirrus_hidden_palette[(s->dac_read_index & 0x0f) * 3 +
- s->dac_sub_index];
- if (++s->dac_sub_index == 3) {
- s->dac_sub_index = 0;
- s->dac_read_index++;
- }
- return CIRRUS_HOOK_HANDLED;
-}
-
-static int cirrus_hook_write_palette(CirrusVGAState * s, int reg_value)
-{
- if (!(s->sr[0x12] & CIRRUS_CURSOR_HIDDENPEL))
- return CIRRUS_HOOK_NOT_HANDLED;
- s->dac_cache[s->dac_sub_index] = reg_value;
- if (++s->dac_sub_index == 3) {
- memcpy(&s->cirrus_hidden_palette[(s->dac_write_index & 0x0f) * 3],
- s->dac_cache, 3);
- /* XXX update cursor */
- s->dac_sub_index = 0;
- s->dac_write_index++;
- }
- return CIRRUS_HOOK_HANDLED;
-}
-
-/***************************************
- *
- * I/O access between 0x3ce-0x3cf
- *
- ***************************************/
-
-static int
-cirrus_hook_read_gr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
-{
- switch (reg_index) {
- case 0x00: // Standard VGA, BGCOLOR 0x000000ff
- *reg_value = s->cirrus_shadow_gr0;
- return CIRRUS_HOOK_HANDLED;
- case 0x01: // Standard VGA, FGCOLOR 0x000000ff
- *reg_value = s->cirrus_shadow_gr1;
- return CIRRUS_HOOK_HANDLED;
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- case 0x06: // Standard VGA
- case 0x07: // Standard VGA
- case 0x08: // Standard VGA
- return CIRRUS_HOOK_NOT_HANDLED;
- case 0x05: // Standard VGA, Cirrus extended mode
- default:
- break;
- }
-
- if (reg_index < 0x3a) {
- *reg_value = s->gr[reg_index];
- } else {
-#ifdef DEBUG_CIRRUS
- printf("cirrus: inport gr_index %02x\n", reg_index);
-#endif
- *reg_value = 0xff;
- }
-
- return CIRRUS_HOOK_HANDLED;
-}
-
-static int
-cirrus_hook_write_gr(CirrusVGAState * s, unsigned reg_index, int reg_value)
-{
-#if defined(DEBUG_BITBLT) && 0
- printf("gr%02x: %02x\n", reg_index, reg_value);
-#endif
- switch (reg_index) {
- case 0x00: // Standard VGA, BGCOLOR 0x000000ff
- s->cirrus_shadow_gr0 = reg_value;
- return CIRRUS_HOOK_NOT_HANDLED;
- case 0x01: // Standard VGA, FGCOLOR 0x000000ff
- s->cirrus_shadow_gr1 = reg_value;
- return CIRRUS_HOOK_NOT_HANDLED;
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- case 0x06: // Standard VGA
- case 0x07: // Standard VGA
- case 0x08: // Standard VGA
- return CIRRUS_HOOK_NOT_HANDLED;
- case 0x05: // Standard VGA, Cirrus extended mode
- s->gr[reg_index] = reg_value & 0x7f;
- cirrus_update_memory_access(s);
- break;
- case 0x09: // bank offset #0
- case 0x0A: // bank offset #1
- s->gr[reg_index] = reg_value;
- cirrus_update_bank_ptr(s, 0);
- cirrus_update_bank_ptr(s, 1);
- break;
- case 0x0B:
- s->gr[reg_index] = reg_value;
- cirrus_update_bank_ptr(s, 0);
- cirrus_update_bank_ptr(s, 1);
- cirrus_update_memory_access(s);
- break;
- case 0x10: // BGCOLOR 0x0000ff00
- case 0x11: // FGCOLOR 0x0000ff00
- case 0x12: // BGCOLOR 0x00ff0000
- case 0x13: // FGCOLOR 0x00ff0000
- case 0x14: // BGCOLOR 0xff000000
- case 0x15: // FGCOLOR 0xff000000
- case 0x20: // BLT WIDTH 0x0000ff
- case 0x22: // BLT HEIGHT 0x0000ff
- case 0x24: // BLT DEST PITCH 0x0000ff
- case 0x26: // BLT SRC PITCH 0x0000ff
- case 0x28: // BLT DEST ADDR 0x0000ff
- case 0x29: // BLT DEST ADDR 0x00ff00
- case 0x2c: // BLT SRC ADDR 0x0000ff
- case 0x2d: // BLT SRC ADDR 0x00ff00
- case 0x2f: // BLT WRITEMASK
- case 0x30: // BLT MODE
- case 0x32: // RASTER OP
- case 0x33: // BLT MODEEXT
- case 0x34: // BLT TRANSPARENT COLOR 0x00ff
- case 0x35: // BLT TRANSPARENT COLOR 0xff00
- case 0x38: // BLT TRANSPARENT COLOR MASK 0x00ff
- case 0x39: // BLT TRANSPARENT COLOR MASK 0xff00
- s->gr[reg_index] = reg_value;
- break;
- case 0x21: // BLT WIDTH 0x001f00
- case 0x23: // BLT HEIGHT 0x001f00
- case 0x25: // BLT DEST PITCH 0x001f00
- case 0x27: // BLT SRC PITCH 0x001f00
- s->gr[reg_index] = reg_value & 0x1f;
- break;
- case 0x2a: // BLT DEST ADDR 0x3f0000
- s->gr[reg_index] = reg_value & 0x3f;
- /* if auto start mode, starts bit blt now */
- if (s->gr[0x31] & CIRRUS_BLT_AUTOSTART) {
- cirrus_bitblt_start(s);
- }
- break;
- case 0x2e: // BLT SRC ADDR 0x3f0000
- s->gr[reg_index] = reg_value & 0x3f;
- break;
- case 0x31: // BLT STATUS/START
- cirrus_write_bitblt(s, reg_value);
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: outport gr_index %02x, gr_value %02x\n", reg_index,
- reg_value);
-#endif
- break;
- }
-
- return CIRRUS_HOOK_HANDLED;
-}
-
-/***************************************
- *
- * I/O access between 0x3d4-0x3d5
- *
- ***************************************/
-
-static int
-cirrus_hook_read_cr(CirrusVGAState * s, unsigned reg_index, int *reg_value)
-{
- switch (reg_index) {
- case 0x00: // Standard VGA
- case 0x01: // Standard VGA
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- case 0x05: // Standard VGA
- case 0x06: // Standard VGA
- case 0x07: // Standard VGA
- case 0x08: // Standard VGA
- case 0x09: // Standard VGA
- case 0x0a: // Standard VGA
- case 0x0b: // Standard VGA
- case 0x0c: // Standard VGA
- case 0x0d: // Standard VGA
- case 0x0e: // Standard VGA
- case 0x0f: // Standard VGA
- case 0x10: // Standard VGA
- case 0x11: // Standard VGA
- case 0x12: // Standard VGA
- case 0x13: // Standard VGA
- case 0x14: // Standard VGA
- case 0x15: // Standard VGA
- case 0x16: // Standard VGA
- case 0x17: // Standard VGA
- case 0x18: // Standard VGA
- return CIRRUS_HOOK_NOT_HANDLED;
- case 0x19: // Interlace End
- case 0x1a: // Miscellaneous Control
- case 0x1b: // Extended Display Control
- case 0x1c: // Sync Adjust and Genlock
- case 0x1d: // Overlay Extended Control
- case 0x22: // Graphics Data Latches Readback (R)
- case 0x24: // Attribute Controller Toggle Readback (R)
- case 0x25: // Part Status
- case 0x27: // Part ID (R)
- *reg_value = s->cr[reg_index];
- break;
- case 0x26: // Attribute Controller Index Readback (R)
- *reg_value = s->ar_index & 0x3f;
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: inport cr_index %02x\n", reg_index);
- *reg_value = 0xff;
-#endif
- break;
- }
-
- return CIRRUS_HOOK_HANDLED;
-}
-
-static int
-cirrus_hook_write_cr(CirrusVGAState * s, unsigned reg_index, int reg_value)
-{
- switch (reg_index) {
- case 0x00: // Standard VGA
- case 0x01: // Standard VGA
- case 0x02: // Standard VGA
- case 0x03: // Standard VGA
- case 0x04: // Standard VGA
- case 0x05: // Standard VGA
- case 0x06: // Standard VGA
- case 0x07: // Standard VGA
- case 0x08: // Standard VGA
- case 0x09: // Standard VGA
- case 0x0a: // Standard VGA
- case 0x0b: // Standard VGA
- case 0x0c: // Standard VGA
- case 0x0d: // Standard VGA
- case 0x0e: // Standard VGA
- case 0x0f: // Standard VGA
- case 0x10: // Standard VGA
- case 0x11: // Standard VGA
- case 0x12: // Standard VGA
- case 0x13: // Standard VGA
- case 0x14: // Standard VGA
- case 0x15: // Standard VGA
- case 0x16: // Standard VGA
- case 0x17: // Standard VGA
- case 0x18: // Standard VGA
- return CIRRUS_HOOK_NOT_HANDLED;
- case 0x19: // Interlace End
- case 0x1a: // Miscellaneous Control
- case 0x1b: // Extended Display Control
- case 0x1c: // Sync Adjust and Genlock
- case 0x1d: // Overlay Extended Control
- s->cr[reg_index] = reg_value;
-#ifdef DEBUG_CIRRUS
- printf("cirrus: handled outport cr_index %02x, cr_value %02x\n",
- reg_index, reg_value);
-#endif
- break;
- case 0x22: // Graphics Data Latches Readback (R)
- case 0x24: // Attribute Controller Toggle Readback (R)
- case 0x26: // Attribute Controller Index Readback (R)
- case 0x27: // Part ID (R)
- break;
- case 0x25: // Part Status
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: outport cr_index %02x, cr_value %02x\n", reg_index,
- reg_value);
-#endif
- break;
- }
-
- return CIRRUS_HOOK_HANDLED;
-}
-
-/***************************************
- *
- * memory-mapped I/O (bitblt)
- *
- ***************************************/
-
-static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
-{
- int value = 0xff;
-
- switch (address) {
- case (CIRRUS_MMIO_BLTBGCOLOR + 0):
- cirrus_hook_read_gr(s, 0x00, &value);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 1):
- cirrus_hook_read_gr(s, 0x10, &value);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 2):
- cirrus_hook_read_gr(s, 0x12, &value);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 3):
- cirrus_hook_read_gr(s, 0x14, &value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 0):
- cirrus_hook_read_gr(s, 0x01, &value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 1):
- cirrus_hook_read_gr(s, 0x11, &value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 2):
- cirrus_hook_read_gr(s, 0x13, &value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 3):
- cirrus_hook_read_gr(s, 0x15, &value);
- break;
- case (CIRRUS_MMIO_BLTWIDTH + 0):
- cirrus_hook_read_gr(s, 0x20, &value);
- break;
- case (CIRRUS_MMIO_BLTWIDTH + 1):
- cirrus_hook_read_gr(s, 0x21, &value);
- break;
- case (CIRRUS_MMIO_BLTHEIGHT + 0):
- cirrus_hook_read_gr(s, 0x22, &value);
- break;
- case (CIRRUS_MMIO_BLTHEIGHT + 1):
- cirrus_hook_read_gr(s, 0x23, &value);
- break;
- case (CIRRUS_MMIO_BLTDESTPITCH + 0):
- cirrus_hook_read_gr(s, 0x24, &value);
- break;
- case (CIRRUS_MMIO_BLTDESTPITCH + 1):
- cirrus_hook_read_gr(s, 0x25, &value);
- break;
- case (CIRRUS_MMIO_BLTSRCPITCH + 0):
- cirrus_hook_read_gr(s, 0x26, &value);
- break;
- case (CIRRUS_MMIO_BLTSRCPITCH + 1):
- cirrus_hook_read_gr(s, 0x27, &value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 0):
- cirrus_hook_read_gr(s, 0x28, &value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 1):
- cirrus_hook_read_gr(s, 0x29, &value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 2):
- cirrus_hook_read_gr(s, 0x2a, &value);
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 0):
- cirrus_hook_read_gr(s, 0x2c, &value);
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 1):
- cirrus_hook_read_gr(s, 0x2d, &value);
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 2):
- cirrus_hook_read_gr(s, 0x2e, &value);
- break;
- case CIRRUS_MMIO_BLTWRITEMASK:
- cirrus_hook_read_gr(s, 0x2f, &value);
- break;
- case CIRRUS_MMIO_BLTMODE:
- cirrus_hook_read_gr(s, 0x30, &value);
- break;
- case CIRRUS_MMIO_BLTROP:
- cirrus_hook_read_gr(s, 0x32, &value);
- break;
- case CIRRUS_MMIO_BLTMODEEXT:
- cirrus_hook_read_gr(s, 0x33, &value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
- cirrus_hook_read_gr(s, 0x34, &value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
- cirrus_hook_read_gr(s, 0x35, &value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
- cirrus_hook_read_gr(s, 0x38, &value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
- cirrus_hook_read_gr(s, 0x39, &value);
- break;
- case CIRRUS_MMIO_BLTSTATUS:
- cirrus_hook_read_gr(s, 0x31, &value);
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mmio read - address 0x%04x\n", address);
-#endif
- break;
- }
-
- return (uint8_t) value;
-}
-
-static void cirrus_mmio_blt_write(CirrusVGAState * s, unsigned address,
- uint8_t value)
-{
- switch (address) {
- case (CIRRUS_MMIO_BLTBGCOLOR + 0):
- cirrus_hook_write_gr(s, 0x00, value);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 1):
- cirrus_hook_write_gr(s, 0x10, value);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 2):
- cirrus_hook_write_gr(s, 0x12, value);
- break;
- case (CIRRUS_MMIO_BLTBGCOLOR + 3):
- cirrus_hook_write_gr(s, 0x14, value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 0):
- cirrus_hook_write_gr(s, 0x01, value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 1):
- cirrus_hook_write_gr(s, 0x11, value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 2):
- cirrus_hook_write_gr(s, 0x13, value);
- break;
- case (CIRRUS_MMIO_BLTFGCOLOR + 3):
- cirrus_hook_write_gr(s, 0x15, value);
- break;
- case (CIRRUS_MMIO_BLTWIDTH + 0):
- cirrus_hook_write_gr(s, 0x20, value);
- break;
- case (CIRRUS_MMIO_BLTWIDTH + 1):
- cirrus_hook_write_gr(s, 0x21, value);
- break;
- case (CIRRUS_MMIO_BLTHEIGHT + 0):
- cirrus_hook_write_gr(s, 0x22, value);
- break;
- case (CIRRUS_MMIO_BLTHEIGHT + 1):
- cirrus_hook_write_gr(s, 0x23, value);
- break;
- case (CIRRUS_MMIO_BLTDESTPITCH + 0):
- cirrus_hook_write_gr(s, 0x24, value);
- break;
- case (CIRRUS_MMIO_BLTDESTPITCH + 1):
- cirrus_hook_write_gr(s, 0x25, value);
- break;
- case (CIRRUS_MMIO_BLTSRCPITCH + 0):
- cirrus_hook_write_gr(s, 0x26, value);
- break;
- case (CIRRUS_MMIO_BLTSRCPITCH + 1):
- cirrus_hook_write_gr(s, 0x27, value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 0):
- cirrus_hook_write_gr(s, 0x28, value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 1):
- cirrus_hook_write_gr(s, 0x29, value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 2):
- cirrus_hook_write_gr(s, 0x2a, value);
- break;
- case (CIRRUS_MMIO_BLTDESTADDR + 3):
- /* ignored */
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 0):
- cirrus_hook_write_gr(s, 0x2c, value);
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 1):
- cirrus_hook_write_gr(s, 0x2d, value);
- break;
- case (CIRRUS_MMIO_BLTSRCADDR + 2):
- cirrus_hook_write_gr(s, 0x2e, value);
- break;
- case CIRRUS_MMIO_BLTWRITEMASK:
- cirrus_hook_write_gr(s, 0x2f, value);
- break;
- case CIRRUS_MMIO_BLTMODE:
- cirrus_hook_write_gr(s, 0x30, value);
- break;
- case CIRRUS_MMIO_BLTROP:
- cirrus_hook_write_gr(s, 0x32, value);
- break;
- case CIRRUS_MMIO_BLTMODEEXT:
- cirrus_hook_write_gr(s, 0x33, value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
- cirrus_hook_write_gr(s, 0x34, value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
- cirrus_hook_write_gr(s, 0x35, value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
- cirrus_hook_write_gr(s, 0x38, value);
- break;
- case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
- cirrus_hook_write_gr(s, 0x39, value);
- break;
- case CIRRUS_MMIO_BLTSTATUS:
- cirrus_hook_write_gr(s, 0x31, value);
- break;
- default:
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mmio write - addr 0x%04x val 0x%02x (ignored)\n",
- address, value);
-#endif
- break;
- }
-}
-
-/***************************************
- *
- * write mode 4/5
- *
- * assume TARGET_PAGE_SIZE >= 16
- *
- ***************************************/
-
-static void cirrus_mem_writeb_mode4and5_8bpp(CirrusVGAState * s,
- unsigned mode,
- unsigned offset,
- uint32_t mem_value)
-{
- int x;
- unsigned val = mem_value;
- uint8_t *dst;
-
- dst = s->vram_ptr + offset;
- for (x = 0; x < 8; x++) {
- if (val & 0x80) {
- *dst = s->cirrus_shadow_gr1;
- } else if (mode == 5) {
- *dst = s->cirrus_shadow_gr0;
- }
- val <<= 1;
- dst++;
- }
- cpu_physical_memory_set_dirty(s->vram_offset + offset);
- cpu_physical_memory_set_dirty(s->vram_offset + offset + 7);
-}
-
-static void cirrus_mem_writeb_mode4and5_16bpp(CirrusVGAState * s,
- unsigned mode,
- unsigned offset,
- uint32_t mem_value)
-{
- int x;
- unsigned val = mem_value;
- uint8_t *dst;
-
- dst = s->vram_ptr + offset;
- for (x = 0; x < 8; x++) {
- if (val & 0x80) {
- *dst = s->cirrus_shadow_gr1;
- *(dst + 1) = s->gr[0x11];
- } else if (mode == 5) {
- *dst = s->cirrus_shadow_gr0;
- *(dst + 1) = s->gr[0x10];
- }
- val <<= 1;
- dst += 2;
- }
- cpu_physical_memory_set_dirty(s->vram_offset + offset);
- cpu_physical_memory_set_dirty(s->vram_offset + offset + 15);
-}
-
-/***************************************
- *
- * memory access between 0xa0000-0xbffff
- *
- ***************************************/
-
-static uint32_t cirrus_vga_mem_readb(void *opaque, target_phys_addr_t addr)
-{
- CirrusVGAState *s = opaque;
- unsigned bank_index;
- unsigned bank_offset;
- uint32_t val;
-
- if ((s->sr[0x07] & 0x01) == 0) {
- return vga_mem_readb(s, addr);
- }
-
- addr &= 0x1ffff;
-
- if (addr < 0x10000) {
- /* XXX handle bitblt */
- /* video memory */
- bank_index = addr >> 15;
- bank_offset = addr & 0x7fff;
- if (bank_offset < s->cirrus_bank_limit[bank_index]) {
- bank_offset += s->cirrus_bank_base[bank_index];
- if ((s->gr[0x0B] & 0x14) == 0x14) {
- bank_offset <<= 4;
- } else if (s->gr[0x0B] & 0x02) {
- bank_offset <<= 3;
- }
- bank_offset &= s->cirrus_addr_mask;
- val = *(s->vram_ptr + bank_offset);
- } else
- val = 0xff;
- } else if (addr >= 0x18000 && addr < 0x18100) {
- /* memory-mapped I/O */
- val = 0xff;
- if ((s->sr[0x17] & 0x44) == 0x04) {
- val = cirrus_mmio_blt_read(s, addr & 0xff);
- }
- } else {
- val = 0xff;
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mem_readb %06x\n", addr);
-#endif
- }
- return val;
-}
-
-static uint32_t cirrus_vga_mem_readw(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = cirrus_vga_mem_readb(opaque, addr) << 8;
- v |= cirrus_vga_mem_readb(opaque, addr + 1);
-#else
- v = cirrus_vga_mem_readb(opaque, addr);
- v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
-#endif
- return v;
-}
-
-static uint32_t cirrus_vga_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = cirrus_vga_mem_readb(opaque, addr) << 24;
- v |= cirrus_vga_mem_readb(opaque, addr + 1) << 16;
- v |= cirrus_vga_mem_readb(opaque, addr + 2) << 8;
- v |= cirrus_vga_mem_readb(opaque, addr + 3);
-#else
- v = cirrus_vga_mem_readb(opaque, addr);
- v |= cirrus_vga_mem_readb(opaque, addr + 1) << 8;
- v |= cirrus_vga_mem_readb(opaque, addr + 2) << 16;
- v |= cirrus_vga_mem_readb(opaque, addr + 3) << 24;
-#endif
- return v;
-}
-
-static void cirrus_vga_mem_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t mem_value)
-{
- CirrusVGAState *s = opaque;
- unsigned bank_index;
- unsigned bank_offset;
- unsigned mode;
-
- if ((s->sr[0x07] & 0x01) == 0) {
- vga_mem_writeb(s, addr, mem_value);
- return;
- }
-
- addr &= 0x1ffff;
-
- if (addr < 0x10000) {
- if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
- /* bitblt */
- *s->cirrus_srcptr++ = (uint8_t) mem_value;
- if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
- cirrus_bitblt_cputovideo_next(s);
- }
- } else {
- /* video memory */
- bank_index = addr >> 15;
- bank_offset = addr & 0x7fff;
- if (bank_offset < s->cirrus_bank_limit[bank_index]) {
- bank_offset += s->cirrus_bank_base[bank_index];
- if ((s->gr[0x0B] & 0x14) == 0x14) {
- bank_offset <<= 4;
- } else if (s->gr[0x0B] & 0x02) {
- bank_offset <<= 3;
- }
- bank_offset &= s->cirrus_addr_mask;
- mode = s->gr[0x05] & 0x7;
- if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
- *(s->vram_ptr + bank_offset) = mem_value;
- cpu_physical_memory_set_dirty(s->vram_offset +
- bank_offset);
- } else {
- if ((s->gr[0x0B] & 0x14) != 0x14) {
- cirrus_mem_writeb_mode4and5_8bpp(s, mode,
- bank_offset,
- mem_value);
- } else {
- cirrus_mem_writeb_mode4and5_16bpp(s, mode,
- bank_offset,
- mem_value);
- }
- }
- }
- }
- } else if (addr >= 0x18000 && addr < 0x18100) {
- /* memory-mapped I/O */
- if ((s->sr[0x17] & 0x44) == 0x04) {
- cirrus_mmio_blt_write(s, addr & 0xff, mem_value);
- }
- } else {
-#ifdef DEBUG_CIRRUS
- printf("cirrus: mem_writeb %06x value %02x\n", addr, mem_value);
-#endif
- }
-}
-
-static void cirrus_vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- cirrus_vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
- cirrus_vga_mem_writeb(opaque, addr + 1, val & 0xff);
-#else
- cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
- cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
-}
-
-static void cirrus_vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- cirrus_vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
- cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
- cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
- cirrus_vga_mem_writeb(opaque, addr + 3, val & 0xff);
-#else
- cirrus_vga_mem_writeb(opaque, addr, val & 0xff);
- cirrus_vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
- cirrus_vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
- cirrus_vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-#endif
-}
-
-static CPUReadMemoryFunc *cirrus_vga_mem_read[3] = {
- cirrus_vga_mem_readb,
- cirrus_vga_mem_readw,
- cirrus_vga_mem_readl,
-};
-
-static CPUWriteMemoryFunc *cirrus_vga_mem_write[3] = {
- cirrus_vga_mem_writeb,
- cirrus_vga_mem_writew,
- cirrus_vga_mem_writel,
-};
-
-/***************************************
- *
- * hardware cursor
- *
- ***************************************/
-
-static inline void invalidate_cursor1(CirrusVGAState *s)
-{
- if (s->last_hw_cursor_size) {
- vga_invalidate_scanlines((VGAState *)s,
- s->last_hw_cursor_y + s->last_hw_cursor_y_start,
- s->last_hw_cursor_y + s->last_hw_cursor_y_end);
- }
-}
-
-static inline void cirrus_cursor_compute_yrange(CirrusVGAState *s)
-{
- const uint8_t *src;
- uint32_t content;
- int y, y_min, y_max;
-
- src = s->vram_ptr + s->real_vram_size - 16 * 1024;
- if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
- src += (s->sr[0x13] & 0x3c) * 256;
- y_min = 64;
- y_max = -1;
- for(y = 0; y < 64; y++) {
- content = ((uint32_t *)src)[0] |
- ((uint32_t *)src)[1] |
- ((uint32_t *)src)[2] |
- ((uint32_t *)src)[3];
- if (content) {
- if (y < y_min)
- y_min = y;
- if (y > y_max)
- y_max = y;
- }
- src += 16;
- }
- } else {
- src += (s->sr[0x13] & 0x3f) * 256;
- y_min = 32;
- y_max = -1;
- for(y = 0; y < 32; y++) {
- content = ((uint32_t *)src)[0] |
- ((uint32_t *)(src + 128))[0];
- if (content) {
- if (y < y_min)
- y_min = y;
- if (y > y_max)
- y_max = y;
- }
- src += 4;
- }
- }
- if (y_min > y_max) {
- s->last_hw_cursor_y_start = 0;
- s->last_hw_cursor_y_end = 0;
- } else {
- s->last_hw_cursor_y_start = y_min;
- s->last_hw_cursor_y_end = y_max + 1;
- }
-}
-
-/* NOTE: we do not currently handle the cursor bitmap change, so we
- update the cursor only if it moves. */
-static void cirrus_cursor_invalidate(VGAState *s1)
-{
- CirrusVGAState *s = (CirrusVGAState *)s1;
- int size;
-
- if (!s->sr[0x12] & CIRRUS_CURSOR_SHOW) {
- size = 0;
- } else {
- if (s->sr[0x12] & CIRRUS_CURSOR_LARGE)
- size = 64;
- else
- size = 32;
- }
- /* invalidate last cursor and new cursor if any change */
- if (s->last_hw_cursor_size != size ||
- s->last_hw_cursor_x != s->hw_cursor_x ||
- s->last_hw_cursor_y != s->hw_cursor_y) {
-
- invalidate_cursor1(s);
-
- s->last_hw_cursor_size = size;
- s->last_hw_cursor_x = s->hw_cursor_x;
- s->last_hw_cursor_y = s->hw_cursor_y;
- /* compute the real cursor min and max y */
- cirrus_cursor_compute_yrange(s);
- invalidate_cursor1(s);
- }
-}
-
-static void cirrus_cursor_draw_line(VGAState *s1, uint8_t *d1, int scr_y)
-{
- CirrusVGAState *s = (CirrusVGAState *)s1;
- int w, h, bpp, x1, x2, poffset;
- unsigned int color0, color1;
- const uint8_t *palette, *src;
- uint32_t content;
-
- if (!(s->sr[0x12] & CIRRUS_CURSOR_SHOW))
- return;
- /* fast test to see if the cursor intersects with the scan line */
- if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
- h = 64;
- } else {
- h = 32;
- }
- if (scr_y < s->hw_cursor_y ||
- scr_y >= (s->hw_cursor_y + h))
- return;
-
- src = s->vram_ptr + s->real_vram_size - 16 * 1024;
- if (s->sr[0x12] & CIRRUS_CURSOR_LARGE) {
- src += (s->sr[0x13] & 0x3c) * 256;
- src += (scr_y - s->hw_cursor_y) * 16;
- poffset = 8;
- content = ((uint32_t *)src)[0] |
- ((uint32_t *)src)[1] |
- ((uint32_t *)src)[2] |
- ((uint32_t *)src)[3];
- } else {
- src += (s->sr[0x13] & 0x3f) * 256;
- src += (scr_y - s->hw_cursor_y) * 4;
- poffset = 128;
- content = ((uint32_t *)src)[0] |
- ((uint32_t *)(src + 128))[0];
- }
- /* if nothing to draw, no need to continue */
- if (!content)
- return;
- w = h;
-
- x1 = s->hw_cursor_x;
- if (x1 >= s->last_scr_width)
- return;
- x2 = s->hw_cursor_x + w;
- if (x2 > s->last_scr_width)
- x2 = s->last_scr_width;
- w = x2 - x1;
- palette = s->cirrus_hidden_palette;
- color0 = s->rgb_to_pixel(c6_to_8(palette[0x0 * 3]),
- c6_to_8(palette[0x0 * 3 + 1]),
- c6_to_8(palette[0x0 * 3 + 2]));
- color1 = s->rgb_to_pixel(c6_to_8(palette[0xf * 3]),
- c6_to_8(palette[0xf * 3 + 1]),
- c6_to_8(palette[0xf * 3 + 2]));
- bpp = ((s->ds->depth + 7) >> 3);
- d1 += x1 * bpp;
- switch(s->ds->depth) {
- default:
- break;
- case 8:
- vga_draw_cursor_line_8(d1, src, poffset, w, color0, color1, 0xff);
- break;
- case 15:
- vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0x7fff);
- break;
- case 16:
- vga_draw_cursor_line_16(d1, src, poffset, w, color0, color1, 0xffff);
- break;
- case 32:
- vga_draw_cursor_line_32(d1, src, poffset, w, color0, color1, 0xffffff);
- break;
- }
-}
-
-/***************************************
- *
- * LFB memory access
- *
- ***************************************/
-
-static uint32_t cirrus_linear_readb(void *opaque, target_phys_addr_t addr)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
- uint32_t ret;
-
- addr &= s->cirrus_addr_mask;
-
- if (((s->sr[0x17] & 0x44) == 0x44) &&
- ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
- /* memory-mapped I/O */
- ret = cirrus_mmio_blt_read(s, addr & 0xff);
- } else if (0) {
- /* XXX handle bitblt */
- ret = 0xff;
- } else {
- /* video memory */
- if ((s->gr[0x0B] & 0x14) == 0x14) {
- addr <<= 4;
- } else if (s->gr[0x0B] & 0x02) {
- addr <<= 3;
- }
- addr &= s->cirrus_addr_mask;
- ret = *(s->vram_ptr + addr);
- }
-
- return ret;
-}
-
-static uint32_t cirrus_linear_readw(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = cirrus_linear_readb(opaque, addr) << 8;
- v |= cirrus_linear_readb(opaque, addr + 1);
-#else
- v = cirrus_linear_readb(opaque, addr);
- v |= cirrus_linear_readb(opaque, addr + 1) << 8;
-#endif
- return v;
-}
-
-static uint32_t cirrus_linear_readl(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = cirrus_linear_readb(opaque, addr) << 24;
- v |= cirrus_linear_readb(opaque, addr + 1) << 16;
- v |= cirrus_linear_readb(opaque, addr + 2) << 8;
- v |= cirrus_linear_readb(opaque, addr + 3);
-#else
- v = cirrus_linear_readb(opaque, addr);
- v |= cirrus_linear_readb(opaque, addr + 1) << 8;
- v |= cirrus_linear_readb(opaque, addr + 2) << 16;
- v |= cirrus_linear_readb(opaque, addr + 3) << 24;
-#endif
- return v;
-}
-
-static void cirrus_linear_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
- unsigned mode;
-
- addr &= s->cirrus_addr_mask;
-
- if (((s->sr[0x17] & 0x44) == 0x44) &&
- ((addr & s->linear_mmio_mask) == s->linear_mmio_mask)) {
- /* memory-mapped I/O */
- cirrus_mmio_blt_write(s, addr & 0xff, val);
- } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
- /* bitblt */
- *s->cirrus_srcptr++ = (uint8_t) val;
- if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
- cirrus_bitblt_cputovideo_next(s);
- }
- } else {
- /* video memory */
- if ((s->gr[0x0B] & 0x14) == 0x14) {
- addr <<= 4;
- } else if (s->gr[0x0B] & 0x02) {
- addr <<= 3;
- }
- addr &= s->cirrus_addr_mask;
-
- mode = s->gr[0x05] & 0x7;
- if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
- *(s->vram_ptr + addr) = (uint8_t) val;
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
- } else {
- if ((s->gr[0x0B] & 0x14) != 0x14) {
- cirrus_mem_writeb_mode4and5_8bpp(s, mode, addr, val);
- } else {
- cirrus_mem_writeb_mode4and5_16bpp(s, mode, addr, val);
- }
- }
- }
-}
-
-static void cirrus_linear_writew(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- cirrus_linear_writeb(opaque, addr, (val >> 8) & 0xff);
- cirrus_linear_writeb(opaque, addr + 1, val & 0xff);
-#else
- cirrus_linear_writeb(opaque, addr, val & 0xff);
- cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
-}
-
-static void cirrus_linear_writel(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- cirrus_linear_writeb(opaque, addr, (val >> 24) & 0xff);
- cirrus_linear_writeb(opaque, addr + 1, (val >> 16) & 0xff);
- cirrus_linear_writeb(opaque, addr + 2, (val >> 8) & 0xff);
- cirrus_linear_writeb(opaque, addr + 3, val & 0xff);
-#else
- cirrus_linear_writeb(opaque, addr, val & 0xff);
- cirrus_linear_writeb(opaque, addr + 1, (val >> 8) & 0xff);
- cirrus_linear_writeb(opaque, addr + 2, (val >> 16) & 0xff);
- cirrus_linear_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-#endif
-}
-
-
-static CPUReadMemoryFunc *cirrus_linear_read[3] = {
- cirrus_linear_readb,
- cirrus_linear_readw,
- cirrus_linear_readl,
-};
-
-static CPUWriteMemoryFunc *cirrus_linear_write[3] = {
- cirrus_linear_writeb,
- cirrus_linear_writew,
- cirrus_linear_writel,
-};
-
-static void cirrus_linear_mem_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
-
- addr &= s->cirrus_addr_mask;
- *(s->vram_ptr + addr) = val;
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
-}
-
-static void cirrus_linear_mem_writew(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
-
- addr &= s->cirrus_addr_mask;
- cpu_to_le16w((uint16_t *)(s->vram_ptr + addr), val);
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
-}
-
-static void cirrus_linear_mem_writel(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
-
- addr &= s->cirrus_addr_mask;
- cpu_to_le32w((uint32_t *)(s->vram_ptr + addr), val);
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
-}
-
-/***************************************
- *
- * system to screen memory access
- *
- ***************************************/
-
-
-static uint32_t cirrus_linear_bitblt_readb(void *opaque, target_phys_addr_t addr)
-{
- uint32_t ret;
-
- /* XXX handle bitblt */
- ret = 0xff;
- return ret;
-}
-
-static uint32_t cirrus_linear_bitblt_readw(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = cirrus_linear_bitblt_readb(opaque, addr) << 8;
- v |= cirrus_linear_bitblt_readb(opaque, addr + 1);
-#else
- v = cirrus_linear_bitblt_readb(opaque, addr);
- v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
-#endif
- return v;
-}
-
-static uint32_t cirrus_linear_bitblt_readl(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = cirrus_linear_bitblt_readb(opaque, addr) << 24;
- v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 16;
- v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 8;
- v |= cirrus_linear_bitblt_readb(opaque, addr + 3);
-#else
- v = cirrus_linear_bitblt_readb(opaque, addr);
- v |= cirrus_linear_bitblt_readb(opaque, addr + 1) << 8;
- v |= cirrus_linear_bitblt_readb(opaque, addr + 2) << 16;
- v |= cirrus_linear_bitblt_readb(opaque, addr + 3) << 24;
-#endif
- return v;
-}
-
-static void cirrus_linear_bitblt_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
-
- if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
- /* bitblt */
- *s->cirrus_srcptr++ = (uint8_t) val;
- if (s->cirrus_srcptr >= s->cirrus_srcptr_end) {
- cirrus_bitblt_cputovideo_next(s);
- }
- }
-}
-
-static void cirrus_linear_bitblt_writew(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- cirrus_linear_bitblt_writeb(opaque, addr, (val >> 8) & 0xff);
- cirrus_linear_bitblt_writeb(opaque, addr + 1, val & 0xff);
-#else
- cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
- cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
-}
-
-static void cirrus_linear_bitblt_writel(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- cirrus_linear_bitblt_writeb(opaque, addr, (val >> 24) & 0xff);
- cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 16) & 0xff);
- cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 8) & 0xff);
- cirrus_linear_bitblt_writeb(opaque, addr + 3, val & 0xff);
-#else
- cirrus_linear_bitblt_writeb(opaque, addr, val & 0xff);
- cirrus_linear_bitblt_writeb(opaque, addr + 1, (val >> 8) & 0xff);
- cirrus_linear_bitblt_writeb(opaque, addr + 2, (val >> 16) & 0xff);
- cirrus_linear_bitblt_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-#endif
-}
-
-
-static CPUReadMemoryFunc *cirrus_linear_bitblt_read[3] = {
- cirrus_linear_bitblt_readb,
- cirrus_linear_bitblt_readw,
- cirrus_linear_bitblt_readl,
-};
-
-static CPUWriteMemoryFunc *cirrus_linear_bitblt_write[3] = {
- cirrus_linear_bitblt_writeb,
- cirrus_linear_bitblt_writew,
- cirrus_linear_bitblt_writel,
-};
-
-/* Compute the memory access functions */
-static void cirrus_update_memory_access(CirrusVGAState *s)
-{
- unsigned mode;
-
- if ((s->sr[0x17] & 0x44) == 0x44) {
- goto generic_io;
- } else if (s->cirrus_srcptr != s->cirrus_srcptr_end) {
- goto generic_io;
- } else {
- if ((s->gr[0x0B] & 0x14) == 0x14) {
- goto generic_io;
- } else if (s->gr[0x0B] & 0x02) {
- goto generic_io;
- }
-
- mode = s->gr[0x05] & 0x7;
- if (mode < 4 || mode > 5 || ((s->gr[0x0B] & 0x4) == 0)) {
- s->cirrus_linear_write[0] = cirrus_linear_mem_writeb;
- s->cirrus_linear_write[1] = cirrus_linear_mem_writew;
- s->cirrus_linear_write[2] = cirrus_linear_mem_writel;
- } else {
- generic_io:
- s->cirrus_linear_write[0] = cirrus_linear_writeb;
- s->cirrus_linear_write[1] = cirrus_linear_writew;
- s->cirrus_linear_write[2] = cirrus_linear_writel;
- }
- }
-}
-
-
-/* I/O ports */
-
-static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
-{
- CirrusVGAState *s = opaque;
- int val, index;
-
- /* check port range access depending on color/monochrome mode */
- if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION))
- || (addr >= 0x3d0 && addr <= 0x3df
- && !(s->msr & MSR_COLOR_EMULATION))) {
- val = 0xff;
- } else {
- switch (addr) {
- case 0x3c0:
- if (s->ar_flip_flop == 0) {
- val = s->ar_index;
- } else {
- val = 0;
- }
- break;
- case 0x3c1:
- index = s->ar_index & 0x1f;
- if (index < 21)
- val = s->ar[index];
- else
- val = 0;
- break;
- case 0x3c2:
- val = s->st00;
- break;
- case 0x3c4:
- val = s->sr_index;
- break;
- case 0x3c5:
- if (cirrus_hook_read_sr(s, s->sr_index, &val))
- break;
- val = s->sr[s->sr_index];
-#ifdef DEBUG_VGA_REG
- printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
-#endif
- break;
- case 0x3c6:
- cirrus_read_hidden_dac(s, &val);
- break;
- case 0x3c7:
- val = s->dac_state;
- break;
- case 0x3c8:
- val = s->dac_write_index;
- s->cirrus_hidden_dac_lockindex = 0;
- break;
- case 0x3c9:
- if (cirrus_hook_read_palette(s, &val))
- break;
- val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
- if (++s->dac_sub_index == 3) {
- s->dac_sub_index = 0;
- s->dac_read_index++;
- }
- break;
- case 0x3ca:
- val = s->fcr;
- break;
- case 0x3cc:
- val = s->msr;
- break;
- case 0x3ce:
- val = s->gr_index;
- break;
- case 0x3cf:
- if (cirrus_hook_read_gr(s, s->gr_index, &val))
- break;
- val = s->gr[s->gr_index];
-#ifdef DEBUG_VGA_REG
- printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
-#endif
- break;
- case 0x3b4:
- case 0x3d4:
- val = s->cr_index;
- break;
- case 0x3b5:
- case 0x3d5:
- if (cirrus_hook_read_cr(s, s->cr_index, &val))
- break;
- val = s->cr[s->cr_index];
-#ifdef DEBUG_VGA_REG
- printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
-#endif
- break;
- case 0x3ba:
- case 0x3da:
- /* just toggle to fool polling */
- s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
- val = s->st01;
- s->ar_flip_flop = 0;
- break;
- default:
- val = 0x00;
- break;
- }
- }
-#if defined(DEBUG_VGA)
- printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
-#endif
- return val;
-}
-
-static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- CirrusVGAState *s = opaque;
- int index;
-
- /* check port range access depending on color/monochrome mode */
- if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION))
- || (addr >= 0x3d0 && addr <= 0x3df
- && !(s->msr & MSR_COLOR_EMULATION)))
- return;
-
-#ifdef DEBUG_VGA
- printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
-#endif
-
- switch (addr) {
- case 0x3c0:
- if (s->ar_flip_flop == 0) {
- val &= 0x3f;
- s->ar_index = val;
- } else {
- index = s->ar_index & 0x1f;
- switch (index) {
- case 0x00 ... 0x0f:
- s->ar[index] = val & 0x3f;
- break;
- case 0x10:
- s->ar[index] = val & ~0x10;
- break;
- case 0x11:
- s->ar[index] = val;
- break;
- case 0x12:
- s->ar[index] = val & ~0xc0;
- break;
- case 0x13:
- s->ar[index] = val & ~0xf0;
- break;
- case 0x14:
- s->ar[index] = val & ~0xf0;
- break;
- default:
- break;
- }
- }
- s->ar_flip_flop ^= 1;
- break;
- case 0x3c2:
- s->msr = val & ~0x10;
- break;
- case 0x3c4:
- s->sr_index = val;
- break;
- case 0x3c5:
- if (cirrus_hook_write_sr(s, s->sr_index, val))
- break;
-#ifdef DEBUG_VGA_REG
- printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
-#endif
- s->sr[s->sr_index] = val & sr_mask[s->sr_index];
- break;
- case 0x3c6:
- cirrus_write_hidden_dac(s, val);
- break;
- case 0x3c7:
- s->dac_read_index = val;
- s->dac_sub_index = 0;
- s->dac_state = 3;
- break;
- case 0x3c8:
- s->dac_write_index = val;
- s->dac_sub_index = 0;
- s->dac_state = 0;
- break;
- case 0x3c9:
- if (cirrus_hook_write_palette(s, val))
- break;
- s->dac_cache[s->dac_sub_index] = val;
- if (++s->dac_sub_index == 3) {
- memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
- s->dac_sub_index = 0;
- s->dac_write_index++;
- }
- break;
- case 0x3ce:
- s->gr_index = val;
- break;
- case 0x3cf:
- if (cirrus_hook_write_gr(s, s->gr_index, val))
- break;
-#ifdef DEBUG_VGA_REG
- printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
-#endif
- s->gr[s->gr_index] = val & gr_mask[s->gr_index];
- break;
- case 0x3b4:
- case 0x3d4:
- s->cr_index = val;
- break;
- case 0x3b5:
- case 0x3d5:
- if (cirrus_hook_write_cr(s, s->cr_index, val))
- break;
-#ifdef DEBUG_VGA_REG
- printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
-#endif
- /* handle CR0-7 protection */
- if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
- /* can always write bit 4 of CR7 */
- if (s->cr_index == 7)
- s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
- return;
- }
- switch (s->cr_index) {
- case 0x01: /* horizontal display end */
- case 0x07:
- case 0x09:
- case 0x0c:
- case 0x0d:
- case 0x12: /* veritcal display end */
- s->cr[s->cr_index] = val;
- break;
-
- default:
- s->cr[s->cr_index] = val;
- break;
- }
- break;
- case 0x3ba:
- case 0x3da:
- s->fcr = val & 0x10;
- break;
- }
-}
-
-/***************************************
- *
- * memory-mapped I/O access
- *
- ***************************************/
-
-static uint32_t cirrus_mmio_readb(void *opaque, target_phys_addr_t addr)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
-
- addr &= CIRRUS_PNPMMIO_SIZE - 1;
-
- if (addr >= 0x100) {
- return cirrus_mmio_blt_read(s, addr - 0x100);
- } else {
- return vga_ioport_read(s, addr + 0x3c0);
- }
-}
-
-static uint32_t cirrus_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = cirrus_mmio_readb(opaque, addr) << 8;
- v |= cirrus_mmio_readb(opaque, addr + 1);
-#else
- v = cirrus_mmio_readb(opaque, addr);
- v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
-#endif
- return v;
-}
-
-static uint32_t cirrus_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = cirrus_mmio_readb(opaque, addr) << 24;
- v |= cirrus_mmio_readb(opaque, addr + 1) << 16;
- v |= cirrus_mmio_readb(opaque, addr + 2) << 8;
- v |= cirrus_mmio_readb(opaque, addr + 3);
-#else
- v = cirrus_mmio_readb(opaque, addr);
- v |= cirrus_mmio_readb(opaque, addr + 1) << 8;
- v |= cirrus_mmio_readb(opaque, addr + 2) << 16;
- v |= cirrus_mmio_readb(opaque, addr + 3) << 24;
-#endif
- return v;
-}
-
-static void cirrus_mmio_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- CirrusVGAState *s = (CirrusVGAState *) opaque;
-
- addr &= CIRRUS_PNPMMIO_SIZE - 1;
-
- if (addr >= 0x100) {
- cirrus_mmio_blt_write(s, addr - 0x100, val);
- } else {
- vga_ioport_write(s, addr + 0x3c0, val);
- }
-}
-
-static void cirrus_mmio_writew(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- cirrus_mmio_writeb(opaque, addr, (val >> 8) & 0xff);
- cirrus_mmio_writeb(opaque, addr + 1, val & 0xff);
-#else
- cirrus_mmio_writeb(opaque, addr, val & 0xff);
- cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
-}
-
-static void cirrus_mmio_writel(void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- cirrus_mmio_writeb(opaque, addr, (val >> 24) & 0xff);
- cirrus_mmio_writeb(opaque, addr + 1, (val >> 16) & 0xff);
- cirrus_mmio_writeb(opaque, addr + 2, (val >> 8) & 0xff);
- cirrus_mmio_writeb(opaque, addr + 3, val & 0xff);
-#else
- cirrus_mmio_writeb(opaque, addr, val & 0xff);
- cirrus_mmio_writeb(opaque, addr + 1, (val >> 8) & 0xff);
- cirrus_mmio_writeb(opaque, addr + 2, (val >> 16) & 0xff);
- cirrus_mmio_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-#endif
-}
-
-
-static CPUReadMemoryFunc *cirrus_mmio_read[3] = {
- cirrus_mmio_readb,
- cirrus_mmio_readw,
- cirrus_mmio_readl,
-};
-
-static CPUWriteMemoryFunc *cirrus_mmio_write[3] = {
- cirrus_mmio_writeb,
- cirrus_mmio_writew,
- cirrus_mmio_writel,
-};
-
-/* load/save state */
-
-static void cirrus_vga_save(QEMUFile *f, void *opaque)
-{
- CirrusVGAState *s = opaque;
-
- qemu_put_be32s(f, &s->latch);
- qemu_put_8s(f, &s->sr_index);
- qemu_put_buffer(f, s->sr, 256);
- qemu_put_8s(f, &s->gr_index);
- qemu_put_8s(f, &s->cirrus_shadow_gr0);
- qemu_put_8s(f, &s->cirrus_shadow_gr1);
- qemu_put_buffer(f, s->gr + 2, 254);
- qemu_put_8s(f, &s->ar_index);
- qemu_put_buffer(f, s->ar, 21);
- qemu_put_be32s(f, &s->ar_flip_flop);
- qemu_put_8s(f, &s->cr_index);
- qemu_put_buffer(f, s->cr, 256);
- qemu_put_8s(f, &s->msr);
- qemu_put_8s(f, &s->fcr);
- qemu_put_8s(f, &s->st00);
- qemu_put_8s(f, &s->st01);
-
- qemu_put_8s(f, &s->dac_state);
- qemu_put_8s(f, &s->dac_sub_index);
- qemu_put_8s(f, &s->dac_read_index);
- qemu_put_8s(f, &s->dac_write_index);
- qemu_put_buffer(f, s->dac_cache, 3);
- qemu_put_buffer(f, s->palette, 768);
-
- qemu_put_be32s(f, &s->bank_offset);
-
- qemu_put_8s(f, &s->cirrus_hidden_dac_lockindex);
- qemu_put_8s(f, &s->cirrus_hidden_dac_data);
-
- qemu_put_be32s(f, &s->hw_cursor_x);
- qemu_put_be32s(f, &s->hw_cursor_y);
- /* XXX: we do not save the bitblt state - we assume we do not save
- the state when the blitter is active */
-}
-
-static int cirrus_vga_load(QEMUFile *f, void *opaque, int version_id)
-{
- CirrusVGAState *s = opaque;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_be32s(f, &s->latch);
- qemu_get_8s(f, &s->sr_index);
- qemu_get_buffer(f, s->sr, 256);
- qemu_get_8s(f, &s->gr_index);
- qemu_get_8s(f, &s->cirrus_shadow_gr0);
- qemu_get_8s(f, &s->cirrus_shadow_gr1);
- s->gr[0x00] = s->cirrus_shadow_gr0 & 0x0f;
- s->gr[0x01] = s->cirrus_shadow_gr1 & 0x0f;
- qemu_get_buffer(f, s->gr + 2, 254);
- qemu_get_8s(f, &s->ar_index);
- qemu_get_buffer(f, s->ar, 21);
- qemu_get_be32s(f, &s->ar_flip_flop);
- qemu_get_8s(f, &s->cr_index);
- qemu_get_buffer(f, s->cr, 256);
- qemu_get_8s(f, &s->msr);
- qemu_get_8s(f, &s->fcr);
- qemu_get_8s(f, &s->st00);
- qemu_get_8s(f, &s->st01);
-
- qemu_get_8s(f, &s->dac_state);
- qemu_get_8s(f, &s->dac_sub_index);
- qemu_get_8s(f, &s->dac_read_index);
- qemu_get_8s(f, &s->dac_write_index);
- qemu_get_buffer(f, s->dac_cache, 3);
- qemu_get_buffer(f, s->palette, 768);
-
- qemu_get_be32s(f, &s->bank_offset);
-
- qemu_get_8s(f, &s->cirrus_hidden_dac_lockindex);
- qemu_get_8s(f, &s->cirrus_hidden_dac_data);
-
- qemu_get_be32s(f, &s->hw_cursor_x);
- qemu_get_be32s(f, &s->hw_cursor_y);
-
- /* force refresh */
- s->graphic_mode = -1;
- cirrus_update_bank_ptr(s, 0);
- cirrus_update_bank_ptr(s, 1);
- return 0;
-}
-
-/***************************************
- *
- * initialize
- *
- ***************************************/
-
-static void cirrus_init_common(CirrusVGAState * s, int device_id, int is_pci)
-{
- int vga_io_memory, i;
- static int inited;
-
- if (!inited) {
- inited = 1;
- for(i = 0;i < 256; i++)
- rop_to_index[i] = CIRRUS_ROP_NOP_INDEX; /* nop rop */
- rop_to_index[CIRRUS_ROP_0] = 0;
- rop_to_index[CIRRUS_ROP_SRC_AND_DST] = 1;
- rop_to_index[CIRRUS_ROP_NOP] = 2;
- rop_to_index[CIRRUS_ROP_SRC_AND_NOTDST] = 3;
- rop_to_index[CIRRUS_ROP_NOTDST] = 4;
- rop_to_index[CIRRUS_ROP_SRC] = 5;
- rop_to_index[CIRRUS_ROP_1] = 6;
- rop_to_index[CIRRUS_ROP_NOTSRC_AND_DST] = 7;
- rop_to_index[CIRRUS_ROP_SRC_XOR_DST] = 8;
- rop_to_index[CIRRUS_ROP_SRC_OR_DST] = 9;
- rop_to_index[CIRRUS_ROP_NOTSRC_OR_NOTDST] = 10;
- rop_to_index[CIRRUS_ROP_SRC_NOTXOR_DST] = 11;
- rop_to_index[CIRRUS_ROP_SRC_OR_NOTDST] = 12;
- rop_to_index[CIRRUS_ROP_NOTSRC] = 13;
- rop_to_index[CIRRUS_ROP_NOTSRC_OR_DST] = 14;
- rop_to_index[CIRRUS_ROP_NOTSRC_AND_NOTDST] = 15;
- }
-
- register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
-
- register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
- register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
- register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
- register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
-
- register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
-
- register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
- register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
- register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
- register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
-
- vga_io_memory = cpu_register_io_memory(0, cirrus_vga_mem_read,
- cirrus_vga_mem_write, s);
- cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
- vga_io_memory);
-
- s->sr[0x06] = 0x0f;
- if (device_id == CIRRUS_ID_CLGD5446) {
- /* 4MB 64 bit memory config, always PCI */
- s->sr[0x1F] = 0x2d; // MemClock
- s->gr[0x18] = 0x0f; // fastest memory configuration
-#if 1
- s->sr[0x0f] = 0x98;
- s->sr[0x17] = 0x20;
- s->sr[0x15] = 0x04; /* memory size, 3=2MB, 4=4MB */
- s->real_vram_size = 4096 * 1024;
-#else
- s->sr[0x0f] = 0x18;
- s->sr[0x17] = 0x20;
- s->sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */
- s->real_vram_size = 2048 * 1024;
-#endif
- } else {
- s->sr[0x1F] = 0x22; // MemClock
- s->sr[0x0F] = CIRRUS_MEMSIZE_2M;
- if (is_pci)
- s->sr[0x17] = CIRRUS_BUSTYPE_PCI;
- else
- s->sr[0x17] = CIRRUS_BUSTYPE_ISA;
- s->real_vram_size = 2048 * 1024;
- s->sr[0x15] = 0x03; /* memory size, 3=2MB, 4=4MB */
- }
- s->cr[0x27] = device_id;
-
- /* Win2K seems to assume that the pattern buffer is at 0xff
- initially ! */
- memset(s->vram_ptr, 0xff, s->real_vram_size);
-
- s->cirrus_hidden_dac_lockindex = 5;
- s->cirrus_hidden_dac_data = 0;
-
- /* I/O handler for LFB */
- s->cirrus_linear_io_addr =
- cpu_register_io_memory(0, cirrus_linear_read, cirrus_linear_write,
- s);
- s->cirrus_linear_write = cpu_get_io_memory_write(s->cirrus_linear_io_addr);
-
- /* I/O handler for LFB */
- s->cirrus_linear_bitblt_io_addr =
- cpu_register_io_memory(0, cirrus_linear_bitblt_read, cirrus_linear_bitblt_write,
- s);
-
- /* I/O handler for memory-mapped I/O */
- s->cirrus_mmio_io_addr =
- cpu_register_io_memory(0, cirrus_mmio_read, cirrus_mmio_write, s);
-
- /* XXX: s->vram_size must be a power of two */
- s->cirrus_addr_mask = s->real_vram_size - 1;
- s->linear_mmio_mask = s->real_vram_size - 256;
-
- s->get_bpp = cirrus_get_bpp;
- s->get_offsets = cirrus_get_offsets;
- s->get_resolution = cirrus_get_resolution;
- s->cursor_invalidate = cirrus_cursor_invalidate;
- s->cursor_draw_line = cirrus_cursor_draw_line;
-
- register_savevm("cirrus_vga", 0, 1, cirrus_vga_save, cirrus_vga_load, s);
-}
-
-/***************************************
- *
- * ISA bus support
- *
- ***************************************/
-
-void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size)
-{
- CirrusVGAState *s;
-
- s = qemu_mallocz(sizeof(CirrusVGAState));
-
- vga_common_init((VGAState *)s,
- ds, vga_ram_base, vga_ram_offset, vga_ram_size);
- cirrus_init_common(s, CIRRUS_ID_CLGD5430, 0);
- /* XXX ISA-LFB support */
-}
-
-/***************************************
- *
- * PCI bus support
- *
- ***************************************/
-
-static void cirrus_pci_lfb_map(PCIDevice *d, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga;
-
- /* XXX: add byte swapping apertures */
- cpu_register_physical_memory(addr, s->vram_size,
- s->cirrus_linear_io_addr);
- cpu_register_physical_memory(addr + 0x1000000, 0x400000,
- s->cirrus_linear_bitblt_io_addr);
-}
-
-static void cirrus_pci_mmio_map(PCIDevice *d, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- CirrusVGAState *s = &((PCICirrusVGAState *)d)->cirrus_vga;
-
- cpu_register_physical_memory(addr, CIRRUS_PNPMMIO_SIZE,
- s->cirrus_mmio_io_addr);
-}
-
-void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size)
-{
- PCICirrusVGAState *d;
- uint8_t *pci_conf;
- CirrusVGAState *s;
- int device_id;
-
- device_id = CIRRUS_ID_CLGD5446;
-
- /* setup PCI configuration registers */
- d = (PCICirrusVGAState *)pci_register_device(bus, "Cirrus VGA",
- sizeof(PCICirrusVGAState),
- -1, NULL, NULL);
- pci_conf = d->dev.config;
- pci_conf[0x00] = (uint8_t) (PCI_VENDOR_CIRRUS & 0xff);
- pci_conf[0x01] = (uint8_t) (PCI_VENDOR_CIRRUS >> 8);
- pci_conf[0x02] = (uint8_t) (device_id & 0xff);
- pci_conf[0x03] = (uint8_t) (device_id >> 8);
- pci_conf[0x04] = PCI_COMMAND_IOACCESS | PCI_COMMAND_MEMACCESS;
- pci_conf[0x0a] = PCI_CLASS_SUB_VGA;
- pci_conf[0x0b] = PCI_CLASS_BASE_DISPLAY;
- pci_conf[0x0e] = PCI_CLASS_HEADERTYPE_00h;
-
- /* setup VGA */
- s = &d->cirrus_vga;
- vga_common_init((VGAState *)s,
- ds, vga_ram_base, vga_ram_offset, vga_ram_size);
- cirrus_init_common(s, device_id, 1);
-
- /* setup memory space */
- /* memory #0 LFB */
- /* memory #1 memory-mapped I/O */
- /* XXX: s->vram_size must be a power of two */
- pci_register_io_region((PCIDevice *)d, 0, 0x2000000,
- PCI_ADDRESS_SPACE_MEM_PREFETCH, cirrus_pci_lfb_map);
- if (device_id == CIRRUS_ID_CLGD5446) {
- pci_register_io_region((PCIDevice *)d, 1, CIRRUS_PNPMMIO_SIZE,
- PCI_ADDRESS_SPACE_MEM, cirrus_pci_mmio_map);
- }
- /* XXX: ROM BIOS */
-}
diff --git a/hw/cirrus_vga_rop.h b/hw/cirrus_vga_rop.h
deleted file mode 100644
index c54f125..0000000
--- a/hw/cirrus_vga_rop.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * QEMU Cirrus CLGD 54xx VGA Emulator.
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-static void
-glue(cirrus_bitblt_rop_fwd_, ROP_NAME)(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
- int dstpitch,int srcpitch,
- int bltwidth,int bltheight)
-{
- int x,y;
- dstpitch -= bltwidth;
- srcpitch -= bltwidth;
- for (y = 0; y < bltheight; y++) {
- for (x = 0; x < bltwidth; x++) {
- ROP_OP(*dst, *src);
- dst++;
- src++;
- }
- dst += dstpitch;
- src += srcpitch;
- }
-}
-
-static void
-glue(cirrus_bitblt_rop_bkwd_, ROP_NAME)(CirrusVGAState *s,
- uint8_t *dst,const uint8_t *src,
- int dstpitch,int srcpitch,
- int bltwidth,int bltheight)
-{
- int x,y;
- dstpitch += bltwidth;
- srcpitch += bltwidth;
- for (y = 0; y < bltheight; y++) {
- for (x = 0; x < bltwidth; x++) {
- ROP_OP(*dst, *src);
- dst--;
- src--;
- }
- dst += dstpitch;
- src += srcpitch;
- }
-}
-
-#define DEPTH 8
-#include "cirrus_vga_rop2.h"
-
-#define DEPTH 16
-#include "cirrus_vga_rop2.h"
-
-#define DEPTH 24
-#include "cirrus_vga_rop2.h"
-
-#define DEPTH 32
-#include "cirrus_vga_rop2.h"
-
-#undef ROP_NAME
-#undef ROP_OP
diff --git a/hw/cirrus_vga_rop2.h b/hw/cirrus_vga_rop2.h
deleted file mode 100644
index da11d0f..0000000
--- a/hw/cirrus_vga_rop2.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * QEMU Cirrus CLGD 54xx VGA Emulator.
- *
- * Copyright (c) 2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#if DEPTH == 8
-#define PUTPIXEL() ROP_OP(d[0], col)
-#elif DEPTH == 16
-#define PUTPIXEL() ROP_OP(((uint16_t *)d)[0], col);
-#elif DEPTH == 24
-#define PUTPIXEL() ROP_OP(d[0], col); \
- ROP_OP(d[1], (col >> 8)); \
- ROP_OP(d[2], (col >> 16))
-#elif DEPTH == 32
-#define PUTPIXEL() ROP_OP(((uint32_t *)d)[0], col)
-#else
-#error unsupported DEPTH
-#endif
-
-static void
-glue(glue(glue(cirrus_patternfill_, ROP_NAME), _),DEPTH)
- (CirrusVGAState * s, uint8_t * dst,
- const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight)
-{
- uint8_t *d;
- int x, y, pattern_y, pattern_pitch, pattern_x;
- unsigned int col;
- const uint8_t *src1;
-#if DEPTH == 24
- int skipleft = s->gr[0x2f] & 0x1f;
-#else
- int skipleft = (s->gr[0x2f] & 0x07) * (DEPTH / 8);
-#endif
-
-#if DEPTH == 8
- pattern_pitch = 8;
-#elif DEPTH == 16
- pattern_pitch = 16;
-#else
- pattern_pitch = 32;
-#endif
- pattern_y = s->cirrus_blt_srcaddr & 7;
- for(y = 0; y < bltheight; y++) {
- pattern_x = skipleft;
- d = dst + skipleft;
- src1 = src + pattern_y * pattern_pitch;
- for (x = skipleft; x < bltwidth; x += (DEPTH / 8)) {
-#if DEPTH == 8
- col = src1[pattern_x];
- pattern_x = (pattern_x + 1) & 7;
-#elif DEPTH == 16
- col = ((uint16_t *)(src1 + pattern_x))[0];
- pattern_x = (pattern_x + 2) & 15;
-#elif DEPTH == 24
- {
- const uint8_t *src2 = src1 + pattern_x * 3;
- col = src2[0] | (src2[1] << 8) | (src2[2] << 16);
- pattern_x = (pattern_x + 1) & 7;
- }
-#else
- col = ((uint32_t *)(src1 + pattern_x))[0];
- pattern_x = (pattern_x + 4) & 31;
-#endif
- PUTPIXEL();
- d += (DEPTH / 8);
- }
- pattern_y = (pattern_y + 1) & 7;
- dst += dstpitch;
- }
-}
-
-/* NOTE: srcpitch is ignored */
-static void
-glue(glue(glue(cirrus_colorexpand_transp_, ROP_NAME), _),DEPTH)
- (CirrusVGAState * s, uint8_t * dst,
- const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight)
-{
- uint8_t *d;
- int x, y;
- unsigned bits, bits_xor;
- unsigned int col;
- unsigned bitmask;
- unsigned index;
-#if DEPTH == 24
- int dstskipleft = s->gr[0x2f] & 0x1f;
- int srcskipleft = dstskipleft / 3;
-#else
- int srcskipleft = s->gr[0x2f] & 0x07;
- int dstskipleft = srcskipleft * (DEPTH / 8);
-#endif
-
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
- bits_xor = 0xff;
- col = s->cirrus_blt_bgcol;
- } else {
- bits_xor = 0x00;
- col = s->cirrus_blt_fgcol;
- }
-
- for(y = 0; y < bltheight; y++) {
- bitmask = 0x80 >> srcskipleft;
- bits = *src++ ^ bits_xor;
- d = dst + dstskipleft;
- for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
- if ((bitmask & 0xff) == 0) {
- bitmask = 0x80;
- bits = *src++ ^ bits_xor;
- }
- index = (bits & bitmask);
- if (index) {
- PUTPIXEL();
- }
- d += (DEPTH / 8);
- bitmask >>= 1;
- }
- dst += dstpitch;
- }
-}
-
-static void
-glue(glue(glue(cirrus_colorexpand_, ROP_NAME), _),DEPTH)
- (CirrusVGAState * s, uint8_t * dst,
- const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight)
-{
- uint32_t colors[2];
- uint8_t *d;
- int x, y;
- unsigned bits;
- unsigned int col;
- unsigned bitmask;
- int srcskipleft = s->gr[0x2f] & 0x07;
- int dstskipleft = srcskipleft * (DEPTH / 8);
-
- colors[0] = s->cirrus_blt_bgcol;
- colors[1] = s->cirrus_blt_fgcol;
- for(y = 0; y < bltheight; y++) {
- bitmask = 0x80 >> srcskipleft;
- bits = *src++;
- d = dst + dstskipleft;
- for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
- if ((bitmask & 0xff) == 0) {
- bitmask = 0x80;
- bits = *src++;
- }
- col = colors[!!(bits & bitmask)];
- PUTPIXEL();
- d += (DEPTH / 8);
- bitmask >>= 1;
- }
- dst += dstpitch;
- }
-}
-
-static void
-glue(glue(glue(cirrus_colorexpand_pattern_transp_, ROP_NAME), _),DEPTH)
- (CirrusVGAState * s, uint8_t * dst,
- const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight)
-{
- uint8_t *d;
- int x, y, bitpos, pattern_y;
- unsigned int bits, bits_xor;
- unsigned int col;
-#if DEPTH == 24
- int dstskipleft = s->gr[0x2f] & 0x1f;
- int srcskipleft = dstskipleft / 3;
-#else
- int srcskipleft = s->gr[0x2f] & 0x07;
- int dstskipleft = srcskipleft * (DEPTH / 8);
-#endif
-
- if (s->cirrus_blt_modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) {
- bits_xor = 0xff;
- col = s->cirrus_blt_bgcol;
- } else {
- bits_xor = 0x00;
- col = s->cirrus_blt_fgcol;
- }
- pattern_y = s->cirrus_blt_srcaddr & 7;
-
- for(y = 0; y < bltheight; y++) {
- bits = src[pattern_y] ^ bits_xor;
- bitpos = 7 - srcskipleft;
- d = dst + dstskipleft;
- for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
- if ((bits >> bitpos) & 1) {
- PUTPIXEL();
- }
- d += (DEPTH / 8);
- bitpos = (bitpos - 1) & 7;
- }
- pattern_y = (pattern_y + 1) & 7;
- dst += dstpitch;
- }
-}
-
-static void
-glue(glue(glue(cirrus_colorexpand_pattern_, ROP_NAME), _),DEPTH)
- (CirrusVGAState * s, uint8_t * dst,
- const uint8_t * src,
- int dstpitch, int srcpitch,
- int bltwidth, int bltheight)
-{
- uint32_t colors[2];
- uint8_t *d;
- int x, y, bitpos, pattern_y;
- unsigned int bits;
- unsigned int col;
- int srcskipleft = s->gr[0x2f] & 0x07;
- int dstskipleft = srcskipleft * (DEPTH / 8);
-
- colors[0] = s->cirrus_blt_bgcol;
- colors[1] = s->cirrus_blt_fgcol;
- pattern_y = s->cirrus_blt_srcaddr & 7;
-
- for(y = 0; y < bltheight; y++) {
- bits = src[pattern_y];
- bitpos = 7 - srcskipleft;
- d = dst + dstskipleft;
- for (x = dstskipleft; x < bltwidth; x += (DEPTH / 8)) {
- col = colors[(bits >> bitpos) & 1];
- PUTPIXEL();
- d += (DEPTH / 8);
- bitpos = (bitpos - 1) & 7;
- }
- pattern_y = (pattern_y + 1) & 7;
- dst += dstpitch;
- }
-}
-
-static void
-glue(glue(glue(cirrus_fill_, ROP_NAME), _),DEPTH)
- (CirrusVGAState *s,
- uint8_t *dst, int dst_pitch,
- int width, int height)
-{
- uint8_t *d, *d1;
- uint32_t col;
- int x, y;
-
- col = s->cirrus_blt_fgcol;
-
- d1 = dst;
- for(y = 0; y < height; y++) {
- d = d1;
- for(x = 0; x < width; x += (DEPTH / 8)) {
- PUTPIXEL();
- d += (DEPTH / 8);
- }
- d1 += dst_pitch;
- }
-}
-
-#undef DEPTH
-#undef PUTPIXEL
diff --git a/hw/cuda.c b/hw/cuda.c
deleted file mode 100644
index f3c2b56..0000000
--- a/hw/cuda.c
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * QEMU CUDA support
- *
- * Copyright (c) 2004 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"
-
-/* XXX: implement all timer modes */
-
-//#define DEBUG_CUDA
-//#define DEBUG_CUDA_PACKET
-
-/* Bits in B data register: all active low */
-#define TREQ 0x08 /* Transfer request (input) */
-#define TACK 0x10 /* Transfer acknowledge (output) */
-#define TIP 0x20 /* Transfer in progress (output) */
-
-/* Bits in ACR */
-#define SR_CTRL 0x1c /* Shift register control bits */
-#define SR_EXT 0x0c /* Shift on external clock */
-#define SR_OUT 0x10 /* Shift out if 1 */
-
-/* Bits in IFR and IER */
-#define IER_SET 0x80 /* set bits in IER */
-#define IER_CLR 0 /* clear bits in IER */
-#define SR_INT 0x04 /* Shift register full/empty */
-#define T1_INT 0x40 /* Timer 1 interrupt */
-#define T2_INT 0x20 /* Timer 2 interrupt */
-
-/* Bits in ACR */
-#define T1MODE 0xc0 /* Timer 1 mode */
-#define T1MODE_CONT 0x40 /* continuous interrupts */
-
-/* commands (1st byte) */
-#define ADB_PACKET 0
-#define CUDA_PACKET 1
-#define ERROR_PACKET 2
-#define TIMER_PACKET 3
-#define POWER_PACKET 4
-#define MACIIC_PACKET 5
-#define PMU_PACKET 6
-
-
-/* CUDA commands (2nd byte) */
-#define CUDA_WARM_START 0x0
-#define CUDA_AUTOPOLL 0x1
-#define CUDA_GET_6805_ADDR 0x2
-#define CUDA_GET_TIME 0x3
-#define CUDA_GET_PRAM 0x7
-#define CUDA_SET_6805_ADDR 0x8
-#define CUDA_SET_TIME 0x9
-#define CUDA_POWERDOWN 0xa
-#define CUDA_POWERUP_TIME 0xb
-#define CUDA_SET_PRAM 0xc
-#define CUDA_MS_RESET 0xd
-#define CUDA_SEND_DFAC 0xe
-#define CUDA_BATTERY_SWAP_SENSE 0x10
-#define CUDA_RESET_SYSTEM 0x11
-#define CUDA_SET_IPL 0x12
-#define CUDA_FILE_SERVER_FLAG 0x13
-#define CUDA_SET_AUTO_RATE 0x14
-#define CUDA_GET_AUTO_RATE 0x16
-#define CUDA_SET_DEVICE_LIST 0x19
-#define CUDA_GET_DEVICE_LIST 0x1a
-#define CUDA_SET_ONE_SECOND_MODE 0x1b
-#define CUDA_SET_POWER_MESSAGES 0x21
-#define CUDA_GET_SET_IIC 0x22
-#define CUDA_WAKEUP 0x23
-#define CUDA_TIMER_TICKLE 0x24
-#define CUDA_COMBINED_FORMAT_IIC 0x25
-
-#define CUDA_TIMER_FREQ (4700000 / 6)
-#define CUDA_ADB_POLL_FREQ 50
-
-/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */
-#define RTC_OFFSET 2082844800
-
-typedef struct CUDATimer {
- int index;
- uint16_t latch;
- uint16_t counter_value; /* counter value at load time */
- int64_t load_time;
- int64_t next_irq_time;
- QEMUTimer *timer;
-} CUDATimer;
-
-typedef struct CUDAState {
- /* cuda registers */
- uint8_t b; /* B-side data */
- uint8_t a; /* A-side data */
- uint8_t dirb; /* B-side direction (1=output) */
- uint8_t dira; /* A-side direction (1=output) */
- uint8_t sr; /* Shift register */
- uint8_t acr; /* Auxiliary control register */
- uint8_t pcr; /* Peripheral control register */
- uint8_t ifr; /* Interrupt flag register */
- uint8_t ier; /* Interrupt enable register */
- uint8_t anh; /* A-side data, no handshake */
-
- CUDATimer timers[2];
-
- uint8_t last_b; /* last value of B register */
- uint8_t last_acr; /* last value of B register */
-
- int data_in_size;
- int data_in_index;
- int data_out_index;
-
- SetIRQFunc *set_irq;
- int irq;
- void *irq_opaque;
- uint8_t autopoll;
- uint8_t data_in[128];
- uint8_t data_out[16];
- QEMUTimer *adb_poll_timer;
-} CUDAState;
-
-static CUDAState cuda_state;
-ADBBusState adb_bus;
-
-static void cuda_update(CUDAState *s);
-static void cuda_receive_packet_from_host(CUDAState *s,
- const uint8_t *data, int len);
-static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
- int64_t current_time);
-
-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);
- } else {
- s->set_irq(s->irq_opaque, s->irq, 0);
- }
-}
-
-static unsigned int get_counter(CUDATimer *s)
-{
- int64_t d;
- unsigned int counter;
-
- d = muldiv64(qemu_get_clock(vm_clock) - s->load_time,
- CUDA_TIMER_FREQ, ticks_per_sec);
- if (s->index == 0) {
- /* the timer goes down from latch to -1 (period of latch + 2) */
- if (d <= (s->counter_value + 1)) {
- counter = (s->counter_value - d) & 0xffff;
- } else {
- counter = (d - (s->counter_value + 1)) % (s->latch + 2);
- counter = (s->latch - counter) & 0xffff;
- }
- } else {
- counter = (s->counter_value - d) & 0xffff;
- }
- return counter;
-}
-
-static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val)
-{
-#ifdef DEBUG_CUDA
- printf("cuda: T%d.counter=%d\n",
- 1 + (ti->timer == NULL), val);
-#endif
- ti->load_time = qemu_get_clock(vm_clock);
- ti->counter_value = val;
- cuda_timer_update(s, ti, ti->load_time);
-}
-
-static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time)
-{
- int64_t d, next_time;
- unsigned int counter;
-
- /* current counter value */
- d = muldiv64(current_time - s->load_time,
- CUDA_TIMER_FREQ, ticks_per_sec);
- /* the timer goes down from latch to -1 (period of latch + 2) */
- if (d <= (s->counter_value + 1)) {
- counter = (s->counter_value - d) & 0xffff;
- } else {
- counter = (d - (s->counter_value + 1)) % (s->latch + 2);
- counter = (s->latch - counter) & 0xffff;
- }
-
- /* Note: we consider the irq is raised on 0 */
- if (counter == 0xffff) {
- next_time = d + s->latch + 1;
- } else if (counter == 0) {
- next_time = d + s->latch + 2;
- } else {
- next_time = d + counter;
- }
-#if 0
-#ifdef DEBUG_CUDA
- printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n",
- s->latch, d, next_time - d);
-#endif
-#endif
- next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) +
- s->load_time;
- if (next_time <= current_time)
- next_time = current_time + 1;
- return next_time;
-}
-
-static void cuda_timer_update(CUDAState *s, CUDATimer *ti,
- int64_t current_time)
-{
- if (!ti->timer)
- return;
- if ((s->acr & T1MODE) != T1MODE_CONT) {
- qemu_del_timer(ti->timer);
- } else {
- ti->next_irq_time = get_next_irq_time(ti, current_time);
- qemu_mod_timer(ti->timer, ti->next_irq_time);
- }
-}
-
-static void cuda_timer1(void *opaque)
-{
- CUDAState *s = opaque;
- CUDATimer *ti = &s->timers[0];
-
- cuda_timer_update(s, ti, ti->next_irq_time);
- s->ifr |= T1_INT;
- cuda_update_irq(s);
-}
-
-static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr)
-{
- CUDAState *s = opaque;
- uint32_t val;
-
- addr = (addr >> 9) & 0xf;
- switch(addr) {
- case 0:
- val = s->b;
- break;
- case 1:
- val = s->a;
- break;
- case 2:
- val = s->dirb;
- break;
- case 3:
- val = s->dira;
- break;
- case 4:
- val = get_counter(&s->timers[0]) & 0xff;
- s->ifr &= ~T1_INT;
- cuda_update_irq(s);
- break;
- case 5:
- val = get_counter(&s->timers[0]) >> 8;
- cuda_update_irq(s);
- break;
- case 6:
- val = s->timers[0].latch & 0xff;
- break;
- case 7:
- /* XXX: check this */
- val = (s->timers[0].latch >> 8) & 0xff;
- break;
- case 8:
- val = get_counter(&s->timers[1]) & 0xff;
- s->ifr &= ~T2_INT;
- break;
- case 9:
- val = get_counter(&s->timers[1]) >> 8;
- break;
- case 10:
- val = s->sr;
- s->ifr &= ~SR_INT;
- cuda_update_irq(s);
- break;
- case 11:
- val = s->acr;
- break;
- case 12:
- val = s->pcr;
- break;
- case 13:
- val = s->ifr;
- if (s->ifr & s->ier)
- val |= 0x80;
- break;
- case 14:
- val = s->ier | 0x80;
- break;
- default:
- case 15:
- val = s->anh;
- break;
- }
-#ifdef DEBUG_CUDA
- if (addr != 13 || val != 0)
- printf("cuda: read: reg=0x%x val=%02x\n", addr, val);
-#endif
- return val;
-}
-
-static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- CUDAState *s = opaque;
-
- addr = (addr >> 9) & 0xf;
-#ifdef DEBUG_CUDA
- printf("cuda: write: reg=0x%x val=%02x\n", addr, val);
-#endif
-
- switch(addr) {
- case 0:
- s->b = val;
- cuda_update(s);
- break;
- case 1:
- s->a = val;
- break;
- case 2:
- s->dirb = val;
- break;
- case 3:
- s->dira = val;
- break;
- case 4:
- s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
- cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
- break;
- case 5:
- s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
- s->ifr &= ~T1_INT;
- set_counter(s, &s->timers[0], s->timers[0].latch);
- break;
- case 6:
- s->timers[0].latch = (s->timers[0].latch & 0xff00) | val;
- cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
- break;
- case 7:
- s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8);
- s->ifr &= ~T1_INT;
- cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
- break;
- case 8:
- s->timers[1].latch = val;
- set_counter(s, &s->timers[1], val);
- break;
- case 9:
- set_counter(s, &s->timers[1], (val << 8) | s->timers[1].latch);
- break;
- case 10:
- s->sr = val;
- break;
- case 11:
- s->acr = val;
- cuda_timer_update(s, &s->timers[0], qemu_get_clock(vm_clock));
- cuda_update(s);
- break;
- case 12:
- s->pcr = val;
- break;
- case 13:
- /* reset bits */
- s->ifr &= ~val;
- cuda_update_irq(s);
- break;
- case 14:
- if (val & IER_SET) {
- /* set bits */
- s->ier |= val & 0x7f;
- } else {
- /* reset bits */
- s->ier &= ~val;
- }
- cuda_update_irq(s);
- break;
- default:
- case 15:
- s->anh = val;
- break;
- }
-}
-
-/* NOTE: TIP and TREQ are negated */
-static void cuda_update(CUDAState *s)
-{
- int packet_received, len;
-
- packet_received = 0;
- if (!(s->b & TIP)) {
- /* transfer requested from host */
-
- if (s->acr & SR_OUT) {
- /* data output */
- if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
- if (s->data_out_index < sizeof(s->data_out)) {
-#ifdef DEBUG_CUDA
- printf("cuda: send: %02x\n", s->sr);
-#endif
- s->data_out[s->data_out_index++] = s->sr;
- s->ifr |= SR_INT;
- cuda_update_irq(s);
- }
- }
- } else {
- if (s->data_in_index < s->data_in_size) {
- /* data input */
- if ((s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) {
- s->sr = s->data_in[s->data_in_index++];
-#ifdef DEBUG_CUDA
- printf("cuda: recv: %02x\n", s->sr);
-#endif
- /* indicate end of transfer */
- if (s->data_in_index >= s->data_in_size) {
- s->b = (s->b | TREQ);
- }
- s->ifr |= SR_INT;
- cuda_update_irq(s);
- }
- }
- }
- } else {
- /* no transfer requested: handle sync case */
- if ((s->last_b & TIP) && (s->b & TACK) != (s->last_b & TACK)) {
- /* update TREQ state each time TACK change state */
- if (s->b & TACK)
- s->b = (s->b | TREQ);
- else
- s->b = (s->b & ~TREQ);
- s->ifr |= SR_INT;
- cuda_update_irq(s);
- } else {
- if (!(s->last_b & TIP)) {
- /* handle end of host to cuda transfert */
- packet_received = (s->data_out_index > 0);
- /* always an IRQ at the end of transfert */
- s->ifr |= SR_INT;
- cuda_update_irq(s);
- }
- /* signal if there is data to read */
- if (s->data_in_index < s->data_in_size) {
- s->b = (s->b & ~TREQ);
- }
- }
- }
-
- s->last_acr = s->acr;
- s->last_b = s->b;
-
- /* NOTE: cuda_receive_packet_from_host() can call cuda_update()
- recursively */
- if (packet_received) {
- len = s->data_out_index;
- s->data_out_index = 0;
- cuda_receive_packet_from_host(s, s->data_out, len);
- }
-}
-
-static void cuda_send_packet_to_host(CUDAState *s,
- const uint8_t *data, int len)
-{
-#ifdef DEBUG_CUDA_PACKET
- {
- int i;
- printf("cuda_send_packet_to_host:\n");
- for(i = 0; i < len; i++)
- printf(" %02x", data[i]);
- printf("\n");
- }
-#endif
- memcpy(s->data_in, data, len);
- s->data_in_size = len;
- s->data_in_index = 0;
- cuda_update(s);
- s->ifr |= SR_INT;
- cuda_update_irq(s);
-}
-
-static void cuda_adb_poll(void *opaque)
-{
- CUDAState *s = opaque;
- uint8_t obuf[ADB_MAX_OUT_LEN + 2];
- int olen;
-
- olen = adb_poll(&adb_bus, obuf + 2);
- if (olen > 0) {
- obuf[0] = ADB_PACKET;
- obuf[1] = 0x40; /* polled data */
- cuda_send_packet_to_host(s, obuf, olen + 2);
- }
- qemu_mod_timer(s->adb_poll_timer,
- qemu_get_clock(vm_clock) +
- (ticks_per_sec / CUDA_ADB_POLL_FREQ));
-}
-
-static void cuda_receive_packet(CUDAState *s,
- const uint8_t *data, int len)
-{
- uint8_t obuf[16];
- int ti, autopoll;
-
- switch(data[0]) {
- case CUDA_AUTOPOLL:
- autopoll = (data[1] != 0);
- if (autopoll != s->autopoll) {
- s->autopoll = autopoll;
- if (autopoll) {
- qemu_mod_timer(s->adb_poll_timer,
- qemu_get_clock(vm_clock) +
- (ticks_per_sec / CUDA_ADB_POLL_FREQ));
- } else {
- qemu_del_timer(s->adb_poll_timer);
- }
- }
- obuf[0] = CUDA_PACKET;
- obuf[1] = data[1];
- cuda_send_packet_to_host(s, obuf, 2);
- break;
- case CUDA_GET_TIME:
- case CUDA_SET_TIME:
- /* XXX: add time support ? */
- ti = time(NULL) + RTC_OFFSET;
- obuf[0] = CUDA_PACKET;
- obuf[1] = 0;
- obuf[2] = 0;
- obuf[3] = ti >> 24;
- obuf[4] = ti >> 16;
- obuf[5] = ti >> 8;
- obuf[6] = ti;
- cuda_send_packet_to_host(s, obuf, 7);
- break;
- case CUDA_FILE_SERVER_FLAG:
- case CUDA_SET_DEVICE_LIST:
- case CUDA_SET_AUTO_RATE:
- case CUDA_SET_POWER_MESSAGES:
- obuf[0] = CUDA_PACKET;
- obuf[1] = 0;
- cuda_send_packet_to_host(s, obuf, 2);
- break;
- case CUDA_POWERDOWN:
- obuf[0] = CUDA_PACKET;
- obuf[1] = 0;
- cuda_send_packet_to_host(s, obuf, 2);
- qemu_system_shutdown_request();
- break;
- default:
- break;
- }
-}
-
-static void cuda_receive_packet_from_host(CUDAState *s,
- const uint8_t *data, int len)
-{
-#ifdef DEBUG_CUDA_PACKET
- {
- int i;
- printf("cuda_receive_packet_from_host:\n");
- for(i = 0; i < len; i++)
- printf(" %02x", data[i]);
- printf("\n");
- }
-#endif
- switch(data[0]) {
- case ADB_PACKET:
- {
- uint8_t obuf[ADB_MAX_OUT_LEN + 2];
- int olen;
- olen = adb_request(&adb_bus, obuf + 2, data + 1, len - 1);
- if (olen > 0) {
- obuf[0] = ADB_PACKET;
- obuf[1] = 0x00;
- } else {
- /* error */
- obuf[0] = ADB_PACKET;
- obuf[1] = -olen;
- olen = 0;
- }
- cuda_send_packet_to_host(s, obuf, olen + 2);
- }
- break;
- case CUDA_PACKET:
- cuda_receive_packet(s, data + 1, len - 1);
- break;
- }
-}
-
-static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-}
-
-static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-}
-
-static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr)
-{
- return 0;
-}
-
-static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr)
-{
- return 0;
-}
-
-static CPUWriteMemoryFunc *cuda_write[] = {
- &cuda_writeb,
- &cuda_writew,
- &cuda_writel,
-};
-
-static CPUReadMemoryFunc *cuda_read[] = {
- &cuda_readb,
- &cuda_readw,
- &cuda_readl,
-};
-
-int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int 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;
- s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s);
- s->timers[0].latch = 0xffff;
- set_counter(s, &s->timers[0], 0xffff);
-
- s->timers[1].index = 1;
- s->timers[1].latch = 0;
- // s->ier = T1_INT | SR_INT;
- s->ier = 0;
- set_counter(s, &s->timers[1], 0xffff);
-
- s->adb_poll_timer = qemu_new_timer(vm_clock, cuda_adb_poll, s);
- cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s);
- return cuda_mem_index;
-}
diff --git a/hw/es1370.c b/hw/es1370.c
deleted file mode 100644
index 0d2d861..0000000
--- a/hw/es1370.c
+++ /dev/null
@@ -1,1062 +0,0 @@
-/*
- * QEMU ES1370 emulation
- *
- * Copyright (c) 2005 Vassili Karpov (malc)
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-/* #define DEBUG_ES1370 */
-/* #define VERBOSE_ES1370 */
-#define SILENT_ES1370
-
-#include "vl.h"
-
-/* Missing stuff:
- SCTRL_P[12](END|ST)INC
- SCTRL_P1SCTRLD
- SCTRL_P2DACSEN
- CTRL_DAC_SYNC
- MIDI
- non looped mode
- surely more
-*/
-
-/*
- Following macros and samplerate array were copied verbatim from
- Linux kernel 2.4.30: drivers/sound/es1370.c
-
- Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
-*/
-
-/* Start blatant GPL violation */
-
-#define ES1370_REG_CONTROL 0x00
-#define ES1370_REG_STATUS 0x04
-#define ES1370_REG_UART_DATA 0x08
-#define ES1370_REG_UART_STATUS 0x09
-#define ES1370_REG_UART_CONTROL 0x09
-#define ES1370_REG_UART_TEST 0x0a
-#define ES1370_REG_MEMPAGE 0x0c
-#define ES1370_REG_CODEC 0x10
-#define ES1370_REG_SERIAL_CONTROL 0x20
-#define ES1370_REG_DAC1_SCOUNT 0x24
-#define ES1370_REG_DAC2_SCOUNT 0x28
-#define ES1370_REG_ADC_SCOUNT 0x2c
-
-#define ES1370_REG_DAC1_FRAMEADR 0xc30
-#define ES1370_REG_DAC1_FRAMECNT 0xc34
-#define ES1370_REG_DAC2_FRAMEADR 0xc38
-#define ES1370_REG_DAC2_FRAMECNT 0xc3c
-#define ES1370_REG_ADC_FRAMEADR 0xd30
-#define ES1370_REG_ADC_FRAMECNT 0xd34
-#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
-#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
-
-static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
-
-#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
-#define DAC2_DIVTOSR(x) (1411200/((x)+2))
-
-#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */
-#define CTRL_XCTL1 0x40000000 /* electret mic bias */
-#define CTRL_OPEN 0x20000000 /* no function, can be read and written */
-#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */
-#define CTRL_SH_PCLKDIV 16
-#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
-#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
-#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
-#define CTRL_SH_WTSRSEL 12
-#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */
-#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */
-#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = MPEG */
-#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */
-#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */
-#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */
-#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */
-#define CTRL_ADC_EN 0x00000010 /* enable ADC */
-#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */
-#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably at address 0x200) */
-#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */
-#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */
-
-#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */
-#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in progress */
-#define STAT_CBUSY 0x00000200 /* 1 = codec busy */
-#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */
-#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
-#define STAT_SH_VC 5
-#define STAT_MCCB 0x00000010 /* CCB int pending */
-#define STAT_UART 0x00000008 /* UART int pending */
-#define STAT_DAC1 0x00000004 /* DAC1 int pending */
-#define STAT_DAC2 0x00000002 /* DAC2 int pending */
-#define STAT_ADC 0x00000001 /* ADC int pending */
-
-#define USTAT_RXINT 0x80 /* UART rx int pending */
-#define USTAT_TXINT 0x04 /* UART tx int pending */
-#define USTAT_TXRDY 0x02 /* UART tx ready */
-#define USTAT_RXRDY 0x01 /* UART rx ready */
-
-#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */
-#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */
-#define UCTRL_ENA_TXINT 0x20 /* enable TX int */
-#define UCTRL_CNTRL 0x03 /* control field */
-#define UCTRL_CNTRL_SWR 0x03 /* software reset command */
-
-#define SCTRL_P2ENDINC 0x00380000 /* */
-#define SCTRL_SH_P2ENDINC 19
-#define SCTRL_P2STINC 0x00070000 /* */
-#define SCTRL_SH_P2STINC 16
-#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */
-#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */
-#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */
-#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */
-#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */
-#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */
-#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */
-#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */
-#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */
-#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */
-#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */
-#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */
-#define SCTRL_R1FMT 0x00000030 /* format mask */
-#define SCTRL_SH_R1FMT 4
-#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */
-#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */
-#define SCTRL_P2FMT 0x0000000c /* format mask */
-#define SCTRL_SH_P2FMT 2
-#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */
-#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */
-#define SCTRL_P1FMT 0x00000003 /* format mask */
-#define SCTRL_SH_P1FMT 0
-
-/* End blatant GPL violation */
-
-#define NB_CHANNELS 3
-#define DAC1_CHANNEL 0
-#define DAC2_CHANNEL 1
-#define ADC_CHANNEL 2
-
-#define IO_READ_PROTO(n) \
-static uint32_t n (void *opaque, uint32_t addr)
-#define IO_WRITE_PROTO(n) \
-static void n (void *opaque, uint32_t addr, uint32_t val)
-
-static void es1370_dac1_callback (void *opaque, int free);
-static void es1370_dac2_callback (void *opaque, int free);
-static void es1370_adc_callback (void *opaque, int avail);
-
-#ifdef DEBUG_ES1370
-
-#define ldebug(...) AUD_log ("es1370", __VA_ARGS__)
-
-static void print_ctl (uint32_t val)
-{
- char buf[1024];
-
- buf[0] = '\0';
-#define a(n) if (val & CTRL_##n) strcat (buf, " "#n)
- a (ADC_STOP);
- a (XCTL1);
- a (OPEN);
- a (MSFMTSEL);
- a (M_SBB);
- a (DAC_SYNC);
- a (CCB_INTRM);
- a (M_CB);
- a (XCTL0);
- a (BREQ);
- a (DAC1_EN);
- a (DAC2_EN);
- a (ADC_EN);
- a (UART_EN);
- a (JYSTK_EN);
- a (CDC_EN);
- a (SERR_DIS);
-#undef a
- AUD_log ("es1370", "ctl - PCLKDIV %d(DAC2 freq %d), freq %d,%s\n",
- (val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV,
- DAC2_DIVTOSR ((val & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
- dac1_samplerate[(val & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
- buf);
-}
-
-static void print_sctl (uint32_t val)
-{
- static const char *fmt_names[] = {"8M", "8S", "16M", "16S"};
- char buf[1024];
-
- buf[0] = '\0';
-
-#define a(n) if (val & SCTRL_##n) strcat (buf, " "#n)
-#define b(n) if (!(val & SCTRL_##n)) strcat (buf, " "#n)
- b (R1LOOPSEL);
- b (P2LOOPSEL);
- b (P1LOOPSEL);
- a (P2PAUSE);
- a (P1PAUSE);
- a (R1INTEN);
- a (P2INTEN);
- a (P1INTEN);
- a (P1SCTRLD);
- a (P2DACSEN);
- if (buf[0]) {
- strcat (buf, "\n ");
- }
- else {
- buf[0] = ' ';
- buf[1] = '\0';
- }
-#undef b
-#undef a
- AUD_log ("es1370",
- "%s"
- "p2_end_inc %d, p2_st_inc %d, r1_fmt %s, p2_fmt %s, p1_fmt %s\n",
- buf,
- (val & SCTRL_P2ENDINC) >> SCTRL_SH_P2ENDINC,
- (val & SCTRL_P2STINC) >> SCTRL_SH_P2STINC,
- fmt_names [(val >> SCTRL_SH_R1FMT) & 3],
- fmt_names [(val >> SCTRL_SH_P2FMT) & 3],
- fmt_names [(val >> SCTRL_SH_P1FMT) & 3]
- );
-}
-#else
-#define ldebug(...)
-#define print_ctl(...)
-#define print_sctl(...)
-#endif
-
-#ifdef VERBOSE_ES1370
-#define dolog(...) AUD_log ("es1370", __VA_ARGS__)
-#else
-#define dolog(...)
-#endif
-
-#ifndef SILENT_ES1370
-#define lwarn(...) AUD_log ("es1370: warning", __VA_ARGS__)
-#else
-#define lwarn(...)
-#endif
-
-struct chan {
- uint32_t shift;
- uint32_t leftover;
- uint32_t scount;
- uint32_t frame_addr;
- uint32_t frame_cnt;
-};
-
-typedef struct ES1370State {
- PCIDevice *pci_dev;
-
- QEMUSoundCard card;
- struct chan chan[NB_CHANNELS];
- SWVoiceOut *dac_voice[2];
- SWVoiceIn *adc_voice;
-
- uint32_t ctl;
- uint32_t status;
- uint32_t mempage;
- uint32_t codec;
- uint32_t sctl;
-} ES1370State;
-
-typedef struct PCIES1370State {
- PCIDevice dev;
- ES1370State es1370;
-} PCIES1370State;
-
-struct chan_bits {
- uint32_t ctl_en;
- uint32_t stat_int;
- uint32_t sctl_pause;
- uint32_t sctl_inten;
- uint32_t sctl_fmt;
- uint32_t sctl_sh_fmt;
- uint32_t sctl_loopsel;
- void (*calc_freq) (ES1370State *s, uint32_t ctl,
- uint32_t *old_freq, uint32_t *new_freq);
-};
-
-static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
- uint32_t *old_freq, uint32_t *new_freq);
-static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
- uint32_t *old_freq,
- uint32_t *new_freq);
-
-static const struct chan_bits es1370_chan_bits[] = {
- {CTRL_DAC1_EN, STAT_DAC1, SCTRL_P1PAUSE, SCTRL_P1INTEN,
- SCTRL_P1FMT, SCTRL_SH_P1FMT, SCTRL_P1LOOPSEL,
- es1370_dac1_calc_freq},
-
- {CTRL_DAC2_EN, STAT_DAC2, SCTRL_P2PAUSE, SCTRL_P2INTEN,
- SCTRL_P2FMT, SCTRL_SH_P2FMT, SCTRL_P2LOOPSEL,
- es1370_dac2_and_adc_calc_freq},
-
- {CTRL_ADC_EN, STAT_ADC, 0, SCTRL_R1INTEN,
- SCTRL_R1FMT, SCTRL_SH_R1FMT, SCTRL_R1LOOPSEL,
- es1370_dac2_and_adc_calc_freq}
-};
-
-static void es1370_update_status (ES1370State *s, uint32_t new_status)
-{
- uint32_t level = new_status & (STAT_DAC1 | STAT_DAC2 | STAT_ADC);
-
- if (level) {
- s->status = new_status | STAT_INTR;
- }
- else {
- s->status = new_status & ~STAT_INTR;
- }
- pci_set_irq (s->pci_dev, 0, !!level);
-}
-
-static void es1370_reset (ES1370State *s)
-{
- size_t i;
-
- s->ctl = 1;
- s->status = 0x60;
- s->mempage = 0;
- s->codec = 0;
- s->sctl = 0;
-
- for (i = 0; i < NB_CHANNELS; ++i) {
- struct chan *d = &s->chan[i];
- d->scount = 0;
- d->leftover = 0;
- if (i == ADC_CHANNEL) {
- AUD_close_in (&s->card, s->adc_voice);
- s->adc_voice = NULL;
- }
- else {
- AUD_close_out (&s->card, s->dac_voice[i]);
- s->dac_voice[i] = NULL;
- }
- }
- pci_set_irq (s->pci_dev, 0, 0);
-}
-
-static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl)
-{
- uint32_t new_status = s->status;
-
- if (!(sctl & SCTRL_P1INTEN) && (s->sctl & SCTRL_P1INTEN)) {
- new_status &= ~STAT_DAC1;
- }
-
- if (!(sctl & SCTRL_P2INTEN) && (s->sctl & SCTRL_P2INTEN)) {
- new_status &= ~STAT_DAC2;
- }
-
- if (!(sctl & SCTRL_R1INTEN) && (s->sctl & SCTRL_R1INTEN)) {
- new_status &= ~STAT_ADC;
- }
-
- if (new_status != s->status) {
- es1370_update_status (s, new_status);
- }
-}
-
-static void es1370_dac1_calc_freq (ES1370State *s, uint32_t ctl,
- uint32_t *old_freq, uint32_t *new_freq)
-
-{
- *old_freq = dac1_samplerate[(s->ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
- *new_freq = dac1_samplerate[(ctl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
-}
-
-static void es1370_dac2_and_adc_calc_freq (ES1370State *s, uint32_t ctl,
- uint32_t *old_freq,
- uint32_t *new_freq)
-
-{
- uint32_t old_pclkdiv, new_pclkdiv;
-
- new_pclkdiv = (ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
- old_pclkdiv = (s->ctl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV;
- *new_freq = DAC2_DIVTOSR (new_pclkdiv);
- *old_freq = DAC2_DIVTOSR (old_pclkdiv);
-}
-
-static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
-{
- size_t i;
- uint32_t old_freq, new_freq, old_fmt, new_fmt;
-
- for (i = 0; i < NB_CHANNELS; ++i) {
- struct chan *d = &s->chan[i];
- const struct chan_bits *b = &es1370_chan_bits[i];
-
- new_fmt = (sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
- old_fmt = (s->sctl & b->sctl_fmt) >> b->sctl_sh_fmt;
-
- b->calc_freq (s, ctl, &old_freq, &new_freq);
-
- if ((old_fmt != new_fmt) || (old_freq != new_freq)) {
- d->shift = (new_fmt & 1) + (new_fmt >> 1);
- ldebug ("channel %d, freq = %d, nchannels %d, fmt %d, shift %d\n",
- i,
- new_freq,
- 1 << (new_fmt & 1),
- (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8,
- d->shift);
- if (new_freq) {
- audsettings_t as;
-
- as.freq = new_freq;
- as.nchannels = 1 << (new_fmt & 1);
- as.fmt = (new_fmt & 2) ? AUD_FMT_S16 : AUD_FMT_U8;
- as.endianness = 0;
-
- if (i == ADC_CHANNEL) {
- s->adc_voice =
- AUD_open_in (
- &s->card,
- s->adc_voice,
- "es1370.adc",
- s,
- es1370_adc_callback,
- &as
- );
- }
- else {
- s->dac_voice[i] =
- AUD_open_out (
- &s->card,
- s->dac_voice[i],
- i ? "es1370.dac2" : "es1370.dac1",
- s,
- i ? es1370_dac2_callback : es1370_dac1_callback,
- &as
- );
- }
- }
- }
-
- if (((ctl ^ s->ctl) & b->ctl_en)
- || ((sctl ^ s->sctl) & b->sctl_pause)) {
- int on = (ctl & b->ctl_en) && !(sctl & b->sctl_pause);
-
- if (i == ADC_CHANNEL) {
- AUD_set_active_in (s->adc_voice, on);
- }
- else {
- AUD_set_active_out (s->dac_voice[i], on);
- }
- }
- }
-
- s->ctl = ctl;
- s->sctl = sctl;
-}
-
-static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
-{
- addr &= 0xff;
- if (addr >= 0x30 && addr <= 0x3f)
- addr |= s->mempage << 8;
- return addr;
-}
-
-IO_WRITE_PROTO (es1370_writeb)
-{
- ES1370State *s = opaque;
- uint32_t shift, mask;
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case ES1370_REG_CONTROL:
- case ES1370_REG_CONTROL + 1:
- case ES1370_REG_CONTROL + 2:
- case ES1370_REG_CONTROL + 3:
- shift = (addr - ES1370_REG_CONTROL) << 3;
- mask = 0xff << shift;
- val = (s->ctl & ~mask) | ((val & 0xff) << shift);
- es1370_update_voices (s, val, s->sctl);
- print_ctl (val);
- break;
- case ES1370_REG_MEMPAGE:
- s->mempage = val;
- break;
- case ES1370_REG_SERIAL_CONTROL:
- case ES1370_REG_SERIAL_CONTROL + 1:
- case ES1370_REG_SERIAL_CONTROL + 2:
- case ES1370_REG_SERIAL_CONTROL + 3:
- shift = (addr - ES1370_REG_SERIAL_CONTROL) << 3;
- mask = 0xff << shift;
- val = (s->sctl & ~mask) | ((val & 0xff) << shift);
- es1370_maybe_lower_irq (s, val);
- es1370_update_voices (s, s->ctl, val);
- print_sctl (val);
- break;
- default:
- lwarn ("writeb %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-IO_WRITE_PROTO (es1370_writew)
-{
- ES1370State *s = opaque;
- addr = es1370_fixup (s, addr);
- uint32_t shift, mask;
- struct chan *d = &s->chan[0];
-
- switch (addr) {
- case ES1370_REG_CODEC:
- dolog ("ignored codec write address %#x, data %#x\n",
- (val >> 8) & 0xff, val & 0xff);
- s->codec = val;
- break;
-
- case ES1370_REG_CONTROL:
- case ES1370_REG_CONTROL + 2:
- shift = (addr != ES1370_REG_CONTROL) << 4;
- mask = 0xffff << shift;
- val = (s->ctl & ~mask) | ((val & 0xffff) << shift);
- es1370_update_voices (s, val, s->sctl);
- print_ctl (val);
- break;
-
- case ES1370_REG_ADC_SCOUNT:
- d++;
- case ES1370_REG_DAC2_SCOUNT:
- d++;
- case ES1370_REG_DAC1_SCOUNT:
- d->scount = (d->scount & ~0xffff) | (val & 0xffff);
- break;
-
- default:
- lwarn ("writew %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-IO_WRITE_PROTO (es1370_writel)
-{
- ES1370State *s = opaque;
- struct chan *d = &s->chan[0];
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case ES1370_REG_CONTROL:
- es1370_update_voices (s, val, s->sctl);
- print_ctl (val);
- break;
-
- case ES1370_REG_MEMPAGE:
- s->mempage = val & 0xf;
- break;
-
- case ES1370_REG_SERIAL_CONTROL:
- es1370_maybe_lower_irq (s, val);
- es1370_update_voices (s, s->ctl, val);
- print_sctl (val);
- break;
-
- case ES1370_REG_ADC_SCOUNT:
- d++;
- case ES1370_REG_DAC2_SCOUNT:
- d++;
- case ES1370_REG_DAC1_SCOUNT:
- d->scount = (val & 0xffff) | (d->scount & ~0xffff);
- ldebug ("chan %d CURR_SAMP_CT %d, SAMP_CT %d\n",
- d - &s->chan[0], val >> 16, (val & 0xffff));
- break;
-
- case ES1370_REG_ADC_FRAMEADR:
- d++;
- case ES1370_REG_DAC2_FRAMEADR:
- d++;
- case ES1370_REG_DAC1_FRAMEADR:
- d->frame_addr = val;
- ldebug ("chan %d frame address %#x\n", d - &s->chan[0], val);
- break;
-
- case ES1370_REG_PHANTOM_FRAMECNT:
- lwarn ("writing to phantom frame count %#x\n", val);
- break;
- case ES1370_REG_PHANTOM_FRAMEADR:
- lwarn ("writing to phantom frame address %#x\n", val);
- break;
-
- case ES1370_REG_ADC_FRAMECNT:
- d++;
- case ES1370_REG_DAC2_FRAMECNT:
- d++;
- case ES1370_REG_DAC1_FRAMECNT:
- d->frame_cnt = val;
- d->leftover = 0;
- ldebug ("chan %d frame count %d, buffer size %d\n",
- d - &s->chan[0], val >> 16, val & 0xffff);
- break;
-
- default:
- lwarn ("writel %#x <- %#x\n", addr, val);
- break;
- }
-}
-
-IO_READ_PROTO (es1370_readb)
-{
- ES1370State *s = opaque;
- uint32_t val;
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case 0x1b: /* Legacy */
- lwarn ("Attempt to read from legacy register\n");
- val = 5;
- break;
- case ES1370_REG_MEMPAGE:
- val = s->mempage;
- break;
- case ES1370_REG_CONTROL + 0:
- case ES1370_REG_CONTROL + 1:
- case ES1370_REG_CONTROL + 2:
- case ES1370_REG_CONTROL + 3:
- val = s->ctl >> ((addr - ES1370_REG_CONTROL) << 3);
- break;
- case ES1370_REG_STATUS + 0:
- case ES1370_REG_STATUS + 1:
- case ES1370_REG_STATUS + 2:
- case ES1370_REG_STATUS + 3:
- val = s->status >> ((addr - ES1370_REG_STATUS) << 3);
- break;
- default:
- val = ~0;
- lwarn ("readb %#x -> %#x\n", addr, val);
- break;
- }
- return val;
-}
-
-IO_READ_PROTO (es1370_readw)
-{
- ES1370State *s = opaque;
- struct chan *d = &s->chan[0];
- uint32_t val;
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case ES1370_REG_ADC_SCOUNT + 2:
- d++;
- case ES1370_REG_DAC2_SCOUNT + 2:
- d++;
- case ES1370_REG_DAC1_SCOUNT + 2:
- val = d->scount >> 16;
- break;
-
- case ES1370_REG_ADC_FRAMECNT:
- d++;
- case ES1370_REG_DAC2_FRAMECNT:
- d++;
- case ES1370_REG_DAC1_FRAMECNT:
- val = d->frame_cnt & 0xffff;
- break;
-
- case ES1370_REG_ADC_FRAMECNT + 2:
- d++;
- case ES1370_REG_DAC2_FRAMECNT + 2:
- d++;
- case ES1370_REG_DAC1_FRAMECNT + 2:
- val = d->frame_cnt >> 16;
- break;
-
- default:
- val = ~0;
- lwarn ("readw %#x -> %#x\n", addr, val);
- break;
- }
-
- return val;
-}
-
-IO_READ_PROTO (es1370_readl)
-{
- ES1370State *s = opaque;
- uint32_t val;
- struct chan *d = &s->chan[0];
-
- addr = es1370_fixup (s, addr);
-
- switch (addr) {
- case ES1370_REG_CONTROL:
- val = s->ctl;
- break;
- case ES1370_REG_STATUS:
- val = s->status;
- break;
- case ES1370_REG_MEMPAGE:
- val = s->mempage;
- break;
- case ES1370_REG_CODEC:
- val = s->codec;
- break;
- case ES1370_REG_SERIAL_CONTROL:
- val = s->sctl;
- break;
-
- case ES1370_REG_ADC_SCOUNT:
- d++;
- case ES1370_REG_DAC2_SCOUNT:
- d++;
- case ES1370_REG_DAC1_SCOUNT:
- val = d->scount;
-#ifdef DEBUG_ES1370
- {
- uint32_t curr_count = d->scount >> 16;
- uint32_t count = d->scount & 0xffff;
-
- curr_count <<= d->shift;
- count <<= d->shift;
- dolog ("read scount curr %d, total %d\n", curr_count, count);
- }
-#endif
- break;
-
- case ES1370_REG_ADC_FRAMECNT:
- d++;
- case ES1370_REG_DAC2_FRAMECNT:
- d++;
- case ES1370_REG_DAC1_FRAMECNT:
- val = d->frame_cnt;
-#ifdef DEBUG_ES1370
- {
- uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2;
- uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2;
- if (curr > size)
- dolog ("read framecnt curr %d, size %d %d\n", curr, size,
- curr > size);
- }
-#endif
- break;
-
- case ES1370_REG_ADC_FRAMEADR:
- d++;
- case ES1370_REG_DAC2_FRAMEADR:
- d++;
- case ES1370_REG_DAC1_FRAMEADR:
- val = d->frame_addr;
- break;
-
- case ES1370_REG_PHANTOM_FRAMECNT:
- val = ~0U;
- lwarn ("reading from phantom frame count\n");
- break;
- case ES1370_REG_PHANTOM_FRAMEADR:
- val = ~0U;
- lwarn ("reading from phantom frame address\n");
- break;
-
- default:
- val = ~0U;
- lwarn ("readl %#x -> %#x\n", addr, val);
- break;
- }
- return val;
-}
-
-
-static void es1370_transfer_audio (ES1370State *s, struct chan *d, int loop_sel,
- int max, int *irq)
-{
- uint8_t tmpbuf[4096];
- uint32_t addr = d->frame_addr;
- int sc = d->scount & 0xffff;
- int csc = d->scount >> 16;
- int csc_bytes = (csc + 1) << d->shift;
- int cnt = d->frame_cnt >> 16;
- int size = d->frame_cnt & 0xffff;
- int left = ((size - cnt + 1) << 2) + d->leftover;
- int transfered = 0;
- int temp = audio_MIN (max, audio_MIN (left, csc_bytes));
- int index = d - &s->chan[0];
-
- addr += (cnt << 2) + d->leftover;
-
- if (index == ADC_CHANNEL) {
- while (temp) {
- int acquired, to_copy;
-
- to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
- acquired = AUD_read (s->adc_voice, tmpbuf, to_copy);
- if (!acquired)
- break;
-
- cpu_physical_memory_write (addr, tmpbuf, acquired);
-
- temp -= acquired;
- addr += acquired;
- transfered += acquired;
- }
- }
- else {
- SWVoiceOut *voice = s->dac_voice[index];
-
- while (temp) {
- int copied, to_copy;
-
- to_copy = audio_MIN ((size_t) temp, sizeof (tmpbuf));
- cpu_physical_memory_read (addr, tmpbuf, to_copy);
- copied = AUD_write (voice, tmpbuf, to_copy);
- if (!copied)
- break;
- temp -= copied;
- addr += copied;
- transfered += copied;
- }
- }
-
- if (csc_bytes == transfered) {
- *irq = 1;
- d->scount = sc | (sc << 16);
- ldebug ("sc = %d, rate = %f\n",
- (sc + 1) << d->shift,
- (sc + 1) / (double) 44100);
- }
- else {
- *irq = 0;
- d->scount = sc | (((csc_bytes - transfered - 1) >> d->shift) << 16);
- }
-
- cnt += (transfered + d->leftover) >> 2;
-
- if (s->sctl & loop_sel) {
- /* Bah, how stupid is that having a 0 represent true value?
- i just spent few hours on this shit */
- AUD_log ("es1370: warning", "non looping mode\n");
- }
- else {
- d->frame_cnt = size;
-
- if ((uint32_t) cnt <= d->frame_cnt)
- d->frame_cnt |= cnt << 16;
- }
-
- d->leftover = (transfered + d->leftover) & 3;
-}
-
-static void es1370_run_channel (ES1370State *s, size_t chan, int free_or_avail)
-{
- uint32_t new_status = s->status;
- int max_bytes, irq;
- struct chan *d = &s->chan[chan];
- const struct chan_bits *b = &es1370_chan_bits[chan];
-
- if (!(s->ctl & b->ctl_en) || (s->sctl & b->sctl_pause)) {
- return;
- }
-
- max_bytes = free_or_avail;
- max_bytes &= ~((1 << d->shift) - 1);
- if (!max_bytes) {
- return;
- }
-
- es1370_transfer_audio (s, d, b->sctl_loopsel, max_bytes, &irq);
-
- if (irq) {
- if (s->sctl & b->sctl_inten) {
- new_status |= b->stat_int;
- }
- }
-
- if (new_status != s->status) {
- es1370_update_status (s, new_status);
- }
-}
-
-static void es1370_dac1_callback (void *opaque, int free)
-{
- ES1370State *s = opaque;
-
- es1370_run_channel (s, DAC1_CHANNEL, free);
-}
-
-static void es1370_dac2_callback (void *opaque, int free)
-{
- ES1370State *s = opaque;
-
- es1370_run_channel (s, DAC2_CHANNEL, free);
-}
-
-static void es1370_adc_callback (void *opaque, int avail)
-{
- ES1370State *s = opaque;
-
- es1370_run_channel (s, ADC_CHANNEL, avail);
-}
-
-static void es1370_map (PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- PCIES1370State *d = (PCIES1370State *) pci_dev;
- ES1370State *s = &d->es1370;
-
- (void) region_num;
- (void) size;
- (void) type;
-
- register_ioport_write (addr, 0x40 * 4, 1, es1370_writeb, s);
- register_ioport_write (addr, 0x40 * 2, 2, es1370_writew, s);
- register_ioport_write (addr, 0x40, 4, es1370_writel, s);
-
- register_ioport_read (addr, 0x40 * 4, 1, es1370_readb, s);
- register_ioport_read (addr, 0x40 * 2, 2, es1370_readw, s);
- register_ioport_read (addr, 0x40, 4, es1370_readl, s);
-}
-
-static void es1370_save (QEMUFile *f, void *opaque)
-{
- ES1370State *s = opaque;
- size_t i;
-
- for (i = 0; i < NB_CHANNELS; ++i) {
- struct chan *d = &s->chan[i];
- qemu_put_be32s (f, &d->shift);
- qemu_put_be32s (f, &d->leftover);
- qemu_put_be32s (f, &d->scount);
- qemu_put_be32s (f, &d->frame_addr);
- qemu_put_be32s (f, &d->frame_cnt);
- }
- qemu_put_be32s (f, &s->ctl);
- qemu_put_be32s (f, &s->status);
- qemu_put_be32s (f, &s->mempage);
- qemu_put_be32s (f, &s->codec);
- qemu_put_be32s (f, &s->sctl);
-}
-
-static int es1370_load (QEMUFile *f, void *opaque, int version_id)
-{
- uint32_t ctl, sctl;
- ES1370State *s = opaque;
- size_t i;
-
- if (version_id != 1)
- return -EINVAL;
-
- for (i = 0; i < NB_CHANNELS; ++i) {
- struct chan *d = &s->chan[i];
- qemu_get_be32s (f, &d->shift);
- qemu_get_be32s (f, &d->leftover);
- qemu_get_be32s (f, &d->scount);
- qemu_get_be32s (f, &d->frame_addr);
- qemu_get_be32s (f, &d->frame_cnt);
- if (i == ADC_CHANNEL) {
- if (s->adc_voice) {
- AUD_close_in (&s->card, s->adc_voice);
- s->adc_voice = NULL;
- }
- }
- else {
- if (s->dac_voice[i]) {
- AUD_close_out (&s->card, s->dac_voice[i]);
- s->dac_voice[i] = NULL;
- }
- }
- }
-
- qemu_get_be32s (f, &ctl);
- qemu_get_be32s (f, &s->status);
- qemu_get_be32s (f, &s->mempage);
- qemu_get_be32s (f, &s->codec);
- qemu_get_be32s (f, &sctl);
-
- s->ctl = 0;
- s->sctl = 0;
- es1370_update_voices (s, ctl, sctl);
- return 0;
-}
-
-static void es1370_on_reset (void *opaque)
-{
- ES1370State *s = opaque;
- es1370_reset (s);
-}
-
-int es1370_init (PCIBus *bus, AudioState *audio)
-{
- PCIES1370State *d;
- ES1370State *s;
- uint8_t *c;
-
- if (!bus) {
- dolog ("No PCI bus\n");
- return -1;
- }
-
- if (!audio) {
- dolog ("No audio state\n");
- return -1;
- }
-
- d = (PCIES1370State *) pci_register_device (bus, "ES1370",
- sizeof (PCIES1370State),
- -1, NULL, NULL);
-
- if (!d) {
- AUD_log (NULL, "Failed to register PCI device for ES1370\n");
- return -1;
- }
-
- c = d->dev.config;
- c[0x00] = 0x74;
- c[0x01] = 0x12;
- c[0x02] = 0x00;
- c[0x03] = 0x50;
- c[0x07] = 2 << 1;
- c[0x0a] = 0x01;
- c[0x0b] = 0x04;
-
-#if 1
- c[0x2c] = 0x42;
- c[0x2d] = 0x49;
- c[0x2e] = 0x4c;
- c[0x2f] = 0x4c;
-#else
- c[0x2c] = 0x74;
- c[0x2d] = 0x12;
- c[0x2e] = 0x71;
- c[0x2f] = 0x13;
- c[0x34] = 0xdc;
- c[0x3c] = 10;
- c[0xdc] = 0x00;
-#endif
-
- c[0x3d] = 1;
- c[0x3e] = 0x0c;
- c[0x3f] = 0x80;
-
- s = &d->es1370;
- s->pci_dev = &d->dev;
-
- pci_register_io_region (&d->dev, 0, 256, PCI_ADDRESS_SPACE_IO, es1370_map);
- register_savevm ("es1370", 0, 1, es1370_save, es1370_load, s);
- qemu_register_reset (es1370_on_reset, s);
-
- AUD_register_card (audio, "es1370", &s->card);
- es1370_reset (s);
- return 0;
-}
diff --git a/hw/esp.c b/hw/esp.c
deleted file mode 100644
index cdd062f..0000000
--- a/hw/esp.c
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * QEMU ESP emulation
- *
- * Copyright (c) 2005-2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "vl.h"
-
-/* debug ESP card */
-//#define DEBUG_ESP
-
-#ifdef DEBUG_ESP
-#define DPRINTF(fmt, args...) \
-do { printf("ESP: " fmt , ##args); } while (0)
-#define pic_set_irq(irq, level) \
-do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
-#else
-#define DPRINTF(fmt, args...)
-#endif
-
-#define ESPDMA_REGS 4
-#define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
-#define ESP_MAXREG 0x3f
-#define TI_BUFSZ 32
-#define DMA_VER 0xa0000000
-#define DMA_INTR 1
-#define DMA_INTREN 0x10
-#define DMA_WRITE_MEM 0x100
-#define DMA_LOADED 0x04000000
-typedef struct ESPState ESPState;
-
-struct ESPState {
- BlockDriverState **bd;
- uint8_t rregs[ESP_MAXREG];
- uint8_t wregs[ESP_MAXREG];
- int irq;
- uint32_t espdmaregs[ESPDMA_REGS];
- uint32_t ti_size;
- uint32_t ti_rptr, ti_wptr;
- uint8_t ti_buf[TI_BUFSZ];
- int sense;
- int dma;
- SCSIDevice *scsi_dev[MAX_DISKS];
- SCSIDevice *current_dev;
- uint8_t cmdbuf[TI_BUFSZ];
- int cmdlen;
- int do_cmd;
-};
-
-#define STAT_DO 0x00
-#define STAT_DI 0x01
-#define STAT_CD 0x02
-#define STAT_ST 0x03
-#define STAT_MI 0x06
-#define STAT_MO 0x07
-
-#define STAT_TC 0x10
-#define STAT_IN 0x80
-
-#define INTR_FC 0x08
-#define INTR_BS 0x10
-#define INTR_DC 0x20
-#define INTR_RST 0x80
-
-#define SEQ_0 0x0
-#define SEQ_CD 0x4
-
-static int get_cmd(ESPState *s, uint8_t *buf)
-{
- uint32_t dmaptr, dmalen;
- int target;
-
- dmalen = s->wregs[0] | (s->wregs[1] << 8);
- target = s->wregs[4] & 7;
- DPRINTF("get_cmd: len %d target %d\n", dmalen, target);
- if (s->dma) {
- dmaptr = iommu_translate(s->espdmaregs[1]);
- DPRINTF("DMA Direction: %c, addr 0x%8.8x\n",
- s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr);
- cpu_physical_memory_read(dmaptr, buf, dmalen);
- } else {
- buf[0] = 0;
- memcpy(&buf[1], s->ti_buf, dmalen);
- dmalen++;
- }
-
- s->ti_size = 0;
- s->ti_rptr = 0;
- s->ti_wptr = 0;
-
- if (target >= 4 || !s->scsi_dev[target]) {
- // No such drive
- s->rregs[4] = STAT_IN;
- s->rregs[5] = INTR_DC;
- s->rregs[6] = SEQ_0;
- s->espdmaregs[0] |= DMA_INTR;
- pic_set_irq(s->irq, 1);
- return 0;
- }
- s->current_dev = s->scsi_dev[target];
- return dmalen;
-}
-
-static void do_cmd(ESPState *s, uint8_t *buf)
-{
- int32_t datalen;
- int lun;
-
- DPRINTF("do_cmd: busid 0x%x\n", buf[0]);
- lun = buf[0] & 7;
- datalen = scsi_send_command(s->current_dev, 0, &buf[1], lun);
- if (datalen == 0) {
- s->ti_size = 0;
- } else {
- s->rregs[4] = STAT_IN | STAT_TC;
- if (datalen > 0) {
- s->rregs[4] |= STAT_DI;
- s->ti_size = datalen;
- } else {
- s->rregs[4] |= STAT_DO;
- s->ti_size = -datalen;
- }
- }
- s->rregs[5] = INTR_BS | INTR_FC;
- s->rregs[6] = SEQ_CD;
- s->espdmaregs[0] |= DMA_INTR;
- pic_set_irq(s->irq, 1);
-}
-
-static void handle_satn(ESPState *s)
-{
- uint8_t buf[32];
- int len;
-
- len = get_cmd(s, buf);
- if (len)
- do_cmd(s, buf);
-}
-
-static void handle_satn_stop(ESPState *s)
-{
- s->cmdlen = get_cmd(s, s->cmdbuf);
- if (s->cmdlen) {
- DPRINTF("Set ATN & Stop: cmdlen %d\n", s->cmdlen);
- s->do_cmd = 1;
- s->espdmaregs[1] += s->cmdlen;
- s->rregs[4] = STAT_IN | STAT_TC | STAT_CD;
- s->rregs[5] = INTR_BS | INTR_FC;
- s->rregs[6] = SEQ_CD;
- s->espdmaregs[0] |= DMA_INTR;
- pic_set_irq(s->irq, 1);
- }
-}
-
-static void write_response(ESPState *s)
-{
- uint32_t dmaptr;
-
- DPRINTF("Transfer status (sense=%d)\n", s->sense);
- s->ti_buf[0] = s->sense;
- s->ti_buf[1] = 0;
- if (s->dma) {
- dmaptr = iommu_translate(s->espdmaregs[1]);
- DPRINTF("DMA Direction: %c\n",
- s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r');
- cpu_physical_memory_write(dmaptr, s->ti_buf, 2);
- s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
- s->rregs[5] = INTR_BS | INTR_FC;
- s->rregs[6] = SEQ_CD;
- } else {
- s->ti_size = 2;
- s->ti_rptr = 0;
- s->ti_wptr = 0;
- s->rregs[7] = 2;
- }
- s->espdmaregs[0] |= DMA_INTR;
- pic_set_irq(s->irq, 1);
-
-}
-
-static void esp_command_complete(void *opaque, uint32_t tag, int sense)
-{
- ESPState *s = (ESPState *)opaque;
-
- DPRINTF("SCSI Command complete\n");
- if (s->ti_size != 0)
- DPRINTF("SCSI command completed unexpectedly\n");
- s->ti_size = 0;
- if (sense)
- DPRINTF("Command failed\n");
- s->sense = sense;
- s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
-}
-
-static void handle_ti(ESPState *s)
-{
- uint32_t dmaptr, dmalen, minlen, len, from, to;
- unsigned int i;
- int to_device;
- uint8_t buf[TARGET_PAGE_SIZE];
-
- dmalen = s->wregs[0] | (s->wregs[1] << 8);
- if (dmalen==0) {
- dmalen=0x10000;
- }
-
- if (s->do_cmd)
- minlen = (dmalen < 32) ? dmalen : 32;
- else
- minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
- DPRINTF("Transfer Information len %d\n", minlen);
- if (s->dma) {
- dmaptr = iommu_translate(s->espdmaregs[1]);
- /* Check if the transfer writes to to reads from the device. */
- to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0;
- DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n",
- to_device ? 'r': 'w', dmaptr, s->ti_size);
- from = s->espdmaregs[1];
- to = from + minlen;
- for (i = 0; i < minlen; i += len, from += len) {
- dmaptr = iommu_translate(s->espdmaregs[1] + i);
- if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
- len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
- } else {
- len = to - from;
- }
- DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to);
- s->ti_size -= len;
- if (s->do_cmd) {
- DPRINTF("command len %d + %d\n", s->cmdlen, len);
- cpu_physical_memory_read(dmaptr, &s->cmdbuf[s->cmdlen], len);
- s->ti_size = 0;
- s->cmdlen = 0;
- s->do_cmd = 0;
- do_cmd(s, s->cmdbuf);
- return;
- } else {
- if (to_device) {
- cpu_physical_memory_read(dmaptr, buf, len);
- scsi_write_data(s->current_dev, buf, len);
- } else {
- scsi_read_data(s->current_dev, buf, len);
- cpu_physical_memory_write(dmaptr, buf, len);
- }
- }
- }
- if (s->ti_size) {
- s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI);
- }
- s->rregs[5] = INTR_BS;
- s->rregs[6] = 0;
- s->rregs[7] = 0;
- s->espdmaregs[0] |= DMA_INTR;
- } else if (s->do_cmd) {
- DPRINTF("command len %d\n", s->cmdlen);
- s->ti_size = 0;
- s->cmdlen = 0;
- s->do_cmd = 0;
- do_cmd(s, s->cmdbuf);
- return;
- }
- pic_set_irq(s->irq, 1);
-}
-
-static void esp_reset(void *opaque)
-{
- ESPState *s = opaque;
- memset(s->rregs, 0, ESP_MAXREG);
- memset(s->wregs, 0, ESP_MAXREG);
- s->rregs[0x0e] = 0x4; // Indicate fas100a
- memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
- s->ti_size = 0;
- s->ti_rptr = 0;
- s->ti_wptr = 0;
- s->dma = 0;
- s->do_cmd = 0;
-}
-
-static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
-{
- ESPState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & ESP_MAXREG) >> 2;
- DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
- switch (saddr) {
- case 2:
- // FIFO
- if (s->ti_size > 0) {
- s->ti_size--;
- if ((s->rregs[4] & 6) == 0) {
- /* Data in/out. */
- scsi_read_data(s->current_dev, &s->rregs[2], 0);
- } else {
- s->rregs[2] = s->ti_buf[s->ti_rptr++];
- }
- pic_set_irq(s->irq, 1);
- }
- if (s->ti_size == 0) {
- s->ti_rptr = 0;
- s->ti_wptr = 0;
- }
- break;
- case 5:
- // interrupt
- // Clear status bits except TC
- s->rregs[4] &= STAT_TC;
- pic_set_irq(s->irq, 0);
- s->espdmaregs[0] &= ~DMA_INTR;
- break;
- default:
- break;
- }
- return s->rregs[saddr];
-}
-
-static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- ESPState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & ESP_MAXREG) >> 2;
- DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
- switch (saddr) {
- case 0:
- case 1:
- s->rregs[saddr] = val;
- break;
- case 2:
- // FIFO
- if (s->do_cmd) {
- s->cmdbuf[s->cmdlen++] = val & 0xff;
- } else if ((s->rregs[4] & 6) == 0) {
- uint8_t buf;
- buf = val & 0xff;
- s->ti_size--;
- scsi_write_data(s->current_dev, &buf, 0);
- } else {
- s->ti_size++;
- s->ti_buf[s->ti_wptr++] = val & 0xff;
- }
- break;
- case 3:
- s->rregs[saddr] = val;
- // Command
- if (val & 0x80) {
- s->dma = 1;
- } else {
- s->dma = 0;
- }
- switch(val & 0x7f) {
- case 0:
- DPRINTF("NOP (%2.2x)\n", val);
- break;
- case 1:
- DPRINTF("Flush FIFO (%2.2x)\n", val);
- //s->ti_size = 0;
- s->rregs[5] = INTR_FC;
- s->rregs[6] = 0;
- break;
- case 2:
- DPRINTF("Chip reset (%2.2x)\n", val);
- esp_reset(s);
- break;
- case 3:
- DPRINTF("Bus reset (%2.2x)\n", val);
- s->rregs[5] = INTR_RST;
- if (!(s->wregs[8] & 0x40)) {
- s->espdmaregs[0] |= DMA_INTR;
- pic_set_irq(s->irq, 1);
- }
- break;
- case 0x10:
- handle_ti(s);
- break;
- case 0x11:
- DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
- write_response(s);
- break;
- case 0x12:
- DPRINTF("Message Accepted (%2.2x)\n", val);
- write_response(s);
- s->rregs[5] = INTR_DC;
- s->rregs[6] = 0;
- break;
- case 0x1a:
- DPRINTF("Set ATN (%2.2x)\n", val);
- break;
- case 0x42:
- DPRINTF("Set ATN (%2.2x)\n", val);
- handle_satn(s);
- break;
- case 0x43:
- DPRINTF("Set ATN & stop (%2.2x)\n", val);
- handle_satn_stop(s);
- break;
- default:
- DPRINTF("Unhandled ESP command (%2.2x)\n", val);
- break;
- }
- break;
- case 4 ... 7:
- break;
- case 8:
- s->rregs[saddr] = val;
- break;
- case 9 ... 10:
- break;
- case 11:
- s->rregs[saddr] = val & 0x15;
- break;
- case 12 ... 15:
- s->rregs[saddr] = val;
- break;
- default:
- break;
- }
- s->wregs[saddr] = val;
-}
-
-static CPUReadMemoryFunc *esp_mem_read[3] = {
- esp_mem_readb,
- esp_mem_readb,
- esp_mem_readb,
-};
-
-static CPUWriteMemoryFunc *esp_mem_write[3] = {
- esp_mem_writeb,
- esp_mem_writeb,
- esp_mem_writeb,
-};
-
-static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- ESPState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & ESPDMA_MAXADDR) >> 2;
- DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
-
- return s->espdmaregs[saddr];
-}
-
-static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- ESPState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & ESPDMA_MAXADDR) >> 2;
- DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
- switch (saddr) {
- case 0:
- if (!(val & DMA_INTREN))
- pic_set_irq(s->irq, 0);
- if (val & 0x80) {
- esp_reset(s);
- } else if (val & 0x40) {
- val &= ~0x40;
- } else if (val == 0)
- val = 0x40;
- val &= 0x0fffffff;
- val |= DMA_VER;
- break;
- case 1:
- s->espdmaregs[0] |= DMA_LOADED;
- break;
- default:
- break;
- }
- s->espdmaregs[saddr] = val;
-}
-
-static CPUReadMemoryFunc *espdma_mem_read[3] = {
- espdma_mem_readl,
- espdma_mem_readl,
- espdma_mem_readl,
-};
-
-static CPUWriteMemoryFunc *espdma_mem_write[3] = {
- espdma_mem_writel,
- espdma_mem_writel,
- espdma_mem_writel,
-};
-
-static void esp_save(QEMUFile *f, void *opaque)
-{
- ESPState *s = opaque;
- unsigned int i;
-
- qemu_put_buffer(f, s->rregs, ESP_MAXREG);
- qemu_put_buffer(f, s->wregs, ESP_MAXREG);
- qemu_put_be32s(f, &s->irq);
- for (i = 0; i < ESPDMA_REGS; i++)
- qemu_put_be32s(f, &s->espdmaregs[i]);
- qemu_put_be32s(f, &s->ti_size);
- 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->dma);
-}
-
-static int esp_load(QEMUFile *f, void *opaque, int version_id)
-{
- ESPState *s = opaque;
- unsigned int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_buffer(f, s->rregs, ESP_MAXREG);
- qemu_get_buffer(f, s->wregs, ESP_MAXREG);
- qemu_get_be32s(f, &s->irq);
- for (i = 0; i < ESPDMA_REGS; i++)
- qemu_get_be32s(f, &s->espdmaregs[i]);
- qemu_get_be32s(f, &s->ti_size);
- 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->dma);
-
- return 0;
-}
-
-void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
-{
- ESPState *s;
- int esp_io_memory, espdma_io_memory;
- int i;
-
- s = qemu_mallocz(sizeof(ESPState));
- if (!s)
- return;
-
- s->bd = bd;
- s->irq = irq;
-
- esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
- cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
-
- espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
- cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
-
- esp_reset(s);
-
- register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
- qemu_register_reset(esp_reset, s);
- for (i = 0; i < MAX_DISKS; i++) {
- if (bs_table[i]) {
- s->scsi_dev[i] =
- scsi_disk_init(bs_table[i], esp_command_complete, s);
- }
- }
-}
-
diff --git a/hw/fdc.c b/hw/fdc.c
deleted file mode 100644
index 3890ace..0000000
--- a/hw/fdc.c
+++ /dev/null
@@ -1,1757 +0,0 @@
-/*
- * QEMU Floppy disk emulator (Intel 82078)
- *
- * Copyright (c) 2003 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.
- */
-/*
- * The controller is used in Sun4m systems in a slightly different
- * way. There are changes in DOR register and DMA is not available.
- */
-#include "vl.h"
-
-/********************************************************/
-/* debug Floppy devices */
-//#define DEBUG_FLOPPY
-
-#ifdef DEBUG_FLOPPY
-#define FLOPPY_DPRINTF(fmt, args...) \
-do { printf("FLOPPY: " fmt , ##args); } while (0)
-#else
-#define FLOPPY_DPRINTF(fmt, args...)
-#endif
-
-#define FLOPPY_ERROR(fmt, args...) \
-do { printf("FLOPPY ERROR: %s: " fmt, __func__ , ##args); } while (0)
-
-/********************************************************/
-/* Floppy drive emulation */
-
-/* Will always be a fixed parameter for us */
-#define FD_SECTOR_LEN 512
-#define FD_SECTOR_SC 2 /* Sector size code */
-
-/* Floppy disk drive emulation */
-typedef enum fdisk_type_t {
- FDRIVE_DISK_288 = 0x01, /* 2.88 MB disk */
- FDRIVE_DISK_144 = 0x02, /* 1.44 MB disk */
- FDRIVE_DISK_720 = 0x03, /* 720 kB disk */
- FDRIVE_DISK_USER = 0x04, /* User defined geometry */
- FDRIVE_DISK_NONE = 0x05, /* No disk */
-} fdisk_type_t;
-
-typedef enum fdrive_type_t {
- FDRIVE_DRV_144 = 0x00, /* 1.44 MB 3"5 drive */
- FDRIVE_DRV_288 = 0x01, /* 2.88 MB 3"5 drive */
- FDRIVE_DRV_120 = 0x02, /* 1.2 MB 5"25 drive */
- FDRIVE_DRV_NONE = 0x03, /* No drive connected */
-} fdrive_type_t;
-
-typedef enum fdrive_flags_t {
- FDRIVE_MOTOR_ON = 0x01, /* motor on/off */
- FDRIVE_REVALIDATE = 0x02, /* Revalidated */
-} fdrive_flags_t;
-
-typedef enum fdisk_flags_t {
- FDISK_DBL_SIDES = 0x01,
-} fdisk_flags_t;
-
-typedef struct fdrive_t {
- BlockDriverState *bs;
- /* Drive status */
- fdrive_type_t drive;
- fdrive_flags_t drflags;
- uint8_t perpendicular; /* 2.88 MB access mode */
- /* Position */
- uint8_t head;
- uint8_t track;
- uint8_t sect;
- /* Last operation status */
- uint8_t dir; /* Direction */
- uint8_t rw; /* Read/write */
- /* Media */
- fdisk_flags_t flags;
- uint8_t last_sect; /* Nb sector per track */
- uint8_t max_track; /* Nb of tracks */
- uint16_t bps; /* Bytes per sector */
- uint8_t ro; /* Is read-only */
-} fdrive_t;
-
-static void fd_init (fdrive_t *drv, BlockDriverState *bs)
-{
- /* Drive */
- drv->bs = bs;
- drv->drive = FDRIVE_DRV_NONE;
- drv->drflags = 0;
- drv->perpendicular = 0;
- /* Disk */
- drv->last_sect = 0;
- drv->max_track = 0;
-}
-
-static int _fd_sector (uint8_t head, uint8_t track,
- uint8_t sect, uint8_t last_sect)
-{
- return (((track * 2) + head) * last_sect) + sect - 1;
-}
-
-/* Returns current position, in sectors, for given drive */
-static int fd_sector (fdrive_t *drv)
-{
- return _fd_sector(drv->head, drv->track, drv->sect, drv->last_sect);
-}
-
-static int fd_seek (fdrive_t *drv, uint8_t head, uint8_t track, uint8_t sect,
- int enable_seek)
-{
- uint32_t sector;
- int ret;
-
- if (track > drv->max_track ||
- (head != 0 && (drv->flags & FDISK_DBL_SIDES) == 0)) {
- FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
- head, track, sect, 1,
- (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
- drv->max_track, drv->last_sect);
- return 2;
- }
- if (sect > drv->last_sect) {
- FLOPPY_DPRINTF("try to read %d %02x %02x (max=%d %d %02x %02x)\n",
- head, track, sect, 1,
- (drv->flags & FDISK_DBL_SIDES) == 0 ? 0 : 1,
- drv->max_track, drv->last_sect);
- return 3;
- }
- sector = _fd_sector(head, track, sect, drv->last_sect);
- ret = 0;
- if (sector != fd_sector(drv)) {
-#if 0
- if (!enable_seek) {
- FLOPPY_ERROR("no implicit seek %d %02x %02x (max=%d %02x %02x)\n",
- head, track, sect, 1, drv->max_track, drv->last_sect);
- return 4;
- }
-#endif
- drv->head = head;
- if (drv->track != track)
- ret = 1;
- drv->track = track;
- drv->sect = sect;
- }
-
- return ret;
-}
-
-/* Set drive back to track 0 */
-static void fd_recalibrate (fdrive_t *drv)
-{
- FLOPPY_DPRINTF("recalibrate\n");
- drv->head = 0;
- drv->track = 0;
- drv->sect = 1;
- drv->dir = 1;
- drv->rw = 0;
-}
-
-/* Recognize floppy formats */
-typedef struct fd_format_t {
- fdrive_type_t drive;
- fdisk_type_t disk;
- uint8_t last_sect;
- uint8_t max_track;
- uint8_t max_head;
- const unsigned char *str;
-} fd_format_t;
-
-static fd_format_t fd_formats[] = {
- /* First entry is default format */
- /* 1.44 MB 3"1/2 floppy disks */
- { FDRIVE_DRV_144, FDRIVE_DISK_144, 18, 80, 1, "1.44 MB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_144, 20, 80, 1, "1.6 MB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 80, 1, "1.68 MB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 82, 1, "1.72 MB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_144, 21, 83, 1, "1.74 MB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_144, 22, 80, 1, "1.76 MB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_144, 23, 80, 1, "1.84 MB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_144, 24, 80, 1, "1.92 MB 3\"1/2", },
- /* 2.88 MB 3"1/2 floppy disks */
- { FDRIVE_DRV_288, FDRIVE_DISK_288, 36, 80, 1, "2.88 MB 3\"1/2", },
- { FDRIVE_DRV_288, FDRIVE_DISK_288, 39, 80, 1, "3.12 MB 3\"1/2", },
- { FDRIVE_DRV_288, FDRIVE_DISK_288, 40, 80, 1, "3.2 MB 3\"1/2", },
- { FDRIVE_DRV_288, FDRIVE_DISK_288, 44, 80, 1, "3.52 MB 3\"1/2", },
- { FDRIVE_DRV_288, FDRIVE_DISK_288, 48, 80, 1, "3.84 MB 3\"1/2", },
- /* 720 kB 3"1/2 floppy disks */
- { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 1, "720 kB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 80, 1, "800 kB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 82, 1, "820 kB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_720, 10, 83, 1, "830 kB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_720, 13, 80, 1, "1.04 MB 3\"1/2", },
- { FDRIVE_DRV_144, FDRIVE_DISK_720, 14, 80, 1, "1.12 MB 3\"1/2", },
- /* 1.2 MB 5"1/4 floppy disks */
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 15, 80, 1, "1.2 kB 5\"1/4", },
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 80, 1, "1.44 MB 5\"1/4", },
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 82, 1, "1.48 MB 5\"1/4", },
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 18, 83, 1, "1.49 MB 5\"1/4", },
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 20, 80, 1, "1.6 MB 5\"1/4", },
- /* 720 kB 5"1/4 floppy disks */
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 80, 1, "720 kB 5\"1/4", },
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 11, 80, 1, "880 kB 5\"1/4", },
- /* 360 kB 5"1/4 floppy disks */
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 1, "360 kB 5\"1/4", },
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 9, 40, 0, "180 kB 5\"1/4", },
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 41, 1, "410 kB 5\"1/4", },
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 10, 42, 1, "420 kB 5\"1/4", },
- /* 320 kB 5"1/4 floppy disks */
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 1, "320 kB 5\"1/4", },
- { FDRIVE_DRV_120, FDRIVE_DISK_288, 8, 40, 0, "160 kB 5\"1/4", },
- /* 360 kB must match 5"1/4 better than 3"1/2... */
- { FDRIVE_DRV_144, FDRIVE_DISK_720, 9, 80, 0, "360 kB 3\"1/2", },
- /* end */
- { FDRIVE_DRV_NONE, FDRIVE_DISK_NONE, -1, -1, 0, NULL, },
-};
-
-/* Revalidate a disk drive after a disk change */
-static void fd_revalidate (fdrive_t *drv)
-{
- fd_format_t *parse;
- int64_t nb_sectors, size;
- int i, first_match, match;
- int nb_heads, max_track, last_sect, ro;
-
- FLOPPY_DPRINTF("revalidate\n");
- drv->drflags &= ~FDRIVE_REVALIDATE;
- if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
- ro = bdrv_is_read_only(drv->bs);
- bdrv_get_geometry_hint(drv->bs, &nb_heads, &max_track, &last_sect);
- if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
- FLOPPY_DPRINTF("User defined disk (%d %d %d)",
- nb_heads - 1, max_track, last_sect);
- } else {
- bdrv_get_geometry(drv->bs, &nb_sectors);
- match = -1;
- first_match = -1;
- for (i = 0;; i++) {
- parse = &fd_formats[i];
- if (parse->drive == FDRIVE_DRV_NONE)
- break;
- if (drv->drive == parse->drive ||
- drv->drive == FDRIVE_DRV_NONE) {
- size = (parse->max_head + 1) * parse->max_track *
- parse->last_sect;
- if (nb_sectors == size) {
- match = i;
- break;
- }
- if (first_match == -1)
- first_match = i;
- }
- }
- if (match == -1) {
- if (first_match == -1)
- match = 1;
- else
- match = first_match;
- parse = &fd_formats[match];
- }
- nb_heads = parse->max_head + 1;
- max_track = parse->max_track;
- last_sect = parse->last_sect;
- drv->drive = parse->drive;
- FLOPPY_DPRINTF("%s floppy disk (%d h %d t %d s) %s\n", parse->str,
- nb_heads, max_track, last_sect, ro ? "ro" : "rw");
- }
- if (nb_heads == 1) {
- drv->flags &= ~FDISK_DBL_SIDES;
- } else {
- drv->flags |= FDISK_DBL_SIDES;
- }
- drv->max_track = max_track;
- drv->last_sect = last_sect;
- drv->ro = ro;
- } else {
- FLOPPY_DPRINTF("No disk in drive\n");
- drv->last_sect = 0;
- drv->max_track = 0;
- drv->flags &= ~FDISK_DBL_SIDES;
- }
- drv->drflags |= FDRIVE_REVALIDATE;
-}
-
-/* Motor control */
-static void fd_start (fdrive_t *drv)
-{
- drv->drflags |= FDRIVE_MOTOR_ON;
-}
-
-static void fd_stop (fdrive_t *drv)
-{
- drv->drflags &= ~FDRIVE_MOTOR_ON;
-}
-
-/* Re-initialise a drives (motor off, repositioned) */
-static void fd_reset (fdrive_t *drv)
-{
- fd_stop(drv);
- fd_recalibrate(drv);
-}
-
-/********************************************************/
-/* Intel 82078 floppy disk controller emulation */
-
-static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq);
-static void fdctrl_reset_fifo (fdctrl_t *fdctrl);
-static int fdctrl_transfer_handler (void *opaque, int nchan,
- int dma_pos, int dma_len);
-static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status);
-static void fdctrl_result_timer(void *opaque);
-
-static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl);
-static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl);
-static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl);
-static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl);
-static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_data (fdctrl_t *fdctrl);
-static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value);
-static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl);
-
-enum {
- FD_CTRL_ACTIVE = 0x01, /* XXX: suppress that */
- FD_CTRL_RESET = 0x02,
- FD_CTRL_SLEEP = 0x04, /* XXX: suppress that */
- FD_CTRL_BUSY = 0x08, /* dma transfer in progress */
- FD_CTRL_INTR = 0x10,
-};
-
-enum {
- FD_DIR_WRITE = 0,
- FD_DIR_READ = 1,
- FD_DIR_SCANE = 2,
- FD_DIR_SCANL = 3,
- FD_DIR_SCANH = 4,
-};
-
-enum {
- FD_STATE_CMD = 0x00,
- FD_STATE_STATUS = 0x01,
- FD_STATE_DATA = 0x02,
- FD_STATE_STATE = 0x03,
- FD_STATE_MULTI = 0x10,
- FD_STATE_SEEK = 0x20,
- FD_STATE_FORMAT = 0x40,
-};
-
-#define FD_STATE(state) ((state) & FD_STATE_STATE)
-#define FD_SET_STATE(state, new_state) \
-do { (state) = ((state) & ~FD_STATE_STATE) | (new_state); } while (0)
-#define FD_MULTI_TRACK(state) ((state) & FD_STATE_MULTI)
-#define FD_DID_SEEK(state) ((state) & FD_STATE_SEEK)
-#define FD_FORMAT_CMD(state) ((state) & FD_STATE_FORMAT)
-
-struct fdctrl_t {
- fdctrl_t *fdctrl;
- /* Controller's identification */
- uint8_t version;
- /* HW */
- int irq_lvl;
- int dma_chann;
- uint32_t io_base;
- /* Controller state */
- QEMUTimer *result_timer;
- uint8_t state;
- uint8_t dma_en;
- uint8_t cur_drv;
- uint8_t bootsel;
- /* Command FIFO */
- uint8_t fifo[FD_SECTOR_LEN];
- uint32_t data_pos;
- uint32_t data_len;
- uint8_t data_state;
- uint8_t data_dir;
- uint8_t int_status;
- uint8_t eot; /* last wanted sector */
- /* States kept only to be returned back */
- /* Timers state */
- uint8_t timer0;
- uint8_t timer1;
- /* precompensation */
- uint8_t precomp_trk;
- uint8_t config;
- uint8_t lock;
- /* Power down config (also with status regB access mode */
- uint8_t pwrd;
- /* Floppy drives */
- fdrive_t drives[2];
-};
-
-static uint32_t fdctrl_read (void *opaque, uint32_t reg)
-{
- fdctrl_t *fdctrl = opaque;
- uint32_t retval;
-
- switch (reg & 0x07) {
-#ifdef TARGET_SPARC
- case 0x00:
- // Identify to Linux as S82078B
- retval = fdctrl_read_statusB(fdctrl);
- break;
-#endif
- case 0x01:
- retval = fdctrl_read_statusB(fdctrl);
- break;
- case 0x02:
- retval = fdctrl_read_dor(fdctrl);
- break;
- case 0x03:
- retval = fdctrl_read_tape(fdctrl);
- break;
- case 0x04:
- retval = fdctrl_read_main_status(fdctrl);
- break;
- case 0x05:
- retval = fdctrl_read_data(fdctrl);
- break;
- case 0x07:
- retval = fdctrl_read_dir(fdctrl);
- break;
- default:
- retval = (uint32_t)(-1);
- break;
- }
- FLOPPY_DPRINTF("read reg%d: 0x%02x\n", reg & 7, retval);
-
- return retval;
-}
-
-static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
-{
- fdctrl_t *fdctrl = opaque;
-
- FLOPPY_DPRINTF("write reg%d: 0x%02x\n", reg & 7, value);
-
- switch (reg & 0x07) {
- case 0x02:
- fdctrl_write_dor(fdctrl, value);
- break;
- case 0x03:
- fdctrl_write_tape(fdctrl, value);
- break;
- case 0x04:
- fdctrl_write_rate(fdctrl, value);
- break;
- case 0x05:
- fdctrl_write_data(fdctrl, value);
- break;
- default:
- break;
- }
-}
-
-static uint32_t fdctrl_read_mem (void *opaque, target_phys_addr_t reg)
-{
- return fdctrl_read(opaque, reg);
-}
-
-static void fdctrl_write_mem (void *opaque,
- target_phys_addr_t reg, uint32_t value)
-{
- fdctrl_write(opaque, reg, value);
-}
-
-static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
- fdctrl_read_mem,
- fdctrl_read_mem,
- fdctrl_read_mem,
-};
-
-static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
- fdctrl_write_mem,
- fdctrl_write_mem,
- fdctrl_write_mem,
-};
-
-static void fd_change_cb (void *opaque)
-{
- fdrive_t *drv = opaque;
-
- FLOPPY_DPRINTF("disk change\n");
- fd_revalidate(drv);
-#if 0
- fd_recalibrate(drv);
- fdctrl_reset_fifo(drv->fdctrl);
- fdctrl_raise_irq(drv->fdctrl, 0x20);
-#endif
-}
-
-fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
- uint32_t io_base,
- BlockDriverState **fds)
-{
- fdctrl_t *fdctrl;
- int io_mem;
- int i;
-
- FLOPPY_DPRINTF("init controller\n");
- fdctrl = qemu_mallocz(sizeof(fdctrl_t));
- if (!fdctrl)
- return NULL;
- fdctrl->result_timer = qemu_new_timer(vm_clock,
- fdctrl_result_timer, fdctrl);
-
- fdctrl->version = 0x90; /* Intel 82078 controller */
- fdctrl->irq_lvl = irq_lvl;
- fdctrl->dma_chann = dma_chann;
- fdctrl->io_base = io_base;
- fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
- if (fdctrl->dma_chann != -1) {
- fdctrl->dma_en = 1;
- DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
- } else {
- fdctrl->dma_en = 0;
- }
- for (i = 0; i < 2; i++) {
- fd_init(&fdctrl->drives[i], fds[i]);
- if (fds[i]) {
- bdrv_set_change_cb(fds[i],
- &fd_change_cb, &fdctrl->drives[i]);
- }
- }
- fdctrl_reset(fdctrl, 0);
- fdctrl->state = FD_CTRL_ACTIVE;
- if (mem_mapped) {
- io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl);
- cpu_register_physical_memory(io_base, 0x08, io_mem);
- } else {
- register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
- register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
- register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl);
- register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl);
- }
- for (i = 0; i < 2; i++) {
- fd_revalidate(&fdctrl->drives[i]);
- }
-
- return fdctrl;
-}
-
-/* XXX: may change if moved to bdrv */
-int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num)
-{
- return fdctrl->drives[drive_num].drive;
-}
-
-/* Change IRQ state */
-static void fdctrl_reset_irq (fdctrl_t *fdctrl)
-{
- FLOPPY_DPRINTF("Reset interrupt\n");
- pic_set_irq(fdctrl->irq_lvl, 0);
- fdctrl->state &= ~FD_CTRL_INTR;
-}
-
-static void fdctrl_raise_irq (fdctrl_t *fdctrl, uint8_t status)
-{
-#ifdef TARGET_SPARC
- // Sparc mutation
- if (!fdctrl->dma_en) {
- fdctrl->state &= ~FD_CTRL_BUSY;
- fdctrl->int_status = status;
- return;
- }
-#endif
- if (~(fdctrl->state & FD_CTRL_INTR)) {
- pic_set_irq(fdctrl->irq_lvl, 1);
- fdctrl->state |= FD_CTRL_INTR;
- }
- FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
- fdctrl->int_status = status;
-}
-
-/* Reset controller */
-static void fdctrl_reset (fdctrl_t *fdctrl, int do_irq)
-{
- int i;
-
- FLOPPY_DPRINTF("reset controller\n");
- fdctrl_reset_irq(fdctrl);
- /* Initialise controller */
- fdctrl->cur_drv = 0;
- /* FIFO state */
- fdctrl->data_pos = 0;
- fdctrl->data_len = 0;
- fdctrl->data_state = FD_STATE_CMD;
- fdctrl->data_dir = FD_DIR_WRITE;
- for (i = 0; i < MAX_FD; i++)
- fd_reset(&fdctrl->drives[i]);
- fdctrl_reset_fifo(fdctrl);
- if (do_irq)
- fdctrl_raise_irq(fdctrl, 0xc0);
-}
-
-static inline fdrive_t *drv0 (fdctrl_t *fdctrl)
-{
- return &fdctrl->drives[fdctrl->bootsel];
-}
-
-static inline fdrive_t *drv1 (fdctrl_t *fdctrl)
-{
- return &fdctrl->drives[1 - fdctrl->bootsel];
-}
-
-static fdrive_t *get_cur_drv (fdctrl_t *fdctrl)
-{
- return fdctrl->cur_drv == 0 ? drv0(fdctrl) : drv1(fdctrl);
-}
-
-/* Status B register : 0x01 (read-only) */
-static uint32_t fdctrl_read_statusB (fdctrl_t *fdctrl)
-{
- FLOPPY_DPRINTF("status register: 0x00\n");
- return 0;
-}
-
-/* Digital output register : 0x02 */
-static uint32_t fdctrl_read_dor (fdctrl_t *fdctrl)
-{
- uint32_t retval = 0;
-
- /* Drive motors state indicators */
- if (drv0(fdctrl)->drflags & FDRIVE_MOTOR_ON)
- retval |= 1 << 5;
- if (drv1(fdctrl)->drflags & FDRIVE_MOTOR_ON)
- retval |= 1 << 4;
- /* DMA enable */
- retval |= fdctrl->dma_en << 3;
- /* Reset indicator */
- retval |= (fdctrl->state & FD_CTRL_RESET) == 0 ? 0x04 : 0;
- /* Selected drive */
- retval |= fdctrl->cur_drv;
- FLOPPY_DPRINTF("digital output register: 0x%02x\n", retval);
-
- return retval;
-}
-
-static void fdctrl_write_dor (fdctrl_t *fdctrl, uint32_t value)
-{
- /* Reset mode */
- if (fdctrl->state & FD_CTRL_RESET) {
- if (!(value & 0x04)) {
- FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
- return;
- }
- }
- FLOPPY_DPRINTF("digital output register set to 0x%02x\n", value);
- /* Drive motors state indicators */
- if (value & 0x20)
- fd_start(drv1(fdctrl));
- else
- fd_stop(drv1(fdctrl));
- if (value & 0x10)
- fd_start(drv0(fdctrl));
- else
- fd_stop(drv0(fdctrl));
- /* DMA enable */
-#if 0
- if (fdctrl->dma_chann != -1)
- fdctrl->dma_en = 1 - ((value >> 3) & 1);
-#endif
- /* Reset */
- if (!(value & 0x04)) {
- if (!(fdctrl->state & FD_CTRL_RESET)) {
- FLOPPY_DPRINTF("controller enter RESET state\n");
- fdctrl->state |= FD_CTRL_RESET;
- }
- } else {
- if (fdctrl->state & FD_CTRL_RESET) {
- FLOPPY_DPRINTF("controller out of RESET state\n");
- fdctrl_reset(fdctrl, 1);
- fdctrl->state &= ~(FD_CTRL_RESET | FD_CTRL_SLEEP);
- }
- }
- /* Selected drive */
- fdctrl->cur_drv = value & 1;
-}
-
-/* Tape drive register : 0x03 */
-static uint32_t fdctrl_read_tape (fdctrl_t *fdctrl)
-{
- uint32_t retval = 0;
-
- /* Disk boot selection indicator */
- retval |= fdctrl->bootsel << 2;
- /* Tape indicators: never allowed */
- FLOPPY_DPRINTF("tape drive register: 0x%02x\n", retval);
-
- return retval;
-}
-
-static void fdctrl_write_tape (fdctrl_t *fdctrl, uint32_t value)
-{
- /* Reset mode */
- if (fdctrl->state & FD_CTRL_RESET) {
- FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
- return;
- }
- FLOPPY_DPRINTF("tape drive register set to 0x%02x\n", value);
- /* Disk boot selection indicator */
- fdctrl->bootsel = (value >> 2) & 1;
- /* Tape indicators: never allow */
-}
-
-/* Main status register : 0x04 (read) */
-static uint32_t fdctrl_read_main_status (fdctrl_t *fdctrl)
-{
- uint32_t retval = 0;
-
- fdctrl->state &= ~(FD_CTRL_SLEEP | FD_CTRL_RESET);
- if (!(fdctrl->state & FD_CTRL_BUSY)) {
- /* Data transfer allowed */
- retval |= 0x80;
- /* Data transfer direction indicator */
- if (fdctrl->data_dir == FD_DIR_READ)
- retval |= 0x40;
- }
- /* Should handle 0x20 for SPECIFY command */
- /* Command busy indicator */
- if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA ||
- FD_STATE(fdctrl->data_state) == FD_STATE_STATUS)
- retval |= 0x10;
- FLOPPY_DPRINTF("main status register: 0x%02x\n", retval);
-
- return retval;
-}
-
-/* Data select rate register : 0x04 (write) */
-static void fdctrl_write_rate (fdctrl_t *fdctrl, uint32_t value)
-{
- /* Reset mode */
- if (fdctrl->state & FD_CTRL_RESET) {
- FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
- return;
- }
- FLOPPY_DPRINTF("select rate register set to 0x%02x\n", value);
- /* Reset: autoclear */
- if (value & 0x80) {
- fdctrl->state |= FD_CTRL_RESET;
- fdctrl_reset(fdctrl, 1);
- fdctrl->state &= ~FD_CTRL_RESET;
- }
- if (value & 0x40) {
- fdctrl->state |= FD_CTRL_SLEEP;
- fdctrl_reset(fdctrl, 1);
- }
-// fdctrl.precomp = (value >> 2) & 0x07;
-}
-
-/* Digital input register : 0x07 (read-only) */
-static uint32_t fdctrl_read_dir (fdctrl_t *fdctrl)
-{
- uint32_t retval = 0;
-
- if (drv0(fdctrl)->drflags & FDRIVE_REVALIDATE ||
- drv1(fdctrl)->drflags & FDRIVE_REVALIDATE)
- retval |= 0x80;
- if (retval != 0)
- FLOPPY_DPRINTF("Floppy digital input register: 0x%02x\n", retval);
- drv0(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
- drv1(fdctrl)->drflags &= ~FDRIVE_REVALIDATE;
-
- return retval;
-}
-
-/* FIFO state control */
-static void fdctrl_reset_fifo (fdctrl_t *fdctrl)
-{
- fdctrl->data_dir = FD_DIR_WRITE;
- fdctrl->data_pos = 0;
- FD_SET_STATE(fdctrl->data_state, FD_STATE_CMD);
-}
-
-/* Set FIFO status for the host to read */
-static void fdctrl_set_fifo (fdctrl_t *fdctrl, int fifo_len, int do_irq)
-{
- fdctrl->data_dir = FD_DIR_READ;
- fdctrl->data_len = fifo_len;
- fdctrl->data_pos = 0;
- FD_SET_STATE(fdctrl->data_state, FD_STATE_STATUS);
- if (do_irq)
- fdctrl_raise_irq(fdctrl, 0x00);
-}
-
-/* Set an error: unimplemented/unknown command */
-static void fdctrl_unimplemented (fdctrl_t *fdctrl)
-{
-#if 0
- fdrive_t *cur_drv;
-
- cur_drv = get_cur_drv(fdctrl);
- fdctrl->fifo[0] = 0x60 | (cur_drv->head << 2) | fdctrl->cur_drv;
- fdctrl->fifo[1] = 0x00;
- fdctrl->fifo[2] = 0x00;
- fdctrl_set_fifo(fdctrl, 3, 1);
-#else
- // fdctrl_reset_fifo(fdctrl);
- fdctrl->fifo[0] = 0x80;
- fdctrl_set_fifo(fdctrl, 1, 0);
-#endif
-}
-
-/* Callback for transfer end (stop or abort) */
-static void fdctrl_stop_transfer (fdctrl_t *fdctrl, uint8_t status0,
- uint8_t status1, uint8_t status2)
-{
- fdrive_t *cur_drv;
-
- cur_drv = get_cur_drv(fdctrl);
- FLOPPY_DPRINTF("transfer status: %02x %02x %02x (%02x)\n",
- status0, status1, status2,
- status0 | (cur_drv->head << 2) | fdctrl->cur_drv);
- fdctrl->fifo[0] = status0 | (cur_drv->head << 2) | fdctrl->cur_drv;
- fdctrl->fifo[1] = status1;
- fdctrl->fifo[2] = status2;
- fdctrl->fifo[3] = cur_drv->track;
- fdctrl->fifo[4] = cur_drv->head;
- fdctrl->fifo[5] = cur_drv->sect;
- fdctrl->fifo[6] = FD_SECTOR_SC;
- fdctrl->data_dir = FD_DIR_READ;
- if (fdctrl->state & FD_CTRL_BUSY) {
- DMA_release_DREQ(fdctrl->dma_chann);
- fdctrl->state &= ~FD_CTRL_BUSY;
- }
- fdctrl_set_fifo(fdctrl, 7, 1);
-}
-
-/* Prepare a data transfer (either DMA or FIFO) */
-static void fdctrl_start_transfer (fdctrl_t *fdctrl, int direction)
-{
- fdrive_t *cur_drv;
- uint8_t kh, kt, ks;
- int did_seek;
-
- fdctrl->cur_drv = fdctrl->fifo[1] & 1;
- cur_drv = get_cur_drv(fdctrl);
- kt = fdctrl->fifo[2];
- kh = fdctrl->fifo[3];
- ks = fdctrl->fifo[4];
- FLOPPY_DPRINTF("Start transfer at %d %d %02x %02x (%d)\n",
- fdctrl->cur_drv, kh, kt, ks,
- _fd_sector(kh, kt, ks, cur_drv->last_sect));
- did_seek = 0;
- switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
- case 2:
- /* sect too big */
- fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 3:
- /* track too big */
- fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 4:
- /* No seek enabled */
- fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 1:
- did_seek = 1;
- break;
- default:
- break;
- }
- /* Set the FIFO state */
- fdctrl->data_dir = direction;
- fdctrl->data_pos = 0;
- FD_SET_STATE(fdctrl->data_state, FD_STATE_DATA); /* FIFO ready for data */
- if (fdctrl->fifo[0] & 0x80)
- fdctrl->data_state |= FD_STATE_MULTI;
- else
- fdctrl->data_state &= ~FD_STATE_MULTI;
- if (did_seek)
- fdctrl->data_state |= FD_STATE_SEEK;
- else
- fdctrl->data_state &= ~FD_STATE_SEEK;
- if (fdctrl->fifo[5] == 00) {
- fdctrl->data_len = fdctrl->fifo[8];
- } else {
- int tmp;
- fdctrl->data_len = 128 << fdctrl->fifo[5];
- tmp = (cur_drv->last_sect - ks + 1);
- if (fdctrl->fifo[0] & 0x80)
- tmp += cur_drv->last_sect;
- fdctrl->data_len *= tmp;
- }
- fdctrl->eot = fdctrl->fifo[6];
- if (fdctrl->dma_en) {
- int dma_mode;
- /* DMA transfer are enabled. Check if DMA channel is well programmed */
- dma_mode = DMA_get_channel_mode(fdctrl->dma_chann);
- dma_mode = (dma_mode >> 2) & 3;
- FLOPPY_DPRINTF("dma_mode=%d direction=%d (%d - %d)\n",
- dma_mode, direction,
- (128 << fdctrl->fifo[5]) *
- (cur_drv->last_sect - ks + 1), fdctrl->data_len);
- if (((direction == FD_DIR_SCANE || direction == FD_DIR_SCANL ||
- direction == FD_DIR_SCANH) && dma_mode == 0) ||
- (direction == FD_DIR_WRITE && dma_mode == 2) ||
- (direction == FD_DIR_READ && dma_mode == 1)) {
- /* No access is allowed until DMA transfer has completed */
- fdctrl->state |= FD_CTRL_BUSY;
- /* Now, we just have to wait for the DMA controller to
- * recall us...
- */
- DMA_hold_DREQ(fdctrl->dma_chann);
- DMA_schedule(fdctrl->dma_chann);
- return;
- } else {
- FLOPPY_ERROR("dma_mode=%d direction=%d\n", dma_mode, direction);
- }
- }
- FLOPPY_DPRINTF("start non-DMA transfer\n");
- /* IO based transfer: calculate len */
- fdctrl_raise_irq(fdctrl, 0x00);
-
- return;
-}
-
-/* Prepare a transfer of deleted data */
-static void fdctrl_start_transfer_del (fdctrl_t *fdctrl, int direction)
-{
- /* We don't handle deleted data,
- * so we don't return *ANYTHING*
- */
- fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
-}
-
-/* handlers for DMA transfers */
-static int fdctrl_transfer_handler (void *opaque, int nchan,
- int dma_pos, int dma_len)
-{
- fdctrl_t *fdctrl;
- fdrive_t *cur_drv;
- int len, start_pos, rel_pos;
- uint8_t status0 = 0x00, status1 = 0x00, status2 = 0x00;
-
- fdctrl = opaque;
- if (!(fdctrl->state & FD_CTRL_BUSY)) {
- FLOPPY_DPRINTF("Not in DMA transfer mode !\n");
- return 0;
- }
- cur_drv = get_cur_drv(fdctrl);
- if (fdctrl->data_dir == FD_DIR_SCANE || fdctrl->data_dir == FD_DIR_SCANL ||
- fdctrl->data_dir == FD_DIR_SCANH)
- status2 = 0x04;
- if (dma_len > fdctrl->data_len)
- dma_len = fdctrl->data_len;
- if (cur_drv->bs == NULL) {
- if (fdctrl->data_dir == FD_DIR_WRITE)
- fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
- else
- fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
- len = 0;
- goto transfer_error;
- }
- rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
- for (start_pos = fdctrl->data_pos; fdctrl->data_pos < dma_len;) {
- len = dma_len - fdctrl->data_pos;
- if (len + rel_pos > FD_SECTOR_LEN)
- len = FD_SECTOR_LEN - rel_pos;
- FLOPPY_DPRINTF("copy %d bytes (%d %d %d) %d pos %d %02x "
- "(%d-0x%08x 0x%08x)\n", len, dma_len, fdctrl->data_pos,
- fdctrl->data_len, fdctrl->cur_drv, cur_drv->head,
- cur_drv->track, cur_drv->sect, fd_sector(cur_drv),
- fd_sector(cur_drv) * 512);
- if (fdctrl->data_dir != FD_DIR_WRITE ||
- len < FD_SECTOR_LEN || rel_pos != 0) {
- /* READ & SCAN commands and realign to a sector for WRITE */
- if (bdrv_read(cur_drv->bs, fd_sector(cur_drv),
- fdctrl->fifo, 1) < 0) {
- FLOPPY_DPRINTF("Floppy: error getting sector %d\n",
- fd_sector(cur_drv));
- /* Sure, image size is too small... */
- memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
- }
- }
- switch (fdctrl->data_dir) {
- case FD_DIR_READ:
- /* READ commands */
- DMA_write_memory (nchan, fdctrl->fifo + rel_pos,
- fdctrl->data_pos, len);
-/* cpu_physical_memory_write(addr + fdctrl->data_pos, */
-/* fdctrl->fifo + rel_pos, len); */
- break;
- case FD_DIR_WRITE:
- /* WRITE commands */
- DMA_read_memory (nchan, fdctrl->fifo + rel_pos,
- fdctrl->data_pos, len);
-/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
-/* fdctrl->fifo + rel_pos, len); */
- if (bdrv_write(cur_drv->bs, fd_sector(cur_drv),
- fdctrl->fifo, 1) < 0) {
- FLOPPY_ERROR("writting sector %d\n", fd_sector(cur_drv));
- fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
- goto transfer_error;
- }
- break;
- default:
- /* SCAN commands */
- {
- uint8_t tmpbuf[FD_SECTOR_LEN];
- int ret;
- DMA_read_memory (nchan, tmpbuf, fdctrl->data_pos, len);
-/* cpu_physical_memory_read(addr + fdctrl->data_pos, */
-/* tmpbuf, len); */
- ret = memcmp(tmpbuf, fdctrl->fifo + rel_pos, len);
- if (ret == 0) {
- status2 = 0x08;
- goto end_transfer;
- }
- if ((ret < 0 && fdctrl->data_dir == FD_DIR_SCANL) ||
- (ret > 0 && fdctrl->data_dir == FD_DIR_SCANH)) {
- status2 = 0x00;
- goto end_transfer;
- }
- }
- break;
- }
- fdctrl->data_pos += len;
- rel_pos = fdctrl->data_pos % FD_SECTOR_LEN;
- if (rel_pos == 0) {
- /* Seek to next sector */
- FLOPPY_DPRINTF("seek to next sector (%d %02x %02x => %d) (%d)\n",
- cur_drv->head, cur_drv->track, cur_drv->sect,
- fd_sector(cur_drv),
- fdctrl->data_pos - len);
- /* XXX: cur_drv->sect >= cur_drv->last_sect should be an
- error in fact */
- if (cur_drv->sect >= cur_drv->last_sect ||
- cur_drv->sect == fdctrl->eot) {
- cur_drv->sect = 1;
- if (FD_MULTI_TRACK(fdctrl->data_state)) {
- if (cur_drv->head == 0 &&
- (cur_drv->flags & FDISK_DBL_SIDES) != 0) {
- cur_drv->head = 1;
- } else {
- cur_drv->head = 0;
- cur_drv->track++;
- if ((cur_drv->flags & FDISK_DBL_SIDES) == 0)
- break;
- }
- } else {
- cur_drv->track++;
- break;
- }
- FLOPPY_DPRINTF("seek to next track (%d %02x %02x => %d)\n",
- cur_drv->head, cur_drv->track,
- cur_drv->sect, fd_sector(cur_drv));
- } else {
- cur_drv->sect++;
- }
- }
- }
-end_transfer:
- len = fdctrl->data_pos - start_pos;
- FLOPPY_DPRINTF("end transfer %d %d %d\n",
- fdctrl->data_pos, len, fdctrl->data_len);
- if (fdctrl->data_dir == FD_DIR_SCANE ||
- fdctrl->data_dir == FD_DIR_SCANL ||
- fdctrl->data_dir == FD_DIR_SCANH)
- status2 = 0x08;
- if (FD_DID_SEEK(fdctrl->data_state))
- status0 |= 0x20;
- fdctrl->data_len -= len;
- // if (fdctrl->data_len == 0)
- fdctrl_stop_transfer(fdctrl, status0, status1, status2);
-transfer_error:
-
- return len;
-}
-
-/* Data register : 0x05 */
-static uint32_t fdctrl_read_data (fdctrl_t *fdctrl)
-{
- fdrive_t *cur_drv;
- uint32_t retval = 0;
- int pos, len;
-
- cur_drv = get_cur_drv(fdctrl);
- fdctrl->state &= ~FD_CTRL_SLEEP;
- if (FD_STATE(fdctrl->data_state) == FD_STATE_CMD) {
- FLOPPY_ERROR("can't read data in CMD state\n");
- return 0;
- }
- pos = fdctrl->data_pos;
- if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
- pos %= FD_SECTOR_LEN;
- if (pos == 0) {
- len = fdctrl->data_len - fdctrl->data_pos;
- if (len > FD_SECTOR_LEN)
- len = FD_SECTOR_LEN;
- bdrv_read(cur_drv->bs, fd_sector(cur_drv),
- fdctrl->fifo, len);
- }
- }
- retval = fdctrl->fifo[pos];
- if (++fdctrl->data_pos == fdctrl->data_len) {
- fdctrl->data_pos = 0;
- /* Switch from transfer mode to status mode
- * then from status mode to command mode
- */
- if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
- fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
- } else {
- fdctrl_reset_fifo(fdctrl);
- fdctrl_reset_irq(fdctrl);
- }
- }
- FLOPPY_DPRINTF("data register: 0x%02x\n", retval);
-
- return retval;
-}
-
-static void fdctrl_format_sector (fdctrl_t *fdctrl)
-{
- fdrive_t *cur_drv;
- uint8_t kh, kt, ks;
- int did_seek;
-
- fdctrl->cur_drv = fdctrl->fifo[1] & 1;
- cur_drv = get_cur_drv(fdctrl);
- kt = fdctrl->fifo[6];
- kh = fdctrl->fifo[7];
- ks = fdctrl->fifo[8];
- FLOPPY_DPRINTF("format sector at %d %d %02x %02x (%d)\n",
- fdctrl->cur_drv, kh, kt, ks,
- _fd_sector(kh, kt, ks, cur_drv->last_sect));
- did_seek = 0;
- switch (fd_seek(cur_drv, kh, kt, ks, fdctrl->config & 0x40)) {
- case 2:
- /* sect too big */
- fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 3:
- /* track too big */
- fdctrl_stop_transfer(fdctrl, 0x40, 0x80, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 4:
- /* No seek enabled */
- fdctrl_stop_transfer(fdctrl, 0x40, 0x00, 0x00);
- fdctrl->fifo[3] = kt;
- fdctrl->fifo[4] = kh;
- fdctrl->fifo[5] = ks;
- return;
- case 1:
- did_seek = 1;
- fdctrl->data_state |= FD_STATE_SEEK;
- break;
- default:
- break;
- }
- memset(fdctrl->fifo, 0, FD_SECTOR_LEN);
- if (cur_drv->bs == NULL ||
- bdrv_write(cur_drv->bs, fd_sector(cur_drv), fdctrl->fifo, 1) < 0) {
- FLOPPY_ERROR("formating sector %d\n", fd_sector(cur_drv));
- fdctrl_stop_transfer(fdctrl, 0x60, 0x00, 0x00);
- } else {
- if (cur_drv->sect == cur_drv->last_sect) {
- fdctrl->data_state &= ~FD_STATE_FORMAT;
- /* Last sector done */
- if (FD_DID_SEEK(fdctrl->data_state))
- fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
- else
- fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
- } else {
- /* More to do */
- fdctrl->data_pos = 0;
- fdctrl->data_len = 4;
- }
- }
-}
-
-static void fdctrl_write_data (fdctrl_t *fdctrl, uint32_t value)
-{
- fdrive_t *cur_drv;
-
- cur_drv = get_cur_drv(fdctrl);
- /* Reset mode */
- if (fdctrl->state & FD_CTRL_RESET) {
- FLOPPY_DPRINTF("Floppy controller in RESET state !\n");
- return;
- }
- fdctrl->state &= ~FD_CTRL_SLEEP;
- if (FD_STATE(fdctrl->data_state) == FD_STATE_STATUS) {
- FLOPPY_ERROR("can't write data in status mode\n");
- return;
- }
- /* Is it write command time ? */
- if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA) {
- /* FIFO data write */
- fdctrl->fifo[fdctrl->data_pos++] = value;
- if (fdctrl->data_pos % FD_SECTOR_LEN == (FD_SECTOR_LEN - 1) ||
- fdctrl->data_pos == fdctrl->data_len) {
- bdrv_write(cur_drv->bs, fd_sector(cur_drv),
- fdctrl->fifo, FD_SECTOR_LEN);
- }
- /* Switch from transfer mode to status mode
- * then from status mode to command mode
- */
- if (FD_STATE(fdctrl->data_state) == FD_STATE_DATA)
- fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
- return;
- }
- if (fdctrl->data_pos == 0) {
- /* Command */
- switch (value & 0x5F) {
- case 0x46:
- /* READ variants */
- FLOPPY_DPRINTF("READ command\n");
- /* 8 parameters cmd */
- fdctrl->data_len = 9;
- goto enqueue;
- case 0x4C:
- /* READ_DELETED variants */
- FLOPPY_DPRINTF("READ_DELETED command\n");
- /* 8 parameters cmd */
- fdctrl->data_len = 9;
- goto enqueue;
- case 0x50:
- /* SCAN_EQUAL variants */
- FLOPPY_DPRINTF("SCAN_EQUAL command\n");
- /* 8 parameters cmd */
- fdctrl->data_len = 9;
- goto enqueue;
- case 0x56:
- /* VERIFY variants */
- FLOPPY_DPRINTF("VERIFY command\n");
- /* 8 parameters cmd */
- fdctrl->data_len = 9;
- goto enqueue;
- case 0x59:
- /* SCAN_LOW_OR_EQUAL variants */
- FLOPPY_DPRINTF("SCAN_LOW_OR_EQUAL command\n");
- /* 8 parameters cmd */
- fdctrl->data_len = 9;
- goto enqueue;
- case 0x5D:
- /* SCAN_HIGH_OR_EQUAL variants */
- FLOPPY_DPRINTF("SCAN_HIGH_OR_EQUAL command\n");
- /* 8 parameters cmd */
- fdctrl->data_len = 9;
- goto enqueue;
- default:
- break;
- }
- switch (value & 0x7F) {
- case 0x45:
- /* WRITE variants */
- FLOPPY_DPRINTF("WRITE command\n");
- /* 8 parameters cmd */
- fdctrl->data_len = 9;
- goto enqueue;
- case 0x49:
- /* WRITE_DELETED variants */
- FLOPPY_DPRINTF("WRITE_DELETED command\n");
- /* 8 parameters cmd */
- fdctrl->data_len = 9;
- goto enqueue;
- default:
- break;
- }
- switch (value) {
- case 0x03:
- /* SPECIFY */
- FLOPPY_DPRINTF("SPECIFY command\n");
- /* 1 parameter cmd */
- fdctrl->data_len = 3;
- goto enqueue;
- case 0x04:
- /* SENSE_DRIVE_STATUS */
- FLOPPY_DPRINTF("SENSE_DRIVE_STATUS command\n");
- /* 1 parameter cmd */
- fdctrl->data_len = 2;
- goto enqueue;
- case 0x07:
- /* RECALIBRATE */
- FLOPPY_DPRINTF("RECALIBRATE command\n");
- /* 1 parameter cmd */
- fdctrl->data_len = 2;
- goto enqueue;
- case 0x08:
- /* SENSE_INTERRUPT_STATUS */
- FLOPPY_DPRINTF("SENSE_INTERRUPT_STATUS command (%02x)\n",
- fdctrl->int_status);
- /* No parameters cmd: returns status if no interrupt */
-#if 0
- fdctrl->fifo[0] =
- fdctrl->int_status | (cur_drv->head << 2) | fdctrl->cur_drv;
-#else
- /* XXX: int_status handling is broken for read/write
- commands, so we do this hack. It should be suppressed
- ASAP */
- fdctrl->fifo[0] =
- 0x20 | (cur_drv->head << 2) | fdctrl->cur_drv;
-#endif
- fdctrl->fifo[1] = cur_drv->track;
- fdctrl_set_fifo(fdctrl, 2, 0);
- fdctrl_reset_irq(fdctrl);
- fdctrl->int_status = 0xC0;
- return;
- case 0x0E:
- /* DUMPREG */
- FLOPPY_DPRINTF("DUMPREG command\n");
- /* Drives position */
- fdctrl->fifo[0] = drv0(fdctrl)->track;
- fdctrl->fifo[1] = drv1(fdctrl)->track;
- fdctrl->fifo[2] = 0;
- fdctrl->fifo[3] = 0;
- /* timers */
- fdctrl->fifo[4] = fdctrl->timer0;
- fdctrl->fifo[5] = (fdctrl->timer1 << 1) | fdctrl->dma_en;
- fdctrl->fifo[6] = cur_drv->last_sect;
- fdctrl->fifo[7] = (fdctrl->lock << 7) |
- (cur_drv->perpendicular << 2);
- fdctrl->fifo[8] = fdctrl->config;
- fdctrl->fifo[9] = fdctrl->precomp_trk;
- fdctrl_set_fifo(fdctrl, 10, 0);
- return;
- case 0x0F:
- /* SEEK */
- FLOPPY_DPRINTF("SEEK command\n");
- /* 2 parameters cmd */
- fdctrl->data_len = 3;
- goto enqueue;
- case 0x10:
- /* VERSION */
- FLOPPY_DPRINTF("VERSION command\n");
- /* No parameters cmd */
- /* Controller's version */
- fdctrl->fifo[0] = fdctrl->version;
- fdctrl_set_fifo(fdctrl, 1, 1);
- return;
- case 0x12:
- /* PERPENDICULAR_MODE */
- FLOPPY_DPRINTF("PERPENDICULAR_MODE command\n");
- /* 1 parameter cmd */
- fdctrl->data_len = 2;
- goto enqueue;
- case 0x13:
- /* CONFIGURE */
- FLOPPY_DPRINTF("CONFIGURE command\n");
- /* 3 parameters cmd */
- fdctrl->data_len = 4;
- goto enqueue;
- case 0x14:
- /* UNLOCK */
- FLOPPY_DPRINTF("UNLOCK command\n");
- /* No parameters cmd */
- fdctrl->lock = 0;
- fdctrl->fifo[0] = 0;
- fdctrl_set_fifo(fdctrl, 1, 0);
- return;
- case 0x17:
- /* POWERDOWN_MODE */
- FLOPPY_DPRINTF("POWERDOWN_MODE command\n");
- /* 2 parameters cmd */
- fdctrl->data_len = 3;
- goto enqueue;
- case 0x18:
- /* PART_ID */
- FLOPPY_DPRINTF("PART_ID command\n");
- /* No parameters cmd */
- fdctrl->fifo[0] = 0x41; /* Stepping 1 */
- fdctrl_set_fifo(fdctrl, 1, 0);
- return;
- case 0x2C:
- /* SAVE */
- FLOPPY_DPRINTF("SAVE command\n");
- /* No parameters cmd */
- fdctrl->fifo[0] = 0;
- fdctrl->fifo[1] = 0;
- /* Drives position */
- fdctrl->fifo[2] = drv0(fdctrl)->track;
- fdctrl->fifo[3] = drv1(fdctrl)->track;
- fdctrl->fifo[4] = 0;
- fdctrl->fifo[5] = 0;
- /* timers */
- fdctrl->fifo[6] = fdctrl->timer0;
- fdctrl->fifo[7] = fdctrl->timer1;
- fdctrl->fifo[8] = cur_drv->last_sect;
- fdctrl->fifo[9] = (fdctrl->lock << 7) |
- (cur_drv->perpendicular << 2);
- fdctrl->fifo[10] = fdctrl->config;
- fdctrl->fifo[11] = fdctrl->precomp_trk;
- fdctrl->fifo[12] = fdctrl->pwrd;
- fdctrl->fifo[13] = 0;
- fdctrl->fifo[14] = 0;
- fdctrl_set_fifo(fdctrl, 15, 1);
- return;
- case 0x33:
- /* OPTION */
- FLOPPY_DPRINTF("OPTION command\n");
- /* 1 parameter cmd */
- fdctrl->data_len = 2;
- goto enqueue;
- case 0x42:
- /* READ_TRACK */
- FLOPPY_DPRINTF("READ_TRACK command\n");
- /* 8 parameters cmd */
- fdctrl->data_len = 9;
- goto enqueue;
- case 0x4A:
- /* READ_ID */
- FLOPPY_DPRINTF("READ_ID command\n");
- /* 1 parameter cmd */
- fdctrl->data_len = 2;
- goto enqueue;
- case 0x4C:
- /* RESTORE */
- FLOPPY_DPRINTF("RESTORE command\n");
- /* 17 parameters cmd */
- fdctrl->data_len = 18;
- goto enqueue;
- case 0x4D:
- /* FORMAT_TRACK */
- FLOPPY_DPRINTF("FORMAT_TRACK command\n");
- /* 5 parameters cmd */
- fdctrl->data_len = 6;
- goto enqueue;
- case 0x8E:
- /* DRIVE_SPECIFICATION_COMMAND */
- FLOPPY_DPRINTF("DRIVE_SPECIFICATION_COMMAND command\n");
- /* 5 parameters cmd */
- fdctrl->data_len = 6;
- goto enqueue;
- case 0x8F:
- /* RELATIVE_SEEK_OUT */
- FLOPPY_DPRINTF("RELATIVE_SEEK_OUT command\n");
- /* 2 parameters cmd */
- fdctrl->data_len = 3;
- goto enqueue;
- case 0x94:
- /* LOCK */
- FLOPPY_DPRINTF("LOCK command\n");
- /* No parameters cmd */
- fdctrl->lock = 1;
- fdctrl->fifo[0] = 0x10;
- fdctrl_set_fifo(fdctrl, 1, 1);
- return;
- case 0xCD:
- /* FORMAT_AND_WRITE */
- FLOPPY_DPRINTF("FORMAT_AND_WRITE command\n");
- /* 10 parameters cmd */
- fdctrl->data_len = 11;
- goto enqueue;
- case 0xCF:
- /* RELATIVE_SEEK_IN */
- FLOPPY_DPRINTF("RELATIVE_SEEK_IN command\n");
- /* 2 parameters cmd */
- fdctrl->data_len = 3;
- goto enqueue;
- default:
- /* Unknown command */
- FLOPPY_ERROR("unknown command: 0x%02x\n", value);
- fdctrl_unimplemented(fdctrl);
- return;
- }
- }
-enqueue:
- FLOPPY_DPRINTF("%s: %02x\n", __func__, value);
- fdctrl->fifo[fdctrl->data_pos] = value;
- if (++fdctrl->data_pos == fdctrl->data_len) {
- /* We now have all parameters
- * and will be able to treat the command
- */
- if (fdctrl->data_state & FD_STATE_FORMAT) {
- fdctrl_format_sector(fdctrl);
- return;
- }
- switch (fdctrl->fifo[0] & 0x1F) {
- case 0x06:
- {
- /* READ variants */
- FLOPPY_DPRINTF("treat READ command\n");
- fdctrl_start_transfer(fdctrl, FD_DIR_READ);
- return;
- }
- case 0x0C:
- /* READ_DELETED variants */
-// FLOPPY_DPRINTF("treat READ_DELETED command\n");
- FLOPPY_ERROR("treat READ_DELETED command\n");
- fdctrl_start_transfer_del(fdctrl, FD_DIR_READ);
- return;
- case 0x16:
- /* VERIFY variants */
-// FLOPPY_DPRINTF("treat VERIFY command\n");
- FLOPPY_ERROR("treat VERIFY command\n");
- fdctrl_stop_transfer(fdctrl, 0x20, 0x00, 0x00);
- return;
- case 0x10:
- /* SCAN_EQUAL variants */
-// FLOPPY_DPRINTF("treat SCAN_EQUAL command\n");
- FLOPPY_ERROR("treat SCAN_EQUAL command\n");
- fdctrl_start_transfer(fdctrl, FD_DIR_SCANE);
- return;
- case 0x19:
- /* SCAN_LOW_OR_EQUAL variants */
-// FLOPPY_DPRINTF("treat SCAN_LOW_OR_EQUAL command\n");
- FLOPPY_ERROR("treat SCAN_LOW_OR_EQUAL command\n");
- fdctrl_start_transfer(fdctrl, FD_DIR_SCANL);
- return;
- case 0x1D:
- /* SCAN_HIGH_OR_EQUAL variants */
-// FLOPPY_DPRINTF("treat SCAN_HIGH_OR_EQUAL command\n");
- FLOPPY_ERROR("treat SCAN_HIGH_OR_EQUAL command\n");
- fdctrl_start_transfer(fdctrl, FD_DIR_SCANH);
- return;
- default:
- break;
- }
- switch (fdctrl->fifo[0] & 0x3F) {
- case 0x05:
- /* WRITE variants */
- FLOPPY_DPRINTF("treat WRITE command (%02x)\n", fdctrl->fifo[0]);
- fdctrl_start_transfer(fdctrl, FD_DIR_WRITE);
- return;
- case 0x09:
- /* WRITE_DELETED variants */
-// FLOPPY_DPRINTF("treat WRITE_DELETED command\n");
- FLOPPY_ERROR("treat WRITE_DELETED command\n");
- fdctrl_start_transfer_del(fdctrl, FD_DIR_WRITE);
- return;
- default:
- break;
- }
- switch (fdctrl->fifo[0]) {
- case 0x03:
- /* SPECIFY */
- FLOPPY_DPRINTF("treat SPECIFY command\n");
- fdctrl->timer0 = (fdctrl->fifo[1] >> 4) & 0xF;
- fdctrl->timer1 = fdctrl->fifo[2] >> 1;
- fdctrl->dma_en = 1 - (fdctrl->fifo[2] & 1) ;
- /* No result back */
- fdctrl_reset_fifo(fdctrl);
- break;
- case 0x04:
- /* SENSE_DRIVE_STATUS */
- FLOPPY_DPRINTF("treat SENSE_DRIVE_STATUS command\n");
- fdctrl->cur_drv = fdctrl->fifo[1] & 1;
- cur_drv = get_cur_drv(fdctrl);
- cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
- /* 1 Byte status back */
- fdctrl->fifo[0] = (cur_drv->ro << 6) |
- (cur_drv->track == 0 ? 0x10 : 0x00) |
- (cur_drv->head << 2) |
- fdctrl->cur_drv |
- 0x28;
- fdctrl_set_fifo(fdctrl, 1, 0);
- break;
- case 0x07:
- /* RECALIBRATE */
- FLOPPY_DPRINTF("treat RECALIBRATE command\n");
- fdctrl->cur_drv = fdctrl->fifo[1] & 1;
- cur_drv = get_cur_drv(fdctrl);
- fd_recalibrate(cur_drv);
- fdctrl_reset_fifo(fdctrl);
- /* Raise Interrupt */
- fdctrl_raise_irq(fdctrl, 0x20);
- break;
- case 0x0F:
- /* SEEK */
- FLOPPY_DPRINTF("treat SEEK command\n");
- fdctrl->cur_drv = fdctrl->fifo[1] & 1;
- cur_drv = get_cur_drv(fdctrl);
- fd_start(cur_drv);
- if (fdctrl->fifo[2] <= cur_drv->track)
- cur_drv->dir = 1;
- else
- cur_drv->dir = 0;
- fdctrl_reset_fifo(fdctrl);
- if (fdctrl->fifo[2] > cur_drv->max_track) {
- fdctrl_raise_irq(fdctrl, 0x60);
- } else {
- cur_drv->track = fdctrl->fifo[2];
- /* Raise Interrupt */
- fdctrl_raise_irq(fdctrl, 0x20);
- }
- break;
- case 0x12:
- /* PERPENDICULAR_MODE */
- FLOPPY_DPRINTF("treat PERPENDICULAR_MODE command\n");
- if (fdctrl->fifo[1] & 0x80)
- cur_drv->perpendicular = fdctrl->fifo[1] & 0x7;
- /* No result back */
- fdctrl_reset_fifo(fdctrl);
- break;
- case 0x13:
- /* CONFIGURE */
- FLOPPY_DPRINTF("treat CONFIGURE command\n");
- fdctrl->config = fdctrl->fifo[2];
- fdctrl->precomp_trk = fdctrl->fifo[3];
- /* No result back */
- fdctrl_reset_fifo(fdctrl);
- break;
- case 0x17:
- /* POWERDOWN_MODE */
- FLOPPY_DPRINTF("treat POWERDOWN_MODE command\n");
- fdctrl->pwrd = fdctrl->fifo[1];
- fdctrl->fifo[0] = fdctrl->fifo[1];
- fdctrl_set_fifo(fdctrl, 1, 1);
- break;
- case 0x33:
- /* OPTION */
- FLOPPY_DPRINTF("treat OPTION command\n");
- /* No result back */
- fdctrl_reset_fifo(fdctrl);
- break;
- case 0x42:
- /* READ_TRACK */
-// FLOPPY_DPRINTF("treat READ_TRACK command\n");
- FLOPPY_ERROR("treat READ_TRACK command\n");
- fdctrl_start_transfer(fdctrl, FD_DIR_READ);
- break;
- case 0x4A:
- /* READ_ID */
- FLOPPY_DPRINTF("treat READ_ID command\n");
- /* XXX: should set main status register to busy */
- cur_drv->head = (fdctrl->fifo[1] >> 2) & 1;
- qemu_mod_timer(fdctrl->result_timer,
- qemu_get_clock(vm_clock) + (ticks_per_sec / 50));
- break;
- case 0x4C:
- /* RESTORE */
- FLOPPY_DPRINTF("treat RESTORE command\n");
- /* Drives position */
- drv0(fdctrl)->track = fdctrl->fifo[3];
- drv1(fdctrl)->track = fdctrl->fifo[4];
- /* timers */
- fdctrl->timer0 = fdctrl->fifo[7];
- fdctrl->timer1 = fdctrl->fifo[8];
- cur_drv->last_sect = fdctrl->fifo[9];
- fdctrl->lock = fdctrl->fifo[10] >> 7;
- cur_drv->perpendicular = (fdctrl->fifo[10] >> 2) & 0xF;
- fdctrl->config = fdctrl->fifo[11];
- fdctrl->precomp_trk = fdctrl->fifo[12];
- fdctrl->pwrd = fdctrl->fifo[13];
- fdctrl_reset_fifo(fdctrl);
- break;
- case 0x4D:
- /* FORMAT_TRACK */
- FLOPPY_DPRINTF("treat FORMAT_TRACK command\n");
- fdctrl->cur_drv = fdctrl->fifo[1] & 1;
- cur_drv = get_cur_drv(fdctrl);
- fdctrl->data_state |= FD_STATE_FORMAT;
- if (fdctrl->fifo[0] & 0x80)
- fdctrl->data_state |= FD_STATE_MULTI;
- else
- fdctrl->data_state &= ~FD_STATE_MULTI;
- fdctrl->data_state &= ~FD_STATE_SEEK;
- cur_drv->bps =
- fdctrl->fifo[2] > 7 ? 16384 : 128 << fdctrl->fifo[2];
-#if 0
- cur_drv->last_sect =
- cur_drv->flags & FDISK_DBL_SIDES ? fdctrl->fifo[3] :
- fdctrl->fifo[3] / 2;
-#else
- cur_drv->last_sect = fdctrl->fifo[3];
-#endif
- /* Bochs BIOS is buggy and don't send format informations
- * for each sector. So, pretend all's done right now...
- */
- fdctrl->data_state &= ~FD_STATE_FORMAT;
- fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
- break;
- case 0x8E:
- /* DRIVE_SPECIFICATION_COMMAND */
- FLOPPY_DPRINTF("treat DRIVE_SPECIFICATION_COMMAND command\n");
- if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x80) {
- /* Command parameters done */
- if (fdctrl->fifo[fdctrl->data_pos - 1] & 0x40) {
- fdctrl->fifo[0] = fdctrl->fifo[1];
- fdctrl->fifo[2] = 0;
- fdctrl->fifo[3] = 0;
- fdctrl_set_fifo(fdctrl, 4, 1);
- } else {
- fdctrl_reset_fifo(fdctrl);
- }
- } else if (fdctrl->data_len > 7) {
- /* ERROR */
- fdctrl->fifo[0] = 0x80 |
- (cur_drv->head << 2) | fdctrl->cur_drv;
- fdctrl_set_fifo(fdctrl, 1, 1);
- }
- break;
- case 0x8F:
- /* RELATIVE_SEEK_OUT */
- FLOPPY_DPRINTF("treat RELATIVE_SEEK_OUT command\n");
- fdctrl->cur_drv = fdctrl->fifo[1] & 1;
- cur_drv = get_cur_drv(fdctrl);
- fd_start(cur_drv);
- cur_drv->dir = 0;
- if (fdctrl->fifo[2] + cur_drv->track >= cur_drv->max_track) {
- cur_drv->track = cur_drv->max_track - 1;
- } else {
- cur_drv->track += fdctrl->fifo[2];
- }
- fdctrl_reset_fifo(fdctrl);
- fdctrl_raise_irq(fdctrl, 0x20);
- break;
- case 0xCD:
- /* FORMAT_AND_WRITE */
-// FLOPPY_DPRINTF("treat FORMAT_AND_WRITE command\n");
- FLOPPY_ERROR("treat FORMAT_AND_WRITE command\n");
- fdctrl_unimplemented(fdctrl);
- break;
- case 0xCF:
- /* RELATIVE_SEEK_IN */
- FLOPPY_DPRINTF("treat RELATIVE_SEEK_IN command\n");
- fdctrl->cur_drv = fdctrl->fifo[1] & 1;
- cur_drv = get_cur_drv(fdctrl);
- fd_start(cur_drv);
- cur_drv->dir = 1;
- if (fdctrl->fifo[2] > cur_drv->track) {
- cur_drv->track = 0;
- } else {
- cur_drv->track -= fdctrl->fifo[2];
- }
- fdctrl_reset_fifo(fdctrl);
- /* Raise Interrupt */
- fdctrl_raise_irq(fdctrl, 0x20);
- break;
- }
- }
-}
-
-static void fdctrl_result_timer(void *opaque)
-{
- fdctrl_t *fdctrl = opaque;
- fdctrl_stop_transfer(fdctrl, 0x00, 0x00, 0x00);
-}
diff --git a/hw/fmopl.c b/hw/fmopl.c
deleted file mode 100644
index 2b0e82b..0000000
--- a/hw/fmopl.c
+++ /dev/null
@@ -1,1390 +0,0 @@
-/*
-**
-** File: fmopl.c -- software implementation of FM sound generator
-**
-** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development
-**
-** Version 0.37a
-**
-*/
-
-/*
- preliminary :
- Problem :
- note:
-*/
-
-/* This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL.
- *
- * 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.1 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 INLINE __inline
-#define HAS_YM3812 1
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <math.h>
-//#include "driver.h" /* use M.A.M.E. */
-#include "fmopl.h"
-
-#ifndef PI
-#define PI 3.14159265358979323846
-#endif
-
-/* -------------------- for debug --------------------- */
-/* #define OPL_OUTPUT_LOG */
-#ifdef OPL_OUTPUT_LOG
-static FILE *opl_dbg_fp = NULL;
-static FM_OPL *opl_dbg_opl[16];
-static int opl_dbg_maxchip,opl_dbg_chip;
-#endif
-
-/* -------------------- preliminary define section --------------------- */
-/* attack/decay rate time rate */
-#define OPL_ARRATE 141280 /* RATE 4 = 2826.24ms @ 3.6MHz */
-#define OPL_DRRATE 1956000 /* RATE 4 = 39280.64ms @ 3.6MHz */
-
-#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */
-
-#define FREQ_BITS 24 /* frequency turn */
-
-/* counter bits = 20 , octerve 7 */
-#define FREQ_RATE (1<<(FREQ_BITS-20))
-#define TL_BITS (FREQ_BITS+2)
-
-/* final output shift , limit minimum and maximum */
-#define OPL_OUTSB (TL_BITS+3-16) /* OPL output final shift 16bit */
-#define OPL_MAXOUT (0x7fff<<OPL_OUTSB)
-#define OPL_MINOUT (-0x8000<<OPL_OUTSB)
-
-/* -------------------- quality selection --------------------- */
-
-/* sinwave entries */
-/* used static memory = SIN_ENT * 4 (byte) */
-#define SIN_ENT 2048
-
-/* output level entries (envelope,sinwave) */
-/* envelope counter lower bits */
-#define ENV_BITS 16
-/* envelope output entries */
-#define EG_ENT 4096
-/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */
-/* used static memory = EG_ENT*4 (byte) */
-
-#define EG_OFF ((2*EG_ENT)<<ENV_BITS) /* OFF */
-#define EG_DED EG_OFF
-#define EG_DST (EG_ENT<<ENV_BITS) /* DECAY START */
-#define EG_AED EG_DST
-#define EG_AST 0 /* ATTACK START */
-
-#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step */
-
-/* LFO table entries */
-#define VIB_ENT 512
-#define VIB_SHIFT (32-9)
-#define AMS_ENT 512
-#define AMS_SHIFT (32-9)
-
-#define VIB_RATE 256
-
-/* -------------------- local defines , macros --------------------- */
-
-/* register number to channel number , slot offset */
-#define SLOT1 0
-#define SLOT2 1
-
-/* envelope phase */
-#define ENV_MOD_RR 0x00
-#define ENV_MOD_DR 0x01
-#define ENV_MOD_AR 0x02
-
-/* -------------------- tables --------------------- */
-static const int slot_array[32]=
-{
- 0, 2, 4, 1, 3, 5,-1,-1,
- 6, 8,10, 7, 9,11,-1,-1,
- 12,14,16,13,15,17,-1,-1,
- -1,-1,-1,-1,-1,-1,-1,-1
-};
-
-/* key scale level */
-/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
-#define DV (EG_STEP/2)
-static const UINT32 KSL_TABLE[8*16]=
-{
- /* OCT 0 */
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- /* OCT 1 */
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV,
- 1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV,
- /* OCT 2 */
- 0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
- 0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV,
- 3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV,
- 4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV,
- /* OCT 3 */
- 0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV,
- 3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV,
- 6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV,
- 7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV,
- /* OCT 4 */
- 0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV,
- 6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV,
- 9.000/DV, 9.750/DV,10.125/DV,10.500/DV,
- 10.875/DV,11.250/DV,11.625/DV,12.000/DV,
- /* OCT 5 */
- 0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV,
- 9.000/DV,10.125/DV,10.875/DV,11.625/DV,
- 12.000/DV,12.750/DV,13.125/DV,13.500/DV,
- 13.875/DV,14.250/DV,14.625/DV,15.000/DV,
- /* OCT 6 */
- 0.000/DV, 6.000/DV, 9.000/DV,10.875/DV,
- 12.000/DV,13.125/DV,13.875/DV,14.625/DV,
- 15.000/DV,15.750/DV,16.125/DV,16.500/DV,
- 16.875/DV,17.250/DV,17.625/DV,18.000/DV,
- /* OCT 7 */
- 0.000/DV, 9.000/DV,12.000/DV,13.875/DV,
- 15.000/DV,16.125/DV,16.875/DV,17.625/DV,
- 18.000/DV,18.750/DV,19.125/DV,19.500/DV,
- 19.875/DV,20.250/DV,20.625/DV,21.000/DV
-};
-#undef DV
-
-/* sustain lebel table (3db per step) */
-/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
-#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
-static const INT32 SL_TABLE[16]={
- SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
- SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
-};
-#undef SC
-
-#define TL_MAX (EG_ENT*2) /* limit(tl + ksr + envelope) + sinwave */
-/* TotalLevel : 48 24 12 6 3 1.5 0.75 (dB) */
-/* TL_TABLE[ 0 to TL_MAX ] : plus section */
-/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
-static INT32 *TL_TABLE;
-
-/* pointers to TL_TABLE with sinwave output offset */
-static INT32 **SIN_TABLE;
-
-/* LFO table */
-static INT32 *AMS_TABLE;
-static INT32 *VIB_TABLE;
-
-/* envelope output curve table */
-/* attack + decay + OFF */
-static INT32 ENV_CURVE[2*EG_ENT+1];
-
-/* multiple table */
-#define ML 2
-static const UINT32 MUL_TABLE[16]= {
-/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
- 0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
- 8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
-};
-#undef ML
-
-/* dummy attack / decay rate ( when rate == 0 ) */
-static INT32 RATE_0[16]=
-{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
-
-/* -------------------- static state --------------------- */
-
-/* lock level of common table */
-static int num_lock = 0;
-
-/* work table */
-static void *cur_chip = NULL; /* current chip point */
-/* currenct chip state */
-/* static OPLSAMPLE *bufL,*bufR; */
-static OPL_CH *S_CH;
-static OPL_CH *E_CH;
-OPL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2;
-
-static INT32 outd[1];
-static INT32 ams;
-static INT32 vib;
-INT32 *ams_table;
-INT32 *vib_table;
-static INT32 amsIncr;
-static INT32 vibIncr;
-static INT32 feedback2; /* connect for SLOT 2 */
-
-/* log output level */
-#define LOG_ERR 3 /* ERROR */
-#define LOG_WAR 2 /* WARNING */
-#define LOG_INF 1 /* INFORMATION */
-
-//#define LOG_LEVEL LOG_INF
-#define LOG_LEVEL LOG_ERR
-
-//#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x
-#define LOG(n,x)
-
-/* --------------------- subroutines --------------------- */
-
-INLINE int Limit( int val, int max, int min ) {
- if ( val > max )
- val = max;
- else if ( val < min )
- val = min;
-
- return val;
-}
-
-/* status set and IRQ handling */
-INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag)
-{
- /* set status flag */
- OPL->status |= flag;
- if(!(OPL->status & 0x80))
- {
- if(OPL->status & OPL->statusmask)
- { /* IRQ on */
- OPL->status |= 0x80;
- /* callback user interrupt handler (IRQ is OFF to ON) */
- if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
- }
- }
-}
-
-/* status reset and IRQ handling */
-INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
-{
- /* reset status flag */
- OPL->status &=~flag;
- if((OPL->status & 0x80))
- {
- if (!(OPL->status & OPL->statusmask) )
- {
- OPL->status &= 0x7f;
- /* callback user interrupt handler (IRQ is ON to OFF) */
- if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
- }
- }
-}
-
-/* IRQ mask set */
-INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
-{
- OPL->statusmask = flag;
- /* IRQ handling check */
- OPL_STATUS_SET(OPL,0);
- OPL_STATUS_RESET(OPL,0);
-}
-
-/* ----- key on ----- */
-INLINE void OPL_KEYON(OPL_SLOT *SLOT)
-{
- /* sin wave restart */
- SLOT->Cnt = 0;
- /* set attack */
- SLOT->evm = ENV_MOD_AR;
- SLOT->evs = SLOT->evsa;
- SLOT->evc = EG_AST;
- SLOT->eve = EG_AED;
-}
-/* ----- key off ----- */
-INLINE void OPL_KEYOFF(OPL_SLOT *SLOT)
-{
- if( SLOT->evm > ENV_MOD_RR)
- {
- /* set envelope counter from envleope output */
- SLOT->evm = ENV_MOD_RR;
- if( !(SLOT->evc&EG_DST) )
- //SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST;
- SLOT->evc = EG_DST;
- SLOT->eve = EG_DED;
- SLOT->evs = SLOT->evsr;
- }
-}
-
-/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
-/* return : envelope output */
-INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
-{
- /* calcrate envelope generator */
- if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
- {
- switch( SLOT->evm ){
- case ENV_MOD_AR: /* ATTACK -> DECAY1 */
- /* next DR */
- SLOT->evm = ENV_MOD_DR;
- SLOT->evc = EG_DST;
- SLOT->eve = SLOT->SL;
- SLOT->evs = SLOT->evsd;
- break;
- case ENV_MOD_DR: /* DECAY -> SL or RR */
- SLOT->evc = SLOT->SL;
- SLOT->eve = EG_DED;
- if(SLOT->eg_typ)
- {
- SLOT->evs = 0;
- }
- else
- {
- SLOT->evm = ENV_MOD_RR;
- SLOT->evs = SLOT->evsr;
- }
- break;
- case ENV_MOD_RR: /* RR -> OFF */
- SLOT->evc = EG_OFF;
- SLOT->eve = EG_OFF+1;
- SLOT->evs = 0;
- break;
- }
- }
- /* calcrate envelope */
- return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0);
-}
-
-/* set algorythm connection */
-static void set_algorythm( OPL_CH *CH)
-{
- INT32 *carrier = &outd[0];
- CH->connect1 = CH->CON ? carrier : &feedback2;
- CH->connect2 = carrier;
-}
-
-/* ---------- frequency counter for operater update ---------- */
-INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
-{
- int ksr;
-
- /* frequency step counter */
- SLOT->Incr = CH->fc * SLOT->mul;
- ksr = CH->kcode >> SLOT->KSR;
-
- if( SLOT->ksr != ksr )
- {
- SLOT->ksr = ksr;
- /* attack , decay rate recalcration */
- SLOT->evsa = SLOT->AR[ksr];
- SLOT->evsd = SLOT->DR[ksr];
- SLOT->evsr = SLOT->RR[ksr];
- }
- SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
-}
-
-/* set multi,am,vib,EG-TYP,KSR,mul */
-INLINE void set_mul(FM_OPL *OPL,int slot,int v)
-{
- OPL_CH *CH = &OPL->P_CH[slot/2];
- OPL_SLOT *SLOT = &CH->SLOT[slot&1];
-
- SLOT->mul = MUL_TABLE[v&0x0f];
- SLOT->KSR = (v&0x10) ? 0 : 2;
- SLOT->eg_typ = (v&0x20)>>5;
- SLOT->vib = (v&0x40);
- SLOT->ams = (v&0x80);
- CALC_FCSLOT(CH,SLOT);
-}
-
-/* set ksl & tl */
-INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v)
-{
- OPL_CH *CH = &OPL->P_CH[slot/2];
- OPL_SLOT *SLOT = &CH->SLOT[slot&1];
- int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */
-
- SLOT->ksl = ksl ? 3-ksl : 31;
- SLOT->TL = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */
-
- if( !(OPL->mode&0x80) )
- { /* not CSM latch total level */
- SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl);
- }
-}
-
-/* set attack rate & decay rate */
-INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
-{
- OPL_CH *CH = &OPL->P_CH[slot/2];
- OPL_SLOT *SLOT = &CH->SLOT[slot&1];
- int ar = v>>4;
- int dr = v&0x0f;
-
- SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0;
- SLOT->evsa = SLOT->AR[SLOT->ksr];
- if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa;
-
- SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0;
- SLOT->evsd = SLOT->DR[SLOT->ksr];
- if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd;
-}
-
-/* set sustain level & release rate */
-INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v)
-{
- OPL_CH *CH = &OPL->P_CH[slot/2];
- OPL_SLOT *SLOT = &CH->SLOT[slot&1];
- int sl = v>>4;
- int rr = v & 0x0f;
-
- SLOT->SL = SL_TABLE[sl];
- if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL;
- SLOT->RR = &OPL->DR_TABLE[rr<<2];
- SLOT->evsr = SLOT->RR[SLOT->ksr];
- if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr;
-}
-
-/* operator output calcrator */
-#define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env]
-/* ---------- calcrate one of channel ---------- */
-INLINE void OPL_CALC_CH( OPL_CH *CH )
-{
- UINT32 env_out;
- OPL_SLOT *SLOT;
-
- feedback2 = 0;
- /* SLOT 1 */
- SLOT = &CH->SLOT[SLOT1];
- env_out=OPL_CALC_SLOT(SLOT);
- if( env_out < EG_ENT-1 )
- {
- /* PG */
- if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
- else SLOT->Cnt += SLOT->Incr;
- /* connectoion */
- if(CH->FB)
- {
- int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB;
- CH->op1_out[1] = CH->op1_out[0];
- *CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
- }
- else
- {
- *CH->connect1 += OP_OUT(SLOT,env_out,0);
- }
- }else
- {
- CH->op1_out[1] = CH->op1_out[0];
- CH->op1_out[0] = 0;
- }
- /* SLOT 2 */
- SLOT = &CH->SLOT[SLOT2];
- env_out=OPL_CALC_SLOT(SLOT);
- if( env_out < EG_ENT-1 )
- {
- /* PG */
- if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
- else SLOT->Cnt += SLOT->Incr;
- /* connectoion */
- outd[0] += OP_OUT(SLOT,env_out, feedback2);
- }
-}
-
-/* ---------- calcrate rythm block ---------- */
-#define WHITE_NOISE_db 6.0
-INLINE void OPL_CALC_RH( OPL_CH *CH )
-{
- UINT32 env_tam,env_sd,env_top,env_hh;
- int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP);
- INT32 tone8;
-
- OPL_SLOT *SLOT;
- int env_out;
-
- /* BD : same as FM serial mode and output level is large */
- feedback2 = 0;
- /* SLOT 1 */
- SLOT = &CH[6].SLOT[SLOT1];
- env_out=OPL_CALC_SLOT(SLOT);
- if( env_out < EG_ENT-1 )
- {
- /* PG */
- if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
- else SLOT->Cnt += SLOT->Incr;
- /* connectoion */
- if(CH[6].FB)
- {
- int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB;
- CH[6].op1_out[1] = CH[6].op1_out[0];
- feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
- }
- else
- {
- feedback2 = OP_OUT(SLOT,env_out,0);
- }
- }else
- {
- feedback2 = 0;
- CH[6].op1_out[1] = CH[6].op1_out[0];
- CH[6].op1_out[0] = 0;
- }
- /* SLOT 2 */
- SLOT = &CH[6].SLOT[SLOT2];
- env_out=OPL_CALC_SLOT(SLOT);
- if( env_out < EG_ENT-1 )
- {
- /* PG */
- if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
- else SLOT->Cnt += SLOT->Incr;
- /* connectoion */
- outd[0] += OP_OUT(SLOT,env_out, feedback2)*2;
- }
-
- // SD (17) = mul14[fnum7] + white noise
- // TAM (15) = mul15[fnum8]
- // TOP (18) = fnum6(mul18[fnum8]+whitenoise)
- // HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise
- env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise;
- env_tam=OPL_CALC_SLOT(SLOT8_1);
- env_top=OPL_CALC_SLOT(SLOT8_2);
- env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise;
-
- /* PG */
- if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE);
- else SLOT7_1->Cnt += 2*SLOT7_1->Incr;
- if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE);
- else SLOT7_2->Cnt += (CH[7].fc*8);
- if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE);
- else SLOT8_1->Cnt += SLOT8_1->Incr;
- if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE);
- else SLOT8_2->Cnt += (CH[8].fc*48);
-
- tone8 = OP_OUT(SLOT8_2,whitenoise,0 );
-
- /* SD */
- if( env_sd < EG_ENT-1 )
- outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8;
- /* TAM */
- if( env_tam < EG_ENT-1 )
- outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2;
- /* TOP-CY */
- if( env_top < EG_ENT-1 )
- outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2;
- /* HH */
- if( env_hh < EG_ENT-1 )
- outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2;
-}
-
-/* ----------- initialize time tabls ----------- */
-static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE )
-{
- int i;
- double rate;
-
- /* make attack rate & decay rate tables */
- for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0;
- for (i = 4;i <= 60;i++){
- rate = OPL->freqbase; /* frequency rate */
- if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */
- rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */
- rate *= (double)(EG_ENT<<ENV_BITS);
- OPL->AR_TABLE[i] = rate / ARRATE;
- OPL->DR_TABLE[i] = rate / DRRATE;
- }
- for (i = 60;i < 76;i++)
- {
- OPL->AR_TABLE[i] = EG_AED-1;
- OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
- }
-#if 0
- for (i = 0;i < 64 ;i++){ /* make for overflow area */
- LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i,
- ((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate),
- ((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) ));
- }
-#endif
-}
-
-/* ---------- generic table initialize ---------- */
-static int OPLOpenTable( void )
-{
- int s,t;
- double rate;
- int i,j;
- double pom;
-
- /* allocate dynamic tables */
- if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL)
- return 0;
- if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
- {
- free(TL_TABLE);
- return 0;
- }
- if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
- {
- free(TL_TABLE);
- free(SIN_TABLE);
- return 0;
- }
- if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL)
- {
- free(TL_TABLE);
- free(SIN_TABLE);
- free(AMS_TABLE);
- return 0;
- }
- /* make total level table */
- for (t = 0;t < EG_ENT-1 ;t++){
- rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20); /* dB -> voltage */
- TL_TABLE[ t] = (int)rate;
- TL_TABLE[TL_MAX+t] = -TL_TABLE[t];
-/* LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/
- }
- /* fill volume off area */
- for ( t = EG_ENT-1; t < TL_MAX ;t++){
- TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;
- }
-
- /* make sinwave table (total level offet) */
- /* degree 0 = degree 180 = off */
- SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1];
- for (s = 1;s <= SIN_ENT/4;s++){
- pom = sin(2*PI*s/SIN_ENT); /* sin */
- pom = 20*log10(1/pom); /* decibel */
- j = pom / EG_STEP; /* TL_TABLE steps */
-
- /* degree 0 - 90 , degree 180 - 90 : plus section */
- SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j];
- /* degree 180 - 270 , degree 360 - 270 : minus section */
- SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j];
-/* LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/
- }
- for (s = 0;s < SIN_ENT;s++)
- {
- SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT];
- SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)];
- SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s];
- }
-
- /* envelope counter -> envelope output table */
- for (i=0; i<EG_ENT; i++)
- {
- /* ATTACK curve */
- pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT;
- /* if( pom >= EG_ENT ) pom = EG_ENT-1; */
- ENV_CURVE[i] = (int)pom;
- /* DECAY ,RELEASE curve */
- ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i;
- }
- /* off */
- ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
- /* make LFO ams table */
- for (i=0; i<AMS_ENT; i++)
- {
- pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */
- AMS_TABLE[i] = (1.0/EG_STEP)*pom; /* 1dB */
- AMS_TABLE[AMS_ENT+i] = (4.8/EG_STEP)*pom; /* 4.8dB */
- }
- /* make LFO vibrate table */
- for (i=0; i<VIB_ENT; i++)
- {
- /* 100cent = 1seminote = 6% ?? */
- pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */
- VIB_TABLE[i] = VIB_RATE + (pom*0.07); /* +- 7cent */
- VIB_TABLE[VIB_ENT+i] = VIB_RATE + (pom*0.14); /* +-14cent */
- /* LOG(LOG_INF,("vib %d=%d\n",i,VIB_TABLE[VIB_ENT+i])); */
- }
- return 1;
-}
-
-
-static void OPLCloseTable( void )
-{
- free(TL_TABLE);
- free(SIN_TABLE);
- free(AMS_TABLE);
- free(VIB_TABLE);
-}
-
-/* CSM Key Controll */
-INLINE void CSMKeyControll(OPL_CH *CH)
-{
- OPL_SLOT *slot1 = &CH->SLOT[SLOT1];
- OPL_SLOT *slot2 = &CH->SLOT[SLOT2];
- /* all key off */
- OPL_KEYOFF(slot1);
- OPL_KEYOFF(slot2);
- /* total level latch */
- slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
- slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl);
- /* key on */
- CH->op1_out[0] = CH->op1_out[1] = 0;
- OPL_KEYON(slot1);
- OPL_KEYON(slot2);
-}
-
-/* ---------- opl initialize ---------- */
-static void OPL_initalize(FM_OPL *OPL)
-{
- int fn;
-
- /* frequency base */
- OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0;
- /* Timer base time */
- OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 );
- /* make time tables */
- init_timetables( OPL , OPL_ARRATE , OPL_DRRATE );
- /* make fnumber -> increment counter table */
- for( fn=0 ; fn < 1024 ; fn++ )
- {
- OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2;
- }
- /* LFO freq.table */
- OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0;
- OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0;
-}
-
-/* ---------- write a OPL registers ---------- */
-static void OPLWriteReg(FM_OPL *OPL, int r, int v)
-{
- OPL_CH *CH;
- int slot;
- int block_fnum;
-
- switch(r&0xe0)
- {
- case 0x00: /* 00-1f:controll */
- switch(r&0x1f)
- {
- case 0x01:
- /* wave selector enable */
- if(OPL->type&OPL_TYPE_WAVESEL)
- {
- OPL->wavesel = v&0x20;
- if(!OPL->wavesel)
- {
- /* preset compatible mode */
- int c;
- for(c=0;c<OPL->max_ch;c++)
- {
- OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
- OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
- }
- }
- }
- return;
- case 0x02: /* Timer 1 */
- OPL->T[0] = (256-v)*4;
- break;
- case 0x03: /* Timer 2 */
- OPL->T[1] = (256-v)*16;
- return;
- case 0x04: /* IRQ clear / mask and Timer enable */
- if(v&0x80)
- { /* IRQ flag clear */
- OPL_STATUS_RESET(OPL,0x7f);
- }
- else
- { /* set IRQ mask ,timer enable*/
- UINT8 st1 = v&1;
- UINT8 st2 = (v>>1)&1;
- /* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
- OPL_STATUS_RESET(OPL,v&0x78);
- OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
- /* timer 2 */
- if(OPL->st[1] != st2)
- {
- double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0;
- OPL->st[1] = st2;
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval);
- }
- /* timer 1 */
- if(OPL->st[0] != st1)
- {
- double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0;
- OPL->st[0] = st1;
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval);
- }
- }
- return;
-#if BUILD_Y8950
- case 0x06: /* Key Board OUT */
- if(OPL->type&OPL_TYPE_KEYBOARD)
- {
- if(OPL->keyboardhandler_w)
- OPL->keyboardhandler_w(OPL->keyboard_param,v);
- else
- LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
- }
- return;
- case 0x07: /* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
- if(OPL->type&OPL_TYPE_ADPCM)
- YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
- return;
- case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
- OPL->mode = v;
- v&=0x1f; /* for DELTA-T unit */
- case 0x09: /* START ADD */
- case 0x0a:
- case 0x0b: /* STOP ADD */
- case 0x0c:
- case 0x0d: /* PRESCALE */
- case 0x0e:
- case 0x0f: /* ADPCM data */
- case 0x10: /* DELTA-N */
- case 0x11: /* DELTA-N */
- case 0x12: /* EG-CTRL */
- if(OPL->type&OPL_TYPE_ADPCM)
- YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
- return;
-#if 0
- case 0x15: /* DAC data */
- case 0x16:
- case 0x17: /* SHIFT */
- return;
- case 0x18: /* I/O CTRL (Direction) */
- if(OPL->type&OPL_TYPE_IO)
- OPL->portDirection = v&0x0f;
- return;
- case 0x19: /* I/O DATA */
- if(OPL->type&OPL_TYPE_IO)
- {
- OPL->portLatch = v;
- if(OPL->porthandler_w)
- OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
- }
- return;
- case 0x1a: /* PCM data */
- return;
-#endif
-#endif
- }
- break;
- case 0x20: /* am,vib,ksr,eg type,mul */
- slot = slot_array[r&0x1f];
- if(slot == -1) return;
- set_mul(OPL,slot,v);
- return;
- case 0x40:
- slot = slot_array[r&0x1f];
- if(slot == -1) return;
- set_ksl_tl(OPL,slot,v);
- return;
- case 0x60:
- slot = slot_array[r&0x1f];
- if(slot == -1) return;
- set_ar_dr(OPL,slot,v);
- return;
- case 0x80:
- slot = slot_array[r&0x1f];
- if(slot == -1) return;
- set_sl_rr(OPL,slot,v);
- return;
- case 0xa0:
- switch(r)
- {
- case 0xbd:
- /* amsep,vibdep,r,bd,sd,tom,tc,hh */
- {
- UINT8 rkey = OPL->rythm^v;
- OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
- OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
- OPL->rythm = v&0x3f;
- if(OPL->rythm&0x20)
- {
-#if 0
- usrintf_showmessage("OPL Rythm mode select");
-#endif
- /* BD key on/off */
- if(rkey&0x10)
- {
- if(v&0x10)
- {
- OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0;
- OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]);
- OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]);
- }
- else
- {
- OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]);
- OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]);
- }
- }
- /* SD key on/off */
- if(rkey&0x08)
- {
- if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]);
- else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]);
- }/* TAM key on/off */
- if(rkey&0x04)
- {
- if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]);
- else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]);
- }
- /* TOP-CY key on/off */
- if(rkey&0x02)
- {
- if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]);
- else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]);
- }
- /* HH key on/off */
- if(rkey&0x01)
- {
- if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]);
- else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]);
- }
- }
- }
- return;
- }
- /* keyon,block,fnum */
- if( (r&0x0f) > 8) return;
- CH = &OPL->P_CH[r&0x0f];
- if(!(r&0x10))
- { /* a0-a8 */
- block_fnum = (CH->block_fnum&0x1f00) | v;
- }
- else
- { /* b0-b8 */
- int keyon = (v>>5)&1;
- block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
- if(CH->keyon != keyon)
- {
- if( (CH->keyon=keyon) )
- {
- CH->op1_out[0] = CH->op1_out[1] = 0;
- OPL_KEYON(&CH->SLOT[SLOT1]);
- OPL_KEYON(&CH->SLOT[SLOT2]);
- }
- else
- {
- OPL_KEYOFF(&CH->SLOT[SLOT1]);
- OPL_KEYOFF(&CH->SLOT[SLOT2]);
- }
- }
- }
- /* update */
- if(CH->block_fnum != block_fnum)
- {
- int blockRv = 7-(block_fnum>>10);
- int fnum = block_fnum&0x3ff;
- CH->block_fnum = block_fnum;
-
- CH->ksl_base = KSL_TABLE[block_fnum>>6];
- CH->fc = OPL->FN_TABLE[fnum]>>blockRv;
- CH->kcode = CH->block_fnum>>9;
- if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1;
- CALC_FCSLOT(CH,&CH->SLOT[SLOT1]);
- CALC_FCSLOT(CH,&CH->SLOT[SLOT2]);
- }
- return;
- case 0xc0:
- /* FB,C */
- if( (r&0x0f) > 8) return;
- CH = &OPL->P_CH[r&0x0f];
- {
- int feedback = (v>>1)&7;
- CH->FB = feedback ? (8+1) - feedback : 0;
- CH->CON = v&1;
- set_algorythm(CH);
- }
- return;
- case 0xe0: /* wave type */
- slot = slot_array[r&0x1f];
- if(slot == -1) return;
- CH = &OPL->P_CH[slot/2];
- if(OPL->wavesel)
- {
- /* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */
- CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT];
- }
- return;
- }
-}
-
-/* lock/unlock for common table */
-static int OPL_LockTable(void)
-{
- num_lock++;
- if(num_lock>1) return 0;
- /* first time */
- cur_chip = NULL;
- /* allocate total level table (128kb space) */
- if( !OPLOpenTable() )
- {
- num_lock--;
- return -1;
- }
- return 0;
-}
-
-static void OPL_UnLockTable(void)
-{
- if(num_lock) num_lock--;
- if(num_lock) return;
- /* last time */
- cur_chip = NULL;
- OPLCloseTable();
-}
-
-#if (BUILD_YM3812 || BUILD_YM3526)
-/*******************************************************************************/
-/* YM3812 local section */
-/*******************************************************************************/
-
-/* ---------- update one of chip ----------- */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
-{
- int i;
- int data;
- OPLSAMPLE *buf = buffer;
- UINT32 amsCnt = OPL->amsCnt;
- UINT32 vibCnt = OPL->vibCnt;
- UINT8 rythm = OPL->rythm&0x20;
- OPL_CH *CH,*R_CH;
-
- if( (void *)OPL != cur_chip ){
- cur_chip = (void *)OPL;
- /* channel pointers */
- S_CH = OPL->P_CH;
- E_CH = &S_CH[9];
- /* rythm slot */
- SLOT7_1 = &S_CH[7].SLOT[SLOT1];
- SLOT7_2 = &S_CH[7].SLOT[SLOT2];
- SLOT8_1 = &S_CH[8].SLOT[SLOT1];
- SLOT8_2 = &S_CH[8].SLOT[SLOT2];
- /* LFO state */
- amsIncr = OPL->amsIncr;
- vibIncr = OPL->vibIncr;
- ams_table = OPL->ams_table;
- vib_table = OPL->vib_table;
- }
- R_CH = rythm ? &S_CH[6] : E_CH;
- for( i=0; i < length ; i++ )
- {
- /* channel A channel B channel C */
- /* LFO */
- ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
- vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
- outd[0] = 0;
- /* FM part */
- for(CH=S_CH ; CH < R_CH ; CH++)
- OPL_CALC_CH(CH);
- /* Rythn part */
- if(rythm)
- OPL_CALC_RH(S_CH);
- /* limit check */
- data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
- /* store to sound buffer */
- buf[i] = data >> OPL_OUTSB;
- }
-
- OPL->amsCnt = amsCnt;
- OPL->vibCnt = vibCnt;
-#ifdef OPL_OUTPUT_LOG
- if(opl_dbg_fp)
- {
- for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++)
- if( opl_dbg_opl[opl_dbg_chip] == OPL) break;
- fprintf(opl_dbg_fp,"%c%c%c",0x20+opl_dbg_chip,length&0xff,length/256);
- }
-#endif
-}
-#endif /* (BUILD_YM3812 || BUILD_YM3526) */
-
-#if BUILD_Y8950
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
-{
- int i;
- int data;
- OPLSAMPLE *buf = buffer;
- UINT32 amsCnt = OPL->amsCnt;
- UINT32 vibCnt = OPL->vibCnt;
- UINT8 rythm = OPL->rythm&0x20;
- OPL_CH *CH,*R_CH;
- YM_DELTAT *DELTAT = OPL->deltat;
-
- /* setup DELTA-T unit */
- YM_DELTAT_DECODE_PRESET(DELTAT);
-
- if( (void *)OPL != cur_chip ){
- cur_chip = (void *)OPL;
- /* channel pointers */
- S_CH = OPL->P_CH;
- E_CH = &S_CH[9];
- /* rythm slot */
- SLOT7_1 = &S_CH[7].SLOT[SLOT1];
- SLOT7_2 = &S_CH[7].SLOT[SLOT2];
- SLOT8_1 = &S_CH[8].SLOT[SLOT1];
- SLOT8_2 = &S_CH[8].SLOT[SLOT2];
- /* LFO state */
- amsIncr = OPL->amsIncr;
- vibIncr = OPL->vibIncr;
- ams_table = OPL->ams_table;
- vib_table = OPL->vib_table;
- }
- R_CH = rythm ? &S_CH[6] : E_CH;
- for( i=0; i < length ; i++ )
- {
- /* channel A channel B channel C */
- /* LFO */
- ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
- vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
- outd[0] = 0;
- /* deltaT ADPCM */
- if( DELTAT->portstate )
- YM_DELTAT_ADPCM_CALC(DELTAT);
- /* FM part */
- for(CH=S_CH ; CH < R_CH ; CH++)
- OPL_CALC_CH(CH);
- /* Rythn part */
- if(rythm)
- OPL_CALC_RH(S_CH);
- /* limit check */
- data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
- /* store to sound buffer */
- buf[i] = data >> OPL_OUTSB;
- }
- OPL->amsCnt = amsCnt;
- OPL->vibCnt = vibCnt;
- /* deltaT START flag */
- if( !DELTAT->portstate )
- OPL->status &= 0xfe;
-}
-#endif
-
-/* ---------- reset one of chip ---------- */
-void OPLResetChip(FM_OPL *OPL)
-{
- int c,s;
- int i;
-
- /* reset chip */
- OPL->mode = 0; /* normal mode */
- OPL_STATUS_RESET(OPL,0x7f);
- /* reset with register write */
- OPLWriteReg(OPL,0x01,0); /* wabesel disable */
- OPLWriteReg(OPL,0x02,0); /* Timer1 */
- OPLWriteReg(OPL,0x03,0); /* Timer2 */
- OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */
- for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0);
- /* reset OPerator paramater */
- for( c = 0 ; c < OPL->max_ch ; c++ )
- {
- OPL_CH *CH = &OPL->P_CH[c];
- /* OPL->P_CH[c].PAN = OPN_CENTER; */
- for(s = 0 ; s < 2 ; s++ )
- {
- /* wave table */
- CH->SLOT[s].wavetable = &SIN_TABLE[0];
- /* CH->SLOT[s].evm = ENV_MOD_RR; */
- CH->SLOT[s].evc = EG_OFF;
- CH->SLOT[s].eve = EG_OFF+1;
- CH->SLOT[s].evs = 0;
- }
- }
-#if BUILD_Y8950
- if(OPL->type&OPL_TYPE_ADPCM)
- {
- YM_DELTAT *DELTAT = OPL->deltat;
-
- DELTAT->freqbase = OPL->freqbase;
- DELTAT->output_pointer = outd;
- DELTAT->portshift = 5;
- DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;
- YM_DELTAT_ADPCM_Reset(DELTAT,0);
- }
-#endif
-}
-
-/* ---------- Create one of vietual YM3812 ---------- */
-/* 'rate' is sampling rate and 'bufsiz' is the size of the */
-FM_OPL *OPLCreate(int type, int clock, int rate)
-{
- char *ptr;
- FM_OPL *OPL;
- int state_size;
- int max_ch = 9; /* normaly 9 channels */
-
- if( OPL_LockTable() ==-1) return NULL;
- /* allocate OPL state space */
- state_size = sizeof(FM_OPL);
- state_size += sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
- if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
-#endif
- /* allocate memory block */
- ptr = malloc(state_size);
- if(ptr==NULL) return NULL;
- /* clear */
- memset(ptr,0,state_size);
- OPL = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
- OPL->P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
- if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);
-#endif
- /* set channel state pointer */
- OPL->type = type;
- OPL->clock = clock;
- OPL->rate = rate;
- OPL->max_ch = max_ch;
- /* init grobal tables */
- OPL_initalize(OPL);
- /* reset chip */
- OPLResetChip(OPL);
-#ifdef OPL_OUTPUT_LOG
- if(!opl_dbg_fp)
- {
- opl_dbg_fp = fopen("opllog.opl","wb");
- opl_dbg_maxchip = 0;
- }
- if(opl_dbg_fp)
- {
- opl_dbg_opl[opl_dbg_maxchip] = OPL;
- fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip,
- type,
- clock&0xff,
- (clock/0x100)&0xff,
- (clock/0x10000)&0xff,
- (clock/0x1000000)&0xff);
- opl_dbg_maxchip++;
- }
-#endif
- return OPL;
-}
-
-/* ---------- Destroy one of vietual YM3812 ---------- */
-void OPLDestroy(FM_OPL *OPL)
-{
-#ifdef OPL_OUTPUT_LOG
- if(opl_dbg_fp)
- {
- fclose(opl_dbg_fp);
- opl_dbg_fp = NULL;
- }
-#endif
- OPL_UnLockTable();
- free(OPL);
-}
-
-/* ---------- Option handlers ---------- */
-
-void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset)
-{
- OPL->TimerHandler = TimerHandler;
- OPL->TimerParam = channelOffset;
-}
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
-{
- OPL->IRQHandler = IRQHandler;
- OPL->IRQParam = param;
-}
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
-{
- OPL->UpdateHandler = UpdateHandler;
- OPL->UpdateParam = param;
-}
-#if BUILD_Y8950
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param)
-{
- OPL->porthandler_w = PortHandler_w;
- OPL->porthandler_r = PortHandler_r;
- OPL->port_param = param;
-}
-
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param)
-{
- OPL->keyboardhandler_w = KeyboardHandler_w;
- OPL->keyboardhandler_r = KeyboardHandler_r;
- OPL->keyboard_param = param;
-}
-#endif
-/* ---------- YM3812 I/O interface ---------- */
-int OPLWrite(FM_OPL *OPL,int a,int v)
-{
- if( !(a&1) )
- { /* address port */
- OPL->address = v & 0xff;
- }
- else
- { /* data port */
- if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
-#ifdef OPL_OUTPUT_LOG
- if(opl_dbg_fp)
- {
- for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++)
- if( opl_dbg_opl[opl_dbg_chip] == OPL) break;
- fprintf(opl_dbg_fp,"%c%c%c",0x10+opl_dbg_chip,OPL->address,v);
- }
-#endif
- OPLWriteReg(OPL,OPL->address,v);
- }
- return OPL->status>>7;
-}
-
-unsigned char OPLRead(FM_OPL *OPL,int a)
-{
- if( !(a&1) )
- { /* status port */
- return OPL->status & (OPL->statusmask|0x80);
- }
- /* data port */
- switch(OPL->address)
- {
- case 0x05: /* KeyBoard IN */
- if(OPL->type&OPL_TYPE_KEYBOARD)
- {
- if(OPL->keyboardhandler_r)
- return OPL->keyboardhandler_r(OPL->keyboard_param);
- else
- LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
- }
- return 0;
-#if 0
- case 0x0f: /* ADPCM-DATA */
- return 0;
-#endif
- case 0x19: /* I/O DATA */
- if(OPL->type&OPL_TYPE_IO)
- {
- if(OPL->porthandler_r)
- return OPL->porthandler_r(OPL->port_param);
- else
- LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
- }
- return 0;
- case 0x1a: /* PCM-DATA */
- return 0;
- }
- return 0;
-}
-
-int OPLTimerOver(FM_OPL *OPL,int c)
-{
- if( c )
- { /* Timer B */
- OPL_STATUS_SET(OPL,0x20);
- }
- else
- { /* Timer A */
- OPL_STATUS_SET(OPL,0x40);
- /* CSM mode key,TL controll */
- if( OPL->mode & 0x80 )
- { /* CSM mode total level latch and auto key on */
- int ch;
- if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
- for(ch=0;ch<9;ch++)
- CSMKeyControll( &OPL->P_CH[ch] );
- }
- }
- /* reload timer */
- if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase);
- return OPL->status>>7;
-}
diff --git a/hw/fmopl.h b/hw/fmopl.h
deleted file mode 100644
index a01ff90..0000000
--- a/hw/fmopl.h
+++ /dev/null
@@ -1,174 +0,0 @@
-#ifndef __FMOPL_H_
-#define __FMOPL_H_
-
-/* --- select emulation chips --- */
-#define BUILD_YM3812 (HAS_YM3812)
-//#define BUILD_YM3526 (HAS_YM3526)
-//#define BUILD_Y8950 (HAS_Y8950)
-
-/* --- system optimize --- */
-/* select bit size of output : 8 or 16 */
-#define OPL_OUTPUT_BIT 16
-
-/* compiler dependence */
-#ifndef OSD_CPU_H
-#define OSD_CPU_H
-typedef unsigned char UINT8; /* unsigned 8bit */
-typedef unsigned short UINT16; /* unsigned 16bit */
-typedef unsigned int UINT32; /* unsigned 32bit */
-typedef signed char INT8; /* signed 8bit */
-typedef signed short INT16; /* signed 16bit */
-typedef signed int INT32; /* signed 32bit */
-#endif
-
-#if (OPL_OUTPUT_BIT==16)
-typedef INT16 OPLSAMPLE;
-#endif
-#if (OPL_OUTPUT_BIT==8)
-typedef unsigned char OPLSAMPLE;
-#endif
-
-
-#if BUILD_Y8950
-#include "ymdeltat.h"
-#endif
-
-typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
-typedef void (*OPL_IRQHANDLER)(int param,int irq);
-typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
-typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
-typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
-
-/* !!!!! here is private section , do not access there member direct !!!!! */
-
-#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
-#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
-#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
-#define OPL_TYPE_IO 0x08 /* I/O port */
-
-/* Saving is necessary for member of the 'R' mark for suspend/resume */
-/* ---------- OPL one of slot ---------- */
-typedef struct fm_opl_slot {
- INT32 TL; /* total level :TL << 8 */
- INT32 TLL; /* adjusted now TL */
- UINT8 KSR; /* key scale rate :(shift down bit) */
- INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */
- INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */
- INT32 SL; /* sustin level :SL_TALBE[SL] */
- INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */
- UINT8 ksl; /* keyscale level :(shift down bits) */
- UINT8 ksr; /* key scale rate :kcode>>KSR */
- UINT32 mul; /* multiple :ML_TABLE[ML] */
- UINT32 Cnt; /* frequency count : */
- UINT32 Incr; /* frequency step : */
- /* envelope generator state */
- UINT8 eg_typ; /* envelope type flag */
- UINT8 evm; /* envelope phase */
- INT32 evc; /* envelope counter */
- INT32 eve; /* envelope counter end point */
- INT32 evs; /* envelope counter step */
- INT32 evsa; /* envelope step for AR :AR[ksr] */
- INT32 evsd; /* envelope step for DR :DR[ksr] */
- INT32 evsr; /* envelope step for RR :RR[ksr] */
- /* LFO */
- UINT8 ams; /* ams flag */
- UINT8 vib; /* vibrate flag */
- /* wave selector */
- INT32 **wavetable;
-}OPL_SLOT;
-
-/* ---------- OPL one of channel ---------- */
-typedef struct fm_opl_channel {
- OPL_SLOT SLOT[2];
- UINT8 CON; /* connection type */
- UINT8 FB; /* feed back :(shift down bit) */
- INT32 *connect1; /* slot1 output pointer */
- INT32 *connect2; /* slot2 output pointer */
- INT32 op1_out[2]; /* slot1 output for selfeedback */
- /* phase generator state */
- UINT32 block_fnum; /* block+fnum : */
- UINT8 kcode; /* key code : KeyScaleCode */
- UINT32 fc; /* Freq. Increment base */
- UINT32 ksl_base; /* KeyScaleLevel Base step */
- UINT8 keyon; /* key on/off flag */
-} OPL_CH;
-
-/* OPL state */
-typedef struct fm_opl_f {
- UINT8 type; /* chip type */
- int clock; /* master clock (Hz) */
- int rate; /* sampling rate (Hz) */
- double freqbase; /* frequency base */
- double TimerBase; /* Timer base time (==sampling time) */
- UINT8 address; /* address register */
- UINT8 status; /* status flag */
- UINT8 statusmask; /* status mask */
- UINT32 mode; /* Reg.08 : CSM , notesel,etc. */
- /* Timer */
- int T[2]; /* timer counter */
- UINT8 st[2]; /* timer enable */
- /* FM channel slots */
- OPL_CH *P_CH; /* pointer of CH */
- int max_ch; /* maximum channel */
- /* Rythm sention */
- UINT8 rythm; /* Rythm mode , key flag */
-#if BUILD_Y8950
- /* Delta-T ADPCM unit (Y8950) */
- YM_DELTAT *deltat; /* DELTA-T ADPCM */
-#endif
- /* Keyboard / I/O interface unit (Y8950) */
- UINT8 portDirection;
- UINT8 portLatch;
- OPL_PORTHANDLER_R porthandler_r;
- OPL_PORTHANDLER_W porthandler_w;
- int port_param;
- OPL_PORTHANDLER_R keyboardhandler_r;
- OPL_PORTHANDLER_W keyboardhandler_w;
- int keyboard_param;
- /* time tables */
- INT32 AR_TABLE[75]; /* atttack rate tables */
- INT32 DR_TABLE[75]; /* decay rate tables */
- UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */
- /* LFO */
- INT32 *ams_table;
- INT32 *vib_table;
- INT32 amsCnt;
- INT32 amsIncr;
- INT32 vibCnt;
- INT32 vibIncr;
- /* wave selector enable flag */
- UINT8 wavesel;
- /* external event callback handler */
- OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
- int TimerParam; /* TIMER parameter */
- OPL_IRQHANDLER IRQHandler; /* IRQ handler */
- int IRQParam; /* IRQ parameter */
- OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
- int UpdateParam; /* stream update parameter */
-} FM_OPL;
-
-/* ---------- Generic interface section ---------- */
-#define OPL_TYPE_YM3526 (0)
-#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
-#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
-
-FM_OPL *OPLCreate(int type, int clock, int rate);
-void OPLDestroy(FM_OPL *OPL);
-void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
-/* Y8950 port handlers */
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
-
-void OPLResetChip(FM_OPL *OPL);
-int OPLWrite(FM_OPL *OPL,int a,int v);
-unsigned char OPLRead(FM_OPL *OPL,int a);
-int OPLTimerOver(FM_OPL *OPL,int c);
-
-/* YM3626/YM3812 local section */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
-#endif
diff --git a/hw/goldfish_audio.c b/hw/goldfish_audio.c
new file mode 100644
index 0000000..69b2ef4
--- /dev/null
+++ b/hw/goldfish_audio.c
@@ -0,0 +1,521 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "goldfish_device.h"
+#include "audio/audio.h"
+#include "android_debug.h"
+
+#define DEBUG 1
+
+#if DEBUG
+# define D(...) VERBOSE_PRINT(audio,__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
+extern void dprint(const char* fmt, ...);
+
+/* define USE_QEMU_AUDIO_IN to 1 to use QEMU's audio subsystem to
+ * implement the audio input. if 0, this will try to read a .wav file
+ * directly...
+ */
+#define USE_QEMU_AUDIO_IN 1
+
+enum {
+ /* audio status register */
+ AUDIO_INT_STATUS = 0x00,
+ /* set this to enable IRQ */
+ AUDIO_INT_ENABLE = 0x04,
+ /* set these to specify buffer addresses */
+ AUDIO_SET_WRITE_BUFFER_1 = 0x08,
+ AUDIO_SET_WRITE_BUFFER_2 = 0x0C,
+ /* set number of bytes in buffer to write */
+ AUDIO_WRITE_BUFFER_1 = 0x10,
+ AUDIO_WRITE_BUFFER_2 = 0x14,
+
+ /* true if audio input is supported */
+ AUDIO_READ_SUPPORTED = 0x18,
+ /* buffer to use for audio input */
+ AUDIO_SET_READ_BUFFER = 0x1C,
+
+ /* driver writes number of bytes to read */
+ AUDIO_START_READ = 0x20,
+
+ /* number of bytes available in read buffer */
+ AUDIO_READ_BUFFER_AVAILABLE = 0x24,
+
+ /* AUDIO_INT_STATUS bits */
+
+ /* this bit set when it is safe to write more bytes to the buffer */
+ AUDIO_INT_WRITE_BUFFER_1_EMPTY = 1U << 0,
+ AUDIO_INT_WRITE_BUFFER_2_EMPTY = 1U << 1,
+ AUDIO_INT_READ_BUFFER_FULL = 1U << 2,
+};
+
+
+struct goldfish_audio_state {
+ struct goldfish_device dev;
+ // pointers to our two write buffers
+ uint32_t buffer_1, buffer_2;
+ uint32_t read_buffer;
+ // buffer flags
+ uint32_t int_status;
+ // irq enable mask for int_status
+ uint32_t int_enable;
+
+#if USE_QEMU_AUDIO_IN
+ uint32_t read_pos;
+ uint32_t read_size;
+#else
+ // path to file or device to use for input
+ const char* input_source;
+ // true if input is a wav file
+ int input_is_wav;
+ // true if we need to convert stereo -> mono
+ int input_is_stereo;
+ // file descriptor to use for input
+ int input_fd;
+#endif
+
+ // number of bytes available in the read buffer
+ int read_buffer_available;
+
+ // set to 1 or 2 to indicate which buffer we are writing from, or zero if both buffers are empty
+ int current_buffer;
+
+ // current data to write
+ uint8* data_1;
+ uint32_t data_1_length;
+ uint8* data_2;
+ uint32_t data_2_length;
+
+
+ // for QEMU sound output
+ QEMUSoundCard card;
+ SWVoiceOut *voice;
+#if USE_QEMU_AUDIO_IN
+ SWVoiceIn* voicein;
+#endif
+};
+
+/* update this whenever you change the goldfish_audio_state structure */
+#define AUDIO_STATE_SAVE_VERSION 1
+
+#define QFIELD_STRUCT struct goldfish_audio_state
+QFIELD_BEGIN(audio_state_fields)
+ QFIELD_INT32(buffer_1),
+ QFIELD_INT32(buffer_2),
+ QFIELD_INT32(read_buffer),
+ QFIELD_INT32(int_status),
+ QFIELD_INT32(int_enable),
+#if USE_QEMU_AUDIO_IN
+ QFIELD_INT32(read_pos),
+ QFIELD_INT32(read_size),
+#endif
+ QFIELD_INT32(read_buffer_available),
+ QFIELD_INT32(current_buffer),
+ QFIELD_INT32(data_1_length),
+ QFIELD_INT32(data_2_length),
+QFIELD_END
+
+static void audio_state_save( QEMUFile* f, void* opaque )
+{
+ struct goldfish_audio_state* s = opaque;
+
+ qemu_put_struct(f, audio_state_fields, s);
+
+ /* we can't write data_1 and data_2 directly */
+ qemu_put_be32( f, s->data_1 - phys_ram_base );
+ qemu_put_be32( f, s->data_2 - phys_ram_base );
+}
+
+static int audio_state_load( QEMUFile* f, void* opaque, int version_id )
+{
+ struct goldfish_audio_state* s = opaque;
+ int ret;
+
+ if (version_id != AUDIO_STATE_SAVE_VERSION)
+ return -1;
+
+ ret = qemu_get_struct(f, audio_state_fields, s);
+ if (!ret) {
+ s->data_1 = qemu_get_be32(f) + phys_ram_base;
+ s->data_2 = qemu_get_be32(f) + phys_ram_base;
+ }
+ return -1;
+}
+
+static void enable_audio(struct goldfish_audio_state *s, int enable)
+{
+ // enable or disable the output voice
+ AUD_set_active_out(s->voice, (enable & (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY)) != 0);
+ AUD_set_active_in (s->voicein, (enable & AUDIO_INT_READ_BUFFER_FULL) != 0);
+ // reset buffer information
+ s->data_1_length = 0;
+ s->data_2_length = 0;
+ s->current_buffer = 0;
+ s->read_pos = 0;
+}
+
+#if USE_QEMU_AUDIO_IN
+static void start_read(struct goldfish_audio_state *s, uint32_t count)
+{
+ //printf( "... goldfish audio start_read, count=%d\n", count );
+ s->read_size = count;
+ s->read_buffer_available = 0;
+ s->read_pos = 0;
+}
+#else
+static void start_read(struct goldfish_audio_state *s, uint32_t count)
+{
+ uint8 wav_header[44];
+ int result;
+
+ if (!s->input_source) return;
+
+ if (s->input_fd < 0) {
+ s->input_fd = open(s->input_source, O_BINARY | O_RDONLY);
+
+ if (s->input_fd < 0) {
+ fprintf(stderr, "goldfish_audio could not open %s for audio input\n", s->input_source);
+ s->input_source = NULL; // set to to avoid endless retries
+ return;
+ }
+
+ // skip WAV header if we have a WAV file
+ if (s->input_is_wav) {
+ if (read(s->input_fd, wav_header, sizeof(wav_header)) != sizeof(wav_header)) {
+ fprintf(stderr, "goldfish_audio could not read WAV file header %s\n", s->input_source);
+ s->input_fd = -1;
+ s->input_source = NULL; // set to to avoid endless retries
+ return;
+ }
+
+ // is the WAV file stereo?
+ s->input_is_stereo = (wav_header[22] == 2);
+ } else {
+ // assume input from an audio device is stereo
+ s->input_is_stereo = 1;
+ }
+ }
+
+ uint8* buffer = (uint8*)phys_ram_base + s->read_buffer;
+ if (s->input_is_stereo) {
+ // need to read twice as much data
+ count *= 2;
+ }
+
+try_again:
+ result = read(s->input_fd, buffer, count);
+ if (result == 0 && s->input_is_wav) {
+ // end of file, so seek back to the beginning
+ lseek(s->input_fd, sizeof(wav_header), SEEK_SET);
+ goto try_again;
+ }
+
+ if (result > 0 && s->input_is_stereo) {
+ // we need to convert stereo to mono
+ uint8* src = (uint8*)buffer;
+ uint8* dest = src;
+ int count = result/2;
+ while (count-- > 0) {
+ int sample1 = src[0] | (src[1] << 8);
+ int sample2 = src[2] | (src[3] << 8);
+ int sample = (sample1 + sample2) >> 1;
+ dst[0] = (uint8_t) sample;
+ dst[1] = (uint8_t)(sample >> 8);
+ src += 4;
+ dst += 2;
+ }
+
+ // we reduced the number of bytes by 2
+ result /= 2;
+ }
+
+ s->read_buffer_available = (result > 0 ? result : 0);
+ s->int_status |= AUDIO_INT_READ_BUFFER_FULL;
+ goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+}
+#endif
+
+static uint32_t goldfish_audio_read(void *opaque, target_phys_addr_t offset)
+{
+ uint32_t ret;
+ struct goldfish_audio_state *s = opaque;
+ offset -= s->dev.base;
+ switch(offset) {
+ case AUDIO_INT_STATUS:
+ // return current buffer status flags
+ ret = s->int_status & s->int_enable;
+ if(ret) {
+ goldfish_device_set_irq(&s->dev, 0, 0);
+ }
+ return ret;
+
+ case AUDIO_READ_SUPPORTED:
+#if USE_QEMU_AUDIO_IN
+ D("%s: AUDIO_READ_SUPPORTED returns %d", __FUNCTION__,
+ (s->voicein != NULL));
+ return (s->voicein != NULL);
+#else
+ return (s->input_source ? 1 : 0);
+#endif
+
+ case AUDIO_READ_BUFFER_AVAILABLE:
+ D("%s: AUDIO_READ_BUFFER_AVAILABLE returns %d", __FUNCTION__,
+ s->read_buffer_available);
+ return s->read_buffer_available;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_audio_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_audio_write(void *opaque, target_phys_addr_t offset, uint32_t val)
+{
+ struct goldfish_audio_state *s = opaque;
+ offset -= s->dev.base;
+
+ switch(offset) {
+ case AUDIO_INT_ENABLE:
+ /* enable buffer empty interrupts */
+ D("%s: AUDIO_INT_ENABLE %d", __FUNCTION__, val );
+ enable_audio(s, val);
+ s->int_enable = val;
+ s->int_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY);
+ goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+ break;
+ case AUDIO_SET_WRITE_BUFFER_1:
+ /* save pointer to buffer 1 */
+ s->buffer_1 = val;
+ break;
+ case AUDIO_SET_WRITE_BUFFER_2:
+ /* save pointer to buffer 2 */
+ s->buffer_2 = val;
+ break;
+ case AUDIO_WRITE_BUFFER_1:
+ /* record that data in buffer 1 is ready to write */
+ if (s->current_buffer == 0) s->current_buffer = 1;
+ s->data_1 = phys_ram_base + s->buffer_1;
+ s->data_1_length = val;
+ s->int_status &= ~AUDIO_INT_WRITE_BUFFER_1_EMPTY;
+ break;
+ case AUDIO_WRITE_BUFFER_2:
+ /* record that data in buffer 2 is ready to write */
+ if (s->current_buffer == 0) s->current_buffer = 2;
+ s->data_2 = phys_ram_base + s->buffer_2;
+ s->data_2_length = val;
+ s->int_status &= ~AUDIO_INT_WRITE_BUFFER_2_EMPTY;
+ break;
+
+ case AUDIO_SET_READ_BUFFER:
+ /* save pointer to the read buffer */
+ s->read_buffer = val;
+ D( "%s: AUDIO_SET_READ_BUFFER %p", __FUNCTION__, (void*)val );
+ break;
+
+ case AUDIO_START_READ:
+ D( "%s: AUDIO_START_READ %d", __FUNCTION__, val );
+ start_read(s, val);
+ s->int_status &= ~AUDIO_INT_READ_BUFFER_FULL;
+ goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+ break;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset %x\n", offset);
+ }
+}
+
+static void goldfish_audio_callback(void *opaque, int free)
+{
+ struct goldfish_audio_state *s = opaque;
+ int new_status = 0;
+
+ /* loop until free is zero or both buffers are empty */
+ while (free && s->current_buffer) {
+
+ /* write data in buffer 1 */
+ while (free && s->current_buffer == 1) {
+ int write = s->data_1_length;
+ if (write > free) write = free;
+
+ int written = AUD_write(s->voice, s->data_1, write);
+ if (written) {
+ D("%s: sent %d bytes to audio output", __FUNCTION__, write);
+ s->data_1 += written;
+ s->data_1_length -= written;
+ free -= written;
+
+ if (s->data_1_length == 0) {
+ new_status |= AUDIO_INT_WRITE_BUFFER_1_EMPTY;
+ s->current_buffer = (s->data_2_length ? 2 : 0);
+ }
+ } else {
+ break;
+ }
+ }
+
+ /* write data in buffer 2 */
+ while (free && s->current_buffer == 2) {
+ int write = s->data_2_length;
+ if (write > free) write = free;
+
+ int written = AUD_write(s->voice, s->data_2, write);
+ if (written) {
+ D("%s: sent %d bytes to audio output", __FUNCTION__, write);
+ s->data_2 += written;
+ s->data_2_length -= written;
+ free -= written;
+
+ if (s->data_2_length == 0) {
+ new_status |= AUDIO_INT_WRITE_BUFFER_2_EMPTY;
+ s->current_buffer = (s->data_1_length ? 1 : 0);
+ }
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (new_status && new_status != s->int_status) {
+ s->int_status |= new_status;
+ goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+ }
+}
+
+#if USE_QEMU_AUDIO_IN
+static void
+goldfish_audio_in_callback(void *opaque, int avail)
+{
+ struct goldfish_audio_state *s = opaque;
+ int new_status = 0;
+
+ if (s->read_pos >= s->read_size)
+ return;
+
+ if (0 && s->read_size > 0)
+ D("%s: in %d (pos=%d size=%d)", __FUNCTION__,
+ avail, s->read_pos, s->read_size );
+
+ while (avail > 0) {
+ int pos = s->read_pos;
+ int missing = s->read_size - pos;
+ uint8* buffer = (uint8*)phys_ram_base + s->read_buffer + pos;
+ int read;
+ int avail2 = (avail > missing) ? missing : avail;
+
+ read = AUD_read(s->voicein, buffer, avail2);
+ if (read == 0)
+ break;
+
+ if (avail2 > 0)
+ D("%s: AUD_read(%d) returned %d", __FUNCTION__, avail2, read);
+
+ s->read_buffer_available += read;
+
+ avail -= read;
+ pos += read;
+ if (pos == s->read_size) {
+ new_status |= AUDIO_INT_READ_BUFFER_FULL;
+ D("%s: AUDIO_INT_READ_BUFFER_FULL available=%d", __FUNCTION__, s->read_buffer_available);
+ }
+ s->read_pos = pos;
+ }
+
+ if (new_status && new_status != s->int_status) {
+ s->int_status |= new_status;
+ goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+ }
+}
+#endif /* USE_QEMU_AUDIO_IN */
+
+static CPUReadMemoryFunc *goldfish_audio_readfn[] = {
+ goldfish_audio_read,
+ goldfish_audio_read,
+ goldfish_audio_read
+};
+
+static CPUWriteMemoryFunc *goldfish_audio_writefn[] = {
+ goldfish_audio_write,
+ goldfish_audio_write,
+ goldfish_audio_write
+};
+
+void goldfish_audio_init(uint32_t base, int id, const char* input_source)
+{
+ struct goldfish_audio_state *s;
+ audsettings_t as;
+
+ s = (struct goldfish_audio_state *)qemu_mallocz(sizeof(*s));
+ s->dev.name = "goldfish_audio";
+ s->dev.id = id;
+ s->dev.base = base;
+ s->dev.size = 0x1000;
+ s->dev.irq_count = 1;
+
+#ifndef USE_QEMU_AUDIO_IN
+ s->input_fd = -1;
+ if (input_source) {
+ s->input_source = input_source;
+ char* extension = strrchr(input_source, '.');
+ if (extension && strcasecmp(extension, ".wav") == 0) {
+ s->input_is_wav = 1;
+ }
+ }
+#endif
+
+ AUD_register_card( &glob_audio_state, "goldfish_audio", &s->card);
+
+ as.freq = 44100;
+ as.nchannels = 2;
+ as.fmt = AUD_FMT_S16;
+ as.endianness = AUDIO_HOST_ENDIANNESS;
+
+ s->voice = AUD_open_out (
+ &s->card,
+ s->voice,
+ "goldfish_audio",
+ s,
+ goldfish_audio_callback,
+ &as
+ );
+ if (!s->voice) {
+ dprint("warning: opening audio output failed\n");
+ return;
+ }
+
+#if USE_QEMU_AUDIO_IN
+ as.freq = 8000;
+ as.nchannels = 1;
+ as.fmt = AUD_FMT_S16;
+ as.endianness = AUDIO_HOST_ENDIANNESS;
+
+ s->voicein = AUD_open_in (
+ &s->card,
+ NULL,
+ "goldfish_audio_in",
+ s,
+ goldfish_audio_in_callback,
+ &as
+ );
+ if (!s->voicein) {
+ dprint("warning: opening audio input failed\n");
+ }
+#endif
+
+ goldfish_device_add(&s->dev, goldfish_audio_readfn, goldfish_audio_writefn, s);
+
+ register_savevm( "audio_state", 0, AUDIO_STATE_SAVE_VERSION,
+ audio_state_save, audio_state_load, s );
+}
+
diff --git a/hw/goldfish_battery.c b/hw/goldfish_battery.c
new file mode 100644
index 0000000..f8452db
--- /dev/null
+++ b/hw/goldfish_battery.c
@@ -0,0 +1,261 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "goldfish_device.h"
+#include "power_supply.h"
+
+
+enum {
+ /* status register */
+ BATTERY_INT_STATUS = 0x00,
+ /* set this to enable IRQ */
+ BATTERY_INT_ENABLE = 0x04,
+
+ BATTERY_AC_ONLINE = 0x08,
+ BATTERY_STATUS = 0x0C,
+ BATTERY_HEALTH = 0x10,
+ BATTERY_PRESENT = 0x14,
+ BATTERY_CAPACITY = 0x18,
+
+ BATTERY_STATUS_CHANGED = 1U << 0,
+ AC_STATUS_CHANGED = 1U << 1,
+ BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED,
+};
+
+
+struct goldfish_battery_state {
+ struct goldfish_device dev;
+ // IRQs
+ uint32_t int_status;
+ // irq enable mask for int_status
+ uint32_t int_enable;
+
+ int ac_online;
+ int status;
+ int health;
+ int present;
+ int capacity;
+};
+
+/* update this each time you update the battery_state struct */
+#define BATTERY_STATE_SAVE_VERSION 1
+
+#define QFIELD_STRUCT struct goldfish_battery_state
+QFIELD_BEGIN(goldfish_battery_fields)
+ QFIELD_INT32(int_status),
+ QFIELD_INT32(int_enable),
+ QFIELD_INT32(ac_online),
+ QFIELD_INT32(status),
+ QFIELD_INT32(health),
+ QFIELD_INT32(present),
+ QFIELD_INT32(capacity),
+QFIELD_END
+
+static void goldfish_battery_save(QEMUFile* f, void* opaque)
+{
+ struct goldfish_battery_state* s = opaque;
+
+ qemu_put_struct(f, goldfish_battery_fields, s);
+}
+
+static int goldfish_battery_load(QEMUFile* f, void* opaque, int version_id)
+{
+ struct goldfish_battery_state* s = opaque;
+
+ if (version_id != BATTERY_STATE_SAVE_VERSION)
+ return -1;
+
+ return qemu_get_struct(f, goldfish_battery_fields, s);
+}
+
+static struct goldfish_battery_state *battery_state;
+
+static uint32_t goldfish_battery_read(void *opaque, target_phys_addr_t offset)
+{
+ uint32_t ret;
+ struct goldfish_battery_state *s = opaque;
+ offset -= s->dev.base;
+ switch(offset) {
+ case BATTERY_INT_STATUS:
+ // return current buffer status flags
+ ret = s->int_status & s->int_enable;
+ if (ret) {
+ goldfish_device_set_irq(&s->dev, 0, 0);
+ s->int_status = 0;
+ }
+ return ret;
+
+ case BATTERY_INT_ENABLE:
+ return s->int_enable;
+ case BATTERY_AC_ONLINE:
+ return s->ac_online;
+ case BATTERY_STATUS:
+ return s->status;
+ case BATTERY_HEALTH:
+ return s->health;
+ case BATTERY_PRESENT:
+ return s->present;
+ case BATTERY_CAPACITY:
+ return s->capacity;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_battery_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_battery_write(void *opaque, target_phys_addr_t offset, uint32_t val)
+{
+ struct goldfish_battery_state *s = opaque;
+ offset -= s->dev.base;
+
+ switch(offset) {
+ case BATTERY_INT_ENABLE:
+ /* enable interrupts */
+ s->int_enable = val;
+// s->int_status = (AUDIO_INT_WRITE_BUFFER_1_EMPTY | AUDIO_INT_WRITE_BUFFER_2_EMPTY);
+// goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+ break;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_audio_write: Bad offset %x\n", offset);
+ }
+}
+
+static CPUReadMemoryFunc *goldfish_battery_readfn[] = {
+ goldfish_battery_read,
+ goldfish_battery_read,
+ goldfish_battery_read
+};
+
+
+static CPUWriteMemoryFunc *goldfish_battery_writefn[] = {
+ goldfish_battery_write,
+ goldfish_battery_write,
+ goldfish_battery_write
+};
+
+void goldfish_battery_init()
+{
+ struct goldfish_battery_state *s;
+
+ s = (struct goldfish_battery_state *)qemu_mallocz(sizeof(*s));
+ s->dev.name = "goldfish-battery";
+ s->dev.base = 0; // will be allocated dynamically
+ s->dev.size = 0x1000;
+ s->dev.irq_count = 1;
+
+ // default values for the battery
+ s->ac_online = 1;
+ s->status = POWER_SUPPLY_STATUS_CHARGING;
+ s->health = POWER_SUPPLY_HEALTH_GOOD;
+ s->present = 1; // battery is present
+ s->capacity = 50; // 50% charged
+
+ battery_state = s;
+
+ goldfish_device_add(&s->dev, goldfish_battery_readfn, goldfish_battery_writefn, s);
+
+ register_savevm( "battery_state", 0, BATTERY_STATE_SAVE_VERSION,
+ goldfish_battery_save, goldfish_battery_load, s);
+}
+
+void goldfish_battery_set_prop(int ac, int property, int value)
+{
+ int new_status = (ac ? AC_STATUS_CHANGED : BATTERY_STATUS_CHANGED);
+
+ if (ac) {
+ switch (property) {
+ case POWER_SUPPLY_PROP_ONLINE:
+ battery_state->ac_online = value;
+ break;
+ }
+ } else {
+ switch (property) {
+ case POWER_SUPPLY_PROP_STATUS:
+ battery_state->status = value;
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ battery_state->health = value;
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ battery_state->present = value;
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ battery_state->capacity = value;
+ break;
+ }
+ }
+
+ if (new_status != battery_state->int_status) {
+ battery_state->int_status |= new_status;
+ goldfish_device_set_irq(&battery_state->dev, 0, (battery_state->int_status & battery_state->int_enable));
+ }
+}
+
+void goldfish_battery_display(void (* callback)(void *data, const char* string), void *data)
+{
+ char buffer[100];
+ char* value;
+
+ sprintf(buffer, "AC: %s\r\n", (battery_state->ac_online ? "online" : "offline"));
+ callback(data, buffer);
+
+ switch (battery_state->status) {
+ case POWER_SUPPLY_STATUS_CHARGING:
+ value = "Charging";
+ break;
+ case POWER_SUPPLY_STATUS_DISCHARGING:
+ value = "Discharging";
+ break;
+ case POWER_SUPPLY_STATUS_NOT_CHARGING:
+ value = "Not charging";
+ break;
+ case POWER_SUPPLY_STATUS_FULL:
+ value = "Full";
+ break;
+ default:
+ value = "Unknown";
+ break;
+ }
+ sprintf(buffer, "status: %s\r\n", value);
+ callback(data, buffer);
+
+ switch (battery_state->health) {
+ case POWER_SUPPLY_HEALTH_GOOD:
+ value = "Good";
+ break;
+ case POWER_SUPPLY_HEALTH_OVERHEAT:
+ value = "Overhead";
+ break;
+ case POWER_SUPPLY_HEALTH_DEAD:
+ value = "Dead";
+ break;
+ case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
+ value = "Overvoltage";
+ break;
+ case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
+ value = "Unspecified failure";
+ break;
+ default:
+ value = "Unknown";
+ break;
+ }
+ sprintf(buffer, "health: %s\r\n", value);
+ callback(data, buffer);
+
+ sprintf(buffer, "present: %s\r\n", (battery_state->present ? "true" : "false"));
+ callback(data, buffer);
+
+ sprintf(buffer, "capacity: %d\r\n", battery_state->capacity);
+ callback(data, buffer);
+}
diff --git a/hw/goldfish_device.c b/hw/goldfish_device.c
new file mode 100644
index 0000000..a7d80a6
--- /dev/null
+++ b/hw/goldfish_device.c
@@ -0,0 +1,200 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "arm_pic.h"
+#include "goldfish_device.h"
+
+#define PDEV_BUS_OP_DONE (0x00)
+#define PDEV_BUS_OP_REMOVE_DEV (0x04)
+#define PDEV_BUS_OP_ADD_DEV (0x08)
+
+#define PDEV_BUS_OP_INIT (0x00)
+
+#define PDEV_BUS_OP (0x00)
+#define PDEV_BUS_GET_NAME (0x04)
+#define PDEV_BUS_NAME_LEN (0x08)
+#define PDEV_BUS_ID (0x0c)
+#define PDEV_BUS_IO_BASE (0x10)
+#define PDEV_BUS_IO_SIZE (0x14)
+#define PDEV_BUS_IRQ (0x18)
+#define PDEV_BUS_IRQ_COUNT (0x1c)
+
+struct bus_state {
+ struct goldfish_device dev;
+ struct goldfish_device *current;
+};
+
+qemu_irq *goldfish_pic;
+static struct goldfish_device *first_device;
+static struct goldfish_device *last_device;
+uint32_t goldfish_free_base;
+uint32_t goldfish_free_irq;
+
+void goldfish_device_set_irq(struct goldfish_device *dev, int irq, int level)
+{
+ if(irq >= dev->irq_count)
+ cpu_abort (cpu_single_env, "goldfish_device_set_irq: Bad irq %d >= %d\n", irq, dev->irq_count);
+ else
+ qemu_set_irq(goldfish_pic[dev->irq + irq], level);
+}
+
+int goldfish_add_device_no_io(struct goldfish_device *dev)
+{
+ if(dev->base == 0) {
+ dev->base = goldfish_free_base;
+ goldfish_free_base += dev->size;
+ }
+ if(dev->irq == 0 && dev->irq_count > 0) {
+ dev->irq = goldfish_free_irq;
+ goldfish_free_irq += dev->irq_count;
+ }
+ //printf("goldfish_add_device: %s, base %x %x, irq %d %d\n",
+ // dev->name, dev->base, dev->size, dev->irq, dev->irq_count);
+ dev->next = NULL;
+ if(last_device) {
+ last_device->next = dev;
+ }
+ else {
+ first_device = dev;
+ }
+ last_device = dev;
+ return 0;
+}
+
+int goldfish_device_add(struct goldfish_device *dev,
+ CPUReadMemoryFunc **mem_read,
+ CPUWriteMemoryFunc **mem_write,
+ void *opaque)
+{
+ int iomemtype;
+ goldfish_add_device_no_io(dev);
+ iomemtype = cpu_register_io_memory(0, mem_read,
+ mem_write, opaque);
+ cpu_register_physical_memory(dev->base, dev->size, iomemtype);
+ return 0;
+}
+
+static uint32_t goldfish_bus_read(void *opaque, target_phys_addr_t offset)
+{
+ struct bus_state *s = (struct bus_state *)opaque;
+ offset -= s->dev.base;
+
+ switch (offset) {
+ case PDEV_BUS_OP:
+ if(s->current) {
+ s->current->reported_state = 1;
+ s->current = s->current->next;
+ }
+ else {
+ s->current = first_device;
+ }
+ while(s->current && s->current->reported_state == 1)
+ s->current = s->current->next;
+ if(s->current)
+ return PDEV_BUS_OP_ADD_DEV;
+ else {
+ goldfish_device_set_irq(&s->dev, 0, 0);
+ return PDEV_BUS_OP_DONE;
+ }
+
+ case PDEV_BUS_NAME_LEN:
+ return s->current ? strlen(s->current->name) : 0;
+ case PDEV_BUS_ID:
+ return s->current ? s->current->id : 0;
+ case PDEV_BUS_IO_BASE:
+ return s->current ? s->current->base : 0;
+ case PDEV_BUS_IO_SIZE:
+ return s->current ? s->current->size : 0;
+ case PDEV_BUS_IRQ:
+ return s->current ? s->current->irq : 0;
+ case PDEV_BUS_IRQ_COUNT:
+ return s->current ? s->current->irq_count : 0;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_bus_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_bus_op_init(struct bus_state *s)
+{
+ struct goldfish_device *dev = first_device;
+ while(dev) {
+ dev->reported_state = 0;
+ dev = dev->next;
+ }
+ s->current = NULL;
+ goldfish_device_set_irq(&s->dev, 0, first_device != NULL);
+}
+
+static void goldfish_bus_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ struct bus_state *s = (struct bus_state *)opaque;
+ offset -= s->dev.base;
+
+ switch(offset) {
+ case PDEV_BUS_OP:
+ switch(value) {
+ case PDEV_BUS_OP_INIT:
+ goldfish_bus_op_init(s);
+ break;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_bus_write: Bad PDEV_BUS_OP value %x\n", value);
+ };
+ break;
+ case PDEV_BUS_GET_NAME:
+ if(s->current)
+ pmemcpy(value, s->current->name, strlen(s->current->name));
+ break;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_bus_write: Bad offset %x\n", offset);
+ }
+}
+
+static CPUReadMemoryFunc *goldfish_bus_readfn[] = {
+ goldfish_bus_read,
+ goldfish_bus_read,
+ goldfish_bus_read
+};
+
+static CPUWriteMemoryFunc *goldfish_bus_writefn[] = {
+ goldfish_bus_write,
+ goldfish_bus_write,
+ goldfish_bus_write
+};
+
+
+static struct bus_state bus_state = {
+ .dev = {
+ .name = "goldfish_device_bus",
+ .id = -1,
+ .base = 0x10001000,
+ .size = 0x1000,
+ .irq = 1,
+ .irq_count = 1,
+ }
+};
+
+void goldfish_device_init(qemu_irq *pic, uint32_t base, uint32_t size, uint32_t irq, uint32_t irq_count)
+{
+ goldfish_pic = pic;
+ goldfish_free_base = base;
+ goldfish_free_irq = irq;
+}
+
+int goldfish_device_bus_init(uint32_t base, uint32_t irq)
+{
+ bus_state.dev.base = base;
+ bus_state.dev.irq = irq;
+
+ return goldfish_device_add(&bus_state.dev, goldfish_bus_readfn, goldfish_bus_writefn, &bus_state);
+}
+
diff --git a/hw/goldfish_device.h b/hw/goldfish_device.h
new file mode 100644
index 0000000..abe102e
--- /dev/null
+++ b/hw/goldfish_device.h
@@ -0,0 +1,58 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef GOLDFISH_DEVICE_H
+#define GOLDFISH_DEVICE_H
+
+struct goldfish_device {
+ struct goldfish_device *next;
+ struct goldfish_device *prev;
+ uint32_t reported_state;
+ void *cookie;
+ const char *name;
+ uint32_t id;
+ uint32_t base; // filled in by goldfish_device_add if 0
+ uint32_t size;
+ uint32_t irq; // filled in by goldfish_device_add if 0
+ uint32_t irq_count;
+};
+
+
+void goldfish_device_set_irq(struct goldfish_device *dev, int irq, int level);
+int goldfish_device_add(struct goldfish_device *dev,
+ CPUReadMemoryFunc **mem_read,
+ CPUWriteMemoryFunc **mem_write,
+ void *opaque);
+
+int goldfish_add_device_no_io(struct goldfish_device *dev);
+
+void goldfish_device_init(qemu_irq *pic, uint32_t base, uint32_t size, uint32_t irq, uint32_t irq_count);
+int goldfish_device_bus_init(uint32_t base, uint32_t irq);
+
+// device init functions:
+qemu_irq *goldfish_interrupt_init(uint32_t base, qemu_irq parent_irq, qemu_irq parent_fiq);
+void goldfish_timer_and_rtc_init(uint32_t timerbase, int timerirq);
+int goldfish_tty_add(CharDriverState *cs, int id, uint32_t base, int irq);
+void goldfish_fb_init(DisplayState *ds, int id);
+void goldfish_audio_init(uint32_t base, int id, const char* input_source);
+void goldfish_battery_init();
+void goldfish_battery_set_prop(int ac, int property, int value);
+void goldfish_battery_display(void (* callback)(void *data, const char* string), void *data);
+void goldfish_mmc_init(uint32_t base, int id, BlockDriverState* bs);
+void *goldfish_switch_add(char *name, uint32_t (*writefn)(void *opaque, uint32_t state), void *writeopaque, int id);
+void goldfish_switch_set_state(void *opaque, uint32_t state);
+
+// these do not add a device
+void trace_dev_init(uint32_t base);
+void events_dev_init(uint32_t base, qemu_irq irq);
+void nand_dev_init(uint32_t base);
+
+#endif
diff --git a/hw/goldfish_events_device.c b/hw/goldfish_events_device.c
new file mode 100644
index 0000000..66ac2fc
--- /dev/null
+++ b/hw/goldfish_events_device.c
@@ -0,0 +1,423 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "android_events.h"
+#include "irq.h"
+
+#if 0
+// From kernel...
+#define EV_SYN 0x00
+#define EV_KEY 0x01
+#define EV_REL 0x02
+#define EV_ABS 0x03
+#define EV_MSC 0x04
+#define EV_SW 0x05
+#define EV_LED 0x11
+#define EV_SND 0x12
+#define EV_REP 0x14
+#define EV_FF 0x15
+#define EV_PWR 0x16
+#define EV_FF_STATUS 0x17
+#define EV_MAX 0x1f
+
+#define BTN_MISC 0x100
+#define BTN_0 0x100
+#define BTN_1 0x101
+#define BTN_2 0x102
+#define BTN_3 0x103
+#define BTN_4 0x104
+#define BTN_5 0x105
+#define BTN_6 0x106
+#define BTN_7 0x107
+#define BTN_8 0x108
+#define BTN_9 0x109
+
+#define BTN_MOUSE 0x110
+#define BTN_LEFT 0x110
+#define BTN_RIGHT 0x111
+#define BTN_MIDDLE 0x112
+#define BTN_SIDE 0x113
+#define BTN_EXTRA 0x114
+#define BTN_FORWARD 0x115
+#define BTN_BACK 0x116
+#define BTN_TASK 0x117
+
+#define BTN_JOYSTICK 0x120
+#define BTN_TRIGGER 0x120
+#define BTN_THUMB 0x121
+#define BTN_THUMB2 0x122
+#define BTN_TOP 0x123
+#define BTN_TOP2 0x124
+#define BTN_PINKIE 0x125
+#define BTN_BASE 0x126
+#define BTN_BASE2 0x127
+#define BTN_BASE3 0x128
+#define BTN_BASE4 0x129
+#define BTN_BASE5 0x12a
+#define BTN_BASE6 0x12b
+#define BTN_DEAD 0x12f
+
+#define BTN_GAMEPAD 0x130
+#define BTN_A 0x130
+#define BTN_B 0x131
+#define BTN_C 0x132
+#define BTN_X 0x133
+#define BTN_Y 0x134
+#define BTN_Z 0x135
+#define BTN_TL 0x136
+#define BTN_TR 0x137
+#define BTN_TL2 0x138
+#define BTN_TR2 0x139
+#define BTN_SELECT 0x13a
+#define BTN_START 0x13b
+#define BTN_MODE 0x13c
+#define BTN_THUMBL 0x13d
+#define BTN_THUMBR 0x13e
+
+#define BTN_DIGI 0x140
+#define BTN_TOOL_PEN 0x140
+#define BTN_TOOL_RUBBER 0x141
+#define BTN_TOOL_BRUSH 0x142
+#define BTN_TOOL_PENCIL 0x143
+#define BTN_TOOL_AIRBRUSH 0x144
+#define BTN_TOOL_FINGER 0x145
+#define BTN_TOOL_MOUSE 0x146
+#define BTN_TOOL_LENS 0x147
+#define BTN_TOUCH 0x14a
+#define BTN_STYLUS 0x14b
+#define BTN_STYLUS2 0x14c
+#define BTN_TOOL_DOUBLETAP 0x14d
+#define BTN_TOOL_TRIPLETAP 0x14e
+
+#define BTN_WHEEL 0x150
+#define BTN_GEAR_DOWN 0x150
+#define BTN_GEAR_UP 0x151
+
+#define REL_X 0x00
+#define REL_Y 0x01
+
+#define ABS_X 0x00
+#define ABS_Y 0x01
+#define ABS_Z 0x02
+#define ABS_RX 0x03
+#define ABS_RY 0x04
+#define ABS_RZ 0x05
+#define ABS_THROTTLE 0x06
+#define ABS_RUDDER 0x07
+#define ABS_WHEEL 0x08
+#define ABS_GAS 0x09
+#define ABS_BRAKE 0x0a
+#define ABS_HAT0X 0x10
+#define ABS_HAT0Y 0x11
+#define ABS_HAT1X 0x12
+#define ABS_HAT1Y 0x13
+#define ABS_HAT2X 0x14
+#define ABS_HAT2Y 0x15
+#define ABS_HAT3X 0x16
+#define ABS_HAT3Y 0x17
+#define ABS_PRESSURE 0x18
+#define ABS_DISTANCE 0x19
+#define ABS_TILT_X 0x1a
+#define ABS_TILT_Y 0x1b
+#define ABS_TOOL_WIDTH 0x1c
+#define ABS_VOLUME 0x20
+#define ABS_MISC 0x28
+#define ABS_MAX 0x3f
+#endif
+
+#define MAX_EVENTS 256*4
+
+enum {
+ REG_READ = 0x00,
+ REG_SET_PAGE = 0x00,
+ REG_LEN = 0x04,
+ REG_DATA = 0x08,
+
+ PAGE_NAME = 0x00000,
+ PAGE_EVBITS = 0x10000,
+ PAGE_ABSDATA = 0x20000 | EV_ABS,
+};
+
+typedef struct
+{
+ uint32_t base;
+ qemu_irq irq;
+ int pending;
+ int page;
+
+ unsigned events[MAX_EVENTS];
+ unsigned first;
+ unsigned last;
+
+ const char *name;
+ struct {
+ size_t len;
+ uint8_t *bits;
+ } ev_bits[EV_MAX + 1];
+ int32_t *abs_info;
+ size_t abs_info_count;
+} events_state;
+
+/* modify this each time you change the events_device structure. you
+ * will also need to upadte events_state_load and events_state_save
+ */
+#define EVENTS_STATE_SAVE_VERSION 1
+
+#undef QFIELD_STRUCT
+#define QFIELD_STRUCT events_state
+
+QFIELD_BEGIN(events_state_fields)
+ QFIELD_INT32(pending),
+ QFIELD_INT32(page),
+ QFIELD_BUFFER(events),
+ QFIELD_INT32(first),
+ QFIELD_INT32(last),
+QFIELD_END
+
+static void events_state_save(QEMUFile* f, void* opaque)
+{
+ events_state* s = opaque;
+
+ qemu_put_struct(f, events_state_fields, s);
+}
+
+static int events_state_load(QEMUFile* f, void* opaque, int version_id)
+{
+ events_state* s = opaque;
+
+ if (version_id != EVENTS_STATE_SAVE_VERSION)
+ return -1;
+
+ return qemu_get_struct(f, events_state_fields, s);
+}
+
+extern const char* android_skin_keycharmap;
+
+static void enqueue_event(events_state *s, unsigned int type, unsigned int code, int value)
+{
+ int enqueued = s->last - s->first;
+
+ if (enqueued < 0)
+ enqueued += MAX_EVENTS;
+
+ if (enqueued + 3 >= MAX_EVENTS-1) {
+ fprintf(stderr, "##KBD: Full queue, lose event\n");
+ return;
+ }
+
+ if(s->first == s->last){
+ qemu_irq_raise(s->irq);
+ }
+
+ //fprintf(stderr, "##KBD: type=%d code=%d value=%d\n", type, code, value);
+
+ s->events[s->last] = type;
+ s->last = (s->last + 1) & (MAX_EVENTS-1);
+ s->events[s->last] = code;
+ s->last = (s->last + 1) & (MAX_EVENTS-1);
+ s->events[s->last] = value;
+ s->last = (s->last + 1) & (MAX_EVENTS-1);
+}
+
+static unsigned dequeue_event(events_state *s)
+{
+ unsigned n;
+
+ if(s->first == s->last) {
+ return 0;
+ }
+
+ n = s->events[s->first];
+
+ s->first = (s->first + 1) & (MAX_EVENTS - 1);
+
+ if(s->first == s->last) {
+ qemu_irq_lower(s->irq);
+ }
+
+ return n;
+}
+
+static int get_page_len(events_state *s)
+{
+ int page = s->page;
+ if (page == PAGE_NAME)
+ return strlen(s->name);
+ if (page >= PAGE_EVBITS && page <= PAGE_EVBITS + EV_MAX)
+ return s->ev_bits[page - PAGE_EVBITS].len;
+ if (page == PAGE_ABSDATA)
+ return s->abs_info_count * sizeof(s->abs_info[0]);
+ return 0;
+}
+
+static int get_page_data(events_state *s, int offset)
+{
+ int page_len = get_page_len(s);
+ int page = s->page;
+ if (offset > page_len)
+ return 0;
+ if (page == PAGE_NAME)
+ return s->name[offset];
+ if (page >= PAGE_EVBITS && page <= PAGE_EVBITS + EV_MAX)
+ return s->ev_bits[page - PAGE_EVBITS].bits[offset];
+ if (page == PAGE_ABSDATA)
+ return s->abs_info[offset / sizeof(s->abs_info[0])];
+ return 0;
+}
+
+static uint32_t events_read(void *x, target_phys_addr_t off)
+{
+ events_state *s = (events_state *) x;
+ int offset = off - s->base;
+ if (offset == REG_READ)
+ return dequeue_event(s);
+ else if (offset == REG_LEN)
+ return get_page_len(s);
+ else if (offset >= REG_DATA)
+ return get_page_data(s, offset - REG_DATA);
+ return 0; // this shouldn't happen, if the driver does the right thing
+}
+
+static void events_write(void *x, target_phys_addr_t off, uint32_t val)
+{
+ events_state *s = (events_state *) x;
+ int offset = off - s->base;
+ if (offset == REG_SET_PAGE)
+ s->page = val;
+}
+
+static CPUReadMemoryFunc *events_readfn[] = {
+ events_read,
+ events_read,
+ events_read
+};
+
+static CPUWriteMemoryFunc *events_writefn[] = {
+ events_write,
+ events_write,
+ events_write
+};
+
+static void events_put_keycode(void *x, int keycode)
+{
+ events_state *s = (events_state *) x;
+
+ enqueue_event(s, EV_KEY, keycode&0x1ff, (keycode&0x200) ? 1 : 0);
+}
+
+static void events_put_mouse(void *opaque, int dx, int dy, int dz, int buttons_state)
+{
+ events_state *s = (events_state *) opaque;
+ if (dz == 0) {
+ enqueue_event(s, EV_ABS, ABS_X, dx);
+ enqueue_event(s, EV_ABS, ABS_Y, dy);
+ enqueue_event(s, EV_ABS, ABS_Z, dz);
+ enqueue_event(s, EV_KEY, BTN_TOUCH, buttons_state&1);
+ } else {
+ enqueue_event(s, EV_REL, REL_X, dx);
+ enqueue_event(s, EV_REL, REL_Y, dy);
+ }
+ enqueue_event(s, EV_SYN, 0, 0);
+}
+
+static void events_put_generic(void* opaque, int type, int code, int value)
+{
+ events_state *s = (events_state *) opaque;
+
+ enqueue_event(s, type, code, value);
+}
+
+static int events_set_bits(events_state *s, int type, int bitl, int bith)
+{
+ uint8_t *bits;
+ uint8_t maskl, maskh;
+ int il, ih;
+ il = bitl / 8;
+ ih = bith / 8;
+ if (ih >= s->ev_bits[type].len) {
+ bits = qemu_mallocz(ih + 1);
+ if (bits == NULL)
+ return -ENOMEM;
+ memcpy(bits, s->ev_bits[type].bits, s->ev_bits[type].len);
+ qemu_free(s->ev_bits[type].bits);
+ s->ev_bits[type].bits = bits;
+ s->ev_bits[type].len = ih + 1;
+ }
+ else
+ bits = s->ev_bits[type].bits;
+ maskl = 0xffU << (bitl & 7);
+ maskh = 0xffU >> (7 - (bith & 7));
+ if (il >= ih)
+ maskh &= maskl;
+ else {
+ bits[il] |= maskl;
+ while (++il < ih)
+ bits[il] = 0xff;
+ }
+ bits[ih] |= maskh;
+ return 0;
+}
+
+#if 0
+static int events_set_abs_info(events_state *s, int axis, int32_t min, int32_t max, int32_t fuzz, int32_t flat)
+{
+ int32_t *info;
+ if (axis * 4 >= s->abs_info_count) {
+ info = qemu_mallocz((axis + 1) * 4 * sizeof(int32_t));
+ if (info == NULL)
+ return -ENOMEM;
+ memcpy(info, s->abs_info, s->abs_info_count);
+ qemu_free(s->abs_info);
+ s->abs_info = info;
+ s->abs_info_count = (axis + 1) * 4;
+ }
+ else
+ info = s->abs_info;
+ info += axis * 4;
+ *info++ = min;
+ *info++ = max;
+ *info++ = fuzz;
+ *info++ = flat;
+}
+#endif
+
+void events_dev_init(uint32_t base, qemu_irq irq)
+{
+ events_state *s;
+ int iomemtype;
+
+ s = (events_state *) qemu_mallocz(sizeof(events_state));
+ s->name = android_skin_keycharmap;
+ events_set_bits(s, EV_SYN, EV_SYN, EV_ABS);
+ events_set_bits(s, EV_SYN, EV_SW, EV_SW);
+ events_set_bits(s, EV_KEY, 1, 0x1ff);
+ events_set_bits(s, EV_REL, REL_X, REL_Y);
+ events_set_bits(s, EV_ABS, ABS_X, ABS_Z);
+ events_set_bits(s, EV_SW, 0, 0);
+ iomemtype = cpu_register_io_memory(0, events_readfn, events_writefn, s);
+
+ cpu_register_physical_memory(base, 0xfff, iomemtype);
+
+ qemu_add_kbd_event_handler(events_put_keycode, s);
+ qemu_add_mouse_event_handler(events_put_mouse, s, 1);
+ qemu_add_generic_event_handler(events_put_generic, s);
+
+ s->base = base;
+ s->irq = irq;
+
+ s->first = 0;
+ s->last = 0;
+
+ register_savevm( "events_state", 0, EVENTS_STATE_SAVE_VERSION,
+ events_state_save, events_state_load, s );
+}
+
diff --git a/hw/goldfish_fb.c b/hw/goldfish_fb.c
new file mode 100644
index 0000000..0924735
--- /dev/null
+++ b/hw/goldfish_fb.c
@@ -0,0 +1,405 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "android.h"
+#include "goldfish_device.h"
+#include "framebuffer.h"
+
+enum {
+ FB_GET_WIDTH = 0x00,
+ FB_GET_HEIGHT = 0x04,
+ FB_INT_STATUS = 0x08,
+ FB_INT_ENABLE = 0x0c,
+ FB_SET_BASE = 0x10,
+ FB_SET_ROTATION = 0x14,
+ FB_SET_BLANK = 0x18,
+ FB_GET_PHYS_WIDTH = 0x1c,
+ FB_GET_PHYS_HEIGHT = 0x20,
+
+ FB_INT_VSYNC = 1U << 0,
+ FB_INT_BASE_UPDATE_DONE = 1U << 1
+};
+
+struct goldfish_fb_state {
+ struct goldfish_device dev;
+ QFrameBuffer* qfbuff;
+ uint32_t fb_base;
+ uint32_t base_valid : 1;
+ uint32_t need_update : 1;
+ uint32_t need_int : 1;
+ uint32_t set_rotation : 2;
+ uint32_t blank : 1;
+ uint32_t int_status;
+ uint32_t int_enable;
+ int rotation; /* 0, 1, 2 or 3 */
+};
+
+#define GOLDFISH_FB_SAVE_VERSION 1
+
+static void goldfish_fb_save(QEMUFile* f, void* opaque)
+{
+ struct goldfish_fb_state* s = opaque;
+
+ QFrameBuffer* q = s->qfbuff;
+
+ qemu_put_be32(f, q->width);
+ qemu_put_be32(f, q->height);
+ qemu_put_be32(f, q->pitch);
+ qemu_put_byte(f, q->rotation);
+
+ qemu_put_be32(f, s->fb_base);
+ qemu_put_byte(f, s->base_valid);
+ qemu_put_byte(f, s->need_update);
+ qemu_put_byte(f, s->need_int);
+ qemu_put_byte(f, s->set_rotation);
+ qemu_put_byte(f, s->blank);
+ qemu_put_be32(f, s->int_status);
+ qemu_put_be32(f, s->int_enable);
+ qemu_put_be32(f, s->rotation);
+}
+
+static int goldfish_fb_load(QEMUFile* f, void* opaque, int version_id)
+{
+ struct goldfish_fb_state* s = opaque;
+
+ QFrameBuffer* q = s->qfbuff;
+ int ret = -1;
+ int ds_w, ds_h, ds_pitch, ds_rot;
+
+ if (version_id != GOLDFISH_FB_SAVE_VERSION)
+ goto Exit;
+
+ ds_w = qemu_get_be32(f);
+ ds_h = qemu_get_be32(f);
+ ds_pitch = qemu_get_be32(f);
+ ds_rot = qemu_get_byte(f);
+
+ if (q->width != ds_w ||
+ q->height != ds_h ||
+ q->pitch != ds_pitch ||
+ q->rotation != ds_rot )
+ {
+ /* XXX: We should be able to force a resize/rotation from here ? */
+ fprintf(stderr, "%s: framebuffer dimensions mismatch\n", __FUNCTION__);
+ goto Exit;
+ }
+
+ s->fb_base = qemu_get_be32(f);
+ s->base_valid = qemu_get_byte(f);
+ s->need_update = qemu_get_byte(f);
+ s->need_int = qemu_get_byte(f);
+ s->set_rotation = qemu_get_byte(f);
+ s->blank = qemu_get_byte(f);
+ s->int_status = qemu_get_be32(f);
+ s->int_enable = qemu_get_be32(f);
+ s->rotation = qemu_get_be32(f);
+
+ /* force a refresh */
+ s->need_update = 1;
+
+ ret = 0;
+Exit:
+ return ret;
+}
+
+
+#define STATS 0
+
+#if STATS
+static int stats_counter;
+static long stats_total;
+static int stats_full_updates;
+static long stats_total_full_updates;
+#endif
+
+static void goldfish_fb_update_display(void *opaque)
+{
+ struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque;
+ uint32_t addr;
+ uint32_t base;
+
+ uint8_t* dst_line;
+ uint8_t* src_line;
+ int y_first, y_last = 0;
+ int full_update = 0;
+ int width, height, pitch;
+
+ base = s->fb_base;
+ if(base == 0)
+ return;
+
+ if((s->int_enable & FB_INT_VSYNC) && !(s->int_status & FB_INT_VSYNC)) {
+ s->int_status |= FB_INT_VSYNC;
+ goldfish_device_set_irq(&s->dev, 0, 1);
+ }
+
+ y_first = -1;
+ addr = base;
+ if(s->need_update) {
+ full_update = 1;
+ if(s->need_int) {
+ s->int_status |= FB_INT_BASE_UPDATE_DONE;
+ if(s->int_enable & FB_INT_BASE_UPDATE_DONE)
+ goldfish_device_set_irq(&s->dev, 0, 1);
+ }
+ s->need_int = 0;
+ s->need_update = 0;
+ }
+
+ src_line = phys_ram_base + base;
+ dst_line = s->qfbuff->pixels;
+ pitch = s->qfbuff->pitch;
+ width = s->qfbuff->width;
+ height = s->qfbuff->height;
+
+#if STATS
+ if (full_update)
+ stats_full_updates += 1;
+ if (++stats_counter == 120) {
+ stats_total += stats_counter;
+ stats_total_full_updates += stats_full_updates;
+
+ printf( "full update stats: peak %.2f %% total %.2f %%\n",
+ stats_full_updates*100.0/stats_counter,
+ stats_total_full_updates*100.0/stats_total );
+
+ stats_counter = 0;
+ stats_full_updates = 0;
+ }
+#endif /* STATS */
+
+ if (s->blank)
+ {
+ memset( dst_line, 0, height*pitch );
+ y_first = 0;
+ y_last = height-1;
+ }
+ else if (full_update)
+ {
+ int yy;
+
+ for (yy = 0; yy < height; yy++, dst_line += pitch, src_line += width*2)
+ {
+ uint16_t* src = (uint16_t*) src_line;
+ uint16_t* dst = (uint16_t*) dst_line;
+ int nn;
+
+ for (nn = 0; nn < width; nn++) {
+ unsigned spix = src[nn];
+ unsigned dpix = dst[nn];
+#if WORDS_BIGENDIAN
+ spix = ((spix << 8) | (spix >> 8)) & 0xffff;
+#else
+ if (spix != dpix)
+ break;
+#endif
+ }
+
+ if (nn == width)
+ continue;
+
+#if WORDS_BIGENDIAN
+ for ( ; nn < width; nn++ ) {
+ unsigned spix = src[nn];
+ dst[nn] = (uint16_t)((spix << 8) | (spix >> 8));
+ }
+#else
+ memcpy( dst+nn, src+nn, (width-nn)*2 );
+#endif
+
+ y_first = (y_first < 0) ? yy : y_first;
+ y_last = yy;
+ }
+ }
+ else /* not a full update, should not happen very often with Android */
+ {
+ int yy;
+
+ for (yy = 0; yy < height; yy++, dst_line += pitch, src_line += width*2)
+ {
+ uint16_t* src = (uint16_t*) src_line;
+ uint16_t* dst = (uint16_t*) dst_line;
+ int len = width*2;
+#if WORDS_BIGENDIAN
+ int nn;
+#endif
+ int dirty = 0;
+
+ while (len > 0) {
+ int len2 = TARGET_PAGE_SIZE - (addr & (TARGET_PAGE_SIZE-1));
+
+ if (len2 > len)
+ len2 = len;
+
+ dirty |= cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG);
+ addr += len2;
+ len -= len2;
+ }
+
+ if (!dirty)
+ continue;
+
+#if WORDS_BIGENDIAN
+ for (nn = 0; nn < width; nn++ ) {
+ unsigned spix = src[nn];
+ dst[nn] = (uint16_t)((spix << 8) | (spix >> 8));
+ }
+#else
+ memcpy( dst, src, width*2 );
+#endif
+
+ y_first = (y_first < 0) ? yy : y_first;
+ y_last = yy;
+ }
+ }
+
+ if (y_first < 0)
+ return;
+
+ y_last += 1;
+ //printf("goldfish_fb_update_display %d %d, base %x\n", first, last, base);
+
+ cpu_physical_memory_reset_dirty(base + y_first * width * 2,
+ base + y_last * width * 2,
+ VGA_DIRTY_FLAG);
+
+ qframebuffer_update( s->qfbuff, 0, y_first, width, y_last-y_first );
+}
+
+static void goldfish_fb_invalidate_display(void * opaque)
+{
+ // is this called?
+ struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque;
+ s->need_update = 1;
+}
+
+static void goldfish_fb_detach_display(void* opaque)
+{
+ struct goldfish_fb_state *s = (struct goldfish_fb_state *)opaque;
+ s->qfbuff = NULL;
+}
+
+static uint32_t goldfish_fb_read(void *opaque, target_phys_addr_t offset)
+{
+ uint32_t ret;
+ struct goldfish_fb_state *s = opaque;
+ offset -= s->dev.base;
+ switch(offset) {
+ case FB_GET_WIDTH:
+ ret = s->qfbuff->width;
+ //printf("FB_GET_WIDTH => %d\n", ret);
+ return ret;
+
+ case FB_GET_HEIGHT:
+ ret = s->qfbuff->height;
+ //printf( "FB_GET_HEIGHT = %d\n", ret);
+ return ret;
+
+ case FB_INT_STATUS:
+ ret = s->int_status & s->int_enable;
+ if(ret) {
+ s->int_status &= ~ret;
+ goldfish_device_set_irq(&s->dev, 0, 0);
+ }
+ return ret;
+
+ case FB_GET_PHYS_WIDTH:
+ ret = s->qfbuff->phys_width_mm;
+ //printf( "FB_GET_PHYS_WIDTH => %d\n", ret );
+ return ret;
+
+ case FB_GET_PHYS_HEIGHT:
+ ret = s->qfbuff->phys_height_mm;
+ //printf( "FB_GET_PHYS_HEIGHT => %d\n", ret );
+ return ret;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_fb_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_fb_write(void *opaque, target_phys_addr_t offset,
+ uint32_t val)
+{
+ struct goldfish_fb_state *s = opaque;
+ offset -= s->dev.base;
+ switch(offset) {
+ case FB_INT_ENABLE:
+ s->int_enable = val;
+ goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+ break;
+ case FB_SET_BASE: {
+ int need_resize = !s->base_valid;
+ s->fb_base = val;
+ s->int_status &= ~FB_INT_BASE_UPDATE_DONE;
+ s->need_update = 1;
+ s->need_int = 1;
+ s->base_valid = 1;
+ if(s->set_rotation != s->rotation) {
+ //printf("FB_SET_BASE: rotation : %d => %d\n", s->rotation, s->set_rotation);
+ s->rotation = s->set_rotation;
+ need_resize = 1;
+ }
+ goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+ if (need_resize) {
+ //printf("FB_SET_BASE: need resize (rotation=%d)\n", s->rotation );
+ qframebuffer_rotate( s->qfbuff, s->rotation );
+ }
+ } break;
+ case FB_SET_ROTATION:
+ //printf( "FB_SET_ROTATION %d\n", val);
+ s->set_rotation = val;
+ break;
+ case FB_SET_BLANK:
+ s->blank = val;
+ s->need_update = 1;
+ break;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_fb_write: Bad offset %x\n", offset);
+ }
+}
+
+static CPUReadMemoryFunc *goldfish_fb_readfn[] = {
+ goldfish_fb_read,
+ goldfish_fb_read,
+ goldfish_fb_read
+};
+
+static CPUWriteMemoryFunc *goldfish_fb_writefn[] = {
+ goldfish_fb_write,
+ goldfish_fb_write,
+ goldfish_fb_write
+};
+
+void goldfish_fb_init(DisplayState *ds, int id)
+{
+ struct goldfish_fb_state *s;
+
+ s = (struct goldfish_fb_state *)qemu_mallocz(sizeof(*s));
+ s->dev.name = "goldfish_fb";
+ s->dev.id = id;
+ s->dev.size = 0x1000;
+ s->dev.irq_count = 1;
+
+ s->qfbuff = qframebuffer_fifo_get();
+ qframebuffer_add_producer( s->qfbuff, s,
+ goldfish_fb_update_display,
+ goldfish_fb_invalidate_display,
+ goldfish_fb_detach_display );
+
+ goldfish_device_add(&s->dev, goldfish_fb_readfn, goldfish_fb_writefn, s);
+
+ register_savevm( "goldfish_fb", 0, GOLDFISH_FB_SAVE_VERSION,
+ goldfish_fb_save, goldfish_fb_load, s);
+}
+
diff --git a/hw/goldfish_interrupt.c b/hw/goldfish_interrupt.c
new file mode 100644
index 0000000..c89130d
--- /dev/null
+++ b/hw/goldfish_interrupt.c
@@ -0,0 +1,190 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "arm_pic.h"
+#include "goldfish_device.h"
+#include "irq.h"
+
+enum {
+ INTERRUPT_STATUS = 0x00, // number of pending interrupts
+ INTERRUPT_NUMBER = 0x04,
+ INTERRUPT_DISABLE_ALL = 0x08,
+ INTERRUPT_DISABLE = 0x0c,
+ INTERRUPT_ENABLE = 0x10
+};
+
+struct goldfish_int_state {
+ struct goldfish_device dev;
+ uint32_t level;
+ uint32_t pending_count;
+ uint32_t irq_enabled;
+ uint32_t fiq_enabled;
+ qemu_irq parent_irq;
+ qemu_irq parent_fiq;
+};
+
+#define GOLDFISH_INT_SAVE_VERSION 1
+
+#define QFIELD_STRUCT struct goldfish_int_state
+QFIELD_BEGIN(goldfish_int_fields)
+ QFIELD_INT32(level),
+ QFIELD_INT32(pending_count),
+ QFIELD_INT32(irq_enabled),
+ QFIELD_INT32(fiq_enabled),
+QFIELD_END
+
+static void goldfish_int_save(QEMUFile* f, void* opaque)
+{
+ struct goldfish_int_state* s = opaque;
+
+ qemu_put_struct(f, goldfish_int_fields, s);
+}
+
+static int goldfish_int_load(QEMUFile* f, void* opaque, int version_id)
+{
+ struct goldfish_int_state* s = opaque;
+
+ if (version_id != GOLDFISH_INT_SAVE_VERSION)
+ return -1;
+
+ return qemu_get_struct(f, goldfish_int_fields, s);
+}
+
+static void goldfish_int_update(struct goldfish_int_state *s)
+{
+ uint32_t flags;
+
+ 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 goldfish_int_set_irq(void *opaque, int irq, int level)
+{
+ struct goldfish_int_state *s = (struct goldfish_int_state *)opaque;
+ uint32_t mask = (1U << irq);
+
+ if(level) {
+ if(!(s->level & mask)) {
+ if(s->irq_enabled & mask)
+ s->pending_count++;
+ s->level |= mask;
+ }
+ }
+ else {
+ if(s->level & mask) {
+ if(s->irq_enabled & mask)
+ s->pending_count--;
+ s->level &= ~mask;
+ }
+ }
+ goldfish_int_update(s);
+}
+
+static uint32_t goldfish_int_read(void *opaque, target_phys_addr_t offset)
+{
+ struct goldfish_int_state *s = (struct goldfish_int_state *)opaque;
+ offset -= s->dev.base;
+
+ switch (offset) {
+ case INTERRUPT_STATUS: /* IRQ_STATUS */
+ return s->pending_count;
+ case INTERRUPT_NUMBER: {
+ int i;
+ uint32_t pending = s->level & s->irq_enabled;
+ for(i = 0; i < 32; i++) {
+ if(pending & (1U << i))
+ return i;
+ }
+ return 0;
+ }
+ default:
+ cpu_abort (cpu_single_env, "goldfish_int_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_int_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ struct goldfish_int_state *s = (struct goldfish_int_state *)opaque;
+ uint32_t mask = (1U << value);
+ offset -= s->dev.base;
+
+ switch (offset) {
+ case INTERRUPT_DISABLE_ALL:
+ s->pending_count = 0;
+ s->level = 0;
+ break;
+
+ case INTERRUPT_DISABLE:
+ if(s->irq_enabled & mask) {
+ if(s->level & mask)
+ s->pending_count--;
+ s->irq_enabled &= ~mask;
+ }
+ break;
+ case INTERRUPT_ENABLE:
+ if(!(s->irq_enabled & mask)) {
+ s->irq_enabled |= mask;
+ if(s->level & mask)
+ s->pending_count++;
+ }
+ break;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_int_write: Bad offset %x\n", offset);
+ return;
+ }
+ goldfish_int_update(s);
+}
+
+static CPUReadMemoryFunc *goldfish_int_readfn[] = {
+ goldfish_int_read,
+ goldfish_int_read,
+ goldfish_int_read
+};
+
+static CPUWriteMemoryFunc *goldfish_int_writefn[] = {
+ goldfish_int_write,
+ goldfish_int_write,
+ goldfish_int_write
+};
+
+qemu_irq* goldfish_interrupt_init(uint32_t base, qemu_irq parent_irq, qemu_irq parent_fiq)
+{
+ int ret;
+ struct goldfish_int_state *s;
+ qemu_irq* qi;
+
+ s = qemu_mallocz(sizeof(*s));
+ qi = qemu_allocate_irqs(goldfish_int_set_irq, s, 32);
+ s->dev.name = "goldfish_interrupt_controller";
+ s->dev.id = -1;
+ s->dev.base = base;
+ s->dev.size = 0x1000;
+ s->parent_irq = parent_irq;
+ s->parent_fiq = parent_fiq;
+
+ ret = goldfish_device_add(&s->dev, goldfish_int_readfn, goldfish_int_writefn, s);
+ if(ret) {
+ qemu_free(s);
+ return NULL;
+ }
+
+ register_savevm( "goldfish_int", 0, GOLDFISH_INT_SAVE_VERSION,
+ goldfish_int_save, goldfish_int_load, s);
+
+ return qi;
+}
+
diff --git a/hw/goldfish_memlog.c b/hw/goldfish_memlog.c
new file mode 100644
index 0000000..e2a89a6
--- /dev/null
+++ b/hw/goldfish_memlog.c
@@ -0,0 +1,78 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "vl.h"
+#include "goldfish_device.h"
+#include "audio/audio.h"
+
+extern void dprint(const char* fmt, ...);
+
+int fd = -1;
+
+static uint32_t memlog_read(void *opaque, target_phys_addr_t offset)
+{
+ struct goldfish_device *dev = opaque;
+ offset -= dev->base;
+
+ return 0;
+}
+
+unsigned info[8];
+
+static void memlog_write(void *opaque, target_phys_addr_t offset, uint32_t val)
+{
+ char buf[128];
+ struct goldfish_device *dev = opaque;
+ offset -= dev->base;
+
+ info[offset / 4] = val;
+
+ if (offset == 0) {
+ /* write PID and VADDR to logfile */
+ sprintf(buf,"%08x %08x\n", info[0], info[1]);
+ write(fd, buf, strlen(buf));
+ }
+}
+
+
+static CPUReadMemoryFunc *memlog_readfn[] = {
+ memlog_read,
+ memlog_read,
+ memlog_read
+};
+
+static CPUWriteMemoryFunc *memlog_writefn[] = {
+ memlog_write,
+ memlog_write,
+ memlog_write
+};
+
+struct goldfish_device memlog_dev;
+
+void goldfish_memlog_init(uint32_t base)
+{
+ struct goldfish_device *dev = &memlog_dev;
+
+ dev->name = "goldfish_memlog";
+ dev->id = 0;
+ dev->base = base;
+ dev->size = 0x1000;
+ dev->irq_count = 0;
+
+ fd = open("mem.log", /* O_CREAT | */ O_TRUNC | O_WRONLY, 0644);
+
+ goldfish_device_add(dev, memlog_readfn, memlog_writefn, dev);
+}
+
diff --git a/hw/goldfish_mmc.c b/hw/goldfish_mmc.c
new file mode 100644
index 0000000..a00340c
--- /dev/null
+++ b/hw/goldfish_mmc.c
@@ -0,0 +1,465 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "goldfish_device.h"
+#include "mmc.h"
+#include "sd.h"
+
+enum {
+ /* status register */
+ MMC_INT_STATUS = 0x00,
+ /* set this to enable IRQ */
+ MMC_INT_ENABLE = 0x04,
+ /* set this to specify buffer address */
+ MMC_SET_BUFFER = 0x08,
+
+ /* MMC command number */
+ MMC_CMD = 0x0C,
+
+ /* MMC argument */
+ MMC_ARG = 0x10,
+
+ /* MMC response (or R2 bits 0 - 31) */
+ MMC_RESP_0 = 0x14,
+
+ /* MMC R2 response bits 32 - 63 */
+ MMC_RESP_1 = 0x18,
+
+ /* MMC R2 response bits 64 - 95 */
+ MMC_RESP_2 = 0x1C,
+
+ /* MMC R2 response bits 96 - 127 */
+ MMC_RESP_3 = 0x20,
+
+ MMC_BLOCK_LENGTH = 0x24,
+ MMC_BLOCK_COUNT = 0x28,
+
+ /* MMC state flags */
+ MMC_STATE = 0x2C,
+
+ /* MMC_INT_STATUS bits */
+
+ MMC_STAT_END_OF_CMD = 1U << 0,
+ MMC_STAT_END_OF_DATA = 1U << 1,
+ MMC_STAT_STATE_CHANGE = 1U << 2,
+
+ /* MMC_STATE bits */
+ MMC_STATE_INSERTED = 1U << 0,
+ MMC_STATE_READ_ONLY = 1U << 1,
+};
+
+
+struct goldfish_mmc_state {
+ struct goldfish_device dev;
+ BlockDriverState *bs;
+ // pointer to our buffer
+ uint8_t* buffer;
+ // offsets for read and write operations
+ uint32_t read_offset, write_offset;
+ // buffer status flags
+ uint32_t int_status;
+ // irq enable mask for int_status
+ uint32_t int_enable;
+
+ // MMC command argument
+ uint32_t arg;
+ uint32_t resp[4];
+
+ uint32_t block_length;
+ uint32_t block_count;
+ int is_SDHC;
+};
+
+#define GOLDFISH_MMC_SAVE_VERSION 1
+#define QFIELD_STRUCT struct goldfish_mmc_state
+QFIELD_BEGIN(goldfish_mmc_fields)
+ QFIELD_INT32(read_offset),
+ QFIELD_INT32(write_offset),
+ QFIELD_INT32(int_status),
+ QFIELD_INT32(int_enable),
+ QFIELD_INT32(arg),
+ QFIELD_INT32(resp[0]),
+ QFIELD_INT32(resp[1]),
+ QFIELD_INT32(resp[2]),
+ QFIELD_INT32(resp[3]),
+ QFIELD_INT32(block_length),
+ QFIELD_INT32(block_count),
+ QFIELD_INT32(is_SDHC),
+QFIELD_END
+
+static void goldfish_mmc_save(QEMUFile* f, void* opaque)
+{
+ struct goldfish_mmc_state* s = opaque;
+
+ qemu_put_be32(f, s->buffer - phys_ram_base);
+ qemu_put_struct(f, goldfish_mmc_fields, s);
+}
+
+static int goldfish_mmc_load(QEMUFile* f, void* opaque, int version_id)
+{
+ struct goldfish_mmc_state* s = opaque;
+
+ if (version_id != GOLDFISH_MMC_SAVE_VERSION)
+ return -1;
+
+ s->buffer = qemu_get_be32(f) + phys_ram_base;
+ return qemu_get_struct(f, goldfish_mmc_fields, s);
+}
+
+struct mmc_opcode {
+ const char* name;
+ int cmd;
+} mmc_opcodes[] = {
+ { "MMC_GO_IDLE_STATE", 0 },
+ { "MMC_SEND_OP_COND", 1 },
+ { "MMC_ALL_SEND_CID", 2 },
+ { "MMC_SET_RELATIVE_ADDR", 3 },
+ { "MMC_SET_DSR", 4 },
+ { "MMC_SWITCH", 6 },
+ { "MMC_SELECT_CARD", 7 },
+ { "MMC_SEND_EXT_CSD", 8 },
+ { "MMC_SEND_CSD", 9 },
+ { "MMC_SEND_CID", 10 },
+ { "MMC_READ_DAT_UNTIL_STOP", 11 },
+ { "MMC_STOP_TRANSMISSION", 12 },
+ { "MMC_SEND_STATUS", 13 },
+ { "MMC_GO_INACTIVE_STATE", 15 },
+ { "MMC_SET_BLOCKLEN", 16 },
+ { "MMC_READ_SINGLE_BLOCK", 17 },
+ { "MMC_READ_MULTIPLE_BLOCK", 18 },
+ { "MMC_WRITE_DAT_UNTIL_STOP", 20 },
+ { "MMC_SET_BLOCK_COUNT", 23 },
+ { "MMC_WRITE_BLOCK", 24 },
+ { "MMC_WRITE_MULTIPLE_BLOCK", 25 },
+ { "MMC_PROGRAM_CID", 26 },
+ { "MMC_PROGRAM_CSD", 27 },
+ { "MMC_SET_WRITE_PROT", 28 },
+ { "MMC_CLR_WRITE_PROT", 29 },
+ { "MMC_SEND_WRITE_PROT", 30 },
+ { "MMC_ERASE_GROUP_START", 35 },
+ { "MMC_ERASE_GROUP_END", 36 },
+ { "MMC_ERASE", 38 },
+ { "MMC_FAST_IO", 39 },
+ { "MMC_GO_IRQ_STATE", 40 },
+ { "MMC_LOCK_UNLOCK", 42 },
+ { "MMC_APP_CMD", 55 },
+ { "MMC_GEN_CMD", 56 },
+ { "SD_APP_OP_COND", 41 },
+ { "SD_APP_SEND_SCR", 51 },
+ { "UNKNOWN" -1 }
+};
+
+static const char* get_command_name(int command)
+{
+ struct mmc_opcode* opcode = mmc_opcodes;
+
+ while (opcode->cmd != command && opcode->cmd != -1) opcode++;
+ return opcode->name;
+}
+
+static void goldfish_mmc_do_command(struct goldfish_mmc_state *s, uint32_t cmd, uint32_t arg)
+{
+ int result;
+ int new_status = MMC_STAT_END_OF_CMD;
+ int opcode = cmd & 63;
+
+// fprintf(stderr, "goldfish_mmc_do_command opcode: %s (0x%04X), arg: %d\n", get_command_name(opcode), cmd, arg);
+
+ s->resp[0] = 0;
+ s->resp[1] = 0;
+ s->resp[2] = 0;
+ s->resp[3] = 0;
+
+#define SET_R1_CURRENT_STATE(s) ((s << 9) & 0x00001E00) /* sx, b (4 bits) */
+
+ switch (opcode) {
+ case MMC_SEND_CSD: {
+ int64_t sector_count = 0;
+ uint64_t capacity;
+ uint8_t exponent;
+ uint32_t m;
+
+ bdrv_get_geometry(s->bs, &sector_count);
+ capacity = sector_count * 512;
+ if (capacity > 2147483648U) {
+ // if storages is > 2 gig, then emulate SDHC card
+ s->is_SDHC = 1;
+
+ // CSD bits borrowed from a real SDHC card, with capacity bits zeroed out
+ s->resp[3] = 0x400E0032;
+ s->resp[2] = 0x5B590000;
+ s->resp[1] = 0x00007F80;
+ s->resp[0] = 0x0A4040DF;
+
+ // stuff in the real capacity
+ // m = UNSTUFF_BITS(resp, 48, 22);
+ m = (uint32_t)(capacity / (512*1024)) - 1;
+ // m must fit into 22 bits
+ if (m & 0xFFC00000) {
+ fprintf(stderr, "SD card too big (%lld bytes). Maximum SDHC card size is 128 gigabytes.\n", capacity);
+ abort();
+ }
+
+ // low 16 bits go in high end of resp[1]
+ s->resp[1] |= ((m & 0x0000FFFF) << 16);
+ // high 6 bits go in low end of resp[2]
+ s->resp[2] |= (m >> 16);
+ } else {
+ // emulate standard SD card
+ s->is_SDHC = 0;
+
+ // CSD bits borrowed from a real SD card, with capacity bits zeroed out
+ s->resp[3] = 0x00260032;
+ s->resp[2] = 0x5F5A8000;
+ s->resp[1] = 0x3EF84FFF;
+ s->resp[0] = 0x928040CB;
+
+ // stuff in the real capacity
+ // e = UNSTUFF_BITS(resp, 47, 3);
+ // m = UNSTUFF_BITS(resp, 62, 12);
+ // csd->capacity = (1 + m) << (e + 2);
+ // need to reverse the formula and calculate e and m
+ exponent = 0;
+ capacity = sector_count * 512;
+ if (capacity > 2147483648U) {
+ fprintf(stderr, "SD card too big (%lld bytes). Maximum SD card size is 2 gigabytes.\n", capacity);
+ abort();
+ }
+ capacity >>= 10; // convert to Kbytes
+ while (capacity > 4096) {
+ // (capacity - 1) must fit into 12 bits
+ exponent++;
+ capacity >>= 1;
+ }
+ capacity -= 1;
+ exponent -= 2;
+ if (exponent > 7)
+ cpu_abort(cpu_single_env, "exponent %d too big\n", exponent);
+
+ s->resp[2] |= (((uint32_t)capacity >> 2) & 0x3FF); // high 10 bits to bottom of resp[2]
+ s->resp[1] |= (((uint32_t)capacity & 3) << 30); // low 2 bits to top of resp[1]
+ s->resp[1] |= (exponent << (47 - 32));
+ }
+ break;
+ }
+
+ case MMC_SEND_EXT_CSD:
+ s->resp[0] = arg;
+ break;
+
+ case MMC_APP_CMD:
+ s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336
+ break;
+
+ case SD_APP_OP_COND:
+ s->resp[0] = 0x80FF8000;
+ break;
+
+ case SD_APP_SEND_SCR:
+ {
+ uint32_t* scr = (uint32_t*)s->buffer;
+ scr[0] = 0x00002502;
+ scr[1] = 0x00000000;
+ s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336
+ new_status |= MMC_STAT_END_OF_DATA;
+ break;
+ }
+ case MMC_SET_RELATIVE_ADDR:
+ s->resp[0] = -518519520;
+ break;
+
+ case MMC_ALL_SEND_CID:
+ s->resp[3] = 55788627;
+ s->resp[2] = 1429221959;
+ s->resp[1] = -2147479692;
+ s->resp[0] = -436179883;
+ break;
+
+ case MMC_SELECT_CARD:
+ s->resp[0] = SET_R1_CURRENT_STATE(3) | R1_READY_FOR_DATA; // 1792
+ break;
+
+ case MMC_SWITCH:
+ if (arg == 0x00FFFFF1 || arg == 0x80FFFFF1) {
+ uint8_t* switchbuf = s->buffer;
+ memset(switchbuf, 0, 64);
+ switchbuf[13] = 2;
+ new_status |= MMC_STAT_END_OF_DATA;
+ }
+ s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA | R1_APP_CMD; //2336
+ break;
+
+ case MMC_SET_BLOCKLEN:
+ s->block_length = arg;
+ s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304
+ break;
+
+ case MMC_READ_SINGLE_BLOCK:
+ s->block_count = 1;
+ // fall through
+ case MMC_READ_MULTIPLE_BLOCK: {
+ if (s->is_SDHC) {
+ // arg is block offset
+ } else {
+ // arg is byte offset
+ if (arg & 511) fprintf(stderr, "offset %d is not multiple of 512 when reading\n", arg);
+ arg /= s->block_length;
+ }
+ result = bdrv_read(s->bs, arg, s->buffer, s->block_count);
+ new_status |= MMC_STAT_END_OF_DATA;
+ s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304
+ break;
+ }
+
+ case MMC_WRITE_BLOCK:
+ s->block_count = 1;
+ // fall through
+ case MMC_WRITE_MULTIPLE_BLOCK: {
+ if (s->is_SDHC) {
+ // arg is block offset
+ } else {
+ // arg is byte offset
+ if (arg & 511) fprintf(stderr, "offset %d is not multiple of 512 when writing\n", arg);
+ arg /= s->block_length;
+ }
+ // arg is byte offset
+ result = bdrv_write(s->bs, arg, s->buffer, s->block_count);
+// bdrv_flush(s->bs);
+ new_status |= MMC_STAT_END_OF_DATA;
+ s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304
+ break;
+ }
+
+ case MMC_STOP_TRANSMISSION:
+ s->resp[0] = SET_R1_CURRENT_STATE(5) | R1_READY_FOR_DATA; // 2816
+ break;
+
+ case MMC_SEND_STATUS:
+ s->resp[0] = SET_R1_CURRENT_STATE(4) | R1_READY_FOR_DATA; // 2304
+ break;
+ }
+
+ s->int_status |= new_status;
+
+ if ((s->int_status & s->int_enable)) {
+ goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+ }
+}
+
+static uint32_t goldfish_mmc_read(void *opaque, target_phys_addr_t offset)
+{
+ uint32_t ret;
+ struct goldfish_mmc_state *s = opaque;
+
+ offset -= s->dev.base;
+ switch(offset) {
+ case MMC_INT_STATUS:
+ // return current buffer status flags
+ return s->int_status & s->int_enable;
+ case MMC_RESP_0:
+ return s->resp[0];
+ case MMC_RESP_1:
+ return s->resp[1];
+ case MMC_RESP_2:
+ return s->resp[2];
+ case MMC_RESP_3:
+ return s->resp[3];
+ case MMC_STATE: {
+ ret = MMC_STATE_INSERTED;
+ if (bdrv_is_read_only(s->bs)) {
+ ret |= MMC_STATE_READ_ONLY;
+ }
+ return ret;
+ }
+ default:
+ cpu_abort(cpu_single_env, "goldfish_mmc_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_mmc_write(void *opaque, target_phys_addr_t offset, uint32_t val)
+{
+ struct goldfish_mmc_state *s = opaque;
+ int status, old_status;
+
+ offset -= s->dev.base;
+
+ switch(offset) {
+
+ case MMC_INT_STATUS:
+ status = s->int_status;
+ old_status = status;
+ status &= ~val;
+ s->int_status = status;
+ if(status != old_status) {
+ goldfish_device_set_irq(&s->dev, 0, status);
+ }
+ break;
+
+ case MMC_INT_ENABLE:
+ /* enable buffer interrupts */
+ s->int_enable = val;
+ s->int_status = 0;
+ goldfish_device_set_irq(&s->dev, 0, (s->int_status & s->int_enable));
+ break;
+ case MMC_SET_BUFFER:
+ /* save pointer to buffer 1 */
+ s->buffer = phys_ram_base + val;
+ break;
+ case MMC_CMD:
+ goldfish_mmc_do_command(s, val, s->arg);
+ break;
+ case MMC_ARG:
+ s->arg = val;
+ break;
+ case MMC_BLOCK_LENGTH:
+ s->block_length = val + 1;
+ break;
+ case MMC_BLOCK_COUNT:
+ s->block_count = val + 1;
+ break;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_mmc_write: Bad offset %x\n", offset);
+ }
+}
+
+static CPUReadMemoryFunc *goldfish_mmc_readfn[] = {
+ goldfish_mmc_read,
+ goldfish_mmc_read,
+ goldfish_mmc_read
+};
+
+static CPUWriteMemoryFunc *goldfish_mmc_writefn[] = {
+ goldfish_mmc_write,
+ goldfish_mmc_write,
+ goldfish_mmc_write
+};
+
+void goldfish_mmc_init(uint32_t base, int id, BlockDriverState* bs)
+{
+ struct goldfish_mmc_state *s;
+
+ s = (struct goldfish_mmc_state *)qemu_mallocz(sizeof(*s));
+ s->dev.name = "goldfish_mmc";
+ s->dev.id = id;
+ s->dev.base = base;
+ s->dev.size = 0x1000;
+ s->dev.irq_count = 1;
+ s->bs = bs;
+
+ goldfish_device_add(&s->dev, goldfish_mmc_readfn, goldfish_mmc_writefn, s);
+
+ register_savevm( "goldfish_mmc", 0, GOLDFISH_MMC_SAVE_VERSION,
+ goldfish_mmc_save, goldfish_mmc_load, s);
+}
+
diff --git a/hw/goldfish_nand.c b/hw/goldfish_nand.c
new file mode 100644
index 0000000..e3042bf
--- /dev/null
+++ b/hw/goldfish_nand.c
@@ -0,0 +1,639 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "goldfish_nand_reg.h"
+#include "goldfish_nand.h"
+#include "android_utils.h"
+#include "android_debug.h"
+#include "android.h"
+
+#define DEBUG 1
+#if DEBUG
+# define D(...) VERBOSE_PRINT(nand,__VA_ARGS__)
+# define D_ACTIVE VERBOSE_CHECK(nand)
+# define T(...) VERBOSE_PRINT(nand_limits,__VA_ARGS__)
+# define T_ACTIVE VERBOSE_CHECK(nand_limits)
+#else
+# define D(...) ((void)0)
+# define D_ACTIVE 0
+# define T(...) ((void)0)
+# define T_ACTIVE 0
+#endif
+
+/* lseek uses 64-bit offsets on Darwin. */
+/* prefer lseek64 on Linux */
+#ifdef __APPLE__
+# define llseek lseek
+#elif defined(__linux__)
+# define llseek lseek64
+#endif
+
+#define XLOG xlog
+
+static void
+xlog( const char* format, ... )
+{
+ va_list args;
+ va_start(args, format);
+ fprintf(stderr, "NAND: ");
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+typedef struct {
+ char* devname;
+ size_t devname_len;
+ char* data;
+ int fd;
+ uint32_t flags;
+ uint32_t page_size;
+ uint32_t extra_size;
+ uint32_t erase_size;
+ uint64_t size;
+} nand_dev;
+
+nand_threshold android_nand_write_threshold;
+nand_threshold android_nand_read_threshold;
+
+#ifdef CONFIG_NAND_THRESHOLD
+
+/* update a threshold, return 1 if limit is hit, 0 otherwise */
+static void
+nand_threshold_update( nand_threshold* t, uint32_t len )
+{
+ if (t->counter < t->limit) {
+ uint64_t avail = t->limit - t->counter;
+ if (avail > len)
+ avail = len;
+
+ if (t->counter == 0) {
+ T("%s: starting threshold counting to %lld",
+ __FUNCTION__, t->limit);
+ }
+ t->counter += avail;
+ if (t->counter >= t->limit) {
+ /* threshold reach, send a signal to an external process */
+ T( "%s: sending signal %d to pid %d !",
+ __FUNCTION__, t->signal, t->pid );
+
+ kill( t->pid, t->signal );
+ }
+ }
+ return;
+}
+
+#define NAND_UPDATE_READ_THRESHOLD(len) \
+ nand_threshold_update( &android_nand_read_threshold, (uint32_t)(len) )
+
+#define NAND_UPDATE_WRITE_THRESHOLD(len) \
+ nand_threshold_update( &android_nand_write_threshold, (uint32_t)(len) )
+
+#else /* !NAND_THRESHOLD */
+
+#define NAND_UPDATE_READ_THRESHOLD(len) \
+ do {} while (0)
+
+#define NAND_UPDATE_WRITE_THRESHOLD(len) \
+ do {} while (0)
+
+#endif /* !NAND_THRESHOLD */
+
+static nand_dev *nand_devs = NULL;
+static uint32_t nand_dev_count = 0;
+
+typedef struct {
+ uint32_t base;
+
+ // register state
+ uint32_t dev;
+ uint32_t addr_low;
+ uint32_t addr_high;
+ uint32_t transfer_size;
+ uint32_t data;
+ uint32_t result;
+} nand_dev_state;
+
+/* update this everytime you change the nand_dev_state structure */
+#define NAND_DEV_STATE_SAVE_VERSION 1
+
+#define QFIELD_STRUCT nand_dev_state
+QFIELD_BEGIN(nand_dev_state_fields)
+ QFIELD_INT32(dev),
+ QFIELD_INT32(addr_low),
+ QFIELD_INT32(addr_high),
+ QFIELD_INT32(transfer_size),
+ QFIELD_INT32(data),
+ QFIELD_INT32(result),
+QFIELD_END
+
+static void nand_dev_state_save(QEMUFile* f, void* opaque)
+{
+ nand_dev_state* s = opaque;
+
+ qemu_put_struct(f, nand_dev_state_fields, s);
+}
+
+static int nand_dev_state_load(QEMUFile* f, void* opaque, int version_id)
+{
+ nand_dev_state* s = opaque;
+
+ if (version_id != NAND_DEV_STATE_SAVE_VERSION)
+ return -1;
+
+ return qemu_get_struct(f, nand_dev_state_fields, s);
+}
+
+
+extern void vmemcpy(target_ulong ptr, char *buf, int size); /* copy memory from the simulated virtual space to a buffer in QEMU */
+extern void pmemcpy(target_ulong ptr, char *buf, int size); /* copy memory from the QEMU buffer to simulated virtual space */
+
+static int do_read(int fd, void* buf, size_t size)
+{
+ int ret;
+ do {
+ ret = read(fd, buf, size);
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+
+static int do_write(int fd, const void* buf, size_t size)
+{
+ int ret;
+ do {
+ ret = write(fd, buf, size);
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+
+static uint32_t nand_dev_read_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len)
+{
+ uint32_t len = total_len;
+ size_t read_len = dev->erase_size;
+ int eof = 0;
+
+ NAND_UPDATE_READ_THRESHOLD(total_len);
+
+ lseek(dev->fd, addr, SEEK_SET);
+ while(len > 0) {
+ if(read_len < dev->erase_size) {
+ memset(dev->data, 0xff, dev->erase_size);
+ read_len = dev->erase_size;
+ eof = 1;
+ }
+ if(len < read_len)
+ read_len = len;
+ if(!eof) {
+ read_len = do_read(dev->fd, dev->data, read_len);
+ }
+ pmemcpy(data, dev->data, read_len);
+ data += read_len;
+ len -= read_len;
+ }
+ return total_len;
+}
+
+static uint32_t nand_dev_write_file(nand_dev *dev, uint32_t data, uint64_t addr, uint32_t total_len)
+{
+ uint32_t len = total_len;
+ size_t write_len = dev->erase_size;
+ int ret;
+
+ NAND_UPDATE_WRITE_THRESHOLD(total_len);
+
+ lseek(dev->fd, addr, SEEK_SET);
+ while(len > 0) {
+ if(len < write_len)
+ write_len = len;
+ vmemcpy(data, dev->data, write_len);
+ ret = do_write(dev->fd, dev->data, write_len);
+ if(ret < write_len) {
+ XLOG("nand_dev_write_file, write failed: %s\n", strerror(errno));
+ break;
+ }
+ data += write_len;
+ len -= write_len;
+ }
+ return total_len - len;
+}
+
+static uint32_t nand_dev_erase_file(nand_dev *dev, uint64_t addr, uint32_t total_len)
+{
+ uint32_t len = total_len;
+ size_t write_len = dev->erase_size;
+ int ret;
+
+ lseek(dev->fd, addr, SEEK_SET);
+ memset(dev->data, 0xff, dev->erase_size);
+ while(len > 0) {
+ if(len < write_len)
+ write_len = len;
+ ret = do_write(dev->fd, dev->data, write_len);
+ if(ret < write_len) {
+ XLOG( "nand_dev_write_file, write failed: %s\n", strerror(errno));
+ break;
+ }
+ len -= write_len;
+ }
+ return total_len - len;
+}
+
+/* this is a huge hack required to make the PowerPC emulator binary usable
+ * on Mac OS X. If you define this function as 'static', the emulated kernel
+ * will panic when attempting to mount the /data partition.
+ *
+ * worse, if you do *not* define the function as static on Linux-x86, the
+ * emulated kernel will also panic !?
+ *
+ * I still wonder if this is a compiler bug, or due to some nasty thing the
+ * emulator does with CPU registers during execution of the translated code.
+ */
+#if !(defined __APPLE__ && defined __powerpc__)
+static
+#endif
+uint32_t nand_dev_do_cmd(nand_dev_state *s, uint32_t cmd)
+{
+ uint32_t size;
+ uint64_t addr;
+ nand_dev *dev;
+
+ addr = s->addr_low | ((uint64_t)s->addr_high << 32);
+ size = s->transfer_size;
+ if(s->dev >= nand_dev_count)
+ return 0;
+ dev = nand_devs + s->dev;
+
+ switch(cmd) {
+ case NAND_CMD_GET_DEV_NAME:
+ if(size > dev->devname_len)
+ size = dev->devname_len;
+ pmemcpy(s->data, dev->devname, size);
+ return size;
+ case NAND_CMD_READ:
+ if(addr >= dev->size)
+ return 0;
+ if(size + addr > dev->size)
+ size = dev->size - addr;
+ if(dev->fd >= 0)
+ return nand_dev_read_file(dev, s->data, addr, size);
+ pmemcpy(s->data, &dev->data[addr], size);
+ return size;
+ case NAND_CMD_WRITE:
+ if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
+ return 0;
+ if(addr >= dev->size)
+ return 0;
+ if(size + addr > dev->size)
+ size = dev->size - addr;
+ if(dev->fd >= 0)
+ return nand_dev_write_file(dev, s->data, addr, size);
+ vmemcpy(s->data, &dev->data[addr], size);
+ return size;
+ case NAND_CMD_ERASE:
+ if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
+ return 0;
+ if(addr >= dev->size)
+ return 0;
+ if(size + addr > dev->size)
+ size = dev->size - addr;
+ if(dev->fd >= 0)
+ return nand_dev_erase_file(dev, addr, size);
+ memset(&dev->data[addr], 0xff, size);
+ return size;
+ case NAND_CMD_BLOCK_BAD_GET: // no bad block support
+ return 0;
+ case NAND_CMD_BLOCK_BAD_SET:
+ if(dev->flags & NAND_DEV_FLAG_READ_ONLY)
+ return 0;
+ return 0;
+ default:
+ cpu_abort(cpu_single_env, "nand_dev_do_cmd: Bad command %x\n", cmd);
+ return 0;
+ }
+}
+
+/* I/O write */
+static void nand_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ nand_dev_state *s = (nand_dev_state *)opaque;
+
+ offset -= s->base;
+ switch (offset) {
+ case NAND_DEV:
+ s->dev = value;
+ if(s->dev >= nand_dev_count) {
+ cpu_abort(cpu_single_env, "nand_dev_write: Bad dev %x\n", value);
+ }
+ break;
+ case NAND_ADDR_HIGH:
+ s->addr_high = value;
+ break;
+ case NAND_ADDR_LOW:
+ s->addr_low = value;
+ break;
+ case NAND_TRANSFER_SIZE:
+ s->transfer_size = value;
+ break;
+ case NAND_DATA:
+ s->data = value;
+ break;
+ case NAND_COMMAND:
+ s->result = nand_dev_do_cmd(s, value);
+ break;
+ default:
+ cpu_abort(cpu_single_env, "nand_dev_write: Bad offset %x\n", offset);
+ break;
+ }
+}
+
+/* I/O read */
+static uint32_t nand_dev_read(void *opaque, target_phys_addr_t offset)
+{
+ nand_dev_state *s = (nand_dev_state *)opaque;
+ nand_dev *dev;
+
+ offset -= s->base;
+ switch (offset) {
+ case NAND_VERSION:
+ return NAND_VERSION_CURRENT;
+ case NAND_NUM_DEV:
+ return nand_dev_count;
+ case NAND_RESULT:
+ return s->result;
+ }
+
+ if(s->dev >= nand_dev_count)
+ return 0;
+
+ dev = nand_devs + s->dev;
+
+ switch (offset) {
+ case NAND_DEV_FLAGS:
+ return dev->flags;
+
+ case NAND_DEV_NAME_LEN:
+ return dev->devname_len;
+
+ case NAND_DEV_PAGE_SIZE:
+ return dev->page_size;
+
+ case NAND_DEV_EXTRA_SIZE:
+ return dev->extra_size;
+
+ case NAND_DEV_ERASE_SIZE:
+ return dev->erase_size;
+
+ case NAND_DEV_SIZE_LOW:
+ return (uint32_t)dev->size;
+
+ case NAND_DEV_SIZE_HIGH:
+ return (uint32_t)(dev->size >> 32);
+
+ default:
+ cpu_abort(cpu_single_env, "nand_dev_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static CPUReadMemoryFunc *nand_dev_readfn[] = {
+ nand_dev_read,
+ nand_dev_read,
+ nand_dev_read
+};
+
+static CPUWriteMemoryFunc *nand_dev_writefn[] = {
+ nand_dev_write,
+ nand_dev_write,
+ nand_dev_write
+};
+
+/* initialize the QFB device */
+void nand_dev_init(uint32_t base)
+{
+ int iomemtype;
+ static int instance_id = 0;
+ nand_dev_state *s;
+
+ s = (nand_dev_state *)qemu_mallocz(sizeof(nand_dev_state));
+ iomemtype = cpu_register_io_memory(0, nand_dev_readfn, nand_dev_writefn, s);
+ cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+ s->base = base;
+
+ register_savevm( "nand_dev", instance_id++, NAND_DEV_STATE_SAVE_VERSION,
+ nand_dev_state_save, nand_dev_state_load, s);
+}
+
+static int arg_match(const char *a, const char *b, size_t b_len)
+{
+ while(*a && b_len--) {
+ if(*a++ != *b++)
+ return 0;
+ }
+ return b_len == 0;
+}
+
+void nand_add_dev(const char *arg)
+{
+ uint64_t dev_size = 0;
+ const char *next_arg;
+ const char *value;
+ size_t arg_len, value_len;
+ nand_dev *new_devs, *dev;
+ char *devname = NULL;
+ size_t devname_len = 0;
+ char *initfilename = NULL;
+ char *rwfilename = NULL;
+ int initfd = -1;
+ int rwfd = -1;
+ int read_only = 0;
+ int pad;
+ ssize_t read_size;
+ uint32_t page_size = 2048;
+ uint32_t extra_size = 64;
+ uint32_t erase_pages = 64;
+
+ while(arg) {
+ next_arg = strchr(arg, ',');
+ value = strchr(arg, '=');
+ if(next_arg != NULL) {
+ arg_len = next_arg - arg;
+ next_arg++;
+ if(value >= next_arg)
+ value = NULL;
+ }
+ else
+ arg_len = strlen(arg);
+ if(value != NULL) {
+ size_t new_arg_len = value - arg;
+ value_len = arg_len - new_arg_len - 1;
+ arg_len = new_arg_len;
+ value++;
+ }
+ else
+ value_len = 0;
+
+ if(devname == NULL) {
+ if(value != NULL)
+ goto bad_arg_and_value;
+ devname_len = arg_len;
+ devname = malloc(arg_len);
+ if(devname == NULL)
+ goto out_of_memory;
+ memcpy(devname, arg, arg_len);
+ }
+ else if(value == NULL) {
+ if(arg_match("readonly", arg, arg_len)) {
+ read_only = 1;
+ }
+ else {
+ XLOG("bad arg: %.*s\n", arg_len, arg);
+ exit(1);
+ }
+ }
+ else {
+ if(arg_match("size", arg, arg_len)) {
+ char *ep;
+ dev_size = strtoull(value, &ep, 0);
+ if(ep != value + value_len)
+ goto bad_arg_and_value;
+ }
+ else if(arg_match("pagesize", arg, arg_len)) {
+ char *ep;
+ page_size = strtoul(value, &ep, 0);
+ if(ep != value + value_len)
+ goto bad_arg_and_value;
+ }
+ else if(arg_match("extrasize", arg, arg_len)) {
+ char *ep;
+ extra_size = strtoul(value, &ep, 0);
+ if(ep != value + value_len)
+ goto bad_arg_and_value;
+ }
+ else if(arg_match("erasepages", arg, arg_len)) {
+ char *ep;
+ erase_pages = strtoul(value, &ep, 0);
+ if(ep != value + value_len)
+ goto bad_arg_and_value;
+ }
+ else if(arg_match("initfile", arg, arg_len)) {
+ initfilename = malloc(value_len + 1);
+ if(initfilename == NULL)
+ goto out_of_memory;
+ memcpy(initfilename, value, value_len);
+ initfilename[value_len] = '\0';
+ }
+ else if(arg_match("file", arg, arg_len)) {
+ rwfilename = malloc(value_len + 1);
+ if(rwfilename == NULL)
+ goto out_of_memory;
+ memcpy(rwfilename, value, value_len);
+ rwfilename[value_len] = '\0';
+ }
+ else {
+ goto bad_arg_and_value;
+ }
+ }
+
+ arg = next_arg;
+ }
+
+ if (rwfilename == NULL) {
+ /* we create a temporary file to store everything */
+ TempFile* tmp = tempfile_create();
+
+ if (tmp == NULL) {
+ XLOG("could not create temp file for %.*s NAND disk image: %s",
+ devname_len, devname, strerror(errno));
+ exit(1);
+ }
+ rwfilename = (char*) tempfile_path(tmp);
+ if (VERBOSE_CHECK(init))
+ dprint( "mapping '%.*s' NAND image to %s", devname_len, devname, rwfilename);
+ }
+
+ if(rwfilename) {
+ rwfd = open(rwfilename, O_BINARY | (read_only ? O_RDONLY : O_RDWR));
+ if(rwfd < 0 && read_only) {
+ XLOG("could not open file %s, %s\n", rwfilename, strerror(errno));
+ exit(1);
+ }
+ /* this could be a writable temporary file. use atexit_close_fd to ensure
+ * that it is properly cleaned up at exit on Win32
+ */
+ if (!read_only)
+ atexit_close_fd(rwfd);
+ }
+
+ if(initfilename) {
+ initfd = open(initfilename, O_BINARY | O_RDONLY);
+ if(initfd < 0) {
+ XLOG("could not open file %s, %s\n", initfilename, strerror(errno));
+ exit(1);
+ }
+ if(dev_size == 0) {
+ dev_size = lseek(initfd, 0, SEEK_END);
+ lseek(initfd, 0, SEEK_SET);
+ }
+ }
+
+ new_devs = realloc(nand_devs, sizeof(nand_devs[0]) * (nand_dev_count + 1));
+ if(new_devs == NULL)
+ goto out_of_memory;
+ nand_devs = new_devs;
+ dev = &new_devs[nand_dev_count];
+
+ dev->page_size = page_size;
+ dev->extra_size = extra_size;
+ dev->erase_size = erase_pages * (page_size + extra_size);
+ pad = dev_size % dev->erase_size;
+ if (pad != 0) {
+ dev_size += (dev->erase_size - pad);
+ XLOG("rounding devsize up to a full eraseunit, now %llx\n", dev_size);
+ }
+ dev->devname = devname;
+ dev->devname_len = devname_len;
+ dev->size = dev_size;
+ dev->data = malloc(dev->erase_size);
+ if(dev->data == NULL)
+ goto out_of_memory;
+ dev->flags = read_only ? NAND_DEV_FLAG_READ_ONLY : 0;
+
+ if (initfd >= 0) {
+ do {
+ read_size = do_read(initfd, dev->data, dev->erase_size);
+ if(read_size < 0) {
+ XLOG("could not read file %s, %s\n", initfilename, strerror(errno));
+ exit(1);
+ }
+ if(do_write(rwfd, dev->data, read_size) != read_size) {
+ XLOG("could not write file %s, %s\n", initfilename, strerror(errno));
+ exit(1);
+ }
+ } while(read_size == dev->erase_size);
+ close(initfd);
+ }
+ dev->fd = rwfd;
+
+ nand_dev_count++;
+
+ return;
+
+out_of_memory:
+ XLOG("out of memory\n");
+ exit(1);
+
+bad_arg_and_value:
+ XLOG("bad arg: %.*s=%.*s\n", arg_len, arg, value_len, value);
+ exit(1);
+}
+
diff --git a/hw/goldfish_nand.h b/hw/goldfish_nand.h
new file mode 100644
index 0000000..dcc59d8
--- /dev/null
+++ b/hw/goldfish_nand.h
@@ -0,0 +1,28 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef NAND_DEVICE_H
+#define NAND_DEVICE_H
+
+void nand_dev_init(uint32_t base);
+void nand_add_dev(const char *arg);
+
+typedef struct {
+ uint64_t limit;
+ uint64_t counter;
+ int pid;
+ int signal;
+} nand_threshold;
+
+extern nand_threshold android_nand_read_threshold;
+extern nand_threshold android_nand_write_threshold;
+
+#endif
diff --git a/hw/goldfish_nand_reg.h b/hw/goldfish_nand_reg.h
new file mode 100644
index 0000000..ea91461
--- /dev/null
+++ b/hw/goldfish_nand_reg.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef NAND_DEVICE_REG_H
+#define NAND_DEVICE_REG_H
+
+enum nand_cmd {
+ NAND_CMD_GET_DEV_NAME, // Write device name for NAND_DEV to NAND_DATA (vaddr)
+ NAND_CMD_READ,
+ NAND_CMD_WRITE,
+ NAND_CMD_ERASE,
+ NAND_CMD_BLOCK_BAD_GET, // NAND_RESULT is 1 if block is bad, 0 if it is not
+ NAND_CMD_BLOCK_BAD_SET
+};
+
+enum nand_dev_flags {
+ NAND_DEV_FLAG_READ_ONLY = 0x00000001
+};
+
+#define NAND_VERSION_CURRENT (1)
+
+enum nand_reg {
+ // Global
+ NAND_VERSION = 0x000,
+ NAND_NUM_DEV = 0x004,
+ NAND_DEV = 0x008,
+
+ // Dev info
+ NAND_DEV_FLAGS = 0x010,
+ NAND_DEV_NAME_LEN = 0x014,
+ NAND_DEV_PAGE_SIZE = 0x018,
+ NAND_DEV_EXTRA_SIZE = 0x01c,
+ NAND_DEV_ERASE_SIZE = 0x020,
+ NAND_DEV_SIZE_LOW = 0x028,
+ NAND_DEV_SIZE_HIGH = 0x02c,
+
+ // Command
+ NAND_RESULT = 0x040,
+ NAND_COMMAND = 0x044,
+ NAND_DATA = 0x048,
+ NAND_TRANSFER_SIZE = 0x04c,
+ NAND_ADDR_LOW = 0x050,
+ NAND_ADDR_HIGH = 0x054,
+};
+
+#endif
diff --git a/hw/goldfish_switch.c b/hw/goldfish_switch.c
new file mode 100644
index 0000000..04fcad7
--- /dev/null
+++ b/hw/goldfish_switch.c
@@ -0,0 +1,172 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "goldfish_device.h"
+
+enum {
+ SW_NAME_LEN = 0x00,
+ SW_NAME_PTR = 0x04,
+ SW_FLAGS = 0x08,
+ SW_STATE = 0x0c,
+ SW_INT_STATUS = 0x10,
+ SW_INT_ENABLE = 0x14,
+
+ SW_FLAGS_OUTPUT = 1U << 0
+};
+
+
+struct switch_state {
+ struct goldfish_device dev;
+ char *name;
+ uint32_t state;
+ uint32_t state_changed : 1;
+ uint32_t int_enable : 1;
+ uint32_t (*writefn)(void *opaque, uint32_t state);
+ void *writeopaque;
+};
+
+#define GOLDFISH_SWITCH_SAVE_VERSION 1
+
+static void goldfish_switch_save(QEMUFile* f, void* opaque)
+{
+ struct switch_state* s = opaque;
+
+ qemu_put_be32(f, s->state);
+ qemu_put_byte(f, s->state_changed);
+ qemu_put_byte(f, s->int_enable);
+}
+
+static int goldfish_switch_load(QEMUFile* f, void* opaque, int version_id)
+{
+ struct switch_state* s = opaque;
+
+ if (version_id != GOLDFISH_SWITCH_SAVE_VERSION)
+ return -1;
+
+ s->state = qemu_get_be32(f);
+ s->state_changed = qemu_get_byte(f);
+ s->int_enable = qemu_get_byte(f);
+
+ return 0;
+}
+
+static uint32_t goldfish_switch_read(void *opaque, target_phys_addr_t offset)
+{
+ struct switch_state *s = (struct switch_state *)opaque;
+ offset -= s->dev.base;
+
+ //printf("goldfish_switch_read %x %x\n", offset, size);
+
+ switch (offset) {
+ case SW_NAME_LEN:
+ return strlen(s->name);
+ case SW_FLAGS:
+ return s->writefn ? SW_FLAGS_OUTPUT : 0;
+ case SW_STATE:
+ return s->state;
+ case SW_INT_STATUS:
+ if(s->state_changed && s->int_enable) {
+ s->state_changed = 0;
+ goldfish_device_set_irq(&s->dev, 0, 0);
+ return 1;
+ }
+ return 0;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_switch_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_switch_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ struct switch_state *s = (struct switch_state *)opaque;
+ offset -= s->dev.base;
+
+ //printf("goldfish_switch_read %x %x %x\n", offset, value, size);
+
+ switch(offset) {
+ case SW_NAME_PTR:
+ pmemcpy(value, s->name, strlen(s->name));
+ break;
+
+ case SW_STATE:
+ if(s->writefn) {
+ uint32_t new_state;
+ new_state = s->writefn(s->writeopaque, value);
+ if(new_state != s->state) {
+ goldfish_switch_set_state(s, new_state);
+ }
+ }
+ else
+ cpu_abort (cpu_single_env, "goldfish_switch_write: write to SW_STATE on input\n");
+ break;
+
+ case SW_INT_ENABLE:
+ value &= 1;
+ if(s->state_changed && s->int_enable != value)
+ goldfish_device_set_irq(&s->dev, 0, value);
+ s->int_enable = value;
+ break;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_switch_write: Bad offset %x\n", offset);
+ }
+}
+
+static CPUReadMemoryFunc *goldfish_switch_readfn[] = {
+ goldfish_switch_read,
+ goldfish_switch_read,
+ goldfish_switch_read
+};
+
+static CPUWriteMemoryFunc *goldfish_switch_writefn[] = {
+ goldfish_switch_write,
+ goldfish_switch_write,
+ goldfish_switch_write
+};
+
+void goldfish_switch_set_state(void *opaque, uint32_t state)
+{
+ struct switch_state *s = opaque;
+ s->state_changed = 1;
+ s->state = state;
+ if(s->int_enable)
+ goldfish_device_set_irq(&s->dev, 0, 1);
+}
+
+void *goldfish_switch_add(char *name, uint32_t (*writefn)(void *opaque, uint32_t state), void *writeopaque, int id)
+{
+ int ret;
+ struct switch_state *s;
+
+ s = qemu_mallocz(sizeof(*s));
+ s->dev.name = "goldfish-switch";
+ s->dev.id = id;
+ s->dev.size = 0x1000;
+ s->dev.irq_count = 1;
+ s->name = name;
+ s->writefn = writefn;
+ s->writeopaque = writeopaque;
+
+
+ ret = goldfish_device_add(&s->dev, goldfish_switch_readfn, goldfish_switch_writefn, s);
+ if(ret) {
+ qemu_free(s);
+ return NULL;
+ }
+
+ register_savevm( "goldfish_switch", 0, GOLDFISH_SWITCH_SAVE_VERSION,
+ goldfish_switch_save, goldfish_switch_load, s);
+
+ return s;
+}
+
diff --git a/hw/goldfish_timer.c b/hw/goldfish_timer.c
new file mode 100644
index 0000000..bb345a5
--- /dev/null
+++ b/hw/goldfish_timer.c
@@ -0,0 +1,255 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "arm_pic.h"
+#include "goldfish_device.h"
+
+enum {
+ TIMER_TIME_LOW = 0x00, // get low bits of current time and update TIMER_TIME_HIGH
+ TIMER_TIME_HIGH = 0x04, // get high bits of time at last TIMER_TIME_LOW read
+ TIMER_ALARM_LOW = 0x08, // set low bits of alarm and activate it
+ TIMER_ALARM_HIGH = 0x0c, // set high bits of next alarm
+ TIMER_CLEAR_INTERRUPT = 0x10,
+ TIMER_CLEAR_ALARM = 0x14
+};
+
+struct timer_state {
+ struct goldfish_device dev;
+ uint32_t alarm_low;
+ int32_t alarm_high;
+ int64_t now;
+ int armed;
+ QEMUTimer *timer;
+};
+
+#define GOLDFISH_TIMER_SAVE_VERSION 1
+
+static void goldfish_timer_save(QEMUFile* f, void* opaque)
+{
+ struct timer_state* s = opaque;
+
+ qemu_put_be64(f, s->now); /* in case the kernel is in the middle of a timer read */
+ qemu_put_byte(f, s->armed);
+ if (s->armed) {
+ int64_t now = qemu_get_clock(vm_clock);
+ int64_t alarm = muldiv64(s->alarm_low | (int64_t)s->alarm_high << 32, ticks_per_sec, 1000000000);
+ qemu_put_be64(f, alarm-now);
+ }
+}
+
+static int goldfish_timer_load(QEMUFile* f, void* opaque, int version_id)
+{
+ struct timer_state* s = opaque;
+
+ if (version_id != GOLDFISH_TIMER_SAVE_VERSION)
+ return -1;
+
+ s->now = qemu_get_be64(f);
+ s->armed = qemu_get_byte(f);
+ if (s->armed) {
+ int64_t now = qemu_get_clock(vm_clock);
+ int64_t diff = qemu_get_be64(f);
+ int64_t alarm = now + diff;
+
+ if (alarm <= now) {
+ goldfish_device_set_irq(&s->dev, 0, 1);
+ s->armed = 0;
+ } else {
+ qemu_mod_timer(s->timer, alarm);
+ }
+ }
+ return 0;
+}
+
+static uint32_t goldfish_timer_read(void *opaque, target_phys_addr_t offset)
+{
+ struct timer_state *s = (struct timer_state *)opaque;
+ offset -= s->dev.base;
+ switch(offset) {
+ case TIMER_TIME_LOW:
+ s->now = muldiv64(qemu_get_clock(vm_clock), 1000000000, ticks_per_sec);
+ return s->now;
+ case TIMER_TIME_HIGH:
+ return s->now >> 32;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_timer_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_timer_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ struct timer_state *s = (struct timer_state *)opaque;
+ int64_t alarm, now;
+ offset -= s->dev.base;
+ switch(offset) {
+ case TIMER_ALARM_LOW:
+ s->alarm_low = value;
+ alarm = muldiv64(s->alarm_low | (int64_t)s->alarm_high << 32, ticks_per_sec, 1000000000);
+ now = qemu_get_clock(vm_clock);
+ if (alarm <= now) {
+ goldfish_device_set_irq(&s->dev, 0, 1);
+ } else {
+ qemu_mod_timer(s->timer, alarm);
+ s->armed = 1;
+ }
+ break;
+ case TIMER_ALARM_HIGH:
+ s->alarm_high = value;
+ //printf("alarm_high %d\n", s->alarm_high);
+ break;
+ case TIMER_CLEAR_ALARM:
+ qemu_del_timer(s->timer);
+ s->armed = 0;
+ /* fall through */
+ case TIMER_CLEAR_INTERRUPT:
+ goldfish_device_set_irq(&s->dev, 0, 0);
+ break;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_timer_write: Bad offset %x\n", offset);
+ }
+}
+
+static void goldfish_timer_tick(void *opaque)
+{
+ struct timer_state *s = (struct timer_state *)opaque;
+
+ s->armed = 0;
+ goldfish_device_set_irq(&s->dev, 0, 1);
+}
+
+struct rtc_state {
+ struct goldfish_device dev;
+ uint32_t alarm_low;
+ int32_t alarm_high;
+ int64_t now;
+};
+
+/* we save the RTC for the case where the kernel is in the middle of a rtc_read
+ * (i.e. it has read the low 32-bit of s->now, but not the high 32-bits yet */
+#define GOLDFISH_RTC_SAVE_VERSION 1
+
+static void goldfish_rtc_save(QEMUFile* f, void* opaque)
+{
+ struct rtc_state* s = opaque;
+
+ qemu_put_be64(f, s->now);
+}
+
+static int goldfish_rtc_load(QEMUFile* f, void* opaque, int version_id)
+{
+ struct rtc_state* s = opaque;
+
+ if (version_id != GOLDFISH_RTC_SAVE_VERSION)
+ return -1;
+
+ /* this is an old value that is not correct. but that's ok anyway */
+ s->now = qemu_get_be64(f);
+ return 0;
+}
+
+static uint32_t goldfish_rtc_read(void *opaque, target_phys_addr_t offset)
+{
+ struct rtc_state *s = (struct rtc_state *)opaque;
+ offset -= s->dev.base;
+ switch(offset) {
+ case 0x0:
+ s->now = (int64_t)time(NULL) * 1000000000;
+ return s->now;
+ case 0x4:
+ return s->now >> 32;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_rtc_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_rtc_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ struct rtc_state *s = (struct rtc_state *)opaque;
+ int64_t alarm;
+ offset -= s->dev.base;
+ switch(offset) {
+ case 0x8:
+ s->alarm_low = value;
+ alarm = s->alarm_low | (int64_t)s->alarm_high << 32;
+ //printf("next alarm at %lld, tps %lld\n", alarm, ticks_per_sec);
+ //qemu_mod_timer(s->timer, alarm);
+ break;
+ case 0xc:
+ s->alarm_high = value;
+ //printf("alarm_high %d\n", s->alarm_high);
+ break;
+ case 0x10:
+ goldfish_device_set_irq(&s->dev, 0, 0);
+ break;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_rtc_write: Bad offset %x\n", offset);
+ }
+}
+
+static struct timer_state timer_state = {
+ .dev = {
+ .name = "goldfish_timer",
+ .id = -1,
+ .size = 0x1000,
+ .irq_count = 1,
+ }
+};
+
+static struct timer_state rtc_state = {
+ .dev = {
+ .name = "goldfish_rtc",
+ .id = -1,
+ .size = 0x1000,
+ .irq_count = 1,
+ }
+};
+
+static CPUReadMemoryFunc *goldfish_timer_readfn[] = {
+ goldfish_timer_read,
+ goldfish_timer_read,
+ goldfish_timer_read
+};
+
+static CPUWriteMemoryFunc *goldfish_timer_writefn[] = {
+ goldfish_timer_write,
+ goldfish_timer_write,
+ goldfish_timer_write
+};
+
+static CPUReadMemoryFunc *goldfish_rtc_readfn[] = {
+ goldfish_rtc_read,
+ goldfish_rtc_read,
+ goldfish_rtc_read
+};
+
+static CPUWriteMemoryFunc *goldfish_rtc_writefn[] = {
+ goldfish_rtc_write,
+ goldfish_rtc_write,
+ goldfish_rtc_write
+};
+
+void goldfish_timer_and_rtc_init(uint32_t timerbase, int timerirq)
+{
+ timer_state.dev.base = timerbase;
+ timer_state.dev.irq = timerirq;
+ timer_state.timer = qemu_new_timer(vm_clock, goldfish_timer_tick, &timer_state);
+ goldfish_device_add(&timer_state.dev, goldfish_timer_readfn, goldfish_timer_writefn, &timer_state);
+ register_savevm( "goldfish_timer", 0, GOLDFISH_TIMER_SAVE_VERSION,
+ goldfish_timer_save, goldfish_timer_load, &timer_state);
+
+ goldfish_device_add(&rtc_state.dev, goldfish_rtc_readfn, goldfish_rtc_writefn, &rtc_state);
+ register_savevm( "goldfish_rtc", 0, GOLDFISH_RTC_SAVE_VERSION,
+ goldfish_rtc_save, goldfish_rtc_load, &rtc_state);
+}
+
diff --git a/hw/goldfish_trace.c b/hw/goldfish_trace.c
new file mode 100644
index 0000000..47822b3
--- /dev/null
+++ b/hw/goldfish_trace.c
@@ -0,0 +1,252 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+/*
+ * Virtual hardware for bridging the FUSE kernel module
+ * in the emulated OS and outside file system
+ */
+#include "vl.h"
+
+#include "goldfish_trace.h"
+
+//#define DEBUG 1
+
+extern void cpu_loop_exit(void);
+
+extern int tracing;
+
+/* for execve */
+static char path[CLIENT_PAGE_SIZE];
+static char arg[CLIENT_PAGE_SIZE];
+static unsigned long vstart; // VM start
+static unsigned long vend; // VM end
+static unsigned long eoff; // offset in EXE file
+static unsigned cmdlen; // cmdline length
+static unsigned pid; // PID (really thread id)
+static unsigned tgid; // thread group id (really process id)
+static unsigned long dsaddr; // dynamic symbol address
+static unsigned long unmap_start; // start address to unmap
+
+/* for context switch */
+//static unsigned long cs_pid; // context switch PID
+
+/* I/O write */
+static void trace_dev_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ trace_dev_state *s = (trace_dev_state *)opaque;
+
+ offset -= s->base;
+ switch (offset >> 2) {
+ case TRACE_DEV_REG_SWITCH: // context switch, switch to pid
+ trace_switch(value);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, context switch %u\n", value);
+#endif
+ break;
+ case TRACE_DEV_REG_TGID: // save the tgid for the following fork/clone
+ tgid = value;
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, tgid %u\n", value);
+#endif
+ break;
+ case TRACE_DEV_REG_FORK: // fork, fork new pid
+ trace_fork(tgid, value);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, fork %u\n", value);
+#endif
+ break;
+ case TRACE_DEV_REG_CLONE: // fork, clone new pid (i.e. thread)
+ trace_clone(tgid, value);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, clone %u\n", value);
+#endif
+ break;
+ case TRACE_DEV_REG_EXECVE_VMSTART: // execve, vstart
+ vstart = value;
+ break;
+ case TRACE_DEV_REG_EXECVE_VMEND: // execve, vend
+ vend = value;
+ break;
+ case TRACE_DEV_REG_EXECVE_OFFSET: // execve, offset in EXE
+ eoff = value;
+ break;
+ case TRACE_DEV_REG_EXECVE_EXEPATH: // init exec, path of EXE
+ vstrcpy(value, path, CLIENT_PAGE_SIZE);
+ trace_init_exec(vstart, vend, eoff, path);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, init exec [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
+#endif
+ path[0] = 0;
+ break;
+ case TRACE_DEV_REG_CMDLINE_LEN: // execve, process cmdline length
+ cmdlen = value;
+ break;
+ case TRACE_DEV_REG_CMDLINE: // execve, process cmdline
+ vmemcpy(value, arg, cmdlen);
+ trace_execve(arg, cmdlen);
+#ifdef DEBUG
+ {
+ int i;
+ for (i = 0; i < cmdlen; i ++)
+ if (i != cmdlen - 1 && arg[i] == 0)
+ arg[i] = ' ';
+ printf("QEMU.trace: kernel, execve %s[%d]\n", arg, cmdlen);
+ }
+#endif
+ arg[0] = 0;
+ break;
+ case TRACE_DEV_REG_EXIT: // exit, exit current process with exit code
+ trace_exit(value);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, exit %x\n", value);
+#endif
+ break;
+ case TRACE_DEV_REG_NAME: // record thread name
+ vstrcpy(value, path, CLIENT_PAGE_SIZE);
+
+ // Remove the trailing newline if it exists
+ int len = strlen(path);
+ if (path[len - 1] == '\n') {
+ path[len - 1] = 0;
+ }
+ trace_name(path);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, name %s\n", path);
+#endif
+ break;
+ case TRACE_DEV_REG_MMAP_EXEPATH: // mmap, path of EXE, the others are same as execve
+ vstrcpy(value, path, CLIENT_PAGE_SIZE);
+ trace_mmap(vstart, vend, eoff, path);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, mmap [%lx,%lx]@%lx [%s]\n", vstart, vend, eoff, path);
+#endif
+ path[0] = 0;
+ break;
+ case TRACE_DEV_REG_INIT_PID: // init, name the pid that starts before device registered
+ pid = value;
+ break;
+ case TRACE_DEV_REG_INIT_NAME: // init, the comm of the init pid
+ vstrcpy(value, path, CLIENT_PAGE_SIZE);
+ trace_init_name(tgid, pid, path);
+#ifdef DEBUG
+ printf("QEMU.trace: kernel, init name %u [%s]\n", pid, path);
+#endif
+ path[0] = 0;
+ break;
+
+ case TRACE_DEV_REG_DYN_SYM_ADDR: // dynamic symbol address
+ dsaddr = value;
+ break;
+ case TRACE_DEV_REG_DYN_SYM: // add dynamic symbol
+ vstrcpy(value, arg, CLIENT_PAGE_SIZE);
+ trace_dynamic_symbol_add(dsaddr, arg);
+#ifdef DEBUG
+ printf("QEMU.trace: dynamic symbol %lx:%s\n", dsaddr, arg);
+#endif
+ arg[0] = 0;
+ break;
+ case TRACE_DEV_REG_REMOVE_ADDR: // remove dynamic symbol addr
+ trace_dynamic_symbol_remove(value);
+#ifdef DEBUG
+ printf("QEMU.trace: dynamic symbol remove %lx\n", dsaddr);
+#endif
+ arg[0] = 0;
+ break;
+
+ case TRACE_DEV_REG_PRINT_STR: // print string
+ vstrcpy(value, arg, CLIENT_PAGE_SIZE);
+ printf("%s", arg);
+ arg[0] = 0;
+ break;
+ case TRACE_DEV_REG_PRINT_NUM_DEC: // print number in decimal
+ printf("%d", value);
+ break;
+ case TRACE_DEV_REG_PRINT_NUM_HEX: // print number in hexical
+ printf("%x", value);
+ break;
+
+ case TRACE_DEV_REG_STOP_EMU: // stop the VM execution
+ // To ensure that the number of instructions executed in this
+ // block is correct, we pretend that there was an exception.
+ trace_exception(0);
+
+ cpu_single_env->exception_index = EXCP_HLT;
+ cpu_single_env->halted = 1;
+ qemu_system_shutdown_request();
+ cpu_loop_exit();
+ break;
+
+ case TRACE_DEV_REG_ENABLE: // tracing enable: 0 = stop, 1 = start
+ if (value == 1)
+ start_tracing();
+ else if (value == 0) {
+ stop_tracing();
+
+ // To ensure that the number of instructions executed in this
+ // block is correct, we pretend that there was an exception.
+ trace_exception(0);
+ }
+ break;
+
+ case TRACE_DEV_REG_UNMAP_START:
+ unmap_start = value;
+ break;
+ case TRACE_DEV_REG_UNMAP_END:
+ trace_munmap(unmap_start, value);
+ break;
+
+ default:
+ cpu_abort(cpu_single_env, "trace_dev_write: Bad offset %x\n", offset);
+ break;
+ }
+}
+
+/* I/O read */
+static uint32_t trace_dev_read(void *opaque, target_phys_addr_t offset)
+{
+ trace_dev_state *s = (trace_dev_state *)opaque;
+
+ offset -= s->base;
+ switch (offset >> 2) {
+ case TRACE_DEV_REG_ENABLE: // tracing enable
+ return tracing;
+ default:
+ cpu_abort(cpu_single_env, "trace_dev_read: Bad offset %x\n", offset);
+ return 0;
+ }
+ return 0;
+}
+
+static CPUReadMemoryFunc *trace_dev_readfn[] = {
+ trace_dev_read,
+ trace_dev_read,
+ trace_dev_read
+};
+
+static CPUWriteMemoryFunc *trace_dev_writefn[] = {
+ trace_dev_write,
+ trace_dev_write,
+ trace_dev_write
+};
+
+/* initialize the trace device */
+void trace_dev_init(uint32_t base)
+{
+ int iomemtype;
+ trace_dev_state *s;
+
+ s = (trace_dev_state *)qemu_mallocz(sizeof(trace_dev_state));
+ iomemtype = cpu_register_io_memory(0, trace_dev_readfn, trace_dev_writefn, s);
+ cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+ s->base = base;
+
+ path[0] = arg[0] = '\0';
+}
diff --git a/hw/goldfish_trace.h b/hw/goldfish_trace.h
new file mode 100644
index 0000000..ea627e8
--- /dev/null
+++ b/hw/goldfish_trace.h
@@ -0,0 +1,78 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _TRACE_DEV_H_
+#define _TRACE_DEV_H_
+
+#define CLIENT_PAGE_SIZE 4096
+
+/* trace device registers */
+#define TRACE_DEV_REG_SWITCH 0
+#define TRACE_DEV_REG_FORK 1
+#define TRACE_DEV_REG_EXECVE_PID 2
+#define TRACE_DEV_REG_EXECVE_VMSTART 3
+#define TRACE_DEV_REG_EXECVE_VMEND 4
+#define TRACE_DEV_REG_EXECVE_OFFSET 5
+#define TRACE_DEV_REG_EXECVE_EXEPATH 6
+#define TRACE_DEV_REG_EXIT 7
+#define TRACE_DEV_REG_CMDLINE 8
+#define TRACE_DEV_REG_CMDLINE_LEN 9
+#define TRACE_DEV_REG_MMAP_EXEPATH 10
+#define TRACE_DEV_REG_INIT_PID 11
+#define TRACE_DEV_REG_INIT_NAME 12
+#define TRACE_DEV_REG_CLONE 13
+#define TRACE_DEV_REG_UNMAP_START 14
+#define TRACE_DEV_REG_UNMAP_END 15
+#define TRACE_DEV_REG_NAME 16
+#define TRACE_DEV_REG_TGID 17
+#define TRACE_DEV_REG_DYN_SYM 50
+#define TRACE_DEV_REG_DYN_SYM_ADDR 51
+#define TRACE_DEV_REG_REMOVE_ADDR 52
+#define TRACE_DEV_REG_PRINT_STR 60
+#define TRACE_DEV_REG_PRINT_NUM_DEC 61
+#define TRACE_DEV_REG_PRINT_NUM_HEX 62
+#define TRACE_DEV_REG_STOP_EMU 90
+#define TRACE_DEV_REG_ENABLE 100
+
+/* the virtual trace device state */
+typedef struct {
+ uint32_t base;
+} trace_dev_state;
+
+/*
+ * interfaces for copy from virtual space
+ * from target-arm/op_helper.c
+ */
+extern unsigned long v2p(target_ulong ptr, int is_user);
+extern void vmemcpy(target_ulong ptr, char *buf, int size);
+extern void vstrcpy(target_ulong ptr, char *buf, int max);
+
+/*
+ * interfaces to trace module to signal kernel events
+ */
+extern void trace_switch(int pid);
+extern void trace_fork(int tgid, int pid);
+extern void trace_clone(int tgid, int pid);
+extern void trace_execve(const char *arg, int len);
+extern void trace_exit(int exitcode);
+extern void trace_mmap(unsigned long vstart, unsigned long vend,
+ unsigned long offset, const char *path);
+extern void trace_munmap(unsigned long vstart, unsigned long vend);
+extern void trace_dynamic_symbol_add(unsigned long vaddr, const char *name);
+extern void trace_dynamic_symbol_remove(unsigned long vaddr);
+extern void trace_init_name(int tgid, int pid, const char *name);
+extern void trace_init_exec(unsigned long start, unsigned long end,
+ unsigned long offset, const char *exe);
+extern void start_tracing(void);
+extern void stop_tracing(void);
+extern void trace_exception(uint32 target_pc);
+
+#endif
diff --git a/hw/goldfish_tty.c b/hw/goldfish_tty.c
new file mode 100644
index 0000000..d61712a
--- /dev/null
+++ b/hw/goldfish_tty.c
@@ -0,0 +1,225 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "vl.h"
+#include "goldfish_device.h"
+
+enum {
+ TTY_PUT_CHAR = 0x00,
+ TTY_BYTES_READY = 0x04,
+ TTY_CMD = 0x08,
+
+ TTY_DATA_PTR = 0x10,
+ TTY_DATA_LEN = 0x14,
+
+ TTY_CMD_INT_DISABLE = 0,
+ TTY_CMD_INT_ENABLE = 1,
+ TTY_CMD_WRITE_BUFFER = 2,
+ TTY_CMD_READ_BUFFER = 3,
+};
+
+struct tty_state {
+ struct goldfish_device dev;
+ CharDriverState *cs;
+ uint32_t ptr;
+ uint32_t ptr_len;
+ uint32_t ready;
+ uint8_t data[128];
+ uint32_t data_count;
+};
+
+#define GOLDFISH_TTY_SAVE_VERSION 1
+
+static void goldfish_tty_save(QEMUFile* f, void* opaque)
+{
+ struct tty_state* s = opaque;
+
+ qemu_put_be32( f, s->ptr );
+ qemu_put_be32( f, s->ptr_len );
+ qemu_put_byte( f, s->ready );
+ qemu_put_byte( f, s->data_count );
+ qemu_put_buffer( f, s->data, s->data_count );
+}
+
+static int goldfish_tty_load(QEMUFile* f, void* opaque, int version_id)
+{
+ struct tty_state* s = opaque;
+
+ if (version_id != GOLDFISH_TTY_SAVE_VERSION)
+ return -1;
+
+ s->ptr = qemu_get_be32(f);
+ s->ptr_len = qemu_get_be32(f);
+ s->ready = qemu_get_byte(f);
+ s->data_count = qemu_get_byte(f);
+ qemu_get_buffer(f, s->data, s->data_count);
+
+ return 0;
+}
+
+static uint32_t goldfish_tty_read(void *opaque, target_phys_addr_t offset)
+{
+ struct tty_state *s = (struct tty_state *)opaque;
+ offset -= s->dev.base;
+
+ //printf("goldfish_tty_read %x %x\n", offset, size);
+
+ switch (offset) {
+ case TTY_BYTES_READY:
+ return s->data_count;
+ default:
+ cpu_abort (cpu_single_env, "goldfish_tty_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void goldfish_tty_write(void *opaque, target_phys_addr_t offset, uint32_t value)
+{
+ struct tty_state *s = (struct tty_state *)opaque;
+ offset -= s->dev.base;
+
+ //printf("goldfish_tty_read %x %x %x\n", offset, value, size);
+
+ switch(offset) {
+ case TTY_PUT_CHAR: {
+ uint8_t ch = value;
+ if(s->cs)
+ qemu_chr_write(s->cs, &ch, 1);
+ } break;
+
+ case TTY_CMD:
+ switch(value) {
+ case TTY_CMD_INT_DISABLE:
+ if(s->ready) {
+ if(s->data_count > 0)
+ goldfish_device_set_irq(&s->dev, 0, 0);
+ s->ready = 0;
+ }
+ break;
+
+ case TTY_CMD_INT_ENABLE:
+ if(!s->ready) {
+ if(s->data_count > 0)
+ goldfish_device_set_irq(&s->dev, 0, 1);
+ s->ready = 1;
+ }
+ break;
+
+ case TTY_CMD_WRITE_BUFFER:
+ if(s->cs) {
+ int len;
+ target_ulong buf;
+
+ buf = s->ptr;
+ len = s->ptr_len;
+
+ while(len) {
+ int page_remain = TARGET_PAGE_SIZE - (buf & ~TARGET_PAGE_MASK);
+ int to_write = len;
+ uint8_t *phys = (uint8_t *)v2p(buf, 0);
+ if(to_write > page_remain)
+ to_write = page_remain;
+ qemu_chr_write(s->cs, phys, to_write);
+ buf += to_write;
+ len -= to_write;
+ }
+ //printf("goldfish_tty_write: got %d bytes from %x\n", s->ptr_len, s->ptr);
+ }
+ break;
+
+ case TTY_CMD_READ_BUFFER:
+ if(s->ptr_len > s->data_count)
+ cpu_abort (cpu_single_env, "goldfish_tty_write: reading more data than available %d %d\n", s->ptr_len, s->data_count);
+ pmemcpy(s->ptr, s->data, s->ptr_len);
+ //printf("goldfish_tty_write: read %d bytes to %x\n", s->ptr_len, s->ptr);
+ if(s->data_count > s->ptr_len)
+ memmove(s->data, s->data + s->ptr_len, s->data_count - s->ptr_len);
+ s->data_count -= s->ptr_len;
+ if(s->data_count == 0 && s->ready)
+ goldfish_device_set_irq(&s->dev, 0, 0);
+ break;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_tty_write: Bad command %x\n", value);
+ };
+ break;
+
+ case TTY_DATA_PTR:
+ s->ptr = value;
+ break;
+
+ case TTY_DATA_LEN:
+ s->ptr_len = value;
+ break;
+
+ default:
+ cpu_abort (cpu_single_env, "goldfish_tty_write: Bad offset %x\n", offset);
+ }
+}
+
+static int tty_can_recieve(void *opaque)
+{
+ struct tty_state *s = opaque;
+
+ return (sizeof(s->data) - s->data_count);
+}
+
+static void tty_recieve(void *opaque, const uint8_t *buf, int size)
+{
+ struct tty_state *s = opaque;
+
+ memcpy(s->data + s->data_count, buf, size);
+ s->data_count += size;
+ if(s->data_count > 0 && s->ready)
+ goldfish_device_set_irq(&s->dev, 0, 1);
+}
+
+static CPUReadMemoryFunc *goldfish_tty_readfn[] = {
+ goldfish_tty_read,
+ goldfish_tty_read,
+ goldfish_tty_read
+};
+
+static CPUWriteMemoryFunc *goldfish_tty_writefn[] = {
+ goldfish_tty_write,
+ goldfish_tty_write,
+ goldfish_tty_write
+};
+
+int goldfish_tty_add(CharDriverState *cs, int id, uint32_t base, int irq)
+{
+ int ret;
+ struct tty_state *s;
+ static int instance_id = 0;
+
+ s = qemu_mallocz(sizeof(*s));
+ s->dev.name = "goldfish_tty";
+ s->dev.id = id;
+ s->dev.base = base;
+ s->dev.size = 0x1000;
+ s->dev.irq = irq;
+ s->dev.irq_count = 1;
+ s->cs = cs;
+
+ if(cs) {
+ qemu_chr_add_read_handler(cs, tty_can_recieve, tty_recieve, s);
+ }
+
+ ret = goldfish_device_add(&s->dev, goldfish_tty_readfn, goldfish_tty_writefn, s);
+ if(ret) {
+ qemu_free(s);
+ } else {
+ register_savevm( "goldfish_tty", instance_id++, GOLDFISH_TTY_SAVE_VERSION,
+ goldfish_tty_save, goldfish_tty_load, s);
+ }
+ return ret;
+}
+
diff --git a/hw/grackle_pci.c b/hw/grackle_pci.c
deleted file mode 100644
index e3cbceb..0000000
--- a/hw/grackle_pci.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * QEMU Grackle (heathrow PPC) PCI host
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "vl.h"
-typedef target_phys_addr_t pci_addr_t;
-#include "pci_host.h"
-
-typedef PCIHostState GrackleState;
-
-static void pci_grackle_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- GrackleState *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- s->config_reg = val;
-}
-
-static uint32_t pci_grackle_config_readl (void *opaque, target_phys_addr_t addr)
-{
- GrackleState *s = opaque;
- uint32_t val;
-
- val = s->config_reg;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_grackle_config_write[] = {
- &pci_grackle_config_writel,
- &pci_grackle_config_writel,
- &pci_grackle_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_grackle_config_read[] = {
- &pci_grackle_config_readl,
- &pci_grackle_config_readl,
- &pci_grackle_config_readl,
-};
-
-static CPUWriteMemoryFunc *pci_grackle_write[] = {
- &pci_host_data_writeb,
- &pci_host_data_writew,
- &pci_host_data_writel,
-};
-
-static CPUReadMemoryFunc *pci_grackle_read[] = {
- &pci_host_data_readb,
- &pci_host_data_readw,
- &pci_host_data_readl,
-};
-
-/* XXX: we do not simulate the hardware - we rely on the BIOS to
- set correctly for irq line field */
-static void pci_grackle_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
-{
- heathrow_pic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level);
-}
-
-PCIBus *pci_grackle_init(uint32_t base, void *pic)
-{
- GrackleState *s;
- PCIDevice *d;
- int pci_mem_config, pci_mem_data;
-
- s = qemu_mallocz(sizeof(GrackleState));
- s->bus = pci_register_bus(pci_grackle_set_irq, pic, 0);
-
- pci_mem_config = cpu_register_io_memory(0, pci_grackle_config_read,
- pci_grackle_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_grackle_read,
- pci_grackle_write, s);
- cpu_register_physical_memory(base, 0x1000, pci_mem_config);
- cpu_register_physical_memory(base + 0x00200000, 0x1000, pci_mem_data);
- d = pci_register_device(s->bus, "Grackle host bridge", sizeof(PCIDevice),
- 0, NULL, NULL);
- d->config[0x00] = 0x57; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x02; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x09] = 0x01;
- d->config[0x0a] = 0x00; // class_sub = host
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
- d->config[0x0e] = 0x00; // header_type
-
- d->config[0x18] = 0x00; // primary_bus
- d->config[0x19] = 0x01; // secondary_bus
- d->config[0x1a] = 0x00; // subordinate_bus
- d->config[0x1c] = 0x00;
- d->config[0x1d] = 0x00;
-
- d->config[0x20] = 0x00; // memory_base
- d->config[0x21] = 0x00;
- d->config[0x22] = 0x01; // memory_limit
- d->config[0x23] = 0x00;
-
- d->config[0x24] = 0x00; // prefetchable_memory_base
- d->config[0x25] = 0x00;
- d->config[0x26] = 0x00; // prefetchable_memory_limit
- d->config[0x27] = 0x00;
-
-#if 0
- /* PCI2PCI bridge same values as PearPC - check this */
- d->config[0x00] = 0x11; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x26; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x02; // revision
- d->config[0x0a] = 0x04; // class_sub = pci2pci
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
- d->config[0x0e] = 0x01; // header_type
-
- d->config[0x18] = 0x0; // primary_bus
- d->config[0x19] = 0x1; // secondary_bus
- d->config[0x1a] = 0x1; // subordinate_bus
- d->config[0x1c] = 0x10; // io_base
- d->config[0x1d] = 0x20; // io_limit
-
- d->config[0x20] = 0x80; // memory_base
- d->config[0x21] = 0x80;
- d->config[0x22] = 0x90; // memory_limit
- d->config[0x23] = 0x80;
-
- d->config[0x24] = 0x00; // prefetchable_memory_base
- d->config[0x25] = 0x84;
- d->config[0x26] = 0x00; // prefetchable_memory_limit
- d->config[0x27] = 0x85;
-#endif
- return s->bus;
-}
-
diff --git a/hw/heathrow_pic.c b/hw/heathrow_pic.c
deleted file mode 100644
index 4980cef..0000000
--- a/hw/heathrow_pic.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Heathrow PIC support (standard PowerMac PIC)
- *
- * Copyright (c) 2005 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"
-
-//#define DEBUG
-
-typedef struct HeathrowPIC {
- uint32_t events;
- uint32_t mask;
- uint32_t levels;
- uint32_t level_triggered;
-} HeathrowPIC;
-
-struct HeathrowPICS {
- HeathrowPIC pics[2];
-};
-
-static inline int check_irq(HeathrowPIC *pic)
-{
- return (pic->events | (pic->levels & pic->level_triggered)) & pic->mask;
-}
-
-/* update the CPU irq state */
-static void heathrow_pic_update(HeathrowPICS *s)
-{
- if (check_irq(&s->pics[0]) || check_irq(&s->pics[1])) {
- cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
- } else {
- cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
- }
-}
-
-static void pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
- unsigned int n;
-
- value = bswap32(value);
-#ifdef DEBUG
- printf("pic_writel: %08x: %08x\n",
- addr, value);
-#endif
- n = ((addr & 0xfff) - 0x10) >> 4;
- if (n >= 2)
- return;
- pic = &s->pics[n];
- switch(addr & 0xf) {
- case 0x04:
- pic->mask = value;
- heathrow_pic_update(s);
- break;
- case 0x08:
- /* do not reset level triggered IRQs */
- value &= ~pic->level_triggered;
- pic->events &= ~value;
- heathrow_pic_update(s);
- break;
- default:
- break;
- }
-}
-
-static uint32_t pic_readl (void *opaque, target_phys_addr_t addr)
-{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
- unsigned int n;
- uint32_t value;
-
- n = ((addr & 0xfff) - 0x10) >> 4;
- if (n >= 2) {
- value = 0;
- } else {
- pic = &s->pics[n];
- switch(addr & 0xf) {
- case 0x0:
- value = pic->events;
- break;
- case 0x4:
- value = pic->mask;
- break;
- case 0xc:
- value = pic->levels;
- break;
- default:
- value = 0;
- break;
- }
- }
-#ifdef DEBUG
- printf("pic_readl: %08x: %08x\n",
- addr, value);
-#endif
- value = bswap32(value);
- return value;
-}
-
-static CPUWriteMemoryFunc *pic_write[] = {
- &pic_writel,
- &pic_writel,
- &pic_writel,
-};
-
-static CPUReadMemoryFunc *pic_read[] = {
- &pic_readl,
- &pic_readl,
- &pic_readl,
-};
-
-
-void heathrow_pic_set_irq(void *opaque, int num, int level)
-{
- HeathrowPICS *s = opaque;
- HeathrowPIC *pic;
- unsigned int irq_bit;
-
-#if defined(DEBUG)
- {
- static int last_level[64];
- if (last_level[num] != level) {
- printf("set_irq: num=0x%02x level=%d\n", num, level);
- last_level[num] = level;
- }
- }
-#endif
- pic = &s->pics[1 - (num >> 5)];
- irq_bit = 1 << (num & 0x1f);
- if (level) {
- pic->events |= irq_bit & ~pic->level_triggered;
- pic->levels |= irq_bit;
- } else {
- pic->levels &= ~irq_bit;
- }
- heathrow_pic_update(s);
-}
-
-HeathrowPICS *heathrow_pic_init(int *pmem_index)
-{
- HeathrowPICS *s;
-
- s = qemu_mallocz(sizeof(HeathrowPICS));
- 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;
-}
diff --git a/hw/i8254.c b/hw/i8254.c
deleted file mode 100644
index a409763..0000000
--- a/hw/i8254.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * QEMU 8253/8254 interval timer emulation
- *
- * Copyright (c) 2003-2004 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"
-
-//#define DEBUG_PIT
-
-#define RW_STATE_LSB 1
-#define RW_STATE_MSB 2
-#define RW_STATE_WORD0 3
-#define RW_STATE_WORD1 4
-
-typedef struct PITChannelState {
- int count; /* can be 65536 */
- uint16_t latched_count;
- uint8_t count_latched;
- uint8_t status_latched;
- uint8_t status;
- uint8_t read_state;
- uint8_t write_state;
- uint8_t write_latch;
- uint8_t rw_mode;
- uint8_t mode;
- uint8_t bcd; /* not supported */
- uint8_t gate; /* timer start */
- int64_t count_load_time;
- /* irq handling */
- int64_t next_transition_time;
- QEMUTimer *irq_timer;
- int irq;
-} PITChannelState;
-
-struct PITState {
- PITChannelState channels[3];
-};
-
-static PITState pit_state;
-
-static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
-
-static int pit_get_count(PITChannelState *s)
-{
- uint64_t d;
- int counter;
-
- d = muldiv64(qemu_get_clock(vm_clock) - s->count_load_time, PIT_FREQ, ticks_per_sec);
- switch(s->mode) {
- case 0:
- case 1:
- case 4:
- case 5:
- counter = (s->count - d) & 0xffff;
- break;
- case 3:
- /* XXX: may be incorrect for odd counts */
- counter = s->count - ((2 * d) % s->count);
- break;
- default:
- counter = s->count - (d % s->count);
- break;
- }
- return counter;
-}
-
-/* get pit output bit */
-static int pit_get_out1(PITChannelState *s, int64_t current_time)
-{
- uint64_t d;
- int out;
-
- d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
- switch(s->mode) {
- default:
- case 0:
- out = (d >= s->count);
- break;
- case 1:
- out = (d < s->count);
- break;
- case 2:
- if ((d % s->count) == 0 && d != 0)
- out = 1;
- else
- out = 0;
- break;
- case 3:
- out = (d % s->count) < ((s->count + 1) >> 1);
- break;
- case 4:
- case 5:
- out = (d == s->count);
- break;
- }
- return out;
-}
-
-int pit_get_out(PITState *pit, int channel, int64_t current_time)
-{
- PITChannelState *s = &pit->channels[channel];
- return pit_get_out1(s, current_time);
-}
-
-/* return -1 if no transition will occur. */
-static int64_t pit_get_next_transition_time(PITChannelState *s,
- int64_t current_time)
-{
- uint64_t d, next_time, base;
- int period2;
-
- d = muldiv64(current_time - s->count_load_time, PIT_FREQ, ticks_per_sec);
- switch(s->mode) {
- default:
- case 0:
- case 1:
- if (d < s->count)
- next_time = s->count;
- else
- return -1;
- break;
- case 2:
- base = (d / s->count) * s->count;
- if ((d - base) == 0 && d != 0)
- next_time = base + s->count;
- else
- next_time = base + s->count + 1;
- break;
- case 3:
- base = (d / s->count) * s->count;
- period2 = ((s->count + 1) >> 1);
- if ((d - base) < period2)
- next_time = base + period2;
- else
- next_time = base + s->count;
- break;
- case 4:
- case 5:
- if (d < s->count)
- next_time = s->count;
- else if (d == s->count)
- next_time = s->count + 1;
- else
- return -1;
- break;
- }
- /* convert to timer units */
- next_time = s->count_load_time + muldiv64(next_time, ticks_per_sec, PIT_FREQ);
- /* fix potential rounding problems */
- /* XXX: better solution: use a clock at PIT_FREQ Hz */
- if (next_time <= current_time)
- next_time = current_time + 1;
- return next_time;
-}
-
-/* val must be 0 or 1 */
-void pit_set_gate(PITState *pit, int channel, int val)
-{
- PITChannelState *s = &pit->channels[channel];
-
- switch(s->mode) {
- default:
- case 0:
- case 4:
- /* XXX: just disable/enable counting */
- break;
- case 1:
- case 5:
- if (s->gate < val) {
- /* restart counting on rising edge */
- s->count_load_time = qemu_get_clock(vm_clock);
- pit_irq_timer_update(s, s->count_load_time);
- }
- break;
- case 2:
- case 3:
- if (s->gate < val) {
- /* restart counting on rising edge */
- s->count_load_time = qemu_get_clock(vm_clock);
- pit_irq_timer_update(s, s->count_load_time);
- }
- /* XXX: disable/enable counting */
- break;
- }
- s->gate = val;
-}
-
-int pit_get_gate(PITState *pit, int channel)
-{
- PITChannelState *s = &pit->channels[channel];
- return s->gate;
-}
-
-int pit_get_initial_count(PITState *pit, int channel)
-{
- PITChannelState *s = &pit->channels[channel];
- return s->count;
-}
-
-int pit_get_mode(PITState *pit, int channel)
-{
- PITChannelState *s = &pit->channels[channel];
- return s->mode;
-}
-
-static inline void pit_load_count(PITChannelState *s, int val)
-{
- if (val == 0)
- val = 0x10000;
- s->count_load_time = qemu_get_clock(vm_clock);
- s->count = val;
- pit_irq_timer_update(s, s->count_load_time);
-}
-
-/* if already latched, do not latch again */
-static void pit_latch_count(PITChannelState *s)
-{
- if (!s->count_latched) {
- s->latched_count = pit_get_count(s);
- s->count_latched = s->rw_mode;
- }
-}
-
-static void pit_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- PITState *pit = opaque;
- int channel, access;
- PITChannelState *s;
-
- addr &= 3;
- if (addr == 3) {
- channel = val >> 6;
- if (channel == 3) {
- /* read back command */
- for(channel = 0; channel < 3; channel++) {
- s = &pit->channels[channel];
- if (val & (2 << channel)) {
- if (!(val & 0x20)) {
- pit_latch_count(s);
- }
- if (!(val & 0x10) && !s->status_latched) {
- /* status latch */
- /* XXX: add BCD and null count */
- s->status = (pit_get_out1(s, qemu_get_clock(vm_clock)) << 7) |
- (s->rw_mode << 4) |
- (s->mode << 1) |
- s->bcd;
- s->status_latched = 1;
- }
- }
- }
- } else {
- s = &pit->channels[channel];
- access = (val >> 4) & 3;
- if (access == 0) {
- pit_latch_count(s);
- } else {
- s->rw_mode = access;
- s->read_state = access;
- s->write_state = access;
-
- s->mode = (val >> 1) & 7;
- s->bcd = val & 1;
- /* XXX: update irq timer ? */
- }
- }
- } else {
- s = &pit->channels[addr];
- switch(s->write_state) {
- default:
- case RW_STATE_LSB:
- pit_load_count(s, val);
- break;
- case RW_STATE_MSB:
- pit_load_count(s, val << 8);
- break;
- case RW_STATE_WORD0:
- s->write_latch = val;
- s->write_state = RW_STATE_WORD1;
- break;
- case RW_STATE_WORD1:
- pit_load_count(s, s->write_latch | (val << 8));
- s->write_state = RW_STATE_WORD0;
- break;
- }
- }
-}
-
-static uint32_t pit_ioport_read(void *opaque, uint32_t addr)
-{
- PITState *pit = opaque;
- int ret, count;
- PITChannelState *s;
-
- addr &= 3;
- s = &pit->channels[addr];
- if (s->status_latched) {
- s->status_latched = 0;
- ret = s->status;
- } else if (s->count_latched) {
- switch(s->count_latched) {
- default:
- case RW_STATE_LSB:
- ret = s->latched_count & 0xff;
- s->count_latched = 0;
- break;
- case RW_STATE_MSB:
- ret = s->latched_count >> 8;
- s->count_latched = 0;
- break;
- case RW_STATE_WORD0:
- ret = s->latched_count & 0xff;
- s->count_latched = RW_STATE_MSB;
- break;
- }
- } else {
- switch(s->read_state) {
- default:
- case RW_STATE_LSB:
- count = pit_get_count(s);
- ret = count & 0xff;
- break;
- case RW_STATE_MSB:
- count = pit_get_count(s);
- ret = (count >> 8) & 0xff;
- break;
- case RW_STATE_WORD0:
- count = pit_get_count(s);
- ret = count & 0xff;
- s->read_state = RW_STATE_WORD1;
- break;
- case RW_STATE_WORD1:
- count = pit_get_count(s);
- ret = (count >> 8) & 0xff;
- s->read_state = RW_STATE_WORD0;
- break;
- }
- }
- return ret;
-}
-
-static void pit_irq_timer_update(PITChannelState *s, int64_t current_time)
-{
- int64_t expire_time;
- int irq_level;
-
- if (!s->irq_timer)
- 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);
-#ifdef DEBUG_PIT
- printf("irq_level=%d next_delay=%f\n",
- irq_level,
- (double)(expire_time - current_time) / ticks_per_sec);
-#endif
- s->next_transition_time = expire_time;
- if (expire_time != -1)
- qemu_mod_timer(s->irq_timer, expire_time);
- else
- qemu_del_timer(s->irq_timer);
-}
-
-static void pit_irq_timer(void *opaque)
-{
- PITChannelState *s = opaque;
-
- pit_irq_timer_update(s, s->next_transition_time);
-}
-
-static void pit_save(QEMUFile *f, void *opaque)
-{
- PITState *pit = opaque;
- PITChannelState *s;
- int i;
-
- for(i = 0; i < 3; i++) {
- s = &pit->channels[i];
- qemu_put_be32s(f, &s->count);
- qemu_put_be16s(f, &s->latched_count);
- qemu_put_8s(f, &s->count_latched);
- qemu_put_8s(f, &s->status_latched);
- qemu_put_8s(f, &s->status);
- qemu_put_8s(f, &s->read_state);
- qemu_put_8s(f, &s->write_state);
- qemu_put_8s(f, &s->write_latch);
- qemu_put_8s(f, &s->rw_mode);
- qemu_put_8s(f, &s->mode);
- qemu_put_8s(f, &s->bcd);
- qemu_put_8s(f, &s->gate);
- qemu_put_be64s(f, &s->count_load_time);
- if (s->irq_timer) {
- qemu_put_be64s(f, &s->next_transition_time);
- qemu_put_timer(f, s->irq_timer);
- }
- }
-}
-
-static int pit_load(QEMUFile *f, void *opaque, int version_id)
-{
- PITState *pit = opaque;
- PITChannelState *s;
- int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- for(i = 0; i < 3; i++) {
- s = &pit->channels[i];
- qemu_get_be32s(f, &s->count);
- qemu_get_be16s(f, &s->latched_count);
- qemu_get_8s(f, &s->count_latched);
- qemu_get_8s(f, &s->status_latched);
- qemu_get_8s(f, &s->status);
- qemu_get_8s(f, &s->read_state);
- qemu_get_8s(f, &s->write_state);
- qemu_get_8s(f, &s->write_latch);
- qemu_get_8s(f, &s->rw_mode);
- qemu_get_8s(f, &s->mode);
- qemu_get_8s(f, &s->bcd);
- qemu_get_8s(f, &s->gate);
- qemu_get_be64s(f, &s->count_load_time);
- if (s->irq_timer) {
- qemu_get_be64s(f, &s->next_transition_time);
- qemu_get_timer(f, s->irq_timer);
- }
- }
- return 0;
-}
-
-static void pit_reset(void *opaque)
-{
- PITState *pit = opaque;
- PITChannelState *s;
- int i;
-
- for(i = 0;i < 3; i++) {
- s = &pit->channels[i];
- s->mode = 3;
- s->gate = (i != 2);
- pit_load_count(s, 0);
- }
-}
-
-PITState *pit_init(int base, int irq)
-{
- PITState *pit = &pit_state;
- PITChannelState *s;
-
- s = &pit->channels[0];
- /* the timer 0 is connected to an IRQ */
- s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
- s->irq = irq;
-
- register_savevm("i8254", base, 1, pit_save, pit_load, pit);
-
- qemu_register_reset(pit_reset, pit);
- register_ioport_write(base, 4, 1, pit_ioport_write, pit);
- register_ioport_read(base, 3, 1, pit_ioport_read, pit);
-
- pit_reset(pit);
-
- return pit;
-}
diff --git a/hw/i8259.c b/hw/i8259.c
deleted file mode 100644
index c747f10..0000000
--- a/hw/i8259.c
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * QEMU 8259 interrupt controller emulation
- *
- * Copyright (c) 2003-2004 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"
-
-/* debug PIC */
-//#define DEBUG_PIC
-
-//#define DEBUG_IRQ_LATENCY
-//#define DEBUG_IRQ_COUNT
-
-typedef struct PicState {
- uint8_t last_irr; /* edge detection */
- uint8_t irr; /* interrupt request register */
- uint8_t imr; /* interrupt mask register */
- uint8_t isr; /* interrupt service register */
- uint8_t priority_add; /* highest irq priority */
- uint8_t irq_base;
- uint8_t read_reg_select;
- uint8_t poll;
- uint8_t special_mask;
- uint8_t init_state;
- uint8_t auto_eoi;
- uint8_t rotate_on_auto_eoi;
- uint8_t special_fully_nested_mode;
- uint8_t init4; /* true if 4 byte init */
- uint8_t elcr; /* PIIX edge/trigger selection*/
- uint8_t elcr_mask;
- PicState2 *pics_state;
-} PicState;
-
-struct PicState2 {
- /* 0 is master pic, 1 is slave pic */
- /* XXX: better separation between the two pics */
- PicState pics[2];
- IRQRequestFunc *irq_request;
- void *irq_request_opaque;
- /* IOAPIC callback support */
- SetIRQFunc *alt_irq_func;
- void *alt_irq_opaque;
-};
-
-#if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
-static int irq_level[16];
-#endif
-#ifdef DEBUG_IRQ_COUNT
-static uint64_t irq_count[16];
-#endif
-
-/* set irq level. If an edge is detected, then the IRR is set to 1 */
-static inline void pic_set_irq1(PicState *s, int irq, int level)
-{
- int mask;
- mask = 1 << irq;
- if (s->elcr & mask) {
- /* level triggered */
- if (level) {
- s->irr |= mask;
- s->last_irr |= mask;
- } else {
- s->irr &= ~mask;
- s->last_irr &= ~mask;
- }
- } else {
- /* edge triggered */
- if (level) {
- if ((s->last_irr & mask) == 0)
- s->irr |= mask;
- s->last_irr |= mask;
- } else {
- s->last_irr &= ~mask;
- }
- }
-}
-
-/* return the highest priority found in mask (highest = smallest
- number). Return 8 if no irq */
-static inline int get_priority(PicState *s, int mask)
-{
- int priority;
- if (mask == 0)
- return 8;
- priority = 0;
- while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
- priority++;
- return priority;
-}
-
-/* return the pic wanted interrupt. return -1 if none */
-static int pic_get_irq(PicState *s)
-{
- int mask, cur_priority, priority;
-
- mask = s->irr & ~s->imr;
- priority = get_priority(s, mask);
- if (priority == 8)
- return -1;
- /* compute current priority. If special fully nested mode on the
- master, the IRQ coming from the slave is not taken into account
- for the priority computation. */
- mask = s->isr;
- if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
- mask &= ~(1 << 2);
- cur_priority = get_priority(s, mask);
- if (priority < cur_priority) {
- /* higher priority found: an irq should be generated */
- return (priority + s->priority_add) & 7;
- } else {
- return -1;
- }
-}
-
-/* raise irq to CPU if necessary. must be called every time the active
- irq may change */
-/* XXX: should not export it, but it is needed for an APIC kludge */
-void pic_update_irq(PicState2 *s)
-{
- int irq2, irq;
-
- /* first look at slave pic */
- irq2 = pic_get_irq(&s->pics[1]);
- if (irq2 >= 0) {
- /* if irq request by slave pic, signal master PIC */
- pic_set_irq1(&s->pics[0], 2, 1);
- pic_set_irq1(&s->pics[0], 2, 0);
- }
- /* look at requested irq */
- irq = pic_get_irq(&s->pics[0]);
- if (irq >= 0) {
-#if defined(DEBUG_PIC)
- {
- int i;
- for(i = 0; i < 2; i++) {
- printf("pic%d: imr=%x irr=%x padd=%d\n",
- i, s->pics[i].imr, s->pics[i].irr,
- s->pics[i].priority_add);
-
- }
- }
- printf("pic: cpu_interrupt\n");
-#endif
- s->irq_request(s->irq_request_opaque, 1);
- }
-}
-
-#ifdef DEBUG_IRQ_LATENCY
-int64_t irq_time[16];
-#endif
-
-void pic_set_irq_new(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);
-#endif
- irq_level[irq] = level;
-#ifdef DEBUG_IRQ_COUNT
- if (level == 1)
- irq_count[irq]++;
-#endif
- }
-#endif
-#ifdef DEBUG_IRQ_LATENCY
- if (level) {
- irq_time[irq] = qemu_get_clock(vm_clock);
- }
-#endif
- pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
- /* used for IOAPIC irqs */
- if (s->alt_irq_func)
- s->alt_irq_func(s->alt_irq_opaque, irq, level);
- 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)
-{
- if (s->auto_eoi) {
- if (s->rotate_on_auto_eoi)
- s->priority_add = (irq + 1) & 7;
- } else {
- s->isr |= (1 << irq);
- }
- /* We don't clear a level sensitive interrupt here */
- if (!(s->elcr & (1 << irq)))
- s->irr &= ~(1 << irq);
-}
-
-int pic_read_irq(PicState2 *s)
-{
- int irq, irq2, intno;
-
- irq = pic_get_irq(&s->pics[0]);
- if (irq >= 0) {
- pic_intack(&s->pics[0], irq);
- if (irq == 2) {
- irq2 = pic_get_irq(&s->pics[1]);
- if (irq2 >= 0) {
- pic_intack(&s->pics[1], irq2);
- } else {
- /* spurious IRQ on slave controller */
- irq2 = 7;
- }
- intno = s->pics[1].irq_base + irq2;
- irq = irq2 + 8;
- } else {
- intno = s->pics[0].irq_base + irq;
- }
- } else {
- /* spurious IRQ on host controller */
- irq = 7;
- intno = s->pics[0].irq_base + irq;
- }
- pic_update_irq(s);
-
-#ifdef DEBUG_IRQ_LATENCY
- printf("IRQ%d latency=%0.3fus\n",
- irq,
- (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec);
-#endif
-#if defined(DEBUG_PIC)
- printf("pic_interrupt: irq=%d\n", irq);
-#endif
- return intno;
-}
-
-static void pic_reset(void *opaque)
-{
- PicState *s = opaque;
-
- s->last_irr = 0;
- s->irr = 0;
- s->imr = 0;
- s->isr = 0;
- s->priority_add = 0;
- s->irq_base = 0;
- s->read_reg_select = 0;
- s->poll = 0;
- s->special_mask = 0;
- s->init_state = 0;
- s->auto_eoi = 0;
- s->rotate_on_auto_eoi = 0;
- s->special_fully_nested_mode = 0;
- s->init4 = 0;
- /* Note: ELCR is not reset */
-}
-
-static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- PicState *s = opaque;
- int priority, cmd, irq;
-
-#ifdef DEBUG_PIC
- printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
-#endif
- addr &= 1;
- if (addr == 0) {
- if (val & 0x10) {
- /* init */
- pic_reset(s);
- /* deassert a pending interrupt */
- s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0);
- s->init_state = 1;
- s->init4 = val & 1;
- if (val & 0x02)
- hw_error("single mode not supported");
- if (val & 0x08)
- hw_error("level sensitive irq not supported");
- } else if (val & 0x08) {
- if (val & 0x04)
- s->poll = 1;
- if (val & 0x02)
- s->read_reg_select = val & 1;
- if (val & 0x40)
- s->special_mask = (val >> 5) & 1;
- } else {
- cmd = val >> 5;
- switch(cmd) {
- case 0:
- case 4:
- s->rotate_on_auto_eoi = cmd >> 2;
- break;
- case 1: /* end of interrupt */
- case 5:
- priority = get_priority(s, s->isr);
- if (priority != 8) {
- irq = (priority + s->priority_add) & 7;
- s->isr &= ~(1 << irq);
- if (cmd == 5)
- s->priority_add = (irq + 1) & 7;
- pic_update_irq(s->pics_state);
- }
- break;
- case 3:
- irq = val & 7;
- s->isr &= ~(1 << irq);
- pic_update_irq(s->pics_state);
- break;
- case 6:
- s->priority_add = (val + 1) & 7;
- pic_update_irq(s->pics_state);
- break;
- case 7:
- irq = val & 7;
- s->isr &= ~(1 << irq);
- s->priority_add = (irq + 1) & 7;
- pic_update_irq(s->pics_state);
- break;
- default:
- /* no operation */
- break;
- }
- }
- } else {
- switch(s->init_state) {
- case 0:
- /* normal mode */
- s->imr = val;
- pic_update_irq(s->pics_state);
- break;
- case 1:
- s->irq_base = val & 0xf8;
- s->init_state = 2;
- break;
- case 2:
- if (s->init4) {
- s->init_state = 3;
- } else {
- s->init_state = 0;
- }
- break;
- case 3:
- s->special_fully_nested_mode = (val >> 4) & 1;
- s->auto_eoi = (val >> 1) & 1;
- s->init_state = 0;
- break;
- }
- }
-}
-
-static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
-{
- int ret;
-
- ret = pic_get_irq(s);
- if (ret >= 0) {
- if (addr1 >> 7) {
- s->pics_state->pics[0].isr &= ~(1 << 2);
- s->pics_state->pics[0].irr &= ~(1 << 2);
- }
- s->irr &= ~(1 << ret);
- s->isr &= ~(1 << ret);
- if (addr1 >> 7 || ret != 2)
- pic_update_irq(s->pics_state);
- } else {
- ret = 0x07;
- pic_update_irq(s->pics_state);
- }
-
- return ret;
-}
-
-static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
-{
- PicState *s = opaque;
- unsigned int addr;
- int ret;
-
- addr = addr1;
- addr &= 1;
- if (s->poll) {
- ret = pic_poll_read(s, addr1);
- s->poll = 0;
- } else {
- if (addr == 0) {
- if (s->read_reg_select)
- ret = s->isr;
- else
- ret = s->irr;
- } else {
- ret = s->imr;
- }
- }
-#ifdef DEBUG_PIC
- printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
-#endif
- return ret;
-}
-
-/* memory mapped interrupt status */
-/* XXX: may be the same than pic_read_irq() */
-uint32_t pic_intack_read(PicState2 *s)
-{
- int ret;
-
- ret = pic_poll_read(&s->pics[0], 0x00);
- if (ret == 2)
- ret = pic_poll_read(&s->pics[1], 0x80) + 8;
- /* Prepare for ISR read */
- s->pics[0].read_reg_select = 1;
-
- return ret;
-}
-
-static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- PicState *s = opaque;
- s->elcr = val & s->elcr_mask;
-}
-
-static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
-{
- PicState *s = opaque;
- return s->elcr;
-}
-
-static void pic_save(QEMUFile *f, void *opaque)
-{
- PicState *s = opaque;
-
- qemu_put_8s(f, &s->last_irr);
- qemu_put_8s(f, &s->irr);
- qemu_put_8s(f, &s->imr);
- qemu_put_8s(f, &s->isr);
- qemu_put_8s(f, &s->priority_add);
- qemu_put_8s(f, &s->irq_base);
- qemu_put_8s(f, &s->read_reg_select);
- qemu_put_8s(f, &s->poll);
- qemu_put_8s(f, &s->special_mask);
- qemu_put_8s(f, &s->init_state);
- qemu_put_8s(f, &s->auto_eoi);
- 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->elcr);
-}
-
-static int pic_load(QEMUFile *f, void *opaque, int version_id)
-{
- PicState *s = opaque;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_8s(f, &s->last_irr);
- qemu_get_8s(f, &s->irr);
- qemu_get_8s(f, &s->imr);
- qemu_get_8s(f, &s->isr);
- qemu_get_8s(f, &s->priority_add);
- qemu_get_8s(f, &s->irq_base);
- qemu_get_8s(f, &s->read_reg_select);
- qemu_get_8s(f, &s->poll);
- qemu_get_8s(f, &s->special_mask);
- qemu_get_8s(f, &s->init_state);
- qemu_get_8s(f, &s->auto_eoi);
- 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->elcr);
- return 0;
-}
-
-/* XXX: add generic master/slave system */
-static void pic_init1(int io_addr, int elcr_addr, PicState *s)
-{
- register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
- register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
- if (elcr_addr >= 0) {
- register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
- register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
- }
- register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
- qemu_register_reset(pic_reset, s);
-}
-
-void pic_info(void)
-{
- int i;
- PicState *s;
-
- if (!isa_pic)
- return;
-
- for(i=0;i<2;i++) {
- s = &isa_pic->pics[i];
- term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
- i, s->irr, s->imr, s->isr, s->priority_add,
- s->irq_base, s->read_reg_select, s->elcr,
- s->special_fully_nested_mode);
- }
-}
-
-void irq_info(void)
-{
-#ifndef DEBUG_IRQ_COUNT
- term_printf("irq statistic code not compiled.\n");
-#else
- int i;
- int64_t count;
-
- term_printf("IRQ statistics:\n");
- for (i = 0; i < 16; i++) {
- count = irq_count[i];
- if (count > 0)
- term_printf("%2d: %" PRId64 "\n", i, count);
- }
-#endif
-}
-
-PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque)
-{
- PicState2 *s;
- s = qemu_mallocz(sizeof(PicState2));
- if (!s)
- return NULL;
- pic_init1(0x20, 0x4d0, &s->pics[0]);
- 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->pics[0].pics_state = s;
- s->pics[1].pics_state = s;
- return s;
-}
-
-void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
- void *alt_irq_opaque)
-{
- s->alt_irq_func = alt_irq_func;
- s->alt_irq_opaque = alt_irq_opaque;
-}
diff --git a/hw/ide.c b/hw/ide.c
deleted file mode 100644
index debbc0f..0000000
--- a/hw/ide.c
+++ /dev/null
@@ -1,2535 +0,0 @@
-/*
- * QEMU IDE disk and CD-ROM Emulator
- *
- * 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"
-
-/* debug IDE devices */
-//#define DEBUG_IDE
-//#define DEBUG_IDE_ATAPI
-
-/* Bits of HD_STATUS */
-#define ERR_STAT 0x01
-#define INDEX_STAT 0x02
-#define ECC_STAT 0x04 /* Corrected error */
-#define DRQ_STAT 0x08
-#define SEEK_STAT 0x10
-#define SRV_STAT 0x10
-#define WRERR_STAT 0x20
-#define READY_STAT 0x40
-#define BUSY_STAT 0x80
-
-/* Bits for HD_ERROR */
-#define MARK_ERR 0x01 /* Bad address mark */
-#define TRK0_ERR 0x02 /* couldn't find track 0 */
-#define ABRT_ERR 0x04 /* Command aborted */
-#define MCR_ERR 0x08 /* media change request */
-#define ID_ERR 0x10 /* ID field not found */
-#define MC_ERR 0x20 /* media changed */
-#define ECC_ERR 0x40 /* Uncorrectable ECC error */
-#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */
-#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */
-
-/* Bits of HD_NSECTOR */
-#define CD 0x01
-#define IO 0x02
-#define REL 0x04
-#define TAG_MASK 0xf8
-
-#define IDE_CMD_RESET 0x04
-#define IDE_CMD_DISABLE_IRQ 0x02
-
-/* ATA/ATAPI Commands pre T13 Spec */
-#define WIN_NOP 0x00
-/*
- * 0x01->0x02 Reserved
- */
-#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */
-/*
- * 0x04->0x07 Reserved
- */
-#define WIN_SRST 0x08 /* ATAPI soft reset command */
-#define WIN_DEVICE_RESET 0x08
-/*
- * 0x09->0x0F Reserved
- */
-#define WIN_RECAL 0x10
-#define WIN_RESTORE WIN_RECAL
-/*
- * 0x10->0x1F Reserved
- */
-#define WIN_READ 0x20 /* 28-Bit */
-#define WIN_READ_ONCE 0x21 /* 28-Bit without retries */
-#define WIN_READ_LONG 0x22 /* 28-Bit */
-#define WIN_READ_LONG_ONCE 0x23 /* 28-Bit without retries */
-#define WIN_READ_EXT 0x24 /* 48-Bit */
-#define WIN_READDMA_EXT 0x25 /* 48-Bit */
-#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */
-#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */
-/*
- * 0x28
- */
-#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */
-/*
- * 0x2A->0x2F Reserved
- */
-#define WIN_WRITE 0x30 /* 28-Bit */
-#define WIN_WRITE_ONCE 0x31 /* 28-Bit without retries */
-#define WIN_WRITE_LONG 0x32 /* 28-Bit */
-#define WIN_WRITE_LONG_ONCE 0x33 /* 28-Bit without retries */
-#define WIN_WRITE_EXT 0x34 /* 48-Bit */
-#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */
-#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */
-#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */
-#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */
-#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */
-/*
- * 0x3A->0x3B Reserved
- */
-#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */
-/*
- * 0x3D->0x3F Reserved
- */
-#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */
-#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - without retries */
-#define WIN_VERIFY_EXT 0x42 /* 48-Bit */
-/*
- * 0x43->0x4F Reserved
- */
-#define WIN_FORMAT 0x50
-/*
- * 0x51->0x5F Reserved
- */
-#define WIN_INIT 0x60
-/*
- * 0x61->0x5F Reserved
- */
-#define WIN_SEEK 0x70 /* 0x70-0x7F Reserved */
-#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */
-#define WIN_DIAGNOSE 0x90
-#define WIN_SPECIFY 0x91 /* set drive geometry translation */
-#define WIN_DOWNLOAD_MICROCODE 0x92
-#define WIN_STANDBYNOW2 0x94
-#define WIN_STANDBY2 0x96
-#define WIN_SETIDLE2 0x97
-#define WIN_CHECKPOWERMODE2 0x98
-#define WIN_SLEEPNOW2 0x99
-/*
- * 0x9A VENDOR
- */
-#define WIN_PACKETCMD 0xA0 /* Send a packet command. */
-#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */
-#define WIN_QUEUED_SERVICE 0xA2
-#define WIN_SMART 0xB0 /* self-monitoring and reporting */
-#define CFA_ERASE_SECTORS 0xC0
-#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/
-#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
-#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
-#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */
-#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */
-#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - without retries */
-#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */
-#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */
-#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */
-#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */
-#define WIN_GETMEDIASTATUS 0xDA
-#define WIN_ACKMEDIACHANGE 0xDB /* ATA-1, ATA-2 vendor */
-#define WIN_POSTBOOT 0xDC
-#define WIN_PREBOOT 0xDD
-#define WIN_DOORLOCK 0xDE /* lock door on removable drives */
-#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */
-#define WIN_STANDBYNOW1 0xE0
-#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */
-#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */
-#define WIN_SETIDLE1 0xE3
-#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */
-#define WIN_CHECKPOWERMODE1 0xE5
-#define WIN_SLEEPNOW1 0xE6
-#define WIN_FLUSH_CACHE 0xE7
-#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */
-#define WIN_WRITE_SAME 0xE9 /* read ata-2 to use */
- /* SET_FEATURES 0x22 or 0xDD */
-#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */
-#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */
-#define WIN_MEDIAEJECT 0xED
-#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */
-#define WIN_SETFEATURES 0xEF /* set special drive features */
-#define EXABYTE_ENABLE_NEST 0xF0
-#define WIN_SECURITY_SET_PASS 0xF1
-#define WIN_SECURITY_UNLOCK 0xF2
-#define WIN_SECURITY_ERASE_PREPARE 0xF3
-#define WIN_SECURITY_ERASE_UNIT 0xF4
-#define WIN_SECURITY_FREEZE_LOCK 0xF5
-#define WIN_SECURITY_DISABLE 0xF6
-#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */
-#define WIN_SET_MAX 0xF9
-#define DISABLE_SEAGATE 0xFB
-
-/* set to 1 set disable mult support */
-#define MAX_MULT_SECTORS 16
-
-/* ATAPI defines */
-
-#define ATAPI_PACKET_SIZE 12
-
-/* The generic packet command opcodes for CD/DVD Logical Units,
- * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */
-#define GPCMD_BLANK 0xa1
-#define GPCMD_CLOSE_TRACK 0x5b
-#define GPCMD_FLUSH_CACHE 0x35
-#define GPCMD_FORMAT_UNIT 0x04
-#define GPCMD_GET_CONFIGURATION 0x46
-#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a
-#define GPCMD_GET_PERFORMANCE 0xac
-#define GPCMD_INQUIRY 0x12
-#define GPCMD_LOAD_UNLOAD 0xa6
-#define GPCMD_MECHANISM_STATUS 0xbd
-#define GPCMD_MODE_SELECT_10 0x55
-#define GPCMD_MODE_SENSE_10 0x5a
-#define GPCMD_PAUSE_RESUME 0x4b
-#define GPCMD_PLAY_AUDIO_10 0x45
-#define GPCMD_PLAY_AUDIO_MSF 0x47
-#define GPCMD_PLAY_AUDIO_TI 0x48
-#define GPCMD_PLAY_CD 0xbc
-#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
-#define GPCMD_READ_10 0x28
-#define GPCMD_READ_12 0xa8
-#define GPCMD_READ_CDVD_CAPACITY 0x25
-#define GPCMD_READ_CD 0xbe
-#define GPCMD_READ_CD_MSF 0xb9
-#define GPCMD_READ_DISC_INFO 0x51
-#define GPCMD_READ_DVD_STRUCTURE 0xad
-#define GPCMD_READ_FORMAT_CAPACITIES 0x23
-#define GPCMD_READ_HEADER 0x44
-#define GPCMD_READ_TRACK_RZONE_INFO 0x52
-#define GPCMD_READ_SUBCHANNEL 0x42
-#define GPCMD_READ_TOC_PMA_ATIP 0x43
-#define GPCMD_REPAIR_RZONE_TRACK 0x58
-#define GPCMD_REPORT_KEY 0xa4
-#define GPCMD_REQUEST_SENSE 0x03
-#define GPCMD_RESERVE_RZONE_TRACK 0x53
-#define GPCMD_SCAN 0xba
-#define GPCMD_SEEK 0x2b
-#define GPCMD_SEND_DVD_STRUCTURE 0xad
-#define GPCMD_SEND_EVENT 0xa2
-#define GPCMD_SEND_KEY 0xa3
-#define GPCMD_SEND_OPC 0x54
-#define GPCMD_SET_READ_AHEAD 0xa7
-#define GPCMD_SET_STREAMING 0xb6
-#define GPCMD_START_STOP_UNIT 0x1b
-#define GPCMD_STOP_PLAY_SCAN 0x4e
-#define GPCMD_TEST_UNIT_READY 0x00
-#define GPCMD_VERIFY_10 0x2f
-#define GPCMD_WRITE_10 0x2a
-#define GPCMD_WRITE_AND_VERIFY_10 0x2e
-/* This is listed as optional in ATAPI 2.6, but is (curiously)
- * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji
- * Table 377 as an MMC command for SCSi devices though... Most ATAPI
- * drives support it. */
-#define GPCMD_SET_SPEED 0xbb
-/* This seems to be a SCSI specific CD-ROM opcode
- * to play data at track/index */
-#define GPCMD_PLAYAUDIO_TI 0x48
-/*
- * From MS Media Status Notification Support Specification. For
- * older drives only.
- */
-#define GPCMD_GET_MEDIA_STATUS 0xda
-
-/* Mode page codes for mode sense/set */
-#define GPMODE_R_W_ERROR_PAGE 0x01
-#define GPMODE_WRITE_PARMS_PAGE 0x05
-#define GPMODE_AUDIO_CTL_PAGE 0x0e
-#define GPMODE_POWER_PAGE 0x1a
-#define GPMODE_FAULT_FAIL_PAGE 0x1c
-#define GPMODE_TO_PROTECT_PAGE 0x1d
-#define GPMODE_CAPABILITIES_PAGE 0x2a
-#define GPMODE_ALL_PAGES 0x3f
-/* Not in Mt. Fuji, but in ATAPI 2.6 -- depricated now in favor
- * of MODE_SENSE_POWER_PAGE */
-#define GPMODE_CDROM_PAGE 0x0d
-
-#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */
-#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */
-#define ATAPI_INT_REASON_REL 0x04
-#define ATAPI_INT_REASON_TAG 0xf8
-
-/* same constants as bochs */
-#define ASC_ILLEGAL_OPCODE 0x20
-#define ASC_LOGICAL_BLOCK_OOR 0x21
-#define ASC_INV_FIELD_IN_CMD_PACKET 0x24
-#define ASC_MEDIUM_NOT_PRESENT 0x3a
-#define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39
-
-#define SENSE_NONE 0
-#define SENSE_NOT_READY 2
-#define SENSE_ILLEGAL_REQUEST 5
-#define SENSE_UNIT_ATTENTION 6
-
-struct IDEState;
-
-typedef void EndTransferFunc(struct IDEState *);
-
-/* NOTE: IDEState represents in fact one drive */
-typedef struct IDEState {
- /* ide config */
- int is_cdrom;
- int cylinders, heads, sectors;
- int64_t nb_sectors;
- int mult_sectors;
- int identify_set;
- uint16_t identify_data[256];
- SetIRQFunc *set_irq;
- void *irq_opaque;
- int irq;
- PCIDevice *pci_dev;
- struct BMDMAState *bmdma;
- int drive_serial;
- /* ide regs */
- uint8_t feature;
- uint8_t error;
- uint32_t nsector;
- uint8_t sector;
- uint8_t lcyl;
- uint8_t hcyl;
- /* other part of tf for lba48 support */
- uint8_t hob_feature;
- uint8_t hob_nsector;
- uint8_t hob_sector;
- uint8_t hob_lcyl;
- uint8_t hob_hcyl;
-
- uint8_t select;
- uint8_t status;
-
- /* 0x3f6 command, only meaningful for drive 0 */
- uint8_t cmd;
- /* set for lba48 access */
- uint8_t lba48;
- /* depends on bit 4 in select, only meaningful for drive 0 */
- struct IDEState *cur_drive;
- BlockDriverState *bs;
- /* ATAPI specific */
- uint8_t sense_key;
- uint8_t asc;
- int packet_transfer_size;
- int elementary_transfer_size;
- int io_buffer_index;
- int lba;
- int cd_sector_size;
- int atapi_dma; /* true if dma is requested for the packet cmd */
- /* ATA DMA state */
- int io_buffer_size;
- /* PIO transfer handling */
- int req_nb_sectors; /* number of sectors per interrupt */
- EndTransferFunc *end_transfer_func;
- uint8_t *data_ptr;
- uint8_t *data_end;
- uint8_t io_buffer[MAX_MULT_SECTORS*512 + 4];
- QEMUTimer *sector_write_timer; /* only used for win2k instal hack */
- uint32_t irq_count; /* counts IRQs when using win2k install hack */
-} IDEState;
-
-#define BM_STATUS_DMAING 0x01
-#define BM_STATUS_ERROR 0x02
-#define BM_STATUS_INT 0x04
-
-#define BM_CMD_START 0x01
-#define BM_CMD_READ 0x08
-
-#define IDE_TYPE_PIIX3 0
-#define IDE_TYPE_CMD646 1
-
-/* CMD646 specific */
-#define MRDMODE 0x71
-#define MRDMODE_INTR_CH0 0x04
-#define MRDMODE_INTR_CH1 0x08
-#define MRDMODE_BLK_CH0 0x10
-#define MRDMODE_BLK_CH1 0x20
-#define UDIDETCR0 0x73
-#define UDIDETCR1 0x7B
-
-typedef int IDEDMAFunc(IDEState *s,
- target_phys_addr_t phys_addr,
- int transfer_size1);
-
-typedef struct BMDMAState {
- uint8_t cmd;
- uint8_t status;
- uint32_t addr;
-
- struct PCIIDEState *pci_dev;
- /* current transfer state */
- IDEState *ide_if;
- IDEDMAFunc *dma_cb;
-} BMDMAState;
-
-typedef struct PCIIDEState {
- PCIDevice dev;
- IDEState ide_if[4];
- BMDMAState bmdma[2];
- int type; /* see IDE_TYPE_xxx */
-} PCIIDEState;
-
-static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb);
-
-static void padstr(char *str, const char *src, int len)
-{
- int i, v;
- for(i = 0; i < len; i++) {
- if (*src)
- v = *src++;
- else
- v = ' ';
- *(char *)((long)str ^ 1) = v;
- str++;
- }
-}
-
-static void padstr8(uint8_t *buf, int buf_size, const char *src)
-{
- int i;
- for(i = 0; i < buf_size; i++) {
- if (*src)
- buf[i] = *src++;
- else
- buf[i] = ' ';
- }
-}
-
-static void put_le16(uint16_t *p, unsigned int v)
-{
- *p = cpu_to_le16(v);
-}
-
-static void ide_identify(IDEState *s)
-{
- uint16_t *p;
- unsigned int oldsize;
- char buf[20];
-
- if (s->identify_set) {
- memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
- return;
- }
-
- memset(s->io_buffer, 0, 512);
- p = (uint16_t *)s->io_buffer;
- put_le16(p + 0, 0x0040);
- put_le16(p + 1, s->cylinders);
- put_le16(p + 3, s->heads);
- put_le16(p + 4, 512 * s->sectors); /* XXX: retired, remove ? */
- put_le16(p + 5, 512); /* XXX: retired, remove ? */
- put_le16(p + 6, s->sectors);
- snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial);
- padstr((uint8_t *)(p + 10), buf, 20); /* serial number */
- put_le16(p + 20, 3); /* XXX: retired, remove ? */
- put_le16(p + 21, 512); /* cache size in sectors */
- put_le16(p + 22, 4); /* ecc bytes */
- padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
- padstr((uint8_t *)(p + 27), "QEMU HARDDISK", 40); /* model */
-#if MAX_MULT_SECTORS > 1
- put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
-#endif
- put_le16(p + 48, 1); /* dword I/O */
- put_le16(p + 49, (1 << 11) | (1 << 9) | (1 << 8)); /* DMA and LBA supported */
- put_le16(p + 51, 0x200); /* PIO transfer cycle */
- put_le16(p + 52, 0x200); /* DMA transfer cycle */
- put_le16(p + 53, 1 | (1 << 1) | (1 << 2)); /* words 54-58,64-70,88 are valid */
- put_le16(p + 54, s->cylinders);
- put_le16(p + 55, s->heads);
- put_le16(p + 56, s->sectors);
- oldsize = s->cylinders * s->heads * s->sectors;
- put_le16(p + 57, oldsize);
- put_le16(p + 58, oldsize >> 16);
- if (s->mult_sectors)
- put_le16(p + 59, 0x100 | s->mult_sectors);
- put_le16(p + 60, s->nb_sectors);
- put_le16(p + 61, s->nb_sectors >> 16);
- put_le16(p + 63, 0x07); /* mdma0-2 supported */
- put_le16(p + 65, 120);
- put_le16(p + 66, 120);
- put_le16(p + 67, 120);
- put_le16(p + 68, 120);
- put_le16(p + 80, 0xf0); /* ata3 -> ata6 supported */
- put_le16(p + 81, 0x16); /* conforms to ata5 */
- put_le16(p + 82, (1 << 14));
- /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
- put_le16(p + 83, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
- put_le16(p + 84, (1 << 14));
- put_le16(p + 85, (1 << 14));
- /* 13=flush_cache_ext,12=flush_cache,10=lba48 */
- put_le16(p + 86, (1 << 14) | (1 << 13) | (1 <<12) | (1 << 10));
- put_le16(p + 87, (1 << 14));
- put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
- put_le16(p + 93, 1 | (1 << 14) | 0x2000);
- put_le16(p + 100, s->nb_sectors);
- put_le16(p + 101, s->nb_sectors >> 16);
- put_le16(p + 102, s->nb_sectors >> 32);
- put_le16(p + 103, s->nb_sectors >> 48);
-
- memcpy(s->identify_data, p, sizeof(s->identify_data));
- s->identify_set = 1;
-}
-
-static void ide_atapi_identify(IDEState *s)
-{
- uint16_t *p;
- char buf[20];
-
- if (s->identify_set) {
- memcpy(s->io_buffer, s->identify_data, sizeof(s->identify_data));
- return;
- }
-
- memset(s->io_buffer, 0, 512);
- p = (uint16_t *)s->io_buffer;
- /* Removable CDROM, 50us response, 12 byte packets */
- put_le16(p + 0, (2 << 14) | (5 << 8) | (1 << 7) | (2 << 5) | (0 << 0));
- snprintf(buf, sizeof(buf), "QM%05d", s->drive_serial);
- padstr((uint8_t *)(p + 10), buf, 20); /* serial number */
- put_le16(p + 20, 3); /* buffer type */
- put_le16(p + 21, 512); /* cache size in sectors */
- put_le16(p + 22, 4); /* ecc bytes */
- padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
- padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */
- put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
- put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
- put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
- put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
- put_le16(p + 64, 1); /* PIO modes */
- put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
- put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
- put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
- put_le16(p + 68, 0xb4); /* minimum PIO cycle time with IORDY flow control */
-
- put_le16(p + 71, 30); /* in ns */
- put_le16(p + 72, 30); /* in ns */
-
- put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
-
- memcpy(s->identify_data, p, sizeof(s->identify_data));
- s->identify_set = 1;
-}
-
-static void ide_set_signature(IDEState *s)
-{
- s->select &= 0xf0; /* clear head */
- /* put signature */
- s->nsector = 1;
- s->sector = 1;
- if (s->is_cdrom) {
- s->lcyl = 0x14;
- s->hcyl = 0xeb;
- } else if (s->bs) {
- s->lcyl = 0;
- s->hcyl = 0;
- } else {
- s->lcyl = 0xff;
- s->hcyl = 0xff;
- }
-}
-
-static inline void ide_abort_command(IDEState *s)
-{
- s->status = READY_STAT | ERR_STAT;
- s->error = ABRT_ERR;
-}
-
-static inline void ide_set_irq(IDEState *s)
-{
- BMDMAState *bm = s->bmdma;
- if (!(s->cmd & IDE_CMD_DISABLE_IRQ)) {
- if (bm) {
- bm->status |= BM_STATUS_INT;
- }
- s->set_irq(s->irq_opaque, s->irq, 1);
- }
-}
-
-/* prepare data transfer and tell what to do after */
-static void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
- EndTransferFunc *end_transfer_func)
-{
- s->end_transfer_func = end_transfer_func;
- s->data_ptr = buf;
- s->data_end = buf + size;
- s->status |= DRQ_STAT;
-}
-
-static void ide_transfer_stop(IDEState *s)
-{
- s->end_transfer_func = ide_transfer_stop;
- s->data_ptr = s->io_buffer;
- s->data_end = s->io_buffer;
- s->status &= ~DRQ_STAT;
-}
-
-static int64_t ide_get_sector(IDEState *s)
-{
- int64_t sector_num;
- if (s->select & 0x40) {
- /* lba */
- if (!s->lba48) {
- sector_num = ((s->select & 0x0f) << 24) | (s->hcyl << 16) |
- (s->lcyl << 8) | s->sector;
- } else {
- sector_num = ((int64_t)s->hob_hcyl << 40) |
- ((int64_t) s->hob_lcyl << 32) |
- ((int64_t) s->hob_sector << 24) |
- ((int64_t) s->hcyl << 16) |
- ((int64_t) s->lcyl << 8) | s->sector;
- }
- } else {
- sector_num = ((s->hcyl << 8) | s->lcyl) * s->heads * s->sectors +
- (s->select & 0x0f) * s->sectors + (s->sector - 1);
- }
- return sector_num;
-}
-
-static void ide_set_sector(IDEState *s, int64_t sector_num)
-{
- unsigned int cyl, r;
- if (s->select & 0x40) {
- if (!s->lba48) {
- s->select = (s->select & 0xf0) | (sector_num >> 24);
- s->hcyl = (sector_num >> 16);
- s->lcyl = (sector_num >> 8);
- s->sector = (sector_num);
- } else {
- s->sector = sector_num;
- s->lcyl = sector_num >> 8;
- s->hcyl = sector_num >> 16;
- s->hob_sector = sector_num >> 24;
- s->hob_lcyl = sector_num >> 32;
- s->hob_hcyl = sector_num >> 40;
- }
- } else {
- cyl = sector_num / (s->heads * s->sectors);
- r = sector_num % (s->heads * s->sectors);
- s->hcyl = cyl >> 8;
- s->lcyl = cyl;
- s->select = (s->select & 0xf0) | ((r / s->sectors) & 0x0f);
- s->sector = (r % s->sectors) + 1;
- }
-}
-
-static void ide_sector_read(IDEState *s)
-{
- int64_t sector_num;
- int ret, n;
-
- s->status = READY_STAT | SEEK_STAT;
- s->error = 0; /* not needed by IDE spec, but needed by Windows */
- sector_num = ide_get_sector(s);
- n = s->nsector;
- if (n == 0) {
- /* no more sector to read from disk */
- ide_transfer_stop(s);
- } else {
-#if defined(DEBUG_IDE)
- printf("read sector=%Ld\n", sector_num);
-#endif
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
- ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
- ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
- ide_set_irq(s);
- ide_set_sector(s, sector_num + n);
- s->nsector -= n;
- }
-}
-
-static int ide_read_dma_cb(IDEState *s,
- target_phys_addr_t phys_addr,
- int transfer_size1)
-{
- int len, transfer_size, n;
- int64_t sector_num;
-
- transfer_size = transfer_size1;
- while (transfer_size > 0) {
- len = s->io_buffer_size - s->io_buffer_index;
- if (len <= 0) {
- /* transfert next data */
- n = s->nsector;
- if (n == 0)
- break;
- if (n > MAX_MULT_SECTORS)
- n = MAX_MULT_SECTORS;
- sector_num = ide_get_sector(s);
- bdrv_read(s->bs, sector_num, s->io_buffer, n);
- s->io_buffer_index = 0;
- s->io_buffer_size = n * 512;
- len = s->io_buffer_size;
- sector_num += n;
- ide_set_sector(s, sector_num);
- s->nsector -= n;
- }
- if (len > transfer_size)
- len = transfer_size;
- cpu_physical_memory_write(phys_addr,
- s->io_buffer + s->io_buffer_index, len);
- s->io_buffer_index += len;
- transfer_size -= len;
- phys_addr += len;
- }
- if (s->io_buffer_index >= s->io_buffer_size && s->nsector == 0) {
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
-#ifdef DEBUG_IDE_ATAPI
- printf("dma status=0x%x\n", s->status);
-#endif
- return 0;
- }
- return transfer_size1 - transfer_size;
-}
-
-static void ide_sector_read_dma(IDEState *s)
-{
- s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
- s->io_buffer_index = 0;
- s->io_buffer_size = 0;
- ide_dma_start(s, ide_read_dma_cb);
-}
-
-static void ide_sector_write_timer_cb(void *opaque)
-{
- IDEState *s = opaque;
- ide_set_irq(s);
-}
-
-static void ide_sector_write(IDEState *s)
-{
- int64_t sector_num;
- int ret, n, n1;
-
- s->status = READY_STAT | SEEK_STAT;
- sector_num = ide_get_sector(s);
-#if defined(DEBUG_IDE)
- printf("write sector=%Ld\n", sector_num);
-#endif
- n = s->nsector;
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
- ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
- s->nsector -= n;
- if (s->nsector == 0) {
- /* no more sector to write */
- ide_transfer_stop(s);
- } else {
- n1 = s->nsector;
- if (n1 > s->req_nb_sectors)
- n1 = s->req_nb_sectors;
- ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
- }
- ide_set_sector(s, sector_num + n);
-
-#ifdef TARGET_I386
- if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
- /* It seems there is a bug in the Windows 2000 installer HDD
- IDE driver which fills the disk with empty logs when the
- IDE write IRQ comes too early. This hack tries to correct
- that at the expense of slower write performances. Use this
- option _only_ to install Windows 2000. You must disable it
- for normal use. */
- qemu_mod_timer(s->sector_write_timer,
- qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
- } else
-#endif
- {
- ide_set_irq(s);
- }
-}
-
-static int ide_write_dma_cb(IDEState *s,
- target_phys_addr_t phys_addr,
- int transfer_size1)
-{
- int len, transfer_size, n;
- int64_t sector_num;
-
- transfer_size = transfer_size1;
- for(;;) {
- len = s->io_buffer_size - s->io_buffer_index;
- if (len == 0) {
- n = s->io_buffer_size >> 9;
- sector_num = ide_get_sector(s);
- bdrv_write(s->bs, sector_num, s->io_buffer,
- s->io_buffer_size >> 9);
- sector_num += n;
- ide_set_sector(s, sector_num);
- s->nsector -= n;
- n = s->nsector;
- if (n == 0) {
- /* end of transfer */
- s->status = READY_STAT | SEEK_STAT;
-#ifdef TARGET_I386
- if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
- /* It seems there is a bug in the Windows 2000 installer
- HDD IDE driver which fills the disk with empty logs
- when the IDE write IRQ comes too early. This hack tries
- to correct that at the expense of slower write
- performances. Use this option _only_ to install Windows
- 2000. You must disable it for normal use. */
- qemu_mod_timer(s->sector_write_timer,
- qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
- } else
-#endif
- ide_set_irq(s);
- return 0;
- }
- if (n > MAX_MULT_SECTORS)
- n = MAX_MULT_SECTORS;
- s->io_buffer_index = 0;
- s->io_buffer_size = n * 512;
- len = s->io_buffer_size;
- }
- if (transfer_size <= 0)
- break;
- if (len > transfer_size)
- len = transfer_size;
- cpu_physical_memory_read(phys_addr,
- s->io_buffer + s->io_buffer_index, len);
- s->io_buffer_index += len;
- transfer_size -= len;
- phys_addr += len;
- }
- return transfer_size1 - transfer_size;
-}
-
-static void ide_sector_write_dma(IDEState *s)
-{
- int n;
- s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
- n = s->nsector;
- if (n > MAX_MULT_SECTORS)
- n = MAX_MULT_SECTORS;
- s->io_buffer_index = 0;
- s->io_buffer_size = n * 512;
- ide_dma_start(s, ide_write_dma_cb);
-}
-
-static void ide_atapi_cmd_ok(IDEState *s)
-{
- s->error = 0;
- s->status = READY_STAT;
- s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
- ide_set_irq(s);
-}
-
-static void ide_atapi_cmd_error(IDEState *s, int sense_key, int asc)
-{
-#ifdef DEBUG_IDE_ATAPI
- printf("atapi_cmd_error: sense=0x%x asc=0x%x\n", sense_key, asc);
-#endif
- s->error = sense_key << 4;
- s->status = READY_STAT | ERR_STAT;
- s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
- s->sense_key = sense_key;
- s->asc = asc;
- ide_set_irq(s);
-}
-
-static inline void cpu_to_ube16(uint8_t *buf, int val)
-{
- buf[0] = val >> 8;
- buf[1] = val;
-}
-
-static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
-{
- buf[0] = val >> 24;
- buf[1] = val >> 16;
- buf[2] = val >> 8;
- buf[3] = val;
-}
-
-static inline int ube16_to_cpu(const uint8_t *buf)
-{
- return (buf[0] << 8) | buf[1];
-}
-
-static inline int ube32_to_cpu(const uint8_t *buf)
-{
- return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
-}
-
-static void lba_to_msf(uint8_t *buf, int lba)
-{
- lba += 150;
- buf[0] = (lba / 75) / 60;
- buf[1] = (lba / 75) % 60;
- buf[2] = lba % 75;
-}
-
-static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
- int sector_size)
-{
- switch(sector_size) {
- case 2048:
- bdrv_read(bs, (int64_t)lba << 2, buf, 4);
- break;
- case 2352:
- /* sync bytes */
- buf[0] = 0x00;
- memset(buf + 1, 0xff, 10);
- buf[11] = 0x00;
- buf += 12;
- /* MSF */
- lba_to_msf(buf, lba);
- buf[3] = 0x01; /* mode 1 data */
- buf += 4;
- /* data */
- bdrv_read(bs, (int64_t)lba << 2, buf, 4);
- buf += 2048;
- /* ECC */
- memset(buf, 0, 288);
- break;
- default:
- break;
- }
-}
-
-/* The whole ATAPI transfer logic is handled in this function */
-static void ide_atapi_cmd_reply_end(IDEState *s)
-{
- int byte_count_limit, size;
-#ifdef DEBUG_IDE_ATAPI
- printf("reply: tx_size=%d elem_tx_size=%d index=%d\n",
- s->packet_transfer_size,
- s->elementary_transfer_size,
- s->io_buffer_index);
-#endif
- if (s->packet_transfer_size <= 0) {
- /* end of transfer */
- ide_transfer_stop(s);
- s->status = READY_STAT;
- s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
- ide_set_irq(s);
-#ifdef DEBUG_IDE_ATAPI
- printf("status=0x%x\n", s->status);
-#endif
- } else {
- /* see if a new sector must be read */
- if (s->lba != -1 && s->io_buffer_index >= s->cd_sector_size) {
- cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size);
- s->lba++;
- s->io_buffer_index = 0;
- }
- if (s->elementary_transfer_size > 0) {
- /* there are some data left to transmit in this elementary
- transfer */
- size = s->cd_sector_size - s->io_buffer_index;
- if (size > s->elementary_transfer_size)
- size = s->elementary_transfer_size;
- ide_transfer_start(s, s->io_buffer + s->io_buffer_index,
- size, ide_atapi_cmd_reply_end);
- s->packet_transfer_size -= size;
- s->elementary_transfer_size -= size;
- s->io_buffer_index += size;
- } else {
- /* a new transfer is needed */
- s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO;
- byte_count_limit = s->lcyl | (s->hcyl << 8);
-#ifdef DEBUG_IDE_ATAPI
- printf("byte_count_limit=%d\n", byte_count_limit);
-#endif
- if (byte_count_limit == 0xffff)
- byte_count_limit--;
- size = s->packet_transfer_size;
- if (size > byte_count_limit) {
- /* byte count limit must be even if this case */
- if (byte_count_limit & 1)
- byte_count_limit--;
- size = byte_count_limit;
- }
- s->lcyl = size;
- s->hcyl = size >> 8;
- s->elementary_transfer_size = size;
- /* we cannot transmit more than one sector at a time */
- if (s->lba != -1) {
- if (size > (s->cd_sector_size - s->io_buffer_index))
- size = (s->cd_sector_size - s->io_buffer_index);
- }
- ide_transfer_start(s, s->io_buffer + s->io_buffer_index,
- size, ide_atapi_cmd_reply_end);
- s->packet_transfer_size -= size;
- s->elementary_transfer_size -= size;
- s->io_buffer_index += size;
- ide_set_irq(s);
-#ifdef DEBUG_IDE_ATAPI
- printf("status=0x%x\n", s->status);
-#endif
- }
- }
-}
-
-/* send a reply of 'size' bytes in s->io_buffer to an ATAPI command */
-static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
-{
- if (size > max_size)
- size = max_size;
- s->lba = -1; /* no sector read */
- s->packet_transfer_size = size;
- s->elementary_transfer_size = 0;
- s->io_buffer_index = 0;
-
- s->status = READY_STAT;
- ide_atapi_cmd_reply_end(s);
-}
-
-/* start a CD-CDROM read command */
-static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
- int sector_size)
-{
- s->lba = lba;
- s->packet_transfer_size = nb_sectors * sector_size;
- s->elementary_transfer_size = 0;
- s->io_buffer_index = sector_size;
- s->cd_sector_size = sector_size;
-
- s->status = READY_STAT;
- ide_atapi_cmd_reply_end(s);
-}
-
-/* ATAPI DMA support */
-static int ide_atapi_cmd_read_dma_cb(IDEState *s,
- target_phys_addr_t phys_addr,
- int transfer_size1)
-{
- int len, transfer_size;
-
- transfer_size = transfer_size1;
- while (transfer_size > 0) {
-#ifdef DEBUG_IDE_ATAPI
- printf("transfer_size: %d phys_addr=%08x\n", transfer_size, phys_addr);
-#endif
- if (s->packet_transfer_size <= 0)
- break;
- len = s->cd_sector_size - s->io_buffer_index;
- if (len <= 0) {
- /* transfert next data */
- cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size);
- s->lba++;
- s->io_buffer_index = 0;
- len = s->cd_sector_size;
- }
- if (len > transfer_size)
- len = transfer_size;
- cpu_physical_memory_write(phys_addr,
- s->io_buffer + s->io_buffer_index, len);
- s->packet_transfer_size -= len;
- s->io_buffer_index += len;
- transfer_size -= len;
- phys_addr += len;
- }
- if (s->packet_transfer_size <= 0) {
- s->status = READY_STAT;
- s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
- ide_set_irq(s);
-#ifdef DEBUG_IDE_ATAPI
- printf("dma status=0x%x\n", s->status);
-#endif
- return 0;
- }
- return transfer_size1 - transfer_size;
-}
-
-/* start a CD-CDROM read command with DMA */
-/* XXX: test if DMA is available */
-static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
- int sector_size)
-{
- s->lba = lba;
- s->packet_transfer_size = nb_sectors * sector_size;
- s->io_buffer_index = sector_size;
- s->cd_sector_size = sector_size;
-
- s->status = READY_STAT | DRQ_STAT;
- ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
-}
-
-static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
- int sector_size)
-{
-#ifdef DEBUG_IDE_ATAPI
- printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors);
-#endif
- if (s->atapi_dma) {
- ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size);
- } else {
- ide_atapi_cmd_read_pio(s, lba, nb_sectors, sector_size);
- }
-}
-
-static void ide_atapi_cmd(IDEState *s)
-{
- const uint8_t *packet;
- uint8_t *buf;
- int max_len;
-
- packet = s->io_buffer;
- buf = s->io_buffer;
-#ifdef DEBUG_IDE_ATAPI
- {
- int i;
- printf("ATAPI limit=0x%x packet:", s->lcyl | (s->hcyl << 8));
- for(i = 0; i < ATAPI_PACKET_SIZE; i++) {
- printf(" %02x", packet[i]);
- }
- printf("\n");
- }
-#endif
- switch(s->io_buffer[0]) {
- case GPCMD_TEST_UNIT_READY:
- if (bdrv_is_inserted(s->bs)) {
- ide_atapi_cmd_ok(s);
- } else {
- ide_atapi_cmd_error(s, SENSE_NOT_READY,
- ASC_MEDIUM_NOT_PRESENT);
- }
- break;
- case GPCMD_MODE_SENSE_10:
- {
- int action, code;
- max_len = ube16_to_cpu(packet + 7);
- action = packet[2] >> 6;
- code = packet[2] & 0x3f;
- switch(action) {
- case 0: /* current values */
- switch(code) {
- case 0x01: /* error recovery */
- cpu_to_ube16(&buf[0], 16 + 6);
- buf[2] = 0x70;
- buf[3] = 0;
- buf[4] = 0;
- buf[5] = 0;
- buf[6] = 0;
- buf[7] = 0;
-
- buf[8] = 0x01;
- buf[9] = 0x06;
- buf[10] = 0x00;
- buf[11] = 0x05;
- buf[12] = 0x00;
- buf[13] = 0x00;
- buf[14] = 0x00;
- buf[15] = 0x00;
- ide_atapi_cmd_reply(s, 16, max_len);
- break;
- case 0x2a:
- cpu_to_ube16(&buf[0], 28 + 6);
- buf[2] = 0x70;
- buf[3] = 0;
- buf[4] = 0;
- buf[5] = 0;
- buf[6] = 0;
- buf[7] = 0;
-
- buf[8] = 0x2a;
- buf[9] = 0x12;
- buf[10] = 0x00;
- buf[11] = 0x00;
-
- buf[12] = 0x70;
- buf[13] = 3 << 5;
- buf[14] = (1 << 0) | (1 << 3) | (1 << 5);
- if (bdrv_is_locked(s->bs))
- buf[6] |= 1 << 1;
- buf[15] = 0x00;
- cpu_to_ube16(&buf[16], 706);
- buf[18] = 0;
- buf[19] = 2;
- cpu_to_ube16(&buf[20], 512);
- cpu_to_ube16(&buf[22], 706);
- buf[24] = 0;
- buf[25] = 0;
- buf[26] = 0;
- buf[27] = 0;
- ide_atapi_cmd_reply(s, 28, max_len);
- break;
- default:
- goto error_cmd;
- }
- break;
- case 1: /* changeable values */
- goto error_cmd;
- case 2: /* default values */
- goto error_cmd;
- default:
- case 3: /* saved values */
- ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_SAVING_PARAMETERS_NOT_SUPPORTED);
- break;
- }
- }
- break;
- case GPCMD_REQUEST_SENSE:
- max_len = packet[4];
- memset(buf, 0, 18);
- buf[0] = 0x70 | (1 << 7);
- buf[2] = s->sense_key;
- buf[7] = 10;
- buf[12] = s->asc;
- ide_atapi_cmd_reply(s, 18, max_len);
- break;
- case GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
- if (bdrv_is_inserted(s->bs)) {
- bdrv_set_locked(s->bs, packet[4] & 1);
- ide_atapi_cmd_ok(s);
- } else {
- ide_atapi_cmd_error(s, SENSE_NOT_READY,
- ASC_MEDIUM_NOT_PRESENT);
- }
- break;
- case GPCMD_READ_10:
- case GPCMD_READ_12:
- {
- int nb_sectors, lba;
-
- if (!bdrv_is_inserted(s->bs)) {
- ide_atapi_cmd_error(s, SENSE_NOT_READY,
- ASC_MEDIUM_NOT_PRESENT);
- break;
- }
- if (packet[0] == GPCMD_READ_10)
- nb_sectors = ube16_to_cpu(packet + 7);
- else
- nb_sectors = ube32_to_cpu(packet + 6);
- lba = ube32_to_cpu(packet + 2);
- if (nb_sectors == 0) {
- ide_atapi_cmd_ok(s);
- break;
- }
- if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) {
- ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_LOGICAL_BLOCK_OOR);
- break;
- }
- ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
- }
- break;
- case GPCMD_READ_CD:
- {
- int nb_sectors, lba, transfer_request;
-
- if (!bdrv_is_inserted(s->bs)) {
- ide_atapi_cmd_error(s, SENSE_NOT_READY,
- ASC_MEDIUM_NOT_PRESENT);
- break;
- }
- nb_sectors = (packet[6] << 16) | (packet[7] << 8) | packet[8];
- lba = ube32_to_cpu(packet + 2);
- if (nb_sectors == 0) {
- ide_atapi_cmd_ok(s);
- break;
- }
- if (((int64_t)(lba + nb_sectors) << 2) > s->nb_sectors) {
- ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_LOGICAL_BLOCK_OOR);
- break;
- }
- transfer_request = packet[9];
- switch(transfer_request & 0xf8) {
- case 0x00:
- /* nothing */
- ide_atapi_cmd_ok(s);
- break;
- case 0x10:
- /* normal read */
- ide_atapi_cmd_read(s, lba, nb_sectors, 2048);
- break;
- case 0xf8:
- /* read all data */
- ide_atapi_cmd_read(s, lba, nb_sectors, 2352);
- break;
- default:
- ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- break;
- }
- }
- break;
- case GPCMD_SEEK:
- {
- int lba;
- if (!bdrv_is_inserted(s->bs)) {
- ide_atapi_cmd_error(s, SENSE_NOT_READY,
- ASC_MEDIUM_NOT_PRESENT);
- break;
- }
- lba = ube32_to_cpu(packet + 2);
- if (((int64_t)lba << 2) > s->nb_sectors) {
- ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_LOGICAL_BLOCK_OOR);
- break;
- }
- ide_atapi_cmd_ok(s);
- }
- break;
- case GPCMD_START_STOP_UNIT:
- {
- int start, eject;
- start = packet[4] & 1;
- eject = (packet[4] >> 1) & 1;
-
- if (eject && !start) {
- /* eject the disk */
- bdrv_close(s->bs);
- }
- ide_atapi_cmd_ok(s);
- }
- break;
- case GPCMD_MECHANISM_STATUS:
- {
- max_len = ube16_to_cpu(packet + 8);
- cpu_to_ube16(buf, 0);
- /* no current LBA */
- buf[2] = 0;
- buf[3] = 0;
- buf[4] = 0;
- buf[5] = 1;
- cpu_to_ube16(buf + 6, 0);
- ide_atapi_cmd_reply(s, 8, max_len);
- }
- break;
- case GPCMD_READ_TOC_PMA_ATIP:
- {
- int format, msf, start_track, len;
-
- if (!bdrv_is_inserted(s->bs)) {
- ide_atapi_cmd_error(s, SENSE_NOT_READY,
- ASC_MEDIUM_NOT_PRESENT);
- break;
- }
- max_len = ube16_to_cpu(packet + 7);
- format = packet[9] >> 6;
- msf = (packet[1] >> 1) & 1;
- start_track = packet[6];
- switch(format) {
- case 0:
- len = cdrom_read_toc(s->nb_sectors >> 2, buf, msf, start_track);
- if (len < 0)
- goto error_cmd;
- ide_atapi_cmd_reply(s, len, max_len);
- break;
- case 1:
- /* multi session : only a single session defined */
- memset(buf, 0, 12);
- buf[1] = 0x0a;
- buf[2] = 0x01;
- buf[3] = 0x01;
- ide_atapi_cmd_reply(s, 12, max_len);
- break;
- case 2:
- len = cdrom_read_toc_raw(s->nb_sectors >> 2, buf, msf, start_track);
- if (len < 0)
- goto error_cmd;
- ide_atapi_cmd_reply(s, len, max_len);
- break;
- default:
- error_cmd:
- ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_INV_FIELD_IN_CMD_PACKET);
- break;
- }
- }
- break;
- case GPCMD_READ_CDVD_CAPACITY:
- if (!bdrv_is_inserted(s->bs)) {
- ide_atapi_cmd_error(s, SENSE_NOT_READY,
- ASC_MEDIUM_NOT_PRESENT);
- break;
- }
- /* NOTE: it is really the number of sectors minus 1 */
- cpu_to_ube32(buf, (s->nb_sectors >> 2) - 1);
- cpu_to_ube32(buf + 4, 2048);
- ide_atapi_cmd_reply(s, 8, 8);
- break;
- case GPCMD_INQUIRY:
- max_len = packet[4];
- buf[0] = 0x05; /* CD-ROM */
- buf[1] = 0x80; /* removable */
- buf[2] = 0x00; /* ISO */
- buf[3] = 0x21; /* ATAPI-2 (XXX: put ATAPI-4 ?) */
- buf[4] = 31; /* additionnal length */
- buf[5] = 0; /* reserved */
- buf[6] = 0; /* reserved */
- buf[7] = 0; /* reserved */
- padstr8(buf + 8, 8, "QEMU");
- padstr8(buf + 16, 16, "QEMU CD-ROM");
- padstr8(buf + 32, 4, QEMU_VERSION);
- ide_atapi_cmd_reply(s, 36, max_len);
- break;
- default:
- ide_atapi_cmd_error(s, SENSE_ILLEGAL_REQUEST,
- ASC_ILLEGAL_OPCODE);
- break;
- }
-}
-
-/* called when the inserted state of the media has changed */
-static void cdrom_change_cb(void *opaque)
-{
- IDEState *s = opaque;
- int64_t nb_sectors;
-
- /* XXX: send interrupt too */
- bdrv_get_geometry(s->bs, &nb_sectors);
- s->nb_sectors = nb_sectors;
-}
-
-static void ide_cmd_lba48_transform(IDEState *s, int lba48)
-{
- s->lba48 = lba48;
-
- /* handle the 'magic' 0 nsector count conversion here. to avoid
- * fiddling with the rest of the read logic, we just store the
- * full sector count in ->nsector and ignore ->hob_nsector from now
- */
- if (!s->lba48) {
- if (!s->nsector)
- s->nsector = 256;
- } else {
- if (!s->nsector && !s->hob_nsector)
- s->nsector = 65536;
- else {
- int lo = s->nsector;
- int hi = s->hob_nsector;
-
- s->nsector = (hi << 8) | lo;
- }
- }
-}
-
-static void ide_clear_hob(IDEState *ide_if)
-{
- /* any write clears HOB high bit of device control register */
- ide_if[0].select &= ~(1 << 7);
- ide_if[1].select &= ~(1 << 7);
-}
-
-static void ide_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- IDEState *ide_if = opaque;
- IDEState *s;
- int unit, n;
- int lba48 = 0;
-
-#ifdef DEBUG_IDE
- printf("IDE: write addr=0x%x val=0x%02x\n", addr, val);
-#endif
-
- addr &= 7;
- switch(addr) {
- case 0:
- break;
- case 1:
- ide_clear_hob(ide_if);
- /* NOTE: data is written to the two drives */
- ide_if[0].hob_feature = ide_if[0].feature;
- ide_if[1].hob_feature = ide_if[1].feature;
- ide_if[0].feature = val;
- ide_if[1].feature = val;
- break;
- case 2:
- ide_clear_hob(ide_if);
- ide_if[0].hob_nsector = ide_if[0].nsector;
- ide_if[1].hob_nsector = ide_if[1].nsector;
- ide_if[0].nsector = val;
- ide_if[1].nsector = val;
- break;
- case 3:
- ide_clear_hob(ide_if);
- ide_if[0].hob_sector = ide_if[0].sector;
- ide_if[1].hob_sector = ide_if[1].sector;
- ide_if[0].sector = val;
- ide_if[1].sector = val;
- break;
- case 4:
- ide_clear_hob(ide_if);
- ide_if[0].hob_lcyl = ide_if[0].lcyl;
- ide_if[1].hob_lcyl = ide_if[1].lcyl;
- ide_if[0].lcyl = val;
- ide_if[1].lcyl = val;
- break;
- case 5:
- ide_clear_hob(ide_if);
- ide_if[0].hob_hcyl = ide_if[0].hcyl;
- ide_if[1].hob_hcyl = ide_if[1].hcyl;
- ide_if[0].hcyl = val;
- ide_if[1].hcyl = val;
- break;
- case 6:
- /* FIXME: HOB readback uses bit 7 */
- ide_if[0].select = (val & ~0x10) | 0xa0;
- ide_if[1].select = (val | 0x10) | 0xa0;
- /* select drive */
- unit = (val >> 4) & 1;
- s = ide_if + unit;
- ide_if->cur_drive = s;
- break;
- default:
- case 7:
- /* command */
-#if defined(DEBUG_IDE)
- printf("ide: CMD=%02x\n", val);
-#endif
- s = ide_if->cur_drive;
- /* ignore commands to non existant slave */
- if (s != ide_if && !s->bs)
- break;
-
- switch(val) {
- case WIN_IDENTIFY:
- if (s->bs && !s->is_cdrom) {
- ide_identify(s);
- s->status = READY_STAT | SEEK_STAT;
- ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
- } else {
- if (s->is_cdrom) {
- ide_set_signature(s);
- }
- ide_abort_command(s);
- }
- ide_set_irq(s);
- break;
- case WIN_SPECIFY:
- case WIN_RECAL:
- s->error = 0;
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
- break;
- case WIN_SETMULT:
- if (s->nsector > MAX_MULT_SECTORS ||
- s->nsector == 0 ||
- (s->nsector & (s->nsector - 1)) != 0) {
- ide_abort_command(s);
- } else {
- s->mult_sectors = s->nsector;
- s->status = READY_STAT;
- }
- ide_set_irq(s);
- break;
- case WIN_VERIFY_EXT:
- lba48 = 1;
- case WIN_VERIFY:
- case WIN_VERIFY_ONCE:
- /* do sector number check ? */
- ide_cmd_lba48_transform(s, lba48);
- s->status = READY_STAT;
- ide_set_irq(s);
- break;
- case WIN_READ_EXT:
- lba48 = 1;
- case WIN_READ:
- case WIN_READ_ONCE:
- if (!s->bs)
- goto abort_cmd;
- ide_cmd_lba48_transform(s, lba48);
- s->req_nb_sectors = 1;
- ide_sector_read(s);
- break;
- case WIN_WRITE_EXT:
- lba48 = 1;
- case WIN_WRITE:
- case WIN_WRITE_ONCE:
- ide_cmd_lba48_transform(s, lba48);
- s->error = 0;
- s->status = SEEK_STAT | READY_STAT;
- s->req_nb_sectors = 1;
- ide_transfer_start(s, s->io_buffer, 512, ide_sector_write);
- break;
- case WIN_MULTREAD_EXT:
- lba48 = 1;
- case WIN_MULTREAD:
- if (!s->mult_sectors)
- goto abort_cmd;
- ide_cmd_lba48_transform(s, lba48);
- s->req_nb_sectors = s->mult_sectors;
- ide_sector_read(s);
- break;
- case WIN_MULTWRITE_EXT:
- lba48 = 1;
- case WIN_MULTWRITE:
- if (!s->mult_sectors)
- goto abort_cmd;
- ide_cmd_lba48_transform(s, lba48);
- s->error = 0;
- s->status = SEEK_STAT | READY_STAT;
- s->req_nb_sectors = s->mult_sectors;
- n = s->nsector;
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
- ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_write);
- break;
- case WIN_READDMA_EXT:
- lba48 = 1;
- case WIN_READDMA:
- case WIN_READDMA_ONCE:
- if (!s->bs)
- goto abort_cmd;
- ide_cmd_lba48_transform(s, lba48);
- ide_sector_read_dma(s);
- break;
- case WIN_WRITEDMA_EXT:
- lba48 = 1;
- case WIN_WRITEDMA:
- case WIN_WRITEDMA_ONCE:
- if (!s->bs)
- goto abort_cmd;
- ide_cmd_lba48_transform(s, lba48);
- ide_sector_write_dma(s);
- break;
- case WIN_READ_NATIVE_MAX_EXT:
- lba48 = 1;
- case WIN_READ_NATIVE_MAX:
- ide_cmd_lba48_transform(s, lba48);
- ide_set_sector(s, s->nb_sectors - 1);
- s->status = READY_STAT;
- ide_set_irq(s);
- break;
- case WIN_CHECKPOWERMODE1:
- s->nsector = 0xff; /* device active or idle */
- s->status = READY_STAT;
- ide_set_irq(s);
- break;
- case WIN_SETFEATURES:
- if (!s->bs)
- goto abort_cmd;
- /* XXX: valid for CDROM ? */
- switch(s->feature) {
- case 0x02: /* write cache enable */
- case 0x82: /* write cache disable */
- case 0xaa: /* read look-ahead enable */
- case 0x55: /* read look-ahead disable */
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
- break;
- case 0x03: { /* set transfer mode */
- uint8_t val = s->nsector & 0x07;
-
- switch (s->nsector >> 3) {
- case 0x00: /* pio default */
- case 0x01: /* pio mode */
- put_le16(s->identify_data + 63,0x07);
- put_le16(s->identify_data + 88,0x3f);
- break;
- case 0x04: /* mdma mode */
- put_le16(s->identify_data + 63,0x07 | (1 << (val + 8)));
- put_le16(s->identify_data + 88,0x3f);
- break;
- case 0x08: /* udma mode */
- put_le16(s->identify_data + 63,0x07);
- put_le16(s->identify_data + 88,0x3f | (1 << (val + 8)));
- break;
- default:
- goto abort_cmd;
- }
- s->status = READY_STAT | SEEK_STAT;
- ide_set_irq(s);
- break;
- }
- default:
- goto abort_cmd;
- }
- break;
- case WIN_FLUSH_CACHE:
- case WIN_FLUSH_CACHE_EXT:
- if (s->bs)
- bdrv_flush(s->bs);
- s->status = READY_STAT;
- ide_set_irq(s);
- break;
- case WIN_STANDBYNOW1:
- case WIN_IDLEIMMEDIATE:
- s->status = READY_STAT;
- ide_set_irq(s);
- break;
- /* ATAPI commands */
- case WIN_PIDENTIFY:
- if (s->is_cdrom) {
- ide_atapi_identify(s);
- s->status = READY_STAT | SEEK_STAT;
- ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);
- } else {
- ide_abort_command(s);
- }
- ide_set_irq(s);
- break;
- case WIN_DIAGNOSE:
- ide_set_signature(s);
- s->status = 0x00; /* NOTE: READY is _not_ set */
- s->error = 0x01;
- break;
- case WIN_SRST:
- if (!s->is_cdrom)
- goto abort_cmd;
- ide_set_signature(s);
- s->status = 0x00; /* NOTE: READY is _not_ set */
- s->error = 0x01;
- break;
- case WIN_PACKETCMD:
- if (!s->is_cdrom)
- goto abort_cmd;
- /* overlapping commands not supported */
- if (s->feature & 0x02)
- goto abort_cmd;
- s->atapi_dma = s->feature & 1;
- s->nsector = 1;
- ide_transfer_start(s, s->io_buffer, ATAPI_PACKET_SIZE,
- ide_atapi_cmd);
- break;
- default:
- abort_cmd:
- ide_abort_command(s);
- ide_set_irq(s);
- break;
- }
- }
-}
-
-static uint32_t ide_ioport_read(void *opaque, uint32_t addr1)
-{
- IDEState *ide_if = opaque;
- IDEState *s = ide_if->cur_drive;
- uint32_t addr;
- int ret, hob;
-
- addr = addr1 & 7;
- /* FIXME: HOB readback uses bit 7, but it's always set right now */
- //hob = s->select & (1 << 7);
- hob = 0;
- switch(addr) {
- case 0:
- ret = 0xff;
- break;
- case 1:
- if (!ide_if[0].bs && !ide_if[1].bs)
- ret = 0;
- else if (!hob)
- ret = s->error;
- else
- ret = s->hob_feature;
- break;
- case 2:
- if (!ide_if[0].bs && !ide_if[1].bs)
- ret = 0;
- else if (!hob)
- ret = s->nsector & 0xff;
- else
- ret = s->hob_nsector;
- break;
- case 3:
- if (!ide_if[0].bs && !ide_if[1].bs)
- ret = 0;
- else if (!hob)
- ret = s->sector;
- else
- ret = s->hob_sector;
- break;
- case 4:
- if (!ide_if[0].bs && !ide_if[1].bs)
- ret = 0;
- else if (!hob)
- ret = s->lcyl;
- else
- ret = s->hob_lcyl;
- break;
- case 5:
- if (!ide_if[0].bs && !ide_if[1].bs)
- ret = 0;
- else if (!hob)
- ret = s->hcyl;
- else
- ret = s->hob_hcyl;
- break;
- case 6:
- if (!ide_if[0].bs && !ide_if[1].bs)
- ret = 0;
- else
- ret = s->select;
- break;
- default:
- case 7:
- if ((!ide_if[0].bs && !ide_if[1].bs) ||
- (s != ide_if && !s->bs))
- ret = 0;
- else
- ret = s->status;
- s->set_irq(s->irq_opaque, s->irq, 0);
- break;
- }
-#ifdef DEBUG_IDE
- printf("ide: read addr=0x%x val=%02x\n", addr1, ret);
-#endif
- return ret;
-}
-
-static uint32_t ide_status_read(void *opaque, uint32_t addr)
-{
- IDEState *ide_if = opaque;
- IDEState *s = ide_if->cur_drive;
- int ret;
-
- if ((!ide_if[0].bs && !ide_if[1].bs) ||
- (s != ide_if && !s->bs))
- ret = 0;
- else
- ret = s->status;
-#ifdef DEBUG_IDE
- printf("ide: read status addr=0x%x val=%02x\n", addr, ret);
-#endif
- return ret;
-}
-
-static void ide_cmd_write(void *opaque, uint32_t addr, uint32_t val)
-{
- IDEState *ide_if = opaque;
- IDEState *s;
- int i;
-
-#ifdef DEBUG_IDE
- printf("ide: write control addr=0x%x val=%02x\n", addr, val);
-#endif
- /* common for both drives */
- if (!(ide_if[0].cmd & IDE_CMD_RESET) &&
- (val & IDE_CMD_RESET)) {
- /* reset low to high */
- for(i = 0;i < 2; i++) {
- s = &ide_if[i];
- s->status = BUSY_STAT | SEEK_STAT;
- s->error = 0x01;
- }
- } else if ((ide_if[0].cmd & IDE_CMD_RESET) &&
- !(val & IDE_CMD_RESET)) {
- /* high to low */
- for(i = 0;i < 2; i++) {
- s = &ide_if[i];
- if (s->is_cdrom)
- s->status = 0x00; /* NOTE: READY is _not_ set */
- else
- s->status = READY_STAT | SEEK_STAT;
- ide_set_signature(s);
- }
- }
-
- ide_if[0].cmd = val;
- ide_if[1].cmd = val;
-}
-
-static void ide_data_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- IDEState *s = ((IDEState *)opaque)->cur_drive;
- uint8_t *p;
-
- p = s->data_ptr;
- *(uint16_t *)p = le16_to_cpu(val);
- p += 2;
- s->data_ptr = p;
- if (p >= s->data_end)
- s->end_transfer_func(s);
-}
-
-static uint32_t ide_data_readw(void *opaque, uint32_t addr)
-{
- IDEState *s = ((IDEState *)opaque)->cur_drive;
- uint8_t *p;
- int ret;
- p = s->data_ptr;
- ret = cpu_to_le16(*(uint16_t *)p);
- p += 2;
- s->data_ptr = p;
- if (p >= s->data_end)
- s->end_transfer_func(s);
- return ret;
-}
-
-static void ide_data_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- IDEState *s = ((IDEState *)opaque)->cur_drive;
- uint8_t *p;
-
- p = s->data_ptr;
- *(uint32_t *)p = le32_to_cpu(val);
- p += 4;
- s->data_ptr = p;
- if (p >= s->data_end)
- s->end_transfer_func(s);
-}
-
-static uint32_t ide_data_readl(void *opaque, uint32_t addr)
-{
- IDEState *s = ((IDEState *)opaque)->cur_drive;
- uint8_t *p;
- int ret;
-
- p = s->data_ptr;
- ret = cpu_to_le32(*(uint32_t *)p);
- p += 4;
- s->data_ptr = p;
- if (p >= s->data_end)
- s->end_transfer_func(s);
- return ret;
-}
-
-static void ide_dummy_transfer_stop(IDEState *s)
-{
- s->data_ptr = s->io_buffer;
- s->data_end = s->io_buffer;
- s->io_buffer[0] = 0xff;
- s->io_buffer[1] = 0xff;
- s->io_buffer[2] = 0xff;
- s->io_buffer[3] = 0xff;
-}
-
-static void ide_reset(IDEState *s)
-{
- s->mult_sectors = MAX_MULT_SECTORS;
- s->cur_drive = s;
- s->select = 0xa0;
- s->status = READY_STAT;
- ide_set_signature(s);
- /* init the transfer handler so that 0xffff is returned on data
- accesses */
- s->end_transfer_func = ide_dummy_transfer_stop;
- ide_dummy_transfer_stop(s);
-}
-
-struct partition {
- uint8_t boot_ind; /* 0x80 - active */
- uint8_t head; /* starting head */
- uint8_t sector; /* starting sector */
- uint8_t cyl; /* starting cylinder */
- uint8_t sys_ind; /* What partition type */
- uint8_t end_head; /* end head */
- uint8_t end_sector; /* end sector */
- uint8_t end_cyl; /* end cylinder */
- uint32_t start_sect; /* starting sector counting from 0 */
- uint32_t nr_sects; /* nr of sectors in partition */
-} __attribute__((packed));
-
-/* try to guess the disk logical geometry from the MSDOS partition table. Return 0 if OK, -1 if could not guess */
-static int guess_disk_lchs(IDEState *s,
- int *pcylinders, int *pheads, int *psectors)
-{
- uint8_t buf[512];
- int ret, i, heads, sectors, cylinders;
- struct partition *p;
- uint32_t nr_sects;
-
- ret = bdrv_read(s->bs, 0, buf, 1);
- if (ret < 0)
- return -1;
- /* test msdos magic */
- if (buf[510] != 0x55 || buf[511] != 0xaa)
- return -1;
- for(i = 0; i < 4; i++) {
- p = ((struct partition *)(buf + 0x1be)) + i;
- nr_sects = le32_to_cpu(p->nr_sects);
- if (nr_sects && p->end_head) {
- /* We make the assumption that the partition terminates on
- a cylinder boundary */
- heads = p->end_head + 1;
- sectors = p->end_sector & 63;
- if (sectors == 0)
- continue;
- cylinders = s->nb_sectors / (heads * sectors);
- if (cylinders < 1 || cylinders > 16383)
- continue;
- *pheads = heads;
- *psectors = sectors;
- *pcylinders = cylinders;
-#if 0
- printf("guessed geometry: LCHS=%d %d %d\n",
- cylinders, heads, sectors);
-#endif
- return 0;
- }
- }
- return -1;
-}
-
-static void ide_init2(IDEState *ide_state,
- BlockDriverState *hd0, BlockDriverState *hd1,
- SetIRQFunc *set_irq, void *irq_opaque, int irq)
-{
- IDEState *s;
- static int drive_serial = 1;
- int i, cylinders, heads, secs, translation;
- int64_t nb_sectors;
-
- for(i = 0; i < 2; i++) {
- s = ide_state + i;
- if (i == 0)
- s->bs = hd0;
- else
- s->bs = hd1;
- if (s->bs) {
- bdrv_get_geometry(s->bs, &nb_sectors);
- s->nb_sectors = nb_sectors;
- /* if a geometry hint is available, use it */
- bdrv_get_geometry_hint(s->bs, &cylinders, &heads, &secs);
- if (cylinders != 0) {
- s->cylinders = cylinders;
- s->heads = heads;
- s->sectors = secs;
- } else {
- if (guess_disk_lchs(s, &cylinders, &heads, &secs) == 0) {
- if (heads > 16) {
- /* if heads > 16, it means that a BIOS LBA
- translation was active, so the default
- hardware geometry is OK */
- goto default_geometry;
- } else {
- s->cylinders = cylinders;
- s->heads = heads;
- s->sectors = secs;
- /* disable any translation to be in sync with
- the logical geometry */
- translation = bdrv_get_translation_hint(s->bs);
- if (translation == BIOS_ATA_TRANSLATION_AUTO) {
- bdrv_set_translation_hint(s->bs,
- BIOS_ATA_TRANSLATION_NONE);
- }
- }
- } else {
- default_geometry:
- /* if no geometry, use a standard physical disk geometry */
- cylinders = nb_sectors / (16 * 63);
- if (cylinders > 16383)
- cylinders = 16383;
- else if (cylinders < 2)
- cylinders = 2;
- s->cylinders = cylinders;
- s->heads = 16;
- s->sectors = 63;
- }
- bdrv_set_geometry_hint(s->bs, s->cylinders, s->heads, s->sectors);
- }
- if (bdrv_get_type_hint(s->bs) == BDRV_TYPE_CDROM) {
- s->is_cdrom = 1;
- bdrv_set_change_cb(s->bs, cdrom_change_cb, s);
- }
- }
- 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);
- ide_reset(s);
- }
-}
-
-static void ide_init_ioport(IDEState *ide_state, int iobase, int iobase2)
-{
- register_ioport_write(iobase, 8, 1, ide_ioport_write, ide_state);
- register_ioport_read(iobase, 8, 1, ide_ioport_read, ide_state);
- if (iobase2) {
- register_ioport_read(iobase2, 1, 1, ide_status_read, ide_state);
- register_ioport_write(iobase2, 1, 1, ide_cmd_write, ide_state);
- }
-
- /* data ports */
- register_ioport_write(iobase, 2, 2, ide_data_writew, ide_state);
- register_ioport_read(iobase, 2, 2, ide_data_readw, ide_state);
- register_ioport_write(iobase, 4, 4, ide_data_writel, ide_state);
- register_ioport_read(iobase, 4, 4, ide_data_readl, ide_state);
-}
-
-/***********************************************************/
-/* ISA IDE definitions */
-
-void isa_ide_init(int iobase, int iobase2, int irq,
- BlockDriverState *hd0, BlockDriverState *hd1)
-{
- IDEState *ide_state;
-
- ide_state = qemu_mallocz(sizeof(IDEState) * 2);
- if (!ide_state)
- return;
-
- ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq);
- ide_init_ioport(ide_state, iobase, iobase2);
-}
-
-/***********************************************************/
-/* PCI IDE definitions */
-
-static void cmd646_update_irq(PCIIDEState *d);
-
-static void ide_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- PCIIDEState *d = (PCIIDEState *)pci_dev;
- IDEState *ide_state;
-
- if (region_num <= 3) {
- ide_state = &d->ide_if[(region_num >> 1) * 2];
- if (region_num & 1) {
- register_ioport_read(addr + 2, 1, 1, ide_status_read, ide_state);
- register_ioport_write(addr + 2, 1, 1, ide_cmd_write, ide_state);
- } else {
- register_ioport_write(addr, 8, 1, ide_ioport_write, ide_state);
- register_ioport_read(addr, 8, 1, ide_ioport_read, ide_state);
-
- /* data ports */
- register_ioport_write(addr, 2, 2, ide_data_writew, ide_state);
- register_ioport_read(addr, 2, 2, ide_data_readw, ide_state);
- register_ioport_write(addr, 4, 4, ide_data_writel, ide_state);
- register_ioport_read(addr, 4, 4, ide_data_readl, ide_state);
- }
- }
-}
-
-/* XXX: full callback usage to prepare non blocking I/Os support -
- error handling */
-static void ide_dma_loop(BMDMAState *bm)
-{
- struct {
- uint32_t addr;
- uint32_t size;
- } prd;
- target_phys_addr_t cur_addr;
- int len, i, len1;
-
- cur_addr = bm->addr;
- /* at most one page to avoid hanging if erroneous parameters */
- for(i = 0; i < 512; i++) {
- cpu_physical_memory_read(cur_addr, (uint8_t *)&prd, 8);
- prd.addr = le32_to_cpu(prd.addr);
- prd.size = le32_to_cpu(prd.size);
-#ifdef DEBUG_IDE
- printf("ide: dma: prd: %08x: addr=0x%08x size=0x%08x\n",
- (int)cur_addr, prd.addr, prd.size);
-#endif
- len = prd.size & 0xfffe;
- if (len == 0)
- len = 0x10000;
- while (len > 0) {
- len1 = bm->dma_cb(bm->ide_if, prd.addr, len);
- if (len1 == 0)
- goto the_end;
- prd.addr += len1;
- len -= len1;
- }
- /* end of transfer */
- if (prd.size & 0x80000000)
- break;
- cur_addr += 8;
- }
- /* end of transfer */
- the_end:
- bm->status &= ~BM_STATUS_DMAING;
- bm->status |= BM_STATUS_INT;
- bm->dma_cb = NULL;
- bm->ide_if = NULL;
-}
-
-static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb)
-{
- BMDMAState *bm = s->bmdma;
- if(!bm)
- return;
- bm->ide_if = s;
- bm->dma_cb = dma_cb;
- if (bm->status & BM_STATUS_DMAING) {
- ide_dma_loop(bm);
- }
-}
-
-static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- BMDMAState *bm = opaque;
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
-#endif
- if (!(val & BM_CMD_START)) {
- /* XXX: do it better */
- bm->status &= ~BM_STATUS_DMAING;
- bm->cmd = val & 0x09;
- } else {
- bm->status |= BM_STATUS_DMAING;
- bm->cmd = val & 0x09;
- /* start dma transfer if possible */
- if (bm->dma_cb)
- ide_dma_loop(bm);
- }
-}
-
-static uint32_t bmdma_readb(void *opaque, uint32_t addr)
-{
- BMDMAState *bm = opaque;
- PCIIDEState *pci_dev;
- uint32_t val;
-
- switch(addr & 3) {
- case 0:
- val = bm->cmd;
- break;
- case 1:
- pci_dev = bm->pci_dev;
- if (pci_dev->type == IDE_TYPE_CMD646) {
- val = pci_dev->dev.config[MRDMODE];
- } else {
- val = 0xff;
- }
- break;
- case 2:
- val = bm->status;
- break;
- case 3:
- pci_dev = bm->pci_dev;
- if (pci_dev->type == IDE_TYPE_CMD646) {
- if (bm == &pci_dev->bmdma[0])
- val = pci_dev->dev.config[UDIDETCR0];
- else
- val = pci_dev->dev.config[UDIDETCR1];
- } else {
- val = 0xff;
- }
- break;
- default:
- val = 0xff;
- break;
- }
-#ifdef DEBUG_IDE
- printf("bmdma: readb 0x%02x : 0x%02x\n", addr, val);
-#endif
- return val;
-}
-
-static void bmdma_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- BMDMAState *bm = opaque;
- PCIIDEState *pci_dev;
-#ifdef DEBUG_IDE
- printf("bmdma: writeb 0x%02x : 0x%02x\n", addr, val);
-#endif
- switch(addr & 3) {
- case 1:
- pci_dev = bm->pci_dev;
- if (pci_dev->type == IDE_TYPE_CMD646) {
- pci_dev->dev.config[MRDMODE] =
- (pci_dev->dev.config[MRDMODE] & ~0x30) | (val & 0x30);
- cmd646_update_irq(pci_dev);
- }
- break;
- case 2:
- bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
- break;
- case 3:
- pci_dev = bm->pci_dev;
- if (pci_dev->type == IDE_TYPE_CMD646) {
- if (bm == &pci_dev->bmdma[0])
- pci_dev->dev.config[UDIDETCR0] = val;
- else
- pci_dev->dev.config[UDIDETCR1] = val;
- }
- break;
- }
-}
-
-static uint32_t bmdma_addr_readl(void *opaque, uint32_t addr)
-{
- BMDMAState *bm = opaque;
- uint32_t val;
- val = bm->addr;
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
-#endif
- return val;
-}
-
-static void bmdma_addr_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- BMDMAState *bm = opaque;
-#ifdef DEBUG_IDE
- printf("%s: 0x%08x\n", __func__, val);
-#endif
- bm->addr = val & ~3;
-}
-
-static void bmdma_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- PCIIDEState *d = (PCIIDEState *)pci_dev;
- int i;
-
- for(i = 0;i < 2; i++) {
- BMDMAState *bm = &d->bmdma[i];
- d->ide_if[2 * i].bmdma = bm;
- d->ide_if[2 * i + 1].bmdma = bm;
- bm->pci_dev = (PCIIDEState *)pci_dev;
-
- register_ioport_write(addr, 1, 1, bmdma_cmd_writeb, bm);
-
- register_ioport_write(addr + 1, 3, 1, bmdma_writeb, bm);
- register_ioport_read(addr, 4, 1, bmdma_readb, bm);
-
- register_ioport_write(addr + 4, 4, 4, bmdma_addr_writel, bm);
- register_ioport_read(addr + 4, 4, 4, bmdma_addr_readl, bm);
- addr += 8;
- }
-}
-
-/* XXX: call it also when the MRDMODE is changed from the PCI config
- registers */
-static void cmd646_update_irq(PCIIDEState *d)
-{
- int pci_level;
- pci_level = ((d->dev.config[MRDMODE] & MRDMODE_INTR_CH0) &&
- !(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);
-}
-
-/* the PCI irq level is the logical OR of the two channels */
-static void cmd646_set_irq(void *opaque, int channel, int level)
-{
- PCIIDEState *d = opaque;
- int irq_mask;
-
- irq_mask = MRDMODE_INTR_CH0 << channel;
- if (level)
- d->dev.config[MRDMODE] |= irq_mask;
- else
- d->dev.config[MRDMODE] &= ~irq_mask;
- cmd646_update_irq(d);
-}
-
-/* CMD646 PCI IDE controller */
-void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
- int secondary_ide_enabled)
-{
- PCIIDEState *d;
- uint8_t *pci_conf;
- int i;
-
- d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE",
- sizeof(PCIIDEState),
- -1,
- NULL, NULL);
- d->type = IDE_TYPE_CMD646;
- pci_conf = d->dev.config;
- pci_conf[0x00] = 0x95; // CMD646
- pci_conf[0x01] = 0x10;
- pci_conf[0x02] = 0x46;
- pci_conf[0x03] = 0x06;
-
- pci_conf[0x08] = 0x07; // IDE controller revision
- pci_conf[0x09] = 0x8f;
-
- pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
- pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
- pci_conf[0x0e] = 0x00; // header_type
-
- if (secondary_ide_enabled) {
- /* XXX: if not enabled, really disable the seconday IDE controller */
- pci_conf[0x51] = 0x80; /* enable IDE1 */
- }
-
- pci_register_io_region((PCIDevice *)d, 0, 0x8,
- PCI_ADDRESS_SPACE_IO, ide_map);
- pci_register_io_region((PCIDevice *)d, 1, 0x4,
- PCI_ADDRESS_SPACE_IO, ide_map);
- pci_register_io_region((PCIDevice *)d, 2, 0x8,
- PCI_ADDRESS_SPACE_IO, ide_map);
- pci_register_io_region((PCIDevice *)d, 3, 0x4,
- PCI_ADDRESS_SPACE_IO, ide_map);
- pci_register_io_region((PCIDevice *)d, 4, 0x10,
- PCI_ADDRESS_SPACE_IO, bmdma_map);
-
- pci_conf[0x3d] = 0x01; // interrupt on pin 1
-
- 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);
-}
-
-/* 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)
-{
- PCIIDEState *d;
- uint8_t *pci_conf;
-
- /* register a function 1 of PIIX3 */
- d = (PCIIDEState *)pci_register_device(bus, "PIIX3 IDE",
- sizeof(PCIIDEState),
- devfn,
- NULL, NULL);
- d->type = IDE_TYPE_PIIX3;
-
- pci_conf = d->dev.config;
- pci_conf[0x00] = 0x86; // Intel
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x10;
- pci_conf[0x03] = 0x70;
- pci_conf[0x09] = 0x80; // legacy ATA mode
- pci_conf[0x0a] = 0x01; // class_sub = PCI_IDE
- pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
- pci_conf[0x0e] = 0x00; // header_type
-
- 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_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
- ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
-}
-
-/***********************************************************/
-/* MacIO based PowerPC IDE */
-
-/* PowerMac IDE memory IO */
-static void pmac_ide_writeb (void *opaque,
- target_phys_addr_t addr, uint32_t val)
-{
- addr = (addr & 0xFFF) >> 4;
- switch (addr) {
- case 1 ... 7:
- ide_ioport_write(opaque, addr, val);
- break;
- case 8:
- case 22:
- ide_cmd_write(opaque, 0, val);
- break;
- default:
- break;
- }
-}
-
-static uint32_t pmac_ide_readb (void *opaque,target_phys_addr_t addr)
-{
- uint8_t retval;
-
- addr = (addr & 0xFFF) >> 4;
- switch (addr) {
- case 1 ... 7:
- retval = ide_ioport_read(opaque, addr);
- break;
- case 8:
- case 22:
- retval = ide_status_read(opaque, 0);
- break;
- default:
- retval = 0xFF;
- break;
- }
- return retval;
-}
-
-static void pmac_ide_writew (void *opaque,
- target_phys_addr_t addr, uint32_t val)
-{
- addr = (addr & 0xFFF) >> 4;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- if (addr == 0) {
- ide_data_writew(opaque, 0, val);
- }
-}
-
-static uint32_t pmac_ide_readw (void *opaque,target_phys_addr_t addr)
-{
- uint16_t retval;
-
- addr = (addr & 0xFFF) >> 4;
- if (addr == 0) {
- retval = ide_data_readw(opaque, 0);
- } else {
- retval = 0xFFFF;
- }
-#ifdef TARGET_WORDS_BIGENDIAN
- retval = bswap16(retval);
-#endif
- return retval;
-}
-
-static void pmac_ide_writel (void *opaque,
- target_phys_addr_t addr, uint32_t val)
-{
- addr = (addr & 0xFFF) >> 4;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- if (addr == 0) {
- ide_data_writel(opaque, 0, val);
- }
-}
-
-static uint32_t pmac_ide_readl (void *opaque,target_phys_addr_t addr)
-{
- uint32_t retval;
-
- addr = (addr & 0xFFF) >> 4;
- if (addr == 0) {
- retval = ide_data_readl(opaque, 0);
- } else {
- retval = 0xFFFFFFFF;
- }
-#ifdef TARGET_WORDS_BIGENDIAN
- retval = bswap32(retval);
-#endif
- return retval;
-}
-
-static CPUWriteMemoryFunc *pmac_ide_write[] = {
- pmac_ide_writeb,
- pmac_ide_writew,
- pmac_ide_writel,
-};
-
-static CPUReadMemoryFunc *pmac_ide_read[] = {
- pmac_ide_readb,
- pmac_ide_readw,
- pmac_ide_readl,
-};
-
-/* 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)
-{
- 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);
-
- pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
- pmac_ide_write, &ide_if[0]);
- return pmac_ide_memory;
-}
diff --git a/hw/integratorcp.c b/hw/integratorcp.c
deleted file mode 100644
index f438af7..0000000
--- a/hw/integratorcp.c
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * ARM Integrator CP System emulation.
- *
- * Copyright (c) 2005-2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the GPL
- */
-
-#include "vl.h"
-#include "arm_pic.h"
-
-void DMA_run (void)
-{
-}
-
-typedef struct {
- uint32_t flash_offset;
- uint32_t cm_osc;
- uint32_t cm_ctrl;
- uint32_t cm_lock;
- uint32_t cm_auxosc;
- uint32_t cm_sdram;
- uint32_t cm_init;
- uint32_t cm_flags;
- uint32_t cm_nvflags;
- uint32_t int_level;
- uint32_t irq_enabled;
- uint32_t fiq_enabled;
-} integratorcm_state;
-
-static uint8_t integrator_spd[128] = {
- 128, 8, 4, 11, 9, 1, 64, 0, 2, 0xa0, 0xa0, 0, 0, 8, 0, 1,
- 0xe, 4, 0x1c, 1, 2, 0x20, 0xc0, 0, 0, 0, 0, 0x30, 0x28, 0x30, 0x28, 0x40
-};
-
-static uint32_t integratorcm_read(void *opaque, target_phys_addr_t offset)
-{
- integratorcm_state *s = (integratorcm_state *)opaque;
- offset -= 0x10000000;
- if (offset >= 0x100 && offset < 0x200) {
- /* CM_SPD */
- if (offset >= 0x180)
- return 0;
- return integrator_spd[offset >> 2];
- }
- switch (offset >> 2) {
- case 0: /* CM_ID */
- return 0x411a3001;
- case 1: /* CM_PROC */
- return 0;
- case 2: /* CM_OSC */
- return s->cm_osc;
- case 3: /* CM_CTRL */
- return s->cm_ctrl;
- case 4: /* CM_STAT */
- return 0x00100000;
- case 5: /* CM_LOCK */
- if (s->cm_lock == 0xa05f) {
- return 0x1a05f;
- } else {
- return s->cm_lock;
- }
- case 6: /* CM_LMBUSCNT */
- /* ??? High frequency timer. */
- cpu_abort(cpu_single_env, "integratorcm_read: CM_LMBUSCNT");
- case 7: /* CM_AUXOSC */
- return s->cm_auxosc;
- case 8: /* CM_SDRAM */
- return s->cm_sdram;
- case 9: /* CM_INIT */
- return s->cm_init;
- case 10: /* CM_REFCT */
- /* ??? High frequency timer. */
- cpu_abort(cpu_single_env, "integratorcm_read: CM_REFCT");
- case 12: /* CM_FLAGS */
- return s->cm_flags;
- case 14: /* CM_NVFLAGS */
- return s->cm_nvflags;
- case 16: /* CM_IRQ_STAT */
- return s->int_level & s->irq_enabled;
- case 17: /* CM_IRQ_RSTAT */
- return s->int_level;
- case 18: /* CM_IRQ_ENSET */
- return s->irq_enabled;
- case 20: /* CM_SOFT_INTSET */
- return s->int_level & 1;
- case 24: /* CM_FIQ_STAT */
- return s->int_level & s->fiq_enabled;
- case 25: /* CM_FIQ_RSTAT */
- return s->int_level;
- case 26: /* CM_FIQ_ENSET */
- return s->fiq_enabled;
- case 32: /* CM_VOLTAGE_CTL0 */
- case 33: /* CM_VOLTAGE_CTL1 */
- case 34: /* CM_VOLTAGE_CTL2 */
- case 35: /* CM_VOLTAGE_CTL3 */
- /* ??? Voltage control unimplemented. */
- return 0;
- default:
- cpu_abort (cpu_single_env,
- "integratorcm_read: Unimplemented offset 0x%x\n", offset);
- return 0;
- }
-}
-
-static void integratorcm_do_remap(integratorcm_state *s, int flash)
-{
- if (flash) {
- cpu_register_physical_memory(0, 0x100000, IO_MEM_RAM);
- } else {
- cpu_register_physical_memory(0, 0x100000, s->flash_offset | IO_MEM_RAM);
- }
- //??? tlb_flush (cpu_single_env, 1);
-}
-
-static void integratorcm_set_ctrl(integratorcm_state *s, uint32_t value)
-{
- if (value & 8) {
- cpu_abort(cpu_single_env, "Board reset\n");
- }
- if ((s->cm_init ^ value) & 4) {
- integratorcm_do_remap(s, (value & 4) == 0);
- }
- if ((s->cm_init ^ value) & 1) {
- printf("Green LED %s\n", (value & 1) ? "on" : "off");
- }
- s->cm_init = (s->cm_init & ~ 5) | (value ^ 5);
-}
-
-static void integratorcm_update(integratorcm_state *s)
-{
- /* ??? The CPU irq/fiq is raised when either the core module or base PIC
- are active. */
- if (s->int_level & (s->irq_enabled | s->fiq_enabled))
- cpu_abort(cpu_single_env, "Core module interrupt\n");
-}
-
-static void integratorcm_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- integratorcm_state *s = (integratorcm_state *)opaque;
- offset -= 0x10000000;
- switch (offset >> 2) {
- case 2: /* CM_OSC */
- if (s->cm_lock == 0xa05f)
- s->cm_osc = value;
- break;
- case 3: /* CM_CTRL */
- integratorcm_set_ctrl(s, value);
- break;
- case 5: /* CM_LOCK */
- s->cm_lock = value & 0xffff;
- break;
- case 7: /* CM_AUXOSC */
- if (s->cm_lock == 0xa05f)
- s->cm_auxosc = value;
- break;
- case 8: /* CM_SDRAM */
- s->cm_sdram = value;
- break;
- case 9: /* CM_INIT */
- /* ??? This can change the memory bus frequency. */
- s->cm_init = value;
- break;
- case 12: /* CM_FLAGSS */
- s->cm_flags |= value;
- break;
- case 13: /* CM_FLAGSC */
- s->cm_flags &= ~value;
- break;
- case 14: /* CM_NVFLAGSS */
- s->cm_nvflags |= value;
- break;
- case 15: /* CM_NVFLAGSS */
- s->cm_nvflags &= ~value;
- break;
- case 18: /* CM_IRQ_ENSET */
- s->irq_enabled |= value;
- integratorcm_update(s);
- break;
- case 19: /* CM_IRQ_ENCLR */
- s->irq_enabled &= ~value;
- integratorcm_update(s);
- break;
- case 20: /* CM_SOFT_INTSET */
- s->int_level |= (value & 1);
- integratorcm_update(s);
- break;
- case 21: /* CM_SOFT_INTCLR */
- s->int_level &= ~(value & 1);
- integratorcm_update(s);
- break;
- case 26: /* CM_FIQ_ENSET */
- s->fiq_enabled |= value;
- integratorcm_update(s);
- break;
- case 27: /* CM_FIQ_ENCLR */
- s->fiq_enabled &= ~value;
- integratorcm_update(s);
- break;
- case 32: /* CM_VOLTAGE_CTL0 */
- case 33: /* CM_VOLTAGE_CTL1 */
- case 34: /* CM_VOLTAGE_CTL2 */
- case 35: /* CM_VOLTAGE_CTL3 */
- /* ??? Voltage control unimplemented. */
- break;
- default:
- cpu_abort (cpu_single_env,
- "integratorcm_write: Unimplemented offset 0x%x\n", offset);
- break;
- }
-}
-
-/* Integrator/CM control registers. */
-
-static CPUReadMemoryFunc *integratorcm_readfn[] = {
- integratorcm_read,
- integratorcm_read,
- integratorcm_read
-};
-
-static CPUWriteMemoryFunc *integratorcm_writefn[] = {
- integratorcm_write,
- integratorcm_write,
- integratorcm_write
-};
-
-static void integratorcm_init(int memsz, uint32_t flash_offset)
-{
- int iomemtype;
- integratorcm_state *s;
-
- s = (integratorcm_state *)qemu_mallocz(sizeof(integratorcm_state));
- s->cm_osc = 0x01000048;
- /* ??? What should the high bits of this value be? */
- s->cm_auxosc = 0x0007feff;
- s->cm_sdram = 0x00011122;
- if (memsz >= 256) {
- integrator_spd[31] = 64;
- s->cm_sdram |= 0x10;
- } else if (memsz >= 128) {
- integrator_spd[31] = 32;
- s->cm_sdram |= 0x0c;
- } else if (memsz >= 64) {
- integrator_spd[31] = 16;
- s->cm_sdram |= 0x08;
- } else if (memsz >= 32) {
- integrator_spd[31] = 4;
- s->cm_sdram |= 0x04;
- } else {
- integrator_spd[31] = 2;
- }
- memcpy(integrator_spd + 73, "QEMU-MEMORY", 11);
- s->cm_init = 0x00000112;
- s->flash_offset = flash_offset;
-
- iomemtype = cpu_register_io_memory(0, integratorcm_readfn,
- integratorcm_writefn, s);
- cpu_register_physical_memory(0x10000000, 0x007fffff, iomemtype);
- integratorcm_do_remap(s, 1);
- /* ??? Save/restore. */
-}
-
-/* Integrator/CP hardware emulation. */
-/* Primary interrupt controller. */
-
-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;
-} 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);
- }
-}
-
-static void icp_pic_set_irq(void *opaque, int irq, int level)
-{
- icp_pic_state *s = (icp_pic_state *)opaque;
- if (level)
- s->level |= 1 << irq;
- else
- s->level &= ~(1 << irq);
- icp_pic_update(s);
-}
-
-static uint32_t icp_pic_read(void *opaque, target_phys_addr_t offset)
-{
- icp_pic_state *s = (icp_pic_state *)opaque;
-
- offset -= s->base;
- switch (offset >> 2) {
- case 0: /* IRQ_STATUS */
- return s->level & s->irq_enabled;
- case 1: /* IRQ_RAWSTAT */
- return s->level;
- case 2: /* IRQ_ENABLESET */
- return s->irq_enabled;
- case 4: /* INT_SOFTSET */
- return s->level & 1;
- case 8: /* FRQ_STATUS */
- return s->level & s->fiq_enabled;
- case 9: /* FRQ_RAWSTAT */
- return s->level;
- case 10: /* FRQ_ENABLESET */
- return s->fiq_enabled;
- case 3: /* IRQ_ENABLECLR */
- case 5: /* INT_SOFTCLR */
- case 11: /* FRQ_ENABLECLR */
- default:
- printf ("icp_pic_read: Bad register offset 0x%x\n", offset);
- return 0;
- }
-}
-
-static void icp_pic_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- icp_pic_state *s = (icp_pic_state *)opaque;
- offset -= s->base;
-
- switch (offset >> 2) {
- case 2: /* IRQ_ENABLESET */
- s->irq_enabled |= value;
- break;
- case 3: /* IRQ_ENABLECLR */
- s->irq_enabled &= ~value;
- break;
- case 4: /* INT_SOFTSET */
- if (value & 1)
- pic_set_irq_new(s, 0, 1);
- break;
- case 5: /* INT_SOFTCLR */
- if (value & 1)
- pic_set_irq_new(s, 0, 0);
- break;
- case 10: /* FRQ_ENABLESET */
- s->fiq_enabled |= value;
- break;
- case 11: /* FRQ_ENABLECLR */
- s->fiq_enabled &= ~value;
- break;
- case 0: /* IRQ_STATUS */
- case 1: /* IRQ_RAWSTAT */
- case 8: /* FRQ_STATUS */
- case 9: /* FRQ_RAWSTAT */
- default:
- printf ("icp_pic_write: Bad register offset 0x%x\n", offset);
- return;
- }
- icp_pic_update(s);
-}
-
-static CPUReadMemoryFunc *icp_pic_readfn[] = {
- icp_pic_read,
- icp_pic_read,
- icp_pic_read
-};
-
-static CPUWriteMemoryFunc *icp_pic_writefn[] = {
- icp_pic_write,
- icp_pic_write,
- icp_pic_write
-};
-
-static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
- int parent_irq, int parent_fiq)
-{
- icp_pic_state *s;
- int iomemtype;
-
- s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state));
- if (!s)
- return NULL;
- s->handler = icp_pic_set_irq;
- 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;
-}
-
-/* CP control registers. */
-typedef struct {
- uint32_t base;
-} icp_control_state;
-
-static uint32_t icp_control_read(void *opaque, target_phys_addr_t offset)
-{
- icp_control_state *s = (icp_control_state *)opaque;
- offset -= s->base;
- switch (offset >> 2) {
- case 0: /* CP_IDFIELD */
- return 0x41034003;
- case 1: /* CP_FLASHPROG */
- return 0;
- case 2: /* CP_INTREG */
- return 0;
- case 3: /* CP_DECODE */
- return 0x11;
- default:
- cpu_abort (cpu_single_env, "icp_control_read: Bad offset %x\n", offset);
- return 0;
- }
-}
-
-static void icp_control_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- icp_control_state *s = (icp_control_state *)opaque;
- offset -= s->base;
- switch (offset >> 2) {
- case 1: /* CP_FLASHPROG */
- case 2: /* CP_INTREG */
- case 3: /* CP_DECODE */
- /* Nothing interesting implemented yet. */
- break;
- default:
- cpu_abort (cpu_single_env, "icp_control_write: Bad offset %x\n", offset);
- }
-}
-static CPUReadMemoryFunc *icp_control_readfn[] = {
- icp_control_read,
- icp_control_read,
- icp_control_read
-};
-
-static CPUWriteMemoryFunc *icp_control_writefn[] = {
- icp_control_write,
- icp_control_write,
- icp_control_write
-};
-
-static void icp_control_init(uint32_t base)
-{
- int iomemtype;
- icp_control_state *s;
-
- s = (icp_control_state *)qemu_mallocz(sizeof(icp_control_state));
- iomemtype = cpu_register_io_memory(0, icp_control_readfn,
- icp_control_writefn, s);
- cpu_register_physical_memory(base, 0x007fffff, iomemtype);
- s->base = base;
- /* ??? Save/restore. */
-}
-
-
-/* Board init. */
-
-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)
-{
- CPUState *env;
- uint32_t bios_offset;
- icp_pic_state *pic;
- void *cpu_pic;
-
- env = cpu_init();
- cpu_arm_set_model(env, cpuid);
- 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. */
- /* SDRAM at address zero*/
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
- /* And again at address 0x80000000 */
- cpu_register_physical_memory(0x80000000, ram_size, IO_MEM_RAM);
-
- 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);
- icp_pit_init(0x13000000, pic, 5);
- 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);
- 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);
- } else {
- fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
- exit (1);
- }
- }
- pl110_init(ds, 0xc0000000, pic, 22, 0);
-
- arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
- initrd_filename, 0x113);
-}
-
-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",
- "ARM Integrator/CP (ARM926EJ-S)",
- integratorcp926_init,
-};
-
-QEMUMachine integratorcp1026_machine = {
- "integratorcp1026",
- "ARM Integrator/CP (ARM1026EJ-S)",
- integratorcp1026_init,
-};
diff --git a/hw/iommu.c b/hw/iommu.c
deleted file mode 100644
index e7d96c8..0000000
--- a/hw/iommu.c
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * QEMU SPARC iommu emulation
- *
- * Copyright (c) 2003-2005 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"
-
-/* debug iommu */
-//#define DEBUG_IOMMU
-
-#ifdef DEBUG_IOMMU
-#define DPRINTF(fmt, args...) \
-do { printf("IOMMU: " fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...)
-#endif
-
-#define IOMMU_NREGS (3*4096/4)
-#define IOMMU_CTRL (0x0000 >> 2)
-#define IOMMU_CTRL_IMPL 0xf0000000 /* Implementation */
-#define IOMMU_CTRL_VERS 0x0f000000 /* Version */
-#define IOMMU_VERSION 0x04000000
-#define IOMMU_CTRL_RNGE 0x0000001c /* Mapping RANGE */
-#define IOMMU_RNGE_16MB 0x00000000 /* 0xff000000 -> 0xffffffff */
-#define IOMMU_RNGE_32MB 0x00000004 /* 0xfe000000 -> 0xffffffff */
-#define IOMMU_RNGE_64MB 0x00000008 /* 0xfc000000 -> 0xffffffff */
-#define IOMMU_RNGE_128MB 0x0000000c /* 0xf8000000 -> 0xffffffff */
-#define IOMMU_RNGE_256MB 0x00000010 /* 0xf0000000 -> 0xffffffff */
-#define IOMMU_RNGE_512MB 0x00000014 /* 0xe0000000 -> 0xffffffff */
-#define IOMMU_RNGE_1GB 0x00000018 /* 0xc0000000 -> 0xffffffff */
-#define IOMMU_RNGE_2GB 0x0000001c /* 0x80000000 -> 0xffffffff */
-#define IOMMU_CTRL_ENAB 0x00000001 /* IOMMU Enable */
-#define IOMMU_CTRL_MASK 0x0000001d
-
-#define IOMMU_BASE (0x0004 >> 2)
-#define IOMMU_BASE_MASK 0x07fffc00
-
-#define IOMMU_TLBFLUSH (0x0014 >> 2)
-#define IOMMU_TLBFLUSH_MASK 0xffffffff
-
-#define IOMMU_PGFLUSH (0x0018 >> 2)
-#define IOMMU_PGFLUSH_MASK 0xffffffff
-
-#define IOMMU_SBCFG0 (0x1010 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG1 (0x1014 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG2 (0x1018 >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG3 (0x101c >> 2) /* SBUS configration per-slot */
-#define IOMMU_SBCFG_SAB30 0x00010000 /* Phys-address bit 30 when bypass enabled */
-#define IOMMU_SBCFG_BA16 0x00000004 /* Slave supports 16 byte bursts */
-#define IOMMU_SBCFG_BA8 0x00000002 /* Slave supports 8 byte bursts */
-#define IOMMU_SBCFG_BYPASS 0x00000001 /* Bypass IOMMU, treat all addresses
- produced by this device as pure
- physical. */
-#define IOMMU_SBCFG_MASK 0x00010003
-
-#define IOMMU_ARBEN (0x2000 >> 2) /* SBUS arbitration enable */
-#define IOMMU_ARBEN_MASK 0x001f0000
-#define IOMMU_MID 0x00000008
-
-/* The format of an iopte in the page tables */
-#define IOPTE_PAGE 0x07ffff00 /* Physical page number (PA[30:12]) */
-#define IOPTE_CACHE 0x00000080 /* Cached (in vme IOCACHE or Viking/MXCC) */
-#define IOPTE_WRITE 0x00000004 /* Writeable */
-#define IOPTE_VALID 0x00000002 /* IOPTE is valid */
-#define IOPTE_WAZ 0x00000001 /* Write as zeros */
-
-#define PAGE_SHIFT 12
-#define PAGE_SIZE (1 << PAGE_SHIFT)
-#define PAGE_MASK (PAGE_SIZE - 1)
-
-typedef struct IOMMUState {
- uint32_t addr;
- uint32_t regs[IOMMU_NREGS];
- uint32_t iostart;
-} IOMMUState;
-
-static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
-{
- IOMMUState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr - s->addr) >> 2;
- switch (saddr) {
- default:
- DPRINTF("read reg[%d] = %x\n", saddr, s->regs[saddr]);
- return s->regs[saddr];
- break;
- }
- return 0;
-}
-
-static void iommu_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- IOMMUState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr - s->addr) >> 2;
- DPRINTF("write reg[%d] = %x\n", saddr, val);
- switch (saddr) {
- case IOMMU_CTRL:
- switch (val & IOMMU_CTRL_RNGE) {
- case IOMMU_RNGE_16MB:
- s->iostart = 0xff000000;
- break;
- case IOMMU_RNGE_32MB:
- s->iostart = 0xfe000000;
- break;
- case IOMMU_RNGE_64MB:
- s->iostart = 0xfc000000;
- break;
- case IOMMU_RNGE_128MB:
- s->iostart = 0xf8000000;
- break;
- case IOMMU_RNGE_256MB:
- s->iostart = 0xf0000000;
- break;
- case IOMMU_RNGE_512MB:
- s->iostart = 0xe0000000;
- break;
- case IOMMU_RNGE_1GB:
- s->iostart = 0xc0000000;
- break;
- default:
- case IOMMU_RNGE_2GB:
- s->iostart = 0x80000000;
- break;
- }
- DPRINTF("iostart = %x\n", s->iostart);
- s->regs[saddr] = ((val & IOMMU_CTRL_MASK) | IOMMU_VERSION);
- break;
- case IOMMU_BASE:
- s->regs[saddr] = val & IOMMU_BASE_MASK;
- break;
- case IOMMU_TLBFLUSH:
- DPRINTF("tlb flush %x\n", val);
- s->regs[saddr] = val & IOMMU_TLBFLUSH_MASK;
- break;
- case IOMMU_PGFLUSH:
- DPRINTF("page flush %x\n", val);
- s->regs[saddr] = val & IOMMU_PGFLUSH_MASK;
- break;
- case IOMMU_SBCFG0:
- case IOMMU_SBCFG1:
- case IOMMU_SBCFG2:
- case IOMMU_SBCFG3:
- s->regs[saddr] = val & IOMMU_SBCFG_MASK;
- break;
- case IOMMU_ARBEN:
- // XXX implement SBus probing: fault when reading unmapped
- // addresses, fault cause and address stored to MMU/IOMMU
- s->regs[saddr] = (val & IOMMU_ARBEN_MASK) | IOMMU_MID;
- break;
- default:
- s->regs[saddr] = val;
- break;
- }
-}
-
-static CPUReadMemoryFunc *iommu_mem_read[3] = {
- iommu_mem_readw,
- iommu_mem_readw,
- iommu_mem_readw,
-};
-
-static CPUWriteMemoryFunc *iommu_mem_write[3] = {
- iommu_mem_writew,
- iommu_mem_writew,
- iommu_mem_writew,
-};
-
-uint32_t iommu_translate_local(void *opaque, uint32_t addr)
-{
- IOMMUState *s = opaque;
- uint32_t iopte, pa, tmppte;
-
- iopte = s->regs[1] << 4;
- addr &= ~s->iostart;
- iopte += (addr >> (PAGE_SHIFT - 2)) & ~3;
- pa = ldl_phys(iopte);
- tmppte = pa;
- pa = ((pa & IOPTE_PAGE) << 4) + (addr & PAGE_MASK);
- DPRINTF("xlate dva %x => pa %x (iopte[%x] = %x)\n", addr, pa, iopte, tmppte);
- return pa;
-}
-
-static void iommu_save(QEMUFile *f, void *opaque)
-{
- IOMMUState *s = opaque;
- int i;
-
- qemu_put_be32s(f, &s->addr);
- for (i = 0; i < IOMMU_NREGS; i++)
- qemu_put_be32s(f, &s->regs[i]);
- qemu_put_be32s(f, &s->iostart);
-}
-
-static int iommu_load(QEMUFile *f, void *opaque, int version_id)
-{
- IOMMUState *s = opaque;
- int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_be32s(f, &s->addr);
- for (i = 0; i < IOMMU_NREGS; i++)
- qemu_put_be32s(f, &s->regs[i]);
- qemu_get_be32s(f, &s->iostart);
-
- return 0;
-}
-
-static void iommu_reset(void *opaque)
-{
- IOMMUState *s = opaque;
-
- memset(s->regs, 0, IOMMU_NREGS * 4);
- s->iostart = 0;
- s->regs[0] = IOMMU_VERSION;
-}
-
-void *iommu_init(uint32_t addr)
-{
- IOMMUState *s;
- int iommu_io_memory;
-
- s = qemu_mallocz(sizeof(IOMMUState));
- if (!s)
- return NULL;
-
- s->addr = addr;
-
- iommu_io_memory = cpu_register_io_memory(0, iommu_mem_read, iommu_mem_write, s);
- cpu_register_physical_memory(addr, IOMMU_NREGS * 4, iommu_io_memory);
-
- register_savevm("iommu", addr, 1, iommu_save, iommu_load, s);
- qemu_register_reset(iommu_reset, s);
- return s;
-}
-
diff --git a/hw/irq.c b/hw/irq.c
new file mode 100644
index 0000000..3621b8e
--- /dev/null
+++ b/hw/irq.c
@@ -0,0 +1,71 @@
+/*
+ * 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"
+#include "irq.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;
+}
+
+static void qemu_notirq(void *opaque, int line, int level)
+{
+ struct IRQState *irq = opaque;
+
+ irq->handler(irq->opaque, irq->n, !level);
+}
+
+qemu_irq qemu_irq_invert(qemu_irq irq)
+{
+ /* The default state for IRQs is low, so raise the output now. */
+ qemu_irq_raise(irq);
+ return qemu_allocate_irqs(qemu_notirq, irq, 1)[0];
+}
diff --git a/hw/irq.h b/hw/irq.h
new file mode 100644
index 0000000..814511a
--- /dev/null
+++ b/hw/irq.h
@@ -0,0 +1,32 @@
+#ifndef QEMU_IRQ_H
+#define QEMU_IRQ_H
+
+/* Generic IRQ/GPIO pin infrastructure. */
+
+typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
+
+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);
+}
+
+static inline void qemu_irq_pulse(qemu_irq irq)
+{
+ qemu_set_irq(irq, 1);
+ qemu_set_irq(irq, 0);
+}
+
+/* Returns an array of N IRQs. */
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
+
+/* Returns a new IRQ with opposite polarity. */
+qemu_irq qemu_irq_invert(qemu_irq irq);
+
+#endif
diff --git a/hw/lance.c b/hw/lance.c
deleted file mode 100644
index d167937..0000000
--- a/hw/lance.c
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * QEMU Lance emulation
- *
- * Copyright (c) 2003-2005 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"
-
-/* debug LANCE card */
-//#define DEBUG_LANCE
-
-#ifdef DEBUG_LANCE
-#define DPRINTF(fmt, args...) \
-do { printf("LANCE: " fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...)
-#endif
-
-#ifndef LANCE_LOG_TX_BUFFERS
-#define LANCE_LOG_TX_BUFFERS 4
-#define LANCE_LOG_RX_BUFFERS 4
-#endif
-
-#define LE_CSR0 0
-#define LE_CSR1 1
-#define LE_CSR2 2
-#define LE_CSR3 3
-#define LE_NREGS (LE_CSR3 + 1)
-#define LE_MAXREG LE_CSR3
-
-#define LE_RDP 0
-#define LE_RAP 1
-
-#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */
-
-#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */
-#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */
-#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */
-#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */
-#define LE_C0_MERR 0x0800 /* ME: Memory error */
-#define LE_C0_RINT 0x0400 /* Received interrupt */
-#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */
-#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */
-#define LE_C0_INTR 0x0080 /* Interrupt or error */
-#define LE_C0_INEA 0x0040 /* Interrupt enable */
-#define LE_C0_RXON 0x0020 /* Receiver on */
-#define LE_C0_TXON 0x0010 /* Transmitter on */
-#define LE_C0_TDMD 0x0008 /* Transmitter demand */
-#define LE_C0_STOP 0x0004 /* Stop the card */
-#define LE_C0_STRT 0x0002 /* Start the card */
-#define LE_C0_INIT 0x0001 /* Init the card */
-
-#define LE_C3_BSWP 0x4 /* SWAP */
-#define LE_C3_ACON 0x2 /* ALE Control */
-#define LE_C3_BCON 0x1 /* Byte control */
-
-/* Receive message descriptor 1 */
-#define LE_R1_OWN 0x80 /* Who owns the entry */
-#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */
-#define LE_R1_FRA 0x20 /* FRA: Frame error */
-#define LE_R1_OFL 0x10 /* OFL: Frame overflow */
-#define LE_R1_CRC 0x08 /* CRC error */
-#define LE_R1_BUF 0x04 /* BUF: Buffer error */
-#define LE_R1_SOP 0x02 /* Start of packet */
-#define LE_R1_EOP 0x01 /* End of packet */
-#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */
-
-#define LE_T1_OWN 0x80 /* Lance owns the packet */
-#define LE_T1_ERR 0x40 /* Error summary */
-#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */
-#define LE_T1_EONE 0x08 /* Error: one retry needed */
-#define LE_T1_EDEF 0x04 /* Error: deferred */
-#define LE_T1_SOP 0x02 /* Start of packet */
-#define LE_T1_EOP 0x01 /* End of packet */
-#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */
-
-#define LE_T3_BUF 0x8000 /* Buffer error */
-#define LE_T3_UFL 0x4000 /* Error underflow */
-#define LE_T3_LCOL 0x1000 /* Error late collision */
-#define LE_T3_CLOS 0x0800 /* Error carrier loss */
-#define LE_T3_RTY 0x0400 /* Error retry */
-#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */
-
-#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS))
-#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
-#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
-
-#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS))
-#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
-#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
-
-#define PKT_BUF_SZ 1544
-#define RX_BUFF_SIZE PKT_BUF_SZ
-#define TX_BUFF_SIZE PKT_BUF_SZ
-
-struct lance_rx_desc {
- unsigned short rmd0; /* low address of packet */
- unsigned char rmd1_bits; /* descriptor bits */
- unsigned char rmd1_hadr; /* high address of packet */
- short length; /* This length is 2s complement (negative)!
- * Buffer length
- */
- unsigned short mblength; /* This is the actual number of bytes received */
-};
-
-struct lance_tx_desc {
- unsigned short tmd0; /* low address of packet */
- unsigned char tmd1_bits; /* descriptor bits */
- unsigned char tmd1_hadr; /* high address of packet */
- short length; /* Length is 2s complement (negative)! */
- unsigned short misc;
-};
-
-/* The LANCE initialization block, described in databook. */
-/* On the Sparc, this block should be on a DMA region */
-struct lance_init_block {
- unsigned short mode; /* Pre-set mode (reg. 15) */
- unsigned char phys_addr[6]; /* Physical ethernet address */
- unsigned filter[2]; /* Multicast filter. */
-
- /* Receive and transmit ring base, along with extra bits. */
- unsigned short rx_ptr; /* receive descriptor addr */
- unsigned short rx_len; /* receive len and high addr */
- unsigned short tx_ptr; /* transmit descriptor addr */
- unsigned short tx_len; /* transmit len and high addr */
-
- /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */
- struct lance_rx_desc brx_ring[RX_RING_SIZE];
- struct lance_tx_desc btx_ring[TX_RING_SIZE];
-
- char tx_buf [TX_RING_SIZE][TX_BUFF_SIZE];
- char pad[2]; /* align rx_buf for copy_and_sum(). */
- char rx_buf [RX_RING_SIZE][RX_BUFF_SIZE];
-};
-
-#define LEDMA_REGS 4
-#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
-
-typedef struct LANCEState {
- VLANClientState *vc;
- uint8_t macaddr[6]; /* init mac address */
- uint32_t leptr;
- uint16_t addr;
- uint16_t regs[LE_NREGS];
- uint8_t phys[6]; /* mac address */
- int irq;
- unsigned int rxptr, txptr;
- uint32_t ledmaregs[LEDMA_REGS];
-} LANCEState;
-
-static void lance_send(void *opaque);
-
-static void lance_reset(void *opaque)
-{
- LANCEState *s = opaque;
- memcpy(s->phys, s->macaddr, 6);
- s->rxptr = 0;
- s->txptr = 0;
- memset(s->regs, 0, LE_NREGS * 2);
- s->regs[LE_CSR0] = LE_C0_STOP;
- memset(s->ledmaregs, 0, LEDMA_REGS * 4);
-}
-
-static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
-{
- LANCEState *s = opaque;
- uint32_t saddr;
-
- saddr = addr & LE_MAXREG;
- switch (saddr >> 1) {
- case LE_RDP:
- DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]);
- return s->regs[s->addr];
- case LE_RAP:
- DPRINTF("read areg = %4.4x\n", s->addr);
- return s->addr;
- default:
- DPRINTF("read unknown(%d)\n", saddr>>1);
- break;
- }
- return 0;
-}
-
-static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- LANCEState *s = opaque;
- uint32_t saddr;
- uint16_t reg;
-
- saddr = addr & LE_MAXREG;
- switch (saddr >> 1) {
- case LE_RDP:
- DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val);
- switch(s->addr) {
- case LE_CSR0:
- if (val & LE_C0_STOP) {
- s->regs[LE_CSR0] = LE_C0_STOP;
- break;
- }
-
- reg = s->regs[LE_CSR0];
-
- // 1 = clear for some bits
- reg &= ~(val & 0x7f00);
-
- // generated bits
- reg &= ~(LE_C0_ERR | LE_C0_INTR);
- if (reg & 0x7100)
- reg |= LE_C0_ERR;
- if (reg & 0x7f00)
- reg |= LE_C0_INTR;
-
- // direct bit
- reg &= ~LE_C0_INEA;
- reg |= val & LE_C0_INEA;
-
- // exclusive bits
- if (val & LE_C0_INIT) {
- reg |= LE_C0_IDON | LE_C0_INIT;
- reg &= ~LE_C0_STOP;
- }
- else if (val & LE_C0_STRT) {
- reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON;
- reg &= ~LE_C0_STOP;
- }
-
- s->regs[LE_CSR0] = reg;
- break;
- case LE_CSR1:
- s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff);
- s->regs[s->addr] = val;
- break;
- case LE_CSR2:
- s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16);
- s->regs[s->addr] = val;
- break;
- case LE_CSR3:
- s->regs[s->addr] = val;
- break;
- }
- break;
- case LE_RAP:
- DPRINTF("write areg = %4.4x\n", val);
- if (val < LE_NREGS)
- s->addr = val;
- break;
- default:
- DPRINTF("write unknown(%d) = %4.4x\n", saddr>>1, val);
- break;
- }
- lance_send(s);
-}
-
-static CPUReadMemoryFunc *lance_mem_read[3] = {
- lance_mem_readw,
- lance_mem_readw,
- lance_mem_readw,
-};
-
-static CPUWriteMemoryFunc *lance_mem_write[3] = {
- lance_mem_writew,
- lance_mem_writew,
- lance_mem_writew,
-};
-
-
-#define MIN_BUF_SIZE 60
-
-static int lance_can_receive(void *opaque)
-{
- return 1;
-}
-
-static void lance_receive(void *opaque, const uint8_t *buf, int size)
-{
- LANCEState *s = opaque;
- uint32_t dmaptr = s->leptr + s->ledmaregs[3];
- struct lance_init_block *ib;
- unsigned int i, old_rxptr;
- uint16_t temp16;
- uint8_t temp8;
-
- DPRINTF("receive size %d\n", size);
- if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
- return;
-
- ib = (void *) iommu_translate(dmaptr);
-
- old_rxptr = s->rxptr;
- for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
- cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
- if (temp8 == (LE_R1_OWN)) {
- s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
- temp16 = size + 4;
- bswap16s(&temp16);
- cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp16, 2);
- cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size);
- temp8 = LE_R1_POK;
- cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp8, 1);
- s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
- if (s->regs[LE_CSR0] & LE_C0_INEA)
- pic_set_irq(s->irq, 1);
- DPRINTF("got packet, len %d\n", size);
- return;
- }
- }
-}
-
-static void lance_send(void *opaque)
-{
- LANCEState *s = opaque;
- uint32_t dmaptr = s->leptr + s->ledmaregs[3];
- struct lance_init_block *ib;
- unsigned int i, old_txptr;
- uint16_t temp16;
- uint8_t temp8;
- char pkt_buf[PKT_BUF_SZ];
-
- DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]);
- if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP)
- return;
-
- ib = (void *) iommu_translate(dmaptr);
-
- DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", dmaptr, ib, &ib->btx_ring);
- old_txptr = s->txptr;
- for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
- cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
- if (temp8 == (LE_T1_POK|LE_T1_OWN)) {
- cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp16, 2);
- bswap16s(&temp16);
- temp16 = (~temp16) + 1;
- cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp16);
- DPRINTF("sending packet, len %d\n", temp16);
- qemu_send_packet(s->vc, pkt_buf, temp16);
- temp8 = LE_T1_POK;
- cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp8, 1);
- s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
- s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
- }
- }
- if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
- pic_set_irq(s->irq, 1);
-}
-
-static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- LANCEState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & LEDMA_MAXADDR) >> 2;
- return s->ledmaregs[saddr];
-}
-
-static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- LANCEState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & LEDMA_MAXADDR) >> 2;
- s->ledmaregs[saddr] = val;
-}
-
-static CPUReadMemoryFunc *ledma_mem_read[3] = {
- ledma_mem_readl,
- ledma_mem_readl,
- ledma_mem_readl,
-};
-
-static CPUWriteMemoryFunc *ledma_mem_write[3] = {
- ledma_mem_writel,
- ledma_mem_writel,
- ledma_mem_writel,
-};
-
-static void lance_save(QEMUFile *f, void *opaque)
-{
- LANCEState *s = opaque;
- int i;
-
- qemu_put_be32s(f, &s->leptr);
- qemu_put_be16s(f, &s->addr);
- for (i = 0; i < LE_NREGS; i ++)
- qemu_put_be16s(f, &s->regs[i]);
- qemu_put_buffer(f, s->phys, 6);
- qemu_put_be32s(f, &s->irq);
- for (i = 0; i < LEDMA_REGS; i ++)
- qemu_put_be32s(f, &s->ledmaregs[i]);
-}
-
-static int lance_load(QEMUFile *f, void *opaque, int version_id)
-{
- LANCEState *s = opaque;
- int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_be32s(f, &s->leptr);
- qemu_get_be16s(f, &s->addr);
- for (i = 0; i < LE_NREGS; i ++)
- qemu_get_be16s(f, &s->regs[i]);
- qemu_get_buffer(f, s->phys, 6);
- qemu_get_be32s(f, &s->irq);
- for (i = 0; i < LEDMA_REGS; i ++)
- qemu_get_be32s(f, &s->ledmaregs[i]);
- return 0;
-}
-
-void lance_init(NICInfo *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
-{
- LANCEState *s;
- int lance_io_memory, ledma_io_memory;
-
- s = qemu_mallocz(sizeof(LANCEState));
- if (!s)
- return;
-
- s->irq = irq;
-
- lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
- cpu_register_physical_memory(leaddr, 4, lance_io_memory);
-
- ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
- cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
-
- memcpy(s->macaddr, nd->macaddr, 6);
-
- lance_reset(s);
-
- s->vc = qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, s);
-
- snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "lance 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]);
-
- register_savevm("lance", leaddr, 1, lance_save, lance_load, s);
- qemu_register_reset(lance_reset, s);
-}
-
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
deleted file mode 100644
index 24dff0e..0000000
--- a/hw/lsi53c895a.c
+++ /dev/null
@@ -1,1571 +0,0 @@
-/*
- * QEMU LSI53C895A SCSI Host Bus Adapter emulation
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the LGPL.
- */
-
-/* ??? Need to check if the {read,write}[wl] routines work properly on
- big-endian targets. */
-
-#include "vl.h"
-
-//#define DEBUG_LSI
-//#define DEBUG_LSI_REG
-
-#ifdef DEBUG_LSI
-#define DPRINTF(fmt, args...) \
-do { printf("lsi_scsi: " fmt , ##args); } while (0)
-#define BADF(fmt, args...) \
-do { fprintf(stderr, "lsi_scsi: " fmt , ##args); exit(1);} while (0)
-#else
-#define DPRINTF(fmt, args...) do {} while(0)
-#define BADF(fmt, args...) \
-do { fprintf(stderr, "lsi_scsi: " fmt , ##args); } while (0)
-#endif
-
-#define LSI_SCNTL0_TRG 0x01
-#define LSI_SCNTL0_AAP 0x02
-#define LSI_SCNTL0_EPC 0x08
-#define LSI_SCNTL0_WATN 0x10
-#define LSI_SCNTL0_START 0x20
-
-#define LSI_SCNTL1_SST 0x01
-#define LSI_SCNTL1_IARB 0x02
-#define LSI_SCNTL1_AESP 0x04
-#define LSI_SCNTL1_RST 0x08
-#define LSI_SCNTL1_CON 0x10
-#define LSI_SCNTL1_DHP 0x20
-#define LSI_SCNTL1_ADB 0x40
-#define LSI_SCNTL1_EXC 0x80
-
-#define LSI_SCNTL2_WSR 0x01
-#define LSI_SCNTL2_VUE0 0x02
-#define LSI_SCNTL2_VUE1 0x04
-#define LSI_SCNTL2_WSS 0x08
-#define LSI_SCNTL2_SLPHBEN 0x10
-#define LSI_SCNTL2_SLPMD 0x20
-#define LSI_SCNTL2_CHM 0x40
-#define LSI_SCNTL2_SDU 0x80
-
-#define LSI_ISTAT0_DIP 0x01
-#define LSI_ISTAT0_SIP 0x02
-#define LSI_ISTAT0_INTF 0x04
-#define LSI_ISTAT0_CON 0x08
-#define LSI_ISTAT0_SEM 0x10
-#define LSI_ISTAT0_SIGP 0x20
-#define LSI_ISTAT0_SRST 0x40
-#define LSI_ISTAT0_ABRT 0x80
-
-#define LSI_ISTAT1_SI 0x01
-#define LSI_ISTAT1_SRUN 0x02
-#define LSI_ISTAT1_FLSH 0x04
-
-#define LSI_SSTAT0_SDP0 0x01
-#define LSI_SSTAT0_RST 0x02
-#define LSI_SSTAT0_WOA 0x04
-#define LSI_SSTAT0_LOA 0x08
-#define LSI_SSTAT0_AIP 0x10
-#define LSI_SSTAT0_OLF 0x20
-#define LSI_SSTAT0_ORF 0x40
-#define LSI_SSTAT0_ILF 0x80
-
-#define LSI_SIST0_PAR 0x01
-#define LSI_SIST0_RST 0x02
-#define LSI_SIST0_UDC 0x04
-#define LSI_SIST0_SGE 0x08
-#define LSI_SIST0_RSL 0x10
-#define LSI_SIST0_SEL 0x20
-#define LSI_SIST0_CMP 0x40
-#define LSI_SIST0_MA 0x80
-
-#define LSI_SIST1_HTH 0x01
-#define LSI_SIST1_GEN 0x02
-#define LSI_SIST1_STO 0x04
-#define LSI_SIST1_SBMC 0x10
-
-#define LSI_SOCL_IO 0x01
-#define LSI_SOCL_CD 0x02
-#define LSI_SOCL_MSG 0x04
-#define LSI_SOCL_ATN 0x08
-#define LSI_SOCL_SEL 0x10
-#define LSI_SOCL_BSY 0x20
-#define LSI_SOCL_ACK 0x40
-#define LSI_SOCL_REQ 0x80
-
-#define LSI_DSTAT_IID 0x01
-#define LSI_DSTAT_SIR 0x04
-#define LSI_DSTAT_SSI 0x08
-#define LSI_DSTAT_ABRT 0x10
-#define LSI_DSTAT_BF 0x20
-#define LSI_DSTAT_MDPE 0x40
-#define LSI_DSTAT_DFE 0x80
-
-#define LSI_DCNTL_COM 0x01
-#define LSI_DCNTL_IRQD 0x02
-#define LSI_DCNTL_STD 0x04
-#define LSI_DCNTL_IRQM 0x08
-#define LSI_DCNTL_SSM 0x10
-#define LSI_DCNTL_PFEN 0x20
-#define LSI_DCNTL_PFF 0x40
-#define LSI_DCNTL_CLSE 0x80
-
-#define LSI_DMODE_MAN 0x01
-#define LSI_DMODE_BOF 0x02
-#define LSI_DMODE_ERMP 0x04
-#define LSI_DMODE_ERL 0x08
-#define LSI_DMODE_DIOM 0x10
-#define LSI_DMODE_SIOM 0x20
-
-#define LSI_CTEST2_DACK 0x01
-#define LSI_CTEST2_DREQ 0x02
-#define LSI_CTEST2_TEOP 0x04
-#define LSI_CTEST2_PCICIE 0x08
-#define LSI_CTEST2_CM 0x10
-#define LSI_CTEST2_CIO 0x20
-#define LSI_CTEST2_SIGP 0x40
-#define LSI_CTEST2_DDIR 0x80
-
-#define LSI_CTEST5_BL2 0x04
-#define LSI_CTEST5_DDIR 0x08
-#define LSI_CTEST5_MASR 0x10
-#define LSI_CTEST5_DFSN 0x20
-#define LSI_CTEST5_BBCK 0x40
-#define LSI_CTEST5_ADCK 0x80
-
-#define LSI_CCNTL0_DILS 0x01
-#define LSI_CCNTL0_DISFC 0x10
-#define LSI_CCNTL0_ENNDJ 0x20
-#define LSI_CCNTL0_PMJCTL 0x40
-#define LSI_CCNTL0_ENPMJ 0x80
-
-#define PHASE_DO 0
-#define PHASE_DI 1
-#define PHASE_CMD 2
-#define PHASE_ST 3
-#define PHASE_MO 6
-#define PHASE_MI 7
-#define PHASE_MASK 7
-
-/* The HBA is ID 7, so for simplicitly limit to 7 devices. */
-#define LSI_MAX_DEVS 7
-
-typedef struct {
- PCIDevice pci_dev;
- int mmio_io_addr;
- int ram_io_addr;
- uint32_t script_ram_base;
- uint32_t data_len;
-
- int carry; /* ??? Should this be an a visible register somewhere? */
- int sense;
- uint8_t msg;
- /* Nonzero if a Wait Reselect instruction has been issued. */
- int waiting;
- SCSIDevice *scsi_dev[LSI_MAX_DEVS];
- SCSIDevice *current_dev;
- int current_lun;
-
- uint32_t dsa;
- uint32_t temp;
- uint32_t dnad;
- uint32_t dbc;
- uint8_t istat0;
- uint8_t istat1;
- uint8_t dcmd;
- uint8_t dstat;
- uint8_t dien;
- uint8_t sist0;
- uint8_t sist1;
- uint8_t sien0;
- uint8_t sien1;
- uint8_t mbox0;
- uint8_t mbox1;
- uint8_t dfifo;
- uint8_t ctest3;
- uint8_t ctest4;
- uint8_t ctest5;
- uint8_t ccntl0;
- uint8_t ccntl1;
- uint32_t dsp;
- uint32_t dsps;
- uint8_t dmode;
- uint8_t dcntl;
- uint8_t scntl0;
- uint8_t scntl1;
- uint8_t scntl2;
- uint8_t scntl3;
- uint8_t sstat0;
- uint8_t sstat1;
- uint8_t scid;
- uint8_t sxfer;
- uint8_t socl;
- uint8_t sdid;
- uint8_t sfbr;
- uint8_t stest1;
- uint8_t stest2;
- uint8_t stest3;
- uint8_t stime0;
- uint8_t respid0;
- uint8_t respid1;
- uint32_t mmrs;
- uint32_t mmws;
- uint32_t sfs;
- uint32_t drs;
- uint32_t sbms;
- uint32_t dmbs;
- uint32_t dnad64;
- uint32_t pmjad1;
- uint32_t pmjad2;
- uint32_t rbc;
- uint32_t ua;
- uint32_t ia;
- uint32_t sbc;
- uint32_t csbc;
- uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */
-
- /* Script ram is stored as 32-bit words in host byteorder. */
- uint32_t script_ram[2048];
-} LSIState;
-
-static void lsi_soft_reset(LSIState *s)
-{
- DPRINTF("Reset\n");
- s->carry = 0;
-
- s->waiting = 0;
- s->dsa = 0;
- s->dnad = 0;
- s->dbc = 0;
- s->temp = 0;
- memset(s->scratch, 0, sizeof(s->scratch));
- s->istat0 = 0;
- s->istat1 = 0;
- s->dcmd = 0;
- s->dstat = 0;
- s->dien = 0;
- s->sist0 = 0;
- s->sist1 = 0;
- s->sien0 = 0;
- s->sien1 = 0;
- s->mbox0 = 0;
- s->mbox1 = 0;
- s->dfifo = 0;
- s->ctest3 = 0;
- s->ctest4 = 0;
- s->ctest5 = 0;
- s->ccntl0 = 0;
- s->ccntl1 = 0;
- s->dsp = 0;
- s->dsps = 0;
- s->dmode = 0;
- s->dcntl = 0;
- s->scntl0 = 0xc0;
- s->scntl1 = 0;
- s->scntl2 = 0;
- s->scntl3 = 0;
- s->sstat0 = 0;
- s->sstat1 = 0;
- s->scid = 7;
- s->sxfer = 0;
- s->socl = 0;
- s->stest1 = 0;
- s->stest2 = 0;
- s->stest3 = 0;
- s->stime0 = 0;
- s->respid0 = 0x80;
- s->respid1 = 0;
- s->mmrs = 0;
- s->mmws = 0;
- s->sfs = 0;
- s->drs = 0;
- s->sbms = 0;
- s->dmbs = 0;
- s->dnad64 = 0;
- s->pmjad1 = 0;
- s->pmjad2 = 0;
- s->rbc = 0;
- s->ua = 0;
- s->ia = 0;
- s->sbc = 0;
- s->csbc = 0;
-}
-
-static uint8_t lsi_reg_readb(LSIState *s, int offset);
-static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val);
-
-static inline uint32_t read_dword(LSIState *s, uint32_t addr)
-{
- uint32_t buf;
-
- /* Optimize reading from SCRIPTS RAM. */
- if ((addr & 0xffffe000) == s->script_ram_base) {
- return s->script_ram[(addr & 0x1fff) >> 2];
- }
- cpu_physical_memory_read(addr, (uint8_t *)&buf, 4);
- return cpu_to_le32(buf);
-}
-
-static void lsi_stop_script(LSIState *s)
-{
- s->istat1 &= ~LSI_ISTAT1_SRUN;
-}
-
-static void lsi_update_irq(LSIState *s)
-{
- int level;
- static int last_level;
-
- /* It's unclear whether the DIP/SIP bits should be cleared when the
- Interrupt Status Registers are cleared or when istat0 is read.
- We currently do the formwer, which seems to work. */
- level = 0;
- if (s->dstat) {
- if (s->dstat & s->dien)
- level = 1;
- s->istat0 |= LSI_ISTAT0_DIP;
- } else {
- s->istat0 &= ~LSI_ISTAT0_DIP;
- }
-
- if (s->sist0 || s->sist1) {
- if ((s->sist0 & s->sien0) || (s->sist1 & s->sien1))
- level = 1;
- s->istat0 |= LSI_ISTAT0_SIP;
- } else {
- s->istat0 &= ~LSI_ISTAT0_SIP;
- }
- if (s->istat0 & LSI_ISTAT0_INTF)
- level = 1;
-
- if (level != last_level) {
- DPRINTF("Update IRQ level %d dstat %02x sist %02x%02x\n",
- level, s->dstat, s->sist1, s->sist0);
- last_level = level;
- }
- pci_set_irq(&s->pci_dev, 0, level);
-}
-
-/* Stop SCRIPTS execution and raise a SCSI interrupt. */
-static void lsi_script_scsi_interrupt(LSIState *s, int stat0, int stat1)
-{
- uint32_t mask0;
- uint32_t mask1;
-
- DPRINTF("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n",
- stat1, stat0, s->sist1, s->sist0);
- s->sist0 |= stat0;
- s->sist1 |= stat1;
- /* Stop processor on fatal or unmasked interrupt. As a special hack
- we don't stop processing when raising STO. Instead continue
- execution and stop at the next insn that accesses the SCSI bus. */
- mask0 = s->sien0 | ~(LSI_SIST0_CMP | LSI_SIST0_SEL | LSI_SIST0_RSL);
- mask1 = s->sien1 | ~(LSI_SIST1_GEN | LSI_SIST1_HTH);
- mask1 &= ~LSI_SIST1_STO;
- if (s->sist0 & mask0 || s->sist1 & mask1) {
- lsi_stop_script(s);
- }
- lsi_update_irq(s);
-}
-
-/* Stop SCRIPTS execution and raise a DMA interrupt. */
-static void lsi_script_dma_interrupt(LSIState *s, int stat)
-{
- DPRINTF("DMA Interrupt 0x%x prev 0x%x\n", stat, s->dstat);
- s->dstat |= stat;
- lsi_update_irq(s);
- lsi_stop_script(s);
-}
-
-static inline void lsi_set_phase(LSIState *s, int phase)
-{
- s->sstat1 = (s->sstat1 & ~PHASE_MASK) | phase;
-}
-
-static void lsi_bad_phase(LSIState *s, int out, int new_phase)
-{
- /* Trigger a phase mismatch. */
- if (s->ccntl0 & LSI_CCNTL0_ENPMJ) {
- if ((s->ccntl0 & LSI_CCNTL0_PMJCTL) || out) {
- s->dsp = s->pmjad1;
- } else {
- s->dsp = s->pmjad2;
- }
- DPRINTF("Data phase mismatch jump to %08x\n", s->dsp);
- } else {
- DPRINTF("Phase mismatch interrupt\n");
- lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
- lsi_stop_script(s);
- }
- lsi_set_phase(s, new_phase);
-}
-
-static void lsi_do_dma(LSIState *s, int out)
-{
- uint8_t buf[TARGET_PAGE_SIZE];
- uint32_t addr;
- uint32_t count;
- int n;
-
- count = s->dbc;
- addr = s->dnad;
- DPRINTF("DMA %s addr=0x%08x len=%d avail=%d\n", out ? "out" : "in",
- addr, count, s->data_len);
- /* ??? Too long transfers are truncated. Don't know if this is the
- correct behavior. */
- if (count > s->data_len) {
- /* If the DMA length is greater then the device data length then
- a phase mismatch will occur. */
- count = s->data_len;
- s->dbc = count;
- lsi_bad_phase(s, out, PHASE_ST);
- }
-
- s->csbc += count;
-
- /* ??? Set SFBR to first data byte. */
- while (count) {
- n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count;
- if (out) {
- cpu_physical_memory_read(addr, buf, n);
- scsi_write_data(s->current_dev, buf, n);
- } else {
- scsi_read_data(s->current_dev, buf, n);
- cpu_physical_memory_write(addr, buf, n);
- }
- addr += n;
- count -= n;
- }
-}
-
-
-static void lsi_do_command(LSIState *s)
-{
- uint8_t buf[16];
- int n;
-
- DPRINTF("Send command len=%d\n", s->dbc);
- if (s->dbc > 16)
- s->dbc = 16;
- cpu_physical_memory_read(s->dnad, buf, s->dbc);
- s->sfbr = buf[0];
- n = scsi_send_command(s->current_dev, 0, buf, s->current_lun);
- if (n > 0) {
- s->data_len = n;
- lsi_set_phase(s, PHASE_DI);
- } else if (n < 0) {
- s->data_len = -n;
- lsi_set_phase(s, PHASE_DO);
- }
-}
-
-static void lsi_command_complete(void *opaque, uint32_t tag, int sense)
-{
- LSIState *s = (LSIState *)opaque;
-
- DPRINTF("Command complete sense=%d\n", sense);
- s->sense = sense;
- lsi_set_phase(s, PHASE_ST);
-}
-
-static void lsi_do_status(LSIState *s)
-{
- DPRINTF("Get status len=%d sense=%d\n", s->dbc, s->sense);
- if (s->dbc != 1)
- BADF("Bad Status move\n");
- s->dbc = 1;
- s->msg = s->sense;
- cpu_physical_memory_write(s->dnad, &s->msg, 1);
- s->sfbr = s->msg;
- lsi_set_phase(s, PHASE_MI);
- s->msg = 0; /* COMMAND COMPLETE */
-}
-
-static void lsi_disconnect(LSIState *s)
-{
- s->scntl1 &= ~LSI_SCNTL1_CON;
- s->sstat1 &= ~PHASE_MASK;
-}
-
-static void lsi_do_msgin(LSIState *s)
-{
- DPRINTF("Message in len=%d\n", s->dbc);
- s->dbc = 1;
- s->sfbr = s->msg;
- cpu_physical_memory_write(s->dnad, &s->msg, 1);
- if (s->msg == 0) {
- lsi_disconnect(s);
- } else {
- /* ??? Check if ATN (not yet implemented) is asserted and maybe
- switch to PHASE_MO. */
- lsi_set_phase(s, PHASE_CMD);
- }
-}
-
-static void lsi_do_msgout(LSIState *s)
-{
- uint8_t msg;
-
- DPRINTF("MSG out len=%d\n", s->dbc);
- if (s->dbc != 1) {
- /* Multibyte messages not implemented. */
- s->msg = 7; /* MESSAGE REJECT */
- //s->dbc = 1;
- //lsi_bad_phase(s, 1, PHASE_MI);
- lsi_set_phase(s, PHASE_MI);
- return;
- }
- cpu_physical_memory_read(s->dnad, &msg, 1);
- s->sfbr = msg;
- s->dnad++;
-
- switch (msg) {
- case 0x00:
- DPRINTF("Got Disconnect\n");
- lsi_disconnect(s);
- return;
- case 0x08:
- DPRINTF("Got No Operation\n");
- lsi_set_phase(s, PHASE_CMD);
- return;
- }
- if ((msg & 0x80) == 0) {
- DPRINTF("Unimplemented message 0x%d\n", msg);
- s->msg = 7; /* MESSAGE REJECT */
- lsi_bad_phase(s, 1, PHASE_MI);
- return;
- }
- s->current_lun = msg & 7;
- DPRINTF("Select LUN %d\n", s->current_lun);
- lsi_set_phase(s, PHASE_CMD);
-}
-
-/* Sign extend a 24-bit value. */
-static inline int32_t sxt24(int32_t n)
-{
- return (n << 8) >> 8;
-}
-
-static void lsi_memcpy(LSIState *s, uint32_t dest, uint32_t src, int count)
-{
- int n;
- uint8_t buf[TARGET_PAGE_SIZE];
-
- DPRINTF("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count);
- while (count) {
- n = (count > TARGET_PAGE_SIZE) ? TARGET_PAGE_SIZE : count;
- cpu_physical_memory_read(src, buf, n);
- cpu_physical_memory_write(dest, buf, n);
- src += n;
- dest += n;
- count -= n;
- }
-}
-
-static void lsi_execute_script(LSIState *s)
-{
- uint32_t insn;
- uint32_t addr;
- int opcode;
-
- s->istat1 |= LSI_ISTAT1_SRUN;
-again:
- insn = read_dword(s, s->dsp);
- addr = read_dword(s, s->dsp + 4);
- DPRINTF("SCRIPTS dsp=%08x opcode %08x arg %08x\n", s->dsp, insn, addr);
- s->dsps = addr;
- s->dcmd = insn >> 24;
- s->dsp += 8;
- switch (insn >> 30) {
- case 0: /* Block move. */
- if (s->sist1 & LSI_SIST1_STO) {
- DPRINTF("Delayed select timeout\n");
- lsi_stop_script(s);
- break;
- }
- s->dbc = insn & 0xffffff;
- s->rbc = s->dbc;
- if (insn & (1 << 29)) {
- /* Indirect addressing. */
- addr = read_dword(s, addr);
- } else if (insn & (1 << 28)) {
- uint32_t buf[2];
- int32_t offset;
- /* Table indirect addressing. */
- offset = sxt24(addr);
- cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8);
- s->dbc = cpu_to_le32(buf[0]);
- addr = cpu_to_le32(buf[1]);
- }
- if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
- DPRINTF("Wrong phase got %d expected %d\n",
- s->sstat1 & PHASE_MASK, (insn >> 24) & 7);
- lsi_script_scsi_interrupt(s, LSI_SIST0_MA, 0);
- break;
- }
- s->dnad = addr;
- switch (s->sstat1 & 0x7) {
- case PHASE_DO:
- lsi_do_dma(s, 1);
- break;
- case PHASE_DI:
- lsi_do_dma(s, 0);
- break;
- case PHASE_CMD:
- lsi_do_command(s);
- break;
- case PHASE_ST:
- lsi_do_status(s);
- break;
- case PHASE_MO:
- lsi_do_msgout(s);
- break;
- case PHASE_MI:
- lsi_do_msgin(s);
- break;
- default:
- BADF("Unimplemented phase %d\n", s->sstat1 & PHASE_MASK);
- exit(1);
- }
- s->dfifo = s->dbc & 0xff;
- s->ctest5 = (s->ctest5 & 0xfc) | ((s->dbc >> 8) & 3);
- 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. */
- opcode = (insn >> 27) & 7;
- if (opcode < 5) {
- uint32_t id;
-
- if (insn & (1 << 25)) {
- id = read_dword(s, s->dsa + sxt24(insn));
- } else {
- id = addr;
- }
- id = (id >> 16) & 0xf;
- if (insn & (1 << 26)) {
- addr = s->dsp + sxt24(addr);
- }
- s->dnad = addr;
- switch (opcode) {
- case 0: /* Select */
- s->sstat0 |= LSI_SSTAT0_WOA;
- s->scntl1 &= ~LSI_SCNTL1_IARB;
- s->sdid = id;
- if (id >= LSI_MAX_DEVS || !s->scsi_dev[id]) {
- DPRINTF("Selected absent target %d\n", id);
- lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
- lsi_disconnect(s);
- break;
- }
- DPRINTF("Selected target %d%s\n",
- id, insn & (1 << 3) ? " ATN" : "");
- /* ??? Linux drivers compain when this is set. Maybe
- it only applies in low-level mode (unimplemented).
- lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
- s->current_dev = s->scsi_dev[id];
- s->scntl1 |= LSI_SCNTL1_CON;
- if (insn & (1 << 3)) {
- s->socl |= LSI_SOCL_ATN;
- }
- lsi_set_phase(s, PHASE_MO);
- break;
- case 1: /* Disconnect */
- DPRINTF("Wait Disconect\n");
- s->scntl1 &= ~LSI_SCNTL1_CON;
- break;
- case 2: /* Wait Reselect */
- DPRINTF("Wait Reselect\n");
- s->waiting = 1;
- break;
- case 3: /* Set */
- DPRINTF("Set%s%s%s%s\n",
- insn & (1 << 3) ? " ATN" : "",
- insn & (1 << 6) ? " ACK" : "",
- insn & (1 << 9) ? " TM" : "",
- insn & (1 << 10) ? " CC" : "");
- if (insn & (1 << 3)) {
- s->socl |= LSI_SOCL_ATN;
- lsi_set_phase(s, PHASE_MO);
- }
- if (insn & (1 << 9)) {
- BADF("Target mode not implemented\n");
- exit(1);
- }
- if (insn & (1 << 10))
- s->carry = 1;
- break;
- case 4: /* Clear */
- DPRINTF("Clear%s%s%s%s\n",
- insn & (1 << 3) ? " ATN" : "",
- insn & (1 << 6) ? " ACK" : "",
- insn & (1 << 9) ? " TM" : "",
- insn & (1 << 10) ? " CC" : "");
- if (insn & (1 << 3)) {
- s->socl &= ~LSI_SOCL_ATN;
- }
- if (insn & (1 << 10))
- s->carry = 0;
- break;
- }
- } else {
- uint8_t op0;
- uint8_t op1;
- uint8_t data8;
- int reg;
- int operator;
-#ifdef DEBUG_LSI
- static const char *opcode_names[3] =
- {"Write", "Read", "Read-Modify-Write"};
- static const char *operator_names[8] =
- {"MOV", "SHL", "OR", "XOR", "AND", "SHR", "ADD", "ADC"};
-#endif
-
- reg = ((insn >> 16) & 0x7f) | (insn & 0x80);
- data8 = (insn >> 8) & 0xff;
- opcode = (insn >> 27) & 7;
- operator = (insn >> 24) & 7;
- DPRINTF("%s reg 0x%x %s data8 %d%s\n",
- opcode_names[opcode - 5], reg,
- operator_names[operator], data8,
- (insn & (1 << 23)) ? " SFBR" : "");
- op0 = op1 = 0;
- switch (opcode) {
- case 5: /* From SFBR */
- op0 = s->sfbr;
- op1 = data8;
- break;
- case 6: /* To SFBR */
- if (operator)
- op0 = lsi_reg_readb(s, reg);
- op1 = data8;
- break;
- case 7: /* Read-modify-write */
- if (operator)
- op0 = lsi_reg_readb(s, reg);
- if (insn & (1 << 23)) {
- op1 = s->sfbr;
- } else {
- op1 = data8;
- }
- break;
- }
-
- switch (operator) {
- case 0: /* move */
- op0 = op1;
- break;
- case 1: /* Shift left */
- op1 = op0 >> 7;
- op0 = (op0 << 1) | s->carry;
- s->carry = op1;
- break;
- case 2: /* OR */
- op0 |= op1;
- break;
- case 3: /* XOR */
- op0 |= op1;
- break;
- case 4: /* AND */
- op0 &= op1;
- break;
- case 5: /* SHR */
- op1 = op0 & 1;
- op0 = (op0 >> 1) | (s->carry << 7);
- break;
- case 6: /* ADD */
- op0 += op1;
- s->carry = op0 < op1;
- break;
- case 7: /* ADC */
- op0 += op1 + s->carry;
- if (s->carry)
- s->carry = op0 <= op1;
- else
- s->carry = op0 < op1;
- break;
- }
-
- switch (opcode) {
- case 5: /* From SFBR */
- case 7: /* Read-modify-write */
- lsi_reg_writeb(s, reg, op0);
- break;
- case 6: /* To SFBR */
- s->sfbr = op0;
- break;
- }
- }
- break;
-
- case 2: /* Transfer Control. */
- {
- int cond;
- int jmp;
-
- if ((insn & 0x002e0000) == 0) {
- DPRINTF("NOP\n");
- break;
- }
- if (s->sist1 & LSI_SIST1_STO) {
- DPRINTF("Delayed select timeout\n");
- lsi_stop_script(s);
- break;
- }
- cond = jmp = (insn & (1 << 19)) != 0;
- if (cond == jmp && (insn & (1 << 21))) {
- DPRINTF("Compare carry %d\n", s->carry == jmp);
- cond = s->carry != 0;
- }
- if (cond == jmp && (insn & (1 << 17))) {
- DPRINTF("Compare phase %d %c= %d\n",
- (s->sstat1 & PHASE_MASK),
- jmp ? '=' : '!',
- ((insn >> 24) & 7));
- cond = (s->sstat1 & PHASE_MASK) == ((insn >> 24) & 7);
- }
- if (cond == jmp && (insn & (1 << 18))) {
- uint8_t mask;
-
- mask = (~insn >> 8) & 0xff;
- DPRINTF("Compare data 0x%x & 0x%x %c= 0x%x\n",
- s->sfbr, mask, jmp ? '=' : '!', insn & mask);
- cond = (s->sfbr & mask) == (insn & mask);
- }
- if (cond == jmp) {
- if (insn & (1 << 23)) {
- /* Relative address. */
- addr = s->dsp + sxt24(addr);
- }
- switch ((insn >> 27) & 7) {
- case 0: /* Jump */
- DPRINTF("Jump to 0x%08x\n", addr);
- s->dsp = addr;
- break;
- case 1: /* Call */
- DPRINTF("Call 0x%08x\n", addr);
- s->temp = s->dsp;
- s->dsp = addr;
- break;
- case 2: /* Return */
- DPRINTF("Return to 0x%08x\n", s->temp);
- s->dsp = s->temp;
- break;
- case 3: /* Interrupt */
- DPRINTF("Interrupt 0x%08x\n", s->dsps);
- if ((insn & (1 << 20)) != 0) {
- s->istat0 |= LSI_ISTAT0_INTF;
- lsi_update_irq(s);
- } else {
- lsi_script_dma_interrupt(s, LSI_DSTAT_SIR);
- }
- break;
- default:
- DPRINTF("Illegal transfer control\n");
- lsi_script_dma_interrupt(s, LSI_DSTAT_IID);
- break;
- }
- } else {
- DPRINTF("Control condition failed\n");
- }
- }
- break;
-
- case 3:
- if ((insn & (1 << 29)) == 0) {
- /* Memory move. */
- uint32_t dest;
- /* ??? The docs imply the destination address is loaded into
- the TEMP register. However the Linux drivers rely on
- the value being presrved. */
- dest = read_dword(s, s->dsp);
- s->dsp += 4;
- lsi_memcpy(s, dest, addr, insn & 0xffffff);
- } else {
- uint8_t data[7];
- int reg;
- int n;
- int i;
-
- if (insn & (1 << 28)) {
- addr = s->dsa + sxt24(addr);
- }
- n = (insn & 7);
- reg = (insn >> 16) & 0xff;
- if (insn & (1 << 24)) {
- DPRINTF("Load reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
- cpu_physical_memory_read(addr, data, n);
- for (i = 0; i < n; i++) {
- lsi_reg_writeb(s, reg + i, data[i]);
- }
- } else {
- DPRINTF("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr);
- for (i = 0; i < n; i++) {
- data[i] = lsi_reg_readb(s, reg + i);
- }
- cpu_physical_memory_write(addr, data, n);
- }
- }
- }
- /* ??? Need to avoid infinite loops. */
- if (s->istat1 & LSI_ISTAT1_SRUN && !s->waiting) {
- if (s->dcntl & LSI_DCNTL_SSM) {
- lsi_script_dma_interrupt(s, LSI_DSTAT_SSI);
- } else {
- goto again;
- }
- }
- DPRINTF("SCRIPTS execution stopped\n");
-}
-
-static uint8_t lsi_reg_readb(LSIState *s, int offset)
-{
- uint8_t tmp;
-#define CASE_GET_REG32(name, addr) \
- case addr: return s->name & 0xff; \
- case addr + 1: return (s->name >> 8) & 0xff; \
- case addr + 2: return (s->name >> 16) & 0xff; \
- case addr + 3: return (s->name >> 24) & 0xff;
-
-#ifdef DEBUG_LSI_REG
- DPRINTF("Read reg %x\n", offset);
-#endif
- switch (offset) {
- case 0x00: /* SCNTL0 */
- return s->scntl0;
- case 0x01: /* SCNTL1 */
- return s->scntl1;
- case 0x02: /* SCNTL2 */
- return s->scntl2;
- case 0x03: /* SCNTL3 */
- return s->scntl3;
- case 0x04: /* SCID */
- return s->scid;
- case 0x05: /* SXFER */
- return s->sxfer;
- case 0x06: /* SDID */
- return s->sdid;
- case 0x07: /* GPREG0 */
- return 0x7f;
- case 0xb: /* SBCL */
- /* ??? This is not correct. However it's (hopefully) only
- used for diagnostics, so should be ok. */
- return 0;
- case 0xc: /* DSTAT */
- tmp = s->dstat | 0x80;
- if ((s->istat0 & LSI_ISTAT0_INTF) == 0)
- s->dstat = 0;
- lsi_update_irq(s);
- return tmp;
- case 0x0d: /* SSTAT0 */
- return s->sstat0;
- case 0x0e: /* SSTAT1 */
- return s->sstat1;
- case 0x0f: /* SSTAT2 */
- return s->scntl1 & LSI_SCNTL1_CON ? 0 : 2;
- CASE_GET_REG32(dsa, 0x10)
- case 0x14: /* ISTAT0 */
- return s->istat0;
- case 0x16: /* MBOX0 */
- return s->mbox0;
- case 0x17: /* MBOX1 */
- return s->mbox1;
- case 0x18: /* CTEST0 */
- return 0xff;
- case 0x19: /* CTEST1 */
- return 0;
- case 0x1a: /* CTEST2 */
- tmp = LSI_CTEST2_DACK | LSI_CTEST2_CM;
- if (s->istat0 & LSI_ISTAT0_SIGP) {
- s->istat0 &= ~LSI_ISTAT0_SIGP;
- tmp |= LSI_CTEST2_SIGP;
- }
- return tmp;
- case 0x1b: /* CTEST3 */
- return s->ctest3;
- CASE_GET_REG32(temp, 0x1c)
- case 0x20: /* DFIFO */
- return 0;
- case 0x21: /* CTEST4 */
- return s->ctest4;
- case 0x22: /* CTEST5 */
- return s->ctest5;
- case 0x24: /* DBC[0:7] */
- return s->dbc & 0xff;
- case 0x25: /* DBC[8:15] */
- return (s->dbc >> 8) & 0xff;
- case 0x26: /* DBC[16->23] */
- return (s->dbc >> 16) & 0xff;
- case 0x27: /* DCMD */
- return s->dcmd;
- CASE_GET_REG32(dsp, 0x2c)
- CASE_GET_REG32(dsps, 0x30)
- CASE_GET_REG32(scratch[0], 0x34)
- case 0x38: /* DMODE */
- return s->dmode;
- case 0x39: /* DIEN */
- return s->dien;
- case 0x3b: /* DCNTL */
- return s->dcntl;
- case 0x40: /* SIEN0 */
- return s->sien0;
- case 0x41: /* SIEN1 */
- return s->sien1;
- case 0x42: /* SIST0 */
- tmp = s->sist0;
- s->sist0 = 0;
- lsi_update_irq(s);
- return tmp;
- case 0x43: /* SIST1 */
- tmp = s->sist1;
- s->sist1 = 0;
- lsi_update_irq(s);
- return tmp;
- case 0x47: /* GPCNTL0 */
- return 0x0f;
- case 0x48: /* STIME0 */
- return s->stime0;
- case 0x4a: /* RESPID0 */
- return s->respid0;
- case 0x4b: /* RESPID1 */
- return s->respid1;
- case 0x4d: /* STEST1 */
- return s->stest1;
- case 0x4e: /* STEST2 */
- return s->stest2;
- case 0x4f: /* STEST3 */
- return s->stest3;
- case 0x52: /* STEST4 */
- return 0xe0;
- case 0x56: /* CCNTL0 */
- return s->ccntl0;
- case 0x57: /* CCNTL1 */
- return s->ccntl1;
- case 0x58: case 0x59: /* SBDL */
- return 0;
- CASE_GET_REG32(mmrs, 0xa0)
- CASE_GET_REG32(mmws, 0xa4)
- CASE_GET_REG32(sfs, 0xa8)
- CASE_GET_REG32(drs, 0xac)
- CASE_GET_REG32(sbms, 0xb0)
- CASE_GET_REG32(dmbs, 0xb4)
- CASE_GET_REG32(dnad64, 0xb8)
- CASE_GET_REG32(pmjad1, 0xc0)
- CASE_GET_REG32(pmjad2, 0xc4)
- CASE_GET_REG32(rbc, 0xc8)
- CASE_GET_REG32(ua, 0xcc)
- CASE_GET_REG32(ia, 0xd4)
- CASE_GET_REG32(sbc, 0xd8)
- CASE_GET_REG32(csbc, 0xdc)
- }
- if (offset >= 0x5c && offset < 0xa0) {
- int n;
- int shift;
- n = (offset - 0x58) >> 2;
- shift = (offset & 3) * 8;
- return (s->scratch[n] >> shift) & 0xff;
- }
- BADF("readb 0x%x\n", offset);
- exit(1);
-#undef CASE_GET_REG32
-}
-
-static void lsi_reg_writeb(LSIState *s, int offset, uint8_t val)
-{
-#define CASE_SET_REG32(name, addr) \
- case addr : s->name &= 0xffffff00; s->name |= val; break; \
- case addr + 1: s->name &= 0xffff00ff; s->name |= val << 8; break; \
- case addr + 2: s->name &= 0xff00ffff; s->name |= val << 16; break; \
- case addr + 3: s->name &= 0x00ffffff; s->name |= val << 24; break;
-
-#ifdef DEBUG_LSI_REG
- DPRINTF("Write reg %x = %02x\n", offset, val);
-#endif
- switch (offset) {
- case 0x00: /* SCNTL0 */
- s->scntl0 = val;
- if (val & LSI_SCNTL0_START) {
- BADF("Start sequence not implemented\n");
- }
- break;
- case 0x01: /* SCNTL1 */
- s->scntl1 = val & ~LSI_SCNTL1_SST;
- if (val & LSI_SCNTL1_IARB) {
- BADF("Immediate Arbritration not implemented\n");
- }
- if (val & LSI_SCNTL1_RST) {
- s->sstat0 |= LSI_SSTAT0_RST;
- lsi_script_scsi_interrupt(s, LSI_SIST0_RST, 0);
- } else {
- s->sstat0 &= ~LSI_SSTAT0_RST;
- }
- break;
- case 0x02: /* SCNTL2 */
- val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS);
- s->scntl3 = val;
- break;
- case 0x03: /* SCNTL3 */
- s->scntl3 = val;
- break;
- case 0x04: /* SCID */
- s->scid = val;
- break;
- case 0x05: /* SXFER */
- s->sxfer = val;
- break;
- case 0x07: /* GPREG0 */
- break;
- case 0x0c: case 0x0d: case 0x0e: case 0x0f:
- /* Linux writes to these readonly registers on startup. */
- return;
- CASE_SET_REG32(dsa, 0x10)
- case 0x14: /* ISTAT0 */
- s->istat0 = (s->istat0 & 0x0f) | (val & 0xf0);
- if (val & LSI_ISTAT0_ABRT) {
- lsi_script_dma_interrupt(s, LSI_DSTAT_ABRT);
- }
- if (val & LSI_ISTAT0_INTF) {
- s->istat0 &= ~LSI_ISTAT0_INTF;
- lsi_update_irq(s);
- }
- if (s->waiting && val & LSI_ISTAT0_SIGP) {
- DPRINTF("Woken by SIGP\n");
- s->waiting = 0;
- s->dsp = s->dnad;
- lsi_execute_script(s);
- }
- if (val & LSI_ISTAT0_SRST) {
- lsi_soft_reset(s);
- }
- case 0x16: /* MBOX0 */
- s->mbox0 = val;
- case 0x17: /* MBOX1 */
- s->mbox1 = val;
- case 0x1b: /* CTEST3 */
- s->ctest3 = val & 0x0f;
- break;
- CASE_SET_REG32(temp, 0x1c)
- case 0x21: /* CTEST4 */
- if (val & 7) {
- BADF("Unimplemented CTEST4-FBL 0x%x\n", val);
- }
- s->ctest4 = val;
- break;
- case 0x22: /* CTEST5 */
- if (val & (LSI_CTEST5_ADCK | LSI_CTEST5_BBCK)) {
- BADF("CTEST5 DMA increment not implemented\n");
- }
- s->ctest5 = val;
- break;
- case 0x2c: /* DSPS[0:7] */
- s->dsp &= 0xffffff00;
- s->dsp |= val;
- break;
- case 0x2d: /* DSPS[8:15] */
- s->dsp &= 0xffff00ff;
- s->dsp |= val << 8;
- break;
- case 0x2e: /* DSPS[16:23] */
- s->dsp &= 0xff00ffff;
- s->dsp |= val << 16;
- break;
- case 0x2f: /* DSPS[14:31] */
- s->dsp &= 0x00ffffff;
- s->dsp |= val << 24;
- if ((s->dmode & LSI_DMODE_MAN) == 0
- && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
- lsi_execute_script(s);
- break;
- CASE_SET_REG32(dsps, 0x30)
- CASE_SET_REG32(scratch[0], 0x34)
- case 0x38: /* DMODE */
- if (val & (LSI_DMODE_SIOM | LSI_DMODE_DIOM)) {
- BADF("IO mappings not implemented\n");
- }
- s->dmode = val;
- break;
- case 0x39: /* DIEN */
- s->dien = val;
- lsi_update_irq(s);
- break;
- case 0x3b: /* DCNTL */
- s->dcntl = val & ~(LSI_DCNTL_PFF | LSI_DCNTL_STD);
- if ((val & LSI_DCNTL_STD) && (s->istat1 & LSI_ISTAT1_SRUN) == 0)
- lsi_execute_script(s);
- break;
- case 0x40: /* SIEN0 */
- s->sien0 = val;
- lsi_update_irq(s);
- break;
- case 0x41: /* SIEN1 */
- s->sien1 = val;
- lsi_update_irq(s);
- break;
- case 0x47: /* GPCNTL0 */
- break;
- case 0x48: /* STIME0 */
- s->stime0 = val;
- break;
- case 0x49: /* STIME1 */
- if (val & 0xf) {
- DPRINTF("General purpose timer not implemented\n");
- /* ??? Raising the interrupt immediately seems to be sufficient
- to keep the FreeBSD driver happy. */
- lsi_script_scsi_interrupt(s, 0, LSI_SIST1_GEN);
- }
- break;
- case 0x4a: /* RESPID0 */
- s->respid0 = val;
- break;
- case 0x4b: /* RESPID1 */
- s->respid1 = val;
- break;
- case 0x4d: /* STEST1 */
- s->stest1 = val;
- break;
- case 0x4e: /* STEST2 */
- if (val & 1) {
- BADF("Low level mode not implemented\n");
- }
- s->stest2 = val;
- break;
- case 0x4f: /* STEST3 */
- if (val & 0x41) {
- BADF("SCSI FIFO test mode not implemented\n");
- }
- s->stest3 = val;
- break;
- case 0x56: /* CCNTL0 */
- s->ccntl0 = val;
- break;
- case 0x57: /* CCNTL1 */
- s->ccntl1 = val;
- break;
- CASE_SET_REG32(mmrs, 0xa0)
- CASE_SET_REG32(mmws, 0xa4)
- CASE_SET_REG32(sfs, 0xa8)
- CASE_SET_REG32(drs, 0xac)
- CASE_SET_REG32(sbms, 0xb0)
- CASE_SET_REG32(dmbs, 0xb4)
- CASE_SET_REG32(dnad64, 0xb8)
- CASE_SET_REG32(pmjad1, 0xc0)
- CASE_SET_REG32(pmjad2, 0xc4)
- CASE_SET_REG32(rbc, 0xc8)
- CASE_SET_REG32(ua, 0xcc)
- CASE_SET_REG32(ia, 0xd4)
- CASE_SET_REG32(sbc, 0xd8)
- CASE_SET_REG32(csbc, 0xdc)
- default:
- if (offset >= 0x5c && offset < 0xa0) {
- int n;
- int shift;
- n = (offset - 0x58) >> 2;
- shift = (offset & 3) * 8;
- s->scratch[n] &= ~(0xff << shift);
- s->scratch[n] |= (val & 0xff) << shift;
- } else {
- BADF("Unhandled writeb 0x%x = 0x%x\n", offset, val);
- }
- }
-#undef CASE_SET_REG32
-}
-
-static void lsi_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- LSIState *s = (LSIState *)opaque;
-
- lsi_reg_writeb(s, addr & 0xff, val);
-}
-
-static void lsi_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- LSIState *s = (LSIState *)opaque;
-
- addr &= 0xff;
- lsi_reg_writeb(s, addr, val & 0xff);
- lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
-}
-
-static void lsi_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- LSIState *s = (LSIState *)opaque;
-
- addr &= 0xff;
- 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 + 3, (val >> 24) & 0xff);
-}
-
-static uint32_t lsi_mmio_readb(void *opaque, target_phys_addr_t addr)
-{
- LSIState *s = (LSIState *)opaque;
-
- return lsi_reg_readb(s, addr & 0xff);
-}
-
-static uint32_t lsi_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
- LSIState *s = (LSIState *)opaque;
- uint32_t val;
-
- addr &= 0xff;
- val = lsi_reg_readb(s, addr);
- val |= lsi_reg_readb(s, addr + 1) << 8;
- return val;
-}
-
-static uint32_t lsi_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
- LSIState *s = (LSIState *)opaque;
- uint32_t val;
- addr &= 0xff;
- val = lsi_reg_readb(s, addr);
- val |= lsi_reg_readb(s, addr + 1) << 8;
- val |= lsi_reg_readb(s, addr + 2) << 16;
- val |= lsi_reg_readb(s, addr + 3) << 24;
- return val;
-}
-
-static CPUReadMemoryFunc *lsi_mmio_readfn[3] = {
- lsi_mmio_readb,
- lsi_mmio_readw,
- lsi_mmio_readl,
-};
-
-static CPUWriteMemoryFunc *lsi_mmio_writefn[3] = {
- lsi_mmio_writeb,
- lsi_mmio_writew,
- lsi_mmio_writel,
-};
-
-static void lsi_ram_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- LSIState *s = (LSIState *)opaque;
- uint32_t newval;
- int shift;
-
- addr &= 0x1fff;
- newval = s->script_ram[addr >> 2];
- shift = (addr & 3) * 8;
- newval &= ~(0xff << shift);
- newval |= val << shift;
- s->script_ram[addr >> 2] = newval;
-}
-
-static void lsi_ram_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- LSIState *s = (LSIState *)opaque;
- uint32_t newval;
-
- addr &= 0x1fff;
- newval = s->script_ram[addr >> 2];
- if (addr & 2) {
- newval = (newval & 0xffff) | (val << 16);
- } else {
- newval = (newval & 0xffff0000) | val;
- }
- s->script_ram[addr >> 2] = newval;
-}
-
-
-static void lsi_ram_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- LSIState *s = (LSIState *)opaque;
-
- addr &= 0x1fff;
- s->script_ram[addr >> 2] = val;
-}
-
-static uint32_t lsi_ram_readb(void *opaque, target_phys_addr_t addr)
-{
- LSIState *s = (LSIState *)opaque;
- uint32_t val;
-
- addr &= 0x1fff;
- val = s->script_ram[addr >> 2];
- val >>= (addr & 3) * 8;
- return val & 0xff;
-}
-
-static uint32_t lsi_ram_readw(void *opaque, target_phys_addr_t addr)
-{
- LSIState *s = (LSIState *)opaque;
- uint32_t val;
-
- addr &= 0x1fff;
- val = s->script_ram[addr >> 2];
- if (addr & 2)
- val >>= 16;
- return le16_to_cpu(val);
-}
-
-static uint32_t lsi_ram_readl(void *opaque, target_phys_addr_t addr)
-{
- LSIState *s = (LSIState *)opaque;
-
- addr &= 0x1fff;
- return le32_to_cpu(s->script_ram[addr >> 2]);
-}
-
-static CPUReadMemoryFunc *lsi_ram_readfn[3] = {
- lsi_ram_readb,
- lsi_ram_readw,
- lsi_ram_readl,
-};
-
-static CPUWriteMemoryFunc *lsi_ram_writefn[3] = {
- lsi_ram_writeb,
- lsi_ram_writew,
- lsi_ram_writel,
-};
-
-static uint32_t lsi_io_readb(void *opaque, uint32_t addr)
-{
- LSIState *s = (LSIState *)opaque;
- return lsi_reg_readb(s, addr & 0xff);
-}
-
-static uint32_t lsi_io_readw(void *opaque, uint32_t addr)
-{
- LSIState *s = (LSIState *)opaque;
- uint32_t val;
- addr &= 0xff;
- val = lsi_reg_readb(s, addr);
- val |= lsi_reg_readb(s, addr + 1) << 8;
- return val;
-}
-
-static uint32_t lsi_io_readl(void *opaque, uint32_t addr)
-{
- LSIState *s = (LSIState *)opaque;
- uint32_t val;
- addr &= 0xff;
- val = lsi_reg_readb(s, addr);
- val |= lsi_reg_readb(s, addr + 1) << 8;
- val |= lsi_reg_readb(s, addr + 2) << 16;
- val |= lsi_reg_readb(s, addr + 3) << 24;
- return val;
-}
-
-static void lsi_io_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- LSIState *s = (LSIState *)opaque;
- lsi_reg_writeb(s, addr & 0xff, val);
-}
-
-static void lsi_io_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- LSIState *s = (LSIState *)opaque;
- addr &= 0xff;
- lsi_reg_writeb(s, addr, val & 0xff);
- lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
-}
-
-static void lsi_io_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- LSIState *s = (LSIState *)opaque;
- addr &= 0xff;
- 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);
-}
-
-static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- LSIState *s = (LSIState *)pci_dev;
-
- DPRINTF("Mapping IO at %08x\n", addr);
-
- register_ioport_write(addr, 256, 1, lsi_io_writeb, s);
- register_ioport_read(addr, 256, 1, lsi_io_readb, s);
- register_ioport_write(addr, 256, 2, lsi_io_writew, s);
- register_ioport_read(addr, 256, 2, lsi_io_readw, s);
- register_ioport_write(addr, 256, 4, lsi_io_writel, s);
- register_ioport_read(addr, 256, 4, lsi_io_readl, s);
-}
-
-static void lsi_ram_mapfunc(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- LSIState *s = (LSIState *)pci_dev;
-
- DPRINTF("Mapping ram at %08x\n", addr);
- s->script_ram_base = addr;
- cpu_register_physical_memory(addr + 0, 0x2000, s->ram_io_addr);
-}
-
-static void lsi_mmio_mapfunc(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- LSIState *s = (LSIState *)pci_dev;
-
- DPRINTF("Mapping registers at %08x\n", addr);
- cpu_register_physical_memory(addr + 0, 0x400, s->mmio_io_addr);
-}
-
-void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id)
-{
- LSIState *s = (LSIState *)opaque;
-
- if (id < 0) {
- for (id = 0; id < LSI_MAX_DEVS; id++) {
- if (s->scsi_dev[id] == NULL)
- break;
- }
- }
- if (id >= LSI_MAX_DEVS) {
- BADF("Bad Device ID %d\n", id);
- return;
- }
- if (s->scsi_dev[id]) {
- DPRINTF("Destroying device %d\n", id);
- scsi_disk_destroy(s->scsi_dev[id]);
- }
- DPRINTF("Attaching block device %d\n", id);
- s->scsi_dev[id] = scsi_disk_init(bd, lsi_command_complete, s);
-}
-
-void *lsi_scsi_init(PCIBus *bus, int devfn)
-{
- LSIState *s;
-
- s = (LSIState *)pci_register_device(bus, "LSI53C895A SCSI HBA",
- sizeof(*s), devfn, NULL, NULL);
- if (s == NULL) {
- fprintf(stderr, "lsi-scsi: Failed to register PCI device\n");
- return NULL;
- }
-
- s->pci_dev.config[0x00] = 0x00;
- s->pci_dev.config[0x01] = 0x10;
- s->pci_dev.config[0x02] = 0x12;
- s->pci_dev.config[0x03] = 0x00;
- s->pci_dev.config[0x0b] = 0x01;
- s->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
-
- s->mmio_io_addr = cpu_register_io_memory(0, lsi_mmio_readfn,
- lsi_mmio_writefn, s);
- s->ram_io_addr = cpu_register_io_memory(0, lsi_ram_readfn,
- lsi_ram_writefn, s);
-
- pci_register_io_region((struct PCIDevice *)s, 0, 256,
- PCI_ADDRESS_SPACE_IO, lsi_io_mapfunc);
- pci_register_io_region((struct PCIDevice *)s, 1, 0x400,
- PCI_ADDRESS_SPACE_MEM, lsi_mmio_mapfunc);
- pci_register_io_region((struct PCIDevice *)s, 2, 0x2000,
- PCI_ADDRESS_SPACE_MEM, lsi_ram_mapfunc);
-
- lsi_soft_reset(s);
-
- return s;
-}
-
diff --git a/hw/m48t59.c b/hw/m48t59.c
deleted file mode 100644
index daa1c52..0000000
--- a/hw/m48t59.c
+++ /dev/null
@@ -1,614 +0,0 @@
-/*
- * QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
- *
- * Copyright (c) 2003-2005 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 "m48t59.h"
-
-//#define DEBUG_NVRAM
-
-#if defined(DEBUG_NVRAM)
-#define NVRAM_PRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
-#else
-#define NVRAM_PRINTF(fmt, args...) do { } while (0)
-#endif
-
-/*
- * The M48T08 and M48T59 chips are very similar. The newer '59 has
- * alarm and a watchdog timer and related control registers. In the
- * PPC platform there is also a nvram lock function.
- */
-struct m48t59_t {
- /* Model parameters */
- int type; // 8 = m48t08, 59 = m48t59
- /* Hardware parameters */
- int IRQ;
- int mem_index;
- uint32_t mem_base;
- uint32_t io_base;
- uint16_t size;
- /* RTC management */
- time_t time_offset;
- time_t stop_time;
- /* Alarm & watchdog */
- time_t alarm;
- struct QEMUTimer *alrm_timer;
- struct QEMUTimer *wd_timer;
- /* NVRAM storage */
- uint8_t lock;
- uint16_t addr;
- uint8_t *buffer;
-};
-
-/* Fake timer functions */
-/* Generic helpers for BCD */
-static inline uint8_t toBCD (uint8_t value)
-{
- return (((value / 10) % 10) << 4) | (value % 10);
-}
-
-static inline uint8_t fromBCD (uint8_t BCD)
-{
- return ((BCD >> 4) * 10) + (BCD & 0x0F);
-}
-
-/* RTC management helpers */
-static void get_time (m48t59_t *NVRAM, struct tm *tm)
-{
- time_t t;
-
- t = time(NULL) + NVRAM->time_offset;
-#ifdef _WIN32
- memcpy(tm,localtime(&t),sizeof(*tm));
-#else
- localtime_r (&t, tm) ;
-#endif
-}
-
-static void set_time (m48t59_t *NVRAM, struct tm *tm)
-{
- time_t now, new_time;
-
- new_time = mktime(tm);
- now = time(NULL);
- NVRAM->time_offset = new_time - now;
-}
-
-/* Alarm management */
-static void alarm_cb (void *opaque)
-{
- struct tm tm, tm_now;
- uint64_t next_time;
- m48t59_t *NVRAM = opaque;
-
- pic_set_irq(NVRAM->IRQ, 1);
- if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
- /* Repeat once a month */
- get_time(NVRAM, &tm_now);
- memcpy(&tm, &tm_now, sizeof(struct tm));
- tm.tm_mon++;
- if (tm.tm_mon == 13) {
- tm.tm_mon = 1;
- tm.tm_year++;
- }
- next_time = mktime(&tm);
- } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
- /* Repeat once a day */
- next_time = 24 * 60 * 60 + mktime(&tm_now);
- } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
- (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
- /* Repeat once an hour */
- next_time = 60 * 60 + mktime(&tm_now);
- } else if ((NVRAM->buffer[0x1FF5] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF4] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF3] & 0x80) != 0 &&
- (NVRAM->buffer[0x1FF2] & 0x80) == 0) {
- /* Repeat once a minute */
- next_time = 60 + mktime(&tm_now);
- } else {
- /* Repeat once a second */
- next_time = 1 + mktime(&tm_now);
- }
- qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);
- pic_set_irq(NVRAM->IRQ, 0);
-}
-
-
-static void get_alarm (m48t59_t *NVRAM, struct tm *tm)
-{
-#ifdef _WIN32
- memcpy(tm,localtime(&NVRAM->alarm),sizeof(*tm));
-#else
- localtime_r (&NVRAM->alarm, tm);
-#endif
-}
-
-static void set_alarm (m48t59_t *NVRAM, struct tm *tm)
-{
- NVRAM->alarm = mktime(tm);
- if (NVRAM->alrm_timer != NULL) {
- qemu_del_timer(NVRAM->alrm_timer);
- NVRAM->alrm_timer = NULL;
- }
- if (NVRAM->alarm - time(NULL) > 0)
- qemu_mod_timer(NVRAM->alrm_timer, NVRAM->alarm * 1000);
-}
-
-/* Watchdog management */
-static void watchdog_cb (void *opaque)
-{
- m48t59_t *NVRAM = opaque;
-
- NVRAM->buffer[0x1FF0] |= 0x80;
- if (NVRAM->buffer[0x1FF7] & 0x80) {
- NVRAM->buffer[0x1FF7] = 0x00;
- NVRAM->buffer[0x1FFC] &= ~0x40;
- /* 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);
- }
-}
-
-static void set_up_watchdog (m48t59_t *NVRAM, uint8_t value)
-{
- uint64_t interval; /* in 1/16 seconds */
-
- if (NVRAM->wd_timer != NULL) {
- qemu_del_timer(NVRAM->wd_timer);
- NVRAM->wd_timer = NULL;
- }
- NVRAM->buffer[0x1FF0] &= ~0x80;
- if (value != 0) {
- interval = (1 << (2 * (value & 0x03))) * ((value >> 2) & 0x1F);
- qemu_mod_timer(NVRAM->wd_timer, ((uint64_t)time(NULL) * 1000) +
- ((interval * 1000) >> 4));
- }
-}
-
-/* Direct access to NVRAM */
-void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val)
-{
- struct tm tm;
- int tmp;
-
- if (addr > 0x1FF8 && addr < 0x2000)
- NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, addr, val);
- if (NVRAM->type == 8 &&
- (addr >= 0x1ff0 && addr <= 0x1ff7))
- goto do_write;
- switch (addr) {
- case 0x1FF0:
- /* flags register : read-only */
- break;
- case 0x1FF1:
- /* unused */
- break;
- case 0x1FF2:
- /* alarm seconds */
- tmp = fromBCD(val & 0x7F);
- if (tmp >= 0 && tmp <= 59) {
- get_alarm(NVRAM, &tm);
- tm.tm_sec = tmp;
- NVRAM->buffer[0x1FF2] = val;
- set_alarm(NVRAM, &tm);
- }
- break;
- case 0x1FF3:
- /* alarm minutes */
- tmp = fromBCD(val & 0x7F);
- if (tmp >= 0 && tmp <= 59) {
- get_alarm(NVRAM, &tm);
- tm.tm_min = tmp;
- NVRAM->buffer[0x1FF3] = val;
- set_alarm(NVRAM, &tm);
- }
- break;
- case 0x1FF4:
- /* alarm hours */
- tmp = fromBCD(val & 0x3F);
- if (tmp >= 0 && tmp <= 23) {
- get_alarm(NVRAM, &tm);
- tm.tm_hour = tmp;
- NVRAM->buffer[0x1FF4] = val;
- set_alarm(NVRAM, &tm);
- }
- break;
- case 0x1FF5:
- /* alarm date */
- tmp = fromBCD(val & 0x1F);
- if (tmp != 0) {
- get_alarm(NVRAM, &tm);
- tm.tm_mday = tmp;
- NVRAM->buffer[0x1FF5] = val;
- set_alarm(NVRAM, &tm);
- }
- break;
- case 0x1FF6:
- /* interrupts */
- NVRAM->buffer[0x1FF6] = val;
- break;
- case 0x1FF7:
- /* watchdog */
- NVRAM->buffer[0x1FF7] = val;
- set_up_watchdog(NVRAM, val);
- break;
- case 0x1FF8:
- /* control */
- NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
- break;
- case 0x1FF9:
- /* seconds (BCD) */
- tmp = fromBCD(val & 0x7F);
- if (tmp >= 0 && tmp <= 59) {
- get_time(NVRAM, &tm);
- tm.tm_sec = tmp;
- set_time(NVRAM, &tm);
- }
- if ((val & 0x80) ^ (NVRAM->buffer[0x1FF9] & 0x80)) {
- if (val & 0x80) {
- NVRAM->stop_time = time(NULL);
- } else {
- NVRAM->time_offset += NVRAM->stop_time - time(NULL);
- NVRAM->stop_time = 0;
- }
- }
- NVRAM->buffer[0x1FF9] = val & 0x80;
- break;
- case 0x1FFA:
- /* minutes (BCD) */
- tmp = fromBCD(val & 0x7F);
- if (tmp >= 0 && tmp <= 59) {
- get_time(NVRAM, &tm);
- tm.tm_min = tmp;
- set_time(NVRAM, &tm);
- }
- break;
- case 0x1FFB:
- /* hours (BCD) */
- tmp = fromBCD(val & 0x3F);
- if (tmp >= 0 && tmp <= 23) {
- get_time(NVRAM, &tm);
- tm.tm_hour = tmp;
- set_time(NVRAM, &tm);
- }
- break;
- case 0x1FFC:
- /* day of the week / century */
- tmp = fromBCD(val & 0x07);
- get_time(NVRAM, &tm);
- tm.tm_wday = tmp;
- set_time(NVRAM, &tm);
- NVRAM->buffer[0x1FFC] = val & 0x40;
- break;
- case 0x1FFD:
- /* date */
- tmp = fromBCD(val & 0x1F);
- if (tmp != 0) {
- get_time(NVRAM, &tm);
- tm.tm_mday = tmp;
- set_time(NVRAM, &tm);
- }
- break;
- case 0x1FFE:
- /* month */
- tmp = fromBCD(val & 0x1F);
- if (tmp >= 1 && tmp <= 12) {
- get_time(NVRAM, &tm);
- tm.tm_mon = tmp - 1;
- set_time(NVRAM, &tm);
- }
- break;
- case 0x1FFF:
- /* year */
- tmp = fromBCD(val);
- if (tmp >= 0 && tmp <= 99) {
- get_time(NVRAM, &tm);
- if (NVRAM->type == 8)
- tm.tm_year = fromBCD(val) + 68; // Base year is 1968
- else
- tm.tm_year = fromBCD(val);
- set_time(NVRAM, &tm);
- }
- break;
- default:
- /* Check lock registers state */
- if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
- break;
- if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
- break;
- do_write:
- if (addr < NVRAM->size) {
- NVRAM->buffer[addr] = val & 0xFF;
- }
- break;
- }
-}
-
-uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr)
-{
- struct tm tm;
- uint32_t retval = 0xFF;
-
- if (NVRAM->type == 8 &&
- (addr >= 0x1ff0 && addr <= 0x1ff7))
- goto do_read;
- switch (addr) {
- case 0x1FF0:
- /* flags register */
- goto do_read;
- case 0x1FF1:
- /* unused */
- retval = 0;
- break;
- case 0x1FF2:
- /* alarm seconds */
- goto do_read;
- case 0x1FF3:
- /* alarm minutes */
- goto do_read;
- case 0x1FF4:
- /* alarm hours */
- goto do_read;
- case 0x1FF5:
- /* alarm date */
- goto do_read;
- case 0x1FF6:
- /* interrupts */
- goto do_read;
- case 0x1FF7:
- /* A read resets the watchdog */
- set_up_watchdog(NVRAM, NVRAM->buffer[0x1FF7]);
- goto do_read;
- case 0x1FF8:
- /* control */
- goto do_read;
- case 0x1FF9:
- /* seconds (BCD) */
- get_time(NVRAM, &tm);
- retval = (NVRAM->buffer[0x1FF9] & 0x80) | toBCD(tm.tm_sec);
- break;
- case 0x1FFA:
- /* minutes (BCD) */
- get_time(NVRAM, &tm);
- retval = toBCD(tm.tm_min);
- break;
- case 0x1FFB:
- /* hours (BCD) */
- get_time(NVRAM, &tm);
- retval = toBCD(tm.tm_hour);
- break;
- case 0x1FFC:
- /* day of the week / century */
- get_time(NVRAM, &tm);
- retval = NVRAM->buffer[0x1FFC] | tm.tm_wday;
- break;
- case 0x1FFD:
- /* date */
- get_time(NVRAM, &tm);
- retval = toBCD(tm.tm_mday);
- break;
- case 0x1FFE:
- /* month */
- get_time(NVRAM, &tm);
- retval = toBCD(tm.tm_mon + 1);
- break;
- case 0x1FFF:
- /* year */
- get_time(NVRAM, &tm);
- if (NVRAM->type == 8)
- retval = toBCD(tm.tm_year - 68); // Base year is 1968
- else
- retval = toBCD(tm.tm_year);
- break;
- default:
- /* Check lock registers state */
- if (addr >= 0x20 && addr <= 0x2F && (NVRAM->lock & 1))
- break;
- if (addr >= 0x30 && addr <= 0x3F && (NVRAM->lock & 2))
- break;
- do_read:
- if (addr < NVRAM->size) {
- retval = NVRAM->buffer[addr];
- }
- break;
- }
- if (addr > 0x1FF9 && addr < 0x2000)
- NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
-
- return retval;
-}
-
-void m48t59_set_addr (m48t59_t *NVRAM, uint32_t addr)
-{
- NVRAM->addr = addr;
-}
-
-void m48t59_toggle_lock (m48t59_t *NVRAM, int lock)
-{
- NVRAM->lock ^= 1 << lock;
-}
-
-/* IO access to NVRAM */
-static void NVRAM_writeb (void *opaque, uint32_t addr, uint32_t val)
-{
- m48t59_t *NVRAM = opaque;
-
- addr -= NVRAM->io_base;
- NVRAM_PRINTF("0x%08x => 0x%08x\n", addr, val);
- switch (addr) {
- case 0:
- NVRAM->addr &= ~0x00FF;
- NVRAM->addr |= val;
- break;
- case 1:
- NVRAM->addr &= ~0xFF00;
- NVRAM->addr |= val << 8;
- break;
- case 3:
- m48t59_write(NVRAM, val, NVRAM->addr);
- NVRAM->addr = 0x0000;
- break;
- default:
- break;
- }
-}
-
-static uint32_t NVRAM_readb (void *opaque, uint32_t addr)
-{
- m48t59_t *NVRAM = opaque;
- uint32_t retval;
-
- addr -= NVRAM->io_base;
- switch (addr) {
- case 3:
- retval = m48t59_read(NVRAM, NVRAM->addr);
- break;
- default:
- retval = -1;
- break;
- }
- NVRAM_PRINTF("0x%08x <= 0x%08x\n", addr, retval);
-
- return retval;
-}
-
-static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
- m48t59_t *NVRAM = opaque;
-
- addr -= NVRAM->mem_base;
- m48t59_write(NVRAM, addr, value & 0xff);
-}
-
-static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
- m48t59_t *NVRAM = opaque;
-
- addr -= NVRAM->mem_base;
- m48t59_write(NVRAM, addr, (value >> 8) & 0xff);
- m48t59_write(NVRAM, addr + 1, value & 0xff);
-}
-
-static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
- m48t59_t *NVRAM = opaque;
-
- addr -= NVRAM->mem_base;
- m48t59_write(NVRAM, addr, (value >> 24) & 0xff);
- m48t59_write(NVRAM, addr + 1, (value >> 16) & 0xff);
- m48t59_write(NVRAM, addr + 2, (value >> 8) & 0xff);
- m48t59_write(NVRAM, addr + 3, value & 0xff);
-}
-
-static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
-{
- m48t59_t *NVRAM = opaque;
- uint32_t retval;
-
- addr -= NVRAM->mem_base;
- retval = m48t59_read(NVRAM, addr);
- return retval;
-}
-
-static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
-{
- m48t59_t *NVRAM = opaque;
- uint32_t retval;
-
- addr -= NVRAM->mem_base;
- retval = m48t59_read(NVRAM, addr) << 8;
- retval |= m48t59_read(NVRAM, addr + 1);
- return retval;
-}
-
-static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
-{
- m48t59_t *NVRAM = opaque;
- uint32_t retval;
-
- addr -= NVRAM->mem_base;
- retval = m48t59_read(NVRAM, addr) << 24;
- retval |= m48t59_read(NVRAM, addr + 1) << 16;
- retval |= m48t59_read(NVRAM, addr + 2) << 8;
- retval |= m48t59_read(NVRAM, addr + 3);
- return retval;
-}
-
-static CPUWriteMemoryFunc *nvram_write[] = {
- &nvram_writeb,
- &nvram_writew,
- &nvram_writel,
-};
-
-static CPUReadMemoryFunc *nvram_read[] = {
- &nvram_readb,
- &nvram_readw,
- &nvram_readl,
-};
-
-/* Initialisation routine */
-m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
- uint32_t io_base, uint16_t size,
- int type)
-{
- m48t59_t *s;
-
- s = qemu_mallocz(sizeof(m48t59_t));
- if (!s)
- return NULL;
- s->buffer = qemu_mallocz(size);
- if (!s->buffer) {
- qemu_free(s);
- return NULL;
- }
- s->IRQ = IRQ;
- s->size = size;
- s->mem_base = mem_base;
- s->io_base = io_base;
- s->addr = 0;
- s->type = type;
- if (io_base != 0) {
- register_ioport_read(io_base, 0x04, 1, NVRAM_readb, s);
- register_ioport_write(io_base, 0x04, 1, NVRAM_writeb, s);
- }
- if (mem_base != 0) {
- s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
- cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
- }
- if (type == 59) {
- s->alrm_timer = qemu_new_timer(vm_clock, &alarm_cb, s);
- s->wd_timer = qemu_new_timer(vm_clock, &watchdog_cb, s);
- }
- s->lock = 0;
-
- return s;
-}
diff --git a/hw/m48t59.h b/hw/m48t59.h
deleted file mode 100644
index af22dc1..0000000
--- a/hw/m48t59.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#if !defined (__M48T59_H__)
-#define __M48T59_H__
-
-typedef struct m48t59_t m48t59_t;
-
-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,
- uint32_t io_base, uint16_t size,
- int type);
-
-#endif /* !defined (__M48T59_H__) */
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
deleted file mode 100644
index 9d4cbed..0000000
--- a/hw/mc146818rtc.c
+++ /dev/null
@@ -1,463 +0,0 @@
-/*
- * QEMU MC146818 RTC emulation
- *
- * Copyright (c) 2003-2004 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"
-
-//#define DEBUG_CMOS
-
-#define RTC_SECONDS 0
-#define RTC_SECONDS_ALARM 1
-#define RTC_MINUTES 2
-#define RTC_MINUTES_ALARM 3
-#define RTC_HOURS 4
-#define RTC_HOURS_ALARM 5
-#define RTC_ALARM_DONT_CARE 0xC0
-
-#define RTC_DAY_OF_WEEK 6
-#define RTC_DAY_OF_MONTH 7
-#define RTC_MONTH 8
-#define RTC_YEAR 9
-
-#define RTC_REG_A 10
-#define RTC_REG_B 11
-#define RTC_REG_C 12
-#define RTC_REG_D 13
-
-#define REG_A_UIP 0x80
-
-#define REG_B_SET 0x80
-#define REG_B_PIE 0x40
-#define REG_B_AIE 0x20
-#define REG_B_UIE 0x10
-
-struct RTCState {
- uint8_t cmos_data[128];
- uint8_t cmos_index;
- struct tm current_tm;
- int irq;
- /* periodic timer */
- QEMUTimer *periodic_timer;
- int64_t next_periodic_time;
- /* second update */
- int64_t next_second_time;
- QEMUTimer *second_timer;
- QEMUTimer *second_timer2;
-};
-
-static void rtc_set_time(RTCState *s);
-static void rtc_copy_date(RTCState *s);
-
-static void rtc_timer_update(RTCState *s, int64_t current_time)
-{
- int period_code, period;
- int64_t cur_clock, next_irq_clock;
-
- period_code = s->cmos_data[RTC_REG_A] & 0x0f;
- if (period_code != 0 &&
- (s->cmos_data[RTC_REG_B] & REG_B_PIE)) {
- if (period_code <= 2)
- period_code += 7;
- /* period in 32 Khz cycles */
- period = 1 << (period_code - 1);
- /* compute 32 khz clock */
- cur_clock = muldiv64(current_time, 32768, ticks_per_sec);
- next_irq_clock = (cur_clock & ~(period - 1)) + period;
- s->next_periodic_time = muldiv64(next_irq_clock, ticks_per_sec, 32768) + 1;
- qemu_mod_timer(s->periodic_timer, s->next_periodic_time);
- } else {
- qemu_del_timer(s->periodic_timer);
- }
-}
-
-static void rtc_periodic_timer(void *opaque)
-{
- RTCState *s = opaque;
-
- rtc_timer_update(s, s->next_periodic_time);
- s->cmos_data[RTC_REG_C] |= 0xc0;
- pic_set_irq(s->irq, 1);
-}
-
-static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
-{
- RTCState *s = opaque;
-
- if ((addr & 1) == 0) {
- s->cmos_index = data & 0x7f;
- } else {
-#ifdef DEBUG_CMOS
- printf("cmos: write index=0x%02x val=0x%02x\n",
- s->cmos_index, data);
-#endif
- switch(s->cmos_index) {
- case RTC_SECONDS_ALARM:
- case RTC_MINUTES_ALARM:
- case RTC_HOURS_ALARM:
- /* XXX: not supported */
- s->cmos_data[s->cmos_index] = data;
- break;
- case RTC_SECONDS:
- case RTC_MINUTES:
- case RTC_HOURS:
- case RTC_DAY_OF_WEEK:
- case RTC_DAY_OF_MONTH:
- case RTC_MONTH:
- case RTC_YEAR:
- s->cmos_data[s->cmos_index] = data;
- /* if in set mode, do not update the time */
- if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
- rtc_set_time(s);
- }
- break;
- case RTC_REG_A:
- /* UIP bit is read only */
- s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
- (s->cmos_data[RTC_REG_A] & REG_A_UIP);
- rtc_timer_update(s, qemu_get_clock(vm_clock));
- break;
- case RTC_REG_B:
- if (data & REG_B_SET) {
- /* set mode: reset UIP mode */
- s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
- data &= ~REG_B_UIE;
- } else {
- /* if disabling set mode, update the time */
- if (s->cmos_data[RTC_REG_B] & REG_B_SET) {
- rtc_set_time(s);
- }
- }
- s->cmos_data[RTC_REG_B] = data;
- rtc_timer_update(s, qemu_get_clock(vm_clock));
- break;
- case RTC_REG_C:
- case RTC_REG_D:
- /* cannot write to them */
- break;
- default:
- s->cmos_data[s->cmos_index] = data;
- break;
- }
- }
-}
-
-static inline int to_bcd(RTCState *s, int a)
-{
- if (s->cmos_data[RTC_REG_B] & 0x04) {
- return a;
- } else {
- return ((a / 10) << 4) | (a % 10);
- }
-}
-
-static inline int from_bcd(RTCState *s, int a)
-{
- if (s->cmos_data[RTC_REG_B] & 0x04) {
- return a;
- } else {
- return ((a >> 4) * 10) + (a & 0x0f);
- }
-}
-
-static void rtc_set_time(RTCState *s)
-{
- struct tm *tm = &s->current_tm;
-
- tm->tm_sec = from_bcd(s, s->cmos_data[RTC_SECONDS]);
- tm->tm_min = from_bcd(s, s->cmos_data[RTC_MINUTES]);
- tm->tm_hour = from_bcd(s, s->cmos_data[RTC_HOURS] & 0x7f);
- if (!(s->cmos_data[RTC_REG_B] & 0x02) &&
- (s->cmos_data[RTC_HOURS] & 0x80)) {
- tm->tm_hour += 12;
- }
- tm->tm_wday = from_bcd(s, s->cmos_data[RTC_DAY_OF_WEEK]);
- tm->tm_mday = from_bcd(s, s->cmos_data[RTC_DAY_OF_MONTH]);
- tm->tm_mon = from_bcd(s, s->cmos_data[RTC_MONTH]) - 1;
- tm->tm_year = from_bcd(s, s->cmos_data[RTC_YEAR]) + 100;
-}
-
-static void rtc_copy_date(RTCState *s)
-{
- const struct tm *tm = &s->current_tm;
-
- s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
- s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
- if (s->cmos_data[RTC_REG_B] & 0x02) {
- /* 24 hour format */
- s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
- } else {
- /* 12 hour format */
- s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour % 12);
- if (tm->tm_hour >= 12)
- s->cmos_data[RTC_HOURS] |= 0x80;
- }
- s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(s, tm->tm_wday);
- s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(s, tm->tm_mday);
- s->cmos_data[RTC_MONTH] = to_bcd(s, tm->tm_mon + 1);
- s->cmos_data[RTC_YEAR] = to_bcd(s, tm->tm_year % 100);
-}
-
-/* month is between 0 and 11. */
-static int get_days_in_month(int month, int year)
-{
- static const int days_tab[12] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- int d;
- if ((unsigned )month >= 12)
- return 31;
- d = days_tab[month];
- if (month == 1) {
- if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0))
- d++;
- }
- return d;
-}
-
-/* update 'tm' to the next second */
-static void rtc_next_second(struct tm *tm)
-{
- int days_in_month;
-
- tm->tm_sec++;
- if ((unsigned)tm->tm_sec >= 60) {
- tm->tm_sec = 0;
- tm->tm_min++;
- if ((unsigned)tm->tm_min >= 60) {
- tm->tm_min = 0;
- tm->tm_hour++;
- if ((unsigned)tm->tm_hour >= 24) {
- tm->tm_hour = 0;
- /* next day */
- tm->tm_wday++;
- if ((unsigned)tm->tm_wday >= 7)
- tm->tm_wday = 0;
- days_in_month = get_days_in_month(tm->tm_mon,
- tm->tm_year + 1900);
- tm->tm_mday++;
- if (tm->tm_mday < 1) {
- tm->tm_mday = 1;
- } else if (tm->tm_mday > days_in_month) {
- tm->tm_mday = 1;
- tm->tm_mon++;
- if (tm->tm_mon >= 12) {
- tm->tm_mon = 0;
- tm->tm_year++;
- }
- }
- }
- }
- }
-}
-
-
-static void rtc_update_second(void *opaque)
-{
- RTCState *s = opaque;
- int64_t delay;
-
- /* if the oscillator is not in normal operation, we do not update */
- if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
- s->next_second_time += ticks_per_sec;
- qemu_mod_timer(s->second_timer, s->next_second_time);
- } else {
- rtc_next_second(&s->current_tm);
-
- if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
- /* update in progress bit */
- s->cmos_data[RTC_REG_A] |= REG_A_UIP;
- }
- /* should be 244 us = 8 / 32768 seconds, but currently the
- timers do not have the necessary resolution. */
- delay = (ticks_per_sec * 1) / 100;
- if (delay < 1)
- delay = 1;
- qemu_mod_timer(s->second_timer2,
- s->next_second_time + delay);
- }
-}
-
-static void rtc_update_second2(void *opaque)
-{
- RTCState *s = opaque;
-
- if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
- rtc_copy_date(s);
- }
-
- /* check alarm */
- if (s->cmos_data[RTC_REG_B] & REG_B_AIE) {
- if (((s->cmos_data[RTC_SECONDS_ALARM] & 0xc0) == 0xc0 ||
- s->cmos_data[RTC_SECONDS_ALARM] == s->current_tm.tm_sec) &&
- ((s->cmos_data[RTC_MINUTES_ALARM] & 0xc0) == 0xc0 ||
- s->cmos_data[RTC_MINUTES_ALARM] == s->current_tm.tm_mon) &&
- ((s->cmos_data[RTC_HOURS_ALARM] & 0xc0) == 0xc0 ||
- s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
-
- s->cmos_data[RTC_REG_C] |= 0xa0;
- pic_set_irq(s->irq, 1);
- }
- }
-
- /* 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);
- }
-
- /* clear update in progress bit */
- s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
-
- s->next_second_time += ticks_per_sec;
- qemu_mod_timer(s->second_timer, s->next_second_time);
-}
-
-static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
-{
- RTCState *s = opaque;
- int ret;
- if ((addr & 1) == 0) {
- return 0xff;
- } else {
- switch(s->cmos_index) {
- case RTC_SECONDS:
- case RTC_MINUTES:
- case RTC_HOURS:
- case RTC_DAY_OF_WEEK:
- case RTC_DAY_OF_MONTH:
- case RTC_MONTH:
- case RTC_YEAR:
- ret = s->cmos_data[s->cmos_index];
- break;
- case RTC_REG_A:
- ret = s->cmos_data[s->cmos_index];
- break;
- case RTC_REG_C:
- ret = s->cmos_data[s->cmos_index];
- pic_set_irq(s->irq, 0);
- s->cmos_data[RTC_REG_C] = 0x00;
- break;
- default:
- ret = s->cmos_data[s->cmos_index];
- break;
- }
-#ifdef DEBUG_CMOS
- printf("cmos: read index=0x%02x val=0x%02x\n",
- s->cmos_index, ret);
-#endif
- return ret;
- }
-}
-
-void rtc_set_memory(RTCState *s, int addr, int val)
-{
- if (addr >= 0 && addr <= 127)
- s->cmos_data[addr] = val;
-}
-
-void rtc_set_date(RTCState *s, const struct tm *tm)
-{
- s->current_tm = *tm;
- rtc_copy_date(s);
-}
-
-static void rtc_save(QEMUFile *f, void *opaque)
-{
- RTCState *s = opaque;
-
- qemu_put_buffer(f, s->cmos_data, 128);
- qemu_put_8s(f, &s->cmos_index);
-
- qemu_put_be32s(f, &s->current_tm.tm_sec);
- qemu_put_be32s(f, &s->current_tm.tm_min);
- qemu_put_be32s(f, &s->current_tm.tm_hour);
- qemu_put_be32s(f, &s->current_tm.tm_wday);
- qemu_put_be32s(f, &s->current_tm.tm_mday);
- qemu_put_be32s(f, &s->current_tm.tm_mon);
- qemu_put_be32s(f, &s->current_tm.tm_year);
-
- qemu_put_timer(f, s->periodic_timer);
- qemu_put_be64s(f, &s->next_periodic_time);
-
- qemu_put_be64s(f, &s->next_second_time);
- qemu_put_timer(f, s->second_timer);
- qemu_put_timer(f, s->second_timer2);
-}
-
-static int rtc_load(QEMUFile *f, void *opaque, int version_id)
-{
- RTCState *s = opaque;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_buffer(f, s->cmos_data, 128);
- qemu_get_8s(f, &s->cmos_index);
-
- qemu_get_be32s(f, &s->current_tm.tm_sec);
- qemu_get_be32s(f, &s->current_tm.tm_min);
- qemu_get_be32s(f, &s->current_tm.tm_hour);
- qemu_get_be32s(f, &s->current_tm.tm_wday);
- qemu_get_be32s(f, &s->current_tm.tm_mday);
- qemu_get_be32s(f, &s->current_tm.tm_mon);
- qemu_get_be32s(f, &s->current_tm.tm_year);
-
- qemu_get_timer(f, s->periodic_timer);
- qemu_get_be64s(f, &s->next_periodic_time);
-
- qemu_get_be64s(f, &s->next_second_time);
- qemu_get_timer(f, s->second_timer);
- qemu_get_timer(f, s->second_timer2);
- return 0;
-}
-
-RTCState *rtc_init(int base, int irq)
-{
- RTCState *s;
-
- 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->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);
-
- register_ioport_write(base, 2, 1, cmos_ioport_write, s);
- register_ioport_read(base, 2, 1, cmos_ioport_read, s);
-
- register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
- return s;
-}
-
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
deleted file mode 100644
index 22d742a..0000000
--- a/hw/mips_r4k.c
+++ /dev/null
@@ -1,291 +0,0 @@
-#include "vl.h"
-
-#define BIOS_FILENAME "mips_bios.bin"
-//#define BIOS_FILENAME "system.bin"
-#define KERNEL_LOAD_ADDR 0x80010000
-#define INITRD_LOAD_ADDR 0x80800000
-
-#define VIRT_TO_PHYS_ADDEND (-0x80000000LL)
-
-extern FILE *logfile;
-
-static PITState *pit;
-
-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);
- }
-}
-
-void cpu_mips_irqctrl_init (void)
-{
-}
-
-/* XXX: do not use a global */
-uint32_t cpu_mips_get_random (CPUState *env)
-{
- static uint32_t seed = 0;
- uint32_t idx;
- seed = seed * 314159 + 1;
- idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
- return idx;
-}
-
-/* MIPS R4K timer */
-uint32_t cpu_mips_get_count (CPUState *env)
-{
- return env->CP0_Count +
- (uint32_t)muldiv64(qemu_get_clock(vm_clock),
- 100 * 1000 * 1000, ticks_per_sec);
-}
-
-static void cpu_mips_update_count (CPUState *env, uint32_t count,
- uint32_t compare)
-{
- uint64_t now, next;
- uint32_t tmp;
-
- tmp = count;
- if (count == compare)
- tmp++;
- now = qemu_get_clock(vm_clock);
- next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
- if (next == now)
- next++;
-#if 0
- if (logfile) {
- fprintf(logfile, "%s: 0x%08" PRIx64 " %08x %08x => 0x%08" PRIx64 "\n",
- __func__, now, count, compare, next - now);
- }
-#endif
- /* Store new count and compare registers */
- env->CP0_Compare = compare;
- env->CP0_Count =
- count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
- /* Adjust timer */
- qemu_mod_timer(env->timer, next);
-}
-
-void cpu_mips_store_count (CPUState *env, uint32_t value)
-{
- cpu_mips_update_count(env, value, env->CP0_Compare);
-}
-
-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);
-}
-
-static void mips_timer_cb (void *opaque)
-{
- CPUState *env;
-
- env = opaque;
-#if 0
- if (logfile) {
- 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);
-}
-
-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);
-}
-
-
-static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-#if 0
- if (logfile)
- fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
-#endif
- cpu_outb(NULL, addr & 0xffff, value);
-}
-
-static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
-{
- uint32_t ret = cpu_inb(NULL, addr & 0xffff);
-#if 0
- if (logfile)
- fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
-#endif
- return ret;
-}
-
-static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-#if 0
- if (logfile)
- fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
-#endif
-#ifdef TARGET_WORDS_BIGENDIAN
- value = bswap16(value);
-#endif
- cpu_outw(NULL, addr & 0xffff, value);
-}
-
-static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
-{
- uint32_t ret = cpu_inw(NULL, addr & 0xffff);
-#ifdef TARGET_WORDS_BIGENDIAN
- ret = bswap16(ret);
-#endif
-#if 0
- if (logfile)
- fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
-#endif
- return ret;
-}
-
-static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-#if 0
- if (logfile)
- fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
-#endif
-#ifdef TARGET_WORDS_BIGENDIAN
- value = bswap32(value);
-#endif
- cpu_outl(NULL, addr & 0xffff, value);
-}
-
-static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
-{
- uint32_t ret = cpu_inl(NULL, addr & 0xffff);
-
-#ifdef TARGET_WORDS_BIGENDIAN
- ret = bswap32(ret);
-#endif
-#if 0
- if (logfile)
- fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
-#endif
- return ret;
-}
-
-CPUWriteMemoryFunc *io_write[] = {
- &io_writeb,
- &io_writew,
- &io_writel,
-};
-
-CPUReadMemoryFunc *io_read[] = {
- &io_readb,
- &io_readw,
- &io_readl,
-};
-
-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)
-{
- char buf[1024];
- int64_t entry = 0;
- unsigned long bios_offset;
- int io_memory;
- int ret;
- CPUState *env;
- long kernel_size;
-
- env = cpu_init();
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
-
- /* allocate RAM */
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
-
- /* Try to load a BIOS image. If this fails, we continue regardless,
- but initialize the hardware ourselves. When a kernel gets
- preloaded we also initialize the hardware, since the BIOS wasn't
- run. */
- bios_offset = ram_size + vga_ram_size;
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
- ret = load_image(buf, phys_ram_base + bios_offset);
- if (ret == BIOS_SIZE) {
- cpu_register_physical_memory((uint32_t)(0x1fc00000),
- BIOS_SIZE, bios_offset | IO_MEM_ROM);
- } else {
- /* not fatal */
- fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
- buf);
- }
-
- kernel_size = 0;
- if (kernel_filename) {
- kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
- if (kernel_size >= 0)
- env->PC = entry;
- else {
- kernel_size = load_image(kernel_filename,
- phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
- env->PC = KERNEL_LOAD_ADDR;
- }
-
- /* load initrd */
- if (initrd_filename) {
- if (load_image(initrd_filename,
- phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND)
- == (target_ulong) -1) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- initrd_filename);
- exit(1);
- }
- }
-
- /* Store command line. */
- strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
- /* FIXME: little endian support */
- *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
- *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
- }
-
- /* Init internal devices */
- cpu_mips_clock_init(env);
- cpu_mips_irqctrl_init();
-
- /* Register 64 KB of ISA IO space at 0x14000000 */
- io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
- cpu_register_physical_memory(0x14000000, 0x00010000, io_memory);
- isa_mem_base = 0x10000000;
-
- isa_pic = pic_init(pic_irq_request, env);
- pit = pit_init(0x40, 0);
- serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
- vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size,
- vga_ram_size, 0, 0);
-
- 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]);
- } else {
- fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
- exit (1);
- }
- }
-}
-
-QEMUMachine mips_machine = {
- "mips",
- "mips r4k platform",
- mips_r4k_init,
-};
diff --git a/hw/mmc.h b/hw/mmc.h
new file mode 100644
index 0000000..3ae3ea9
--- /dev/null
+++ b/hw/mmc.h
@@ -0,0 +1,214 @@
+/*
+ * Header for MultiMediaCard (MMC)
+ *
+ * Copyright 2002 Hewlett-Packard Company
+ *
+ * Use consistent with the GNU GPL is permitted,
+ * provided that this copyright notice is
+ * preserved in its entirety in all copies and derived works.
+ *
+ * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
+ * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
+ * FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!
+ *
+ * Based strongly on code by:
+ *
+ * Author: Yong-iL Joh <tolkien@mizi.com>
+ * Date : $Date: 2002/06/18 12:37:30 $
+ *
+ * Author: Andrew Christian
+ * 15 May 2002
+ */
+
+#ifndef MMC_MMC_H
+#define MMC_MMC_H
+
+/* Standard MMC commands (4.1) type argument response */
+ /* class 1 */
+#define MMC_GO_IDLE_STATE 0 /* bc */
+#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */
+#define MMC_ALL_SEND_CID 2 /* bcr R2 */
+#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */
+#define MMC_SET_DSR 4 /* bc [31:16] RCA */
+#define MMC_SWITCH 6 /* ac [31:0] See below R1b */
+#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */
+#define MMC_SEND_EXT_CSD 8 /* adtc R1 */
+#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */
+#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */
+#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */
+#define MMC_STOP_TRANSMISSION 12 /* ac R1b */
+#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */
+#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */
+
+ /* class 2 */
+#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */
+#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */
+#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */
+
+ /* class 3 */
+#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */
+
+ /* class 4 */
+#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */
+#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */
+#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */
+#define MMC_PROGRAM_CID 26 /* adtc R1 */
+#define MMC_PROGRAM_CSD 27 /* adtc R1 */
+
+ /* class 6 */
+#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */
+#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */
+#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */
+
+ /* class 5 */
+#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */
+#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */
+#define MMC_ERASE 38 /* ac R1b */
+
+ /* class 9 */
+#define MMC_FAST_IO 39 /* ac <Complex> R4 */
+#define MMC_GO_IRQ_STATE 40 /* bcr R5 */
+
+ /* class 7 */
+#define MMC_LOCK_UNLOCK 42 /* adtc R1b */
+
+ /* class 8 */
+#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */
+#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1 */
+
+/*
+ * MMC_SWITCH argument format:
+ *
+ * [31:26] Always 0
+ * [25:24] Access Mode
+ * [23:16] Location of target Byte in EXT_CSD
+ * [15:08] Value Byte
+ * [07:03] Always 0
+ * [02:00] Command Set
+ */
+
+/*
+ MMC status in R1
+ Type
+ e : error bit
+ s : status bit
+ r : detected and set for the actual command response
+ x : detected and set during command execution. the host must poll
+ the card by sending status command in order to read these bits.
+ Clear condition
+ a : according to the card state
+ b : always related to the previous command. Reception of
+ a valid command will clear it (with a delay of one command)
+ c : clear by read
+ */
+
+#define R1_OUT_OF_RANGE (1 << 31) /* er, c */
+#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */
+#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */
+#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */
+#define R1_ERASE_PARAM (1 << 27) /* ex, c */
+#define R1_WP_VIOLATION (1 << 26) /* erx, c */
+#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */
+#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */
+#define R1_COM_CRC_ERROR (1 << 23) /* er, b */
+#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */
+#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */
+#define R1_CC_ERROR (1 << 20) /* erx, c */
+#define R1_ERROR (1 << 19) /* erx, c */
+#define R1_UNDERRUN (1 << 18) /* ex, c */
+#define R1_OVERRUN (1 << 17) /* ex, c */
+#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */
+#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */
+#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */
+#define R1_ERASE_RESET (1 << 13) /* sr, c */
+#define R1_STATUS(x) (x & 0xFFFFE000)
+#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */
+#define R1_READY_FOR_DATA (1 << 8) /* sx, a */
+#define R1_APP_CMD (1 << 5) /* sr, c */
+
+
+/*
+ * OCR bits are mostly in host.h
+ */
+#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */
+
+/*
+ * Card Command Classes (CCC)
+ */
+#define CCC_BASIC (1<<0) /* (0) Basic protocol functions */
+ /* (CMD0,1,2,3,4,7,9,10,12,13,15) */
+#define CCC_STREAM_READ (1<<1) /* (1) Stream read commands */
+ /* (CMD11) */
+#define CCC_BLOCK_READ (1<<2) /* (2) Block read commands */
+ /* (CMD16,17,18) */
+#define CCC_STREAM_WRITE (1<<3) /* (3) Stream write commands */
+ /* (CMD20) */
+#define CCC_BLOCK_WRITE (1<<4) /* (4) Block write commands */
+ /* (CMD16,24,25,26,27) */
+#define CCC_ERASE (1<<5) /* (5) Ability to erase blocks */
+ /* (CMD32,33,34,35,36,37,38,39) */
+#define CCC_WRITE_PROT (1<<6) /* (6) Able to write protect blocks */
+ /* (CMD28,29,30) */
+#define CCC_LOCK_CARD (1<<7) /* (7) Able to lock down card */
+ /* (CMD16,CMD42) */
+#define CCC_APP_SPEC (1<<8) /* (8) Application specific */
+ /* (CMD55,56,57,ACMD*) */
+#define CCC_IO_MODE (1<<9) /* (9) I/O mode */
+ /* (CMD5,39,40,52,53) */
+#define CCC_SWITCH (1<<10) /* (10) High speed switch */
+ /* (CMD6,34,35,36,37,50) */
+ /* (11) Reserved */
+ /* (CMD?) */
+
+/*
+ * CSD field definitions
+ */
+
+#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */
+#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */
+#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 - 3.2 - 3.31 - 4.0 - 4.1 */
+#define CSD_STRUCT_EXT_CSD 3 /* Version is coded in CSD_STRUCTURE in EXT_CSD */
+
+#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */
+#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */
+#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */
+#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 - 3.2 - 3.31 */
+#define CSD_SPEC_VER_4 4 /* Implements system specification 4.0 - 4.1 */
+
+/*
+ * EXT_CSD fields
+ */
+
+#define EXT_CSD_BUS_WIDTH 183 /* R/W */
+#define EXT_CSD_HS_TIMING 185 /* R/W */
+#define EXT_CSD_CARD_TYPE 196 /* RO */
+#define EXT_CSD_SEC_CNT 212 /* RO, 4 bytes */
+
+/*
+ * EXT_CSD field definitions
+ */
+
+#define EXT_CSD_CMD_SET_NORMAL (1<<0)
+#define EXT_CSD_CMD_SET_SECURE (1<<1)
+#define EXT_CSD_CMD_SET_CPSECURE (1<<2)
+
+#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */
+#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */
+
+#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
+#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
+#define EXT_CSD_BUS_WIDTH_8 2 /* Card is in 8 bit mode */
+
+/*
+ * MMC_SWITCH access modes
+ */
+
+#define MMC_SWITCH_MODE_CMD_SET 0x00 /* Change the command set */
+#define MMC_SWITCH_MODE_SET_BITS 0x01 /* Set bits which are 1 in value */
+#define MMC_SWITCH_MODE_CLEAR_BITS 0x02 /* Clear bits which are 1 in value */
+#define MMC_SWITCH_MODE_WRITE_BYTE 0x03 /* Set target to value */
+
+#endif /* MMC_MMC_PROTOCOL_H */
+
diff --git a/hw/ne2000.c b/hw/ne2000.c
deleted file mode 100644
index e23c6df..0000000
--- a/hw/ne2000.c
+++ /dev/null
@@ -1,816 +0,0 @@
-/*
- * QEMU NE2000 emulation
- *
- * Copyright (c) 2003-2004 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"
-
-/* debug NE2000 card */
-//#define DEBUG_NE2000
-
-#define MAX_ETH_FRAME_SIZE 1514
-
-#define E8390_CMD 0x00 /* The command register (for all pages) */
-/* Page 0 register offsets. */
-#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */
-#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */
-#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */
-#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */
-#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */
-#define EN0_TSR 0x04 /* Transmit status reg RD */
-#define EN0_TPSR 0x04 /* Transmit starting page WR */
-#define EN0_NCR 0x05 /* Number of collision reg RD */
-#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */
-#define EN0_FIFO 0x06 /* FIFO RD */
-#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */
-#define EN0_ISR 0x07 /* Interrupt status reg RD WR */
-#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */
-#define EN0_RSARLO 0x08 /* Remote start address reg 0 */
-#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */
-#define EN0_RSARHI 0x09 /* Remote start address reg 1 */
-#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */
-#define EN0_RTL8029ID0 0x0a /* Realtek ID byte #1 RD */
-#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */
-#define EN0_RTL8029ID1 0x0b /* Realtek ID byte #2 RD */
-#define EN0_RSR 0x0c /* rx status reg RD */
-#define EN0_RXCR 0x0c /* RX configuration reg WR */
-#define EN0_TXCR 0x0d /* TX configuration reg WR */
-#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */
-#define EN0_DCFG 0x0e /* Data configuration reg WR */
-#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */
-#define EN0_IMR 0x0f /* Interrupt mask reg WR */
-#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */
-
-#define EN1_PHYS 0x11
-#define EN1_CURPAG 0x17
-#define EN1_MULT 0x18
-
-#define EN2_STARTPG 0x21 /* Starting page of ring bfr RD */
-#define EN2_STOPPG 0x22 /* Ending page +1 of ring bfr RD */
-
-#define EN3_CONFIG0 0x33
-#define EN3_CONFIG1 0x34
-#define EN3_CONFIG2 0x35
-#define EN3_CONFIG3 0x36
-
-/* Register accessed at EN_CMD, the 8390 base addr. */
-#define E8390_STOP 0x01 /* Stop and reset the chip */
-#define E8390_START 0x02 /* Start the chip, clear reset */
-#define E8390_TRANS 0x04 /* Transmit a frame */
-#define E8390_RREAD 0x08 /* Remote read */
-#define E8390_RWRITE 0x10 /* Remote write */
-#define E8390_NODMA 0x20 /* Remote DMA */
-#define E8390_PAGE0 0x00 /* Select page chip registers */
-#define E8390_PAGE1 0x40 /* using the two high-order bits */
-#define E8390_PAGE2 0x80 /* Page 3 is invalid. */
-
-/* Bits in EN0_ISR - Interrupt status register */
-#define ENISR_RX 0x01 /* Receiver, no error */
-#define ENISR_TX 0x02 /* Transmitter, no error */
-#define ENISR_RX_ERR 0x04 /* Receiver, with error */
-#define ENISR_TX_ERR 0x08 /* Transmitter, with error */
-#define ENISR_OVER 0x10 /* Receiver overwrote the ring */
-#define ENISR_COUNTERS 0x20 /* Counters need emptying */
-#define ENISR_RDC 0x40 /* remote dma complete */
-#define ENISR_RESET 0x80 /* Reset completed */
-#define ENISR_ALL 0x3f /* Interrupts we will enable */
-
-/* Bits in received packet status byte and EN0_RSR*/
-#define ENRSR_RXOK 0x01 /* Received a good packet */
-#define ENRSR_CRC 0x02 /* CRC error */
-#define ENRSR_FAE 0x04 /* frame alignment error */
-#define ENRSR_FO 0x08 /* FIFO overrun */
-#define ENRSR_MPA 0x10 /* missed pkt */
-#define ENRSR_PHY 0x20 /* physical/multicast address */
-#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */
-#define ENRSR_DEF 0x80 /* deferring */
-
-/* Transmitted packet status, EN0_TSR. */
-#define ENTSR_PTX 0x01 /* Packet transmitted without error */
-#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */
-#define ENTSR_COL 0x04 /* The transmit collided at least once. */
-#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */
-#define ENTSR_CRS 0x10 /* The carrier sense was lost. */
-#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */
-#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */
-#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */
-
-#define NE2000_PMEM_SIZE (32*1024)
-#define NE2000_PMEM_START (16*1024)
-#define NE2000_PMEM_END (NE2000_PMEM_SIZE+NE2000_PMEM_START)
-#define NE2000_MEM_SIZE NE2000_PMEM_END
-
-typedef struct NE2000State {
- 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 irq;
- PCIDevice *pci_dev;
- VLANClientState *vc;
- uint8_t macaddr[6];
- uint8_t mem[NE2000_MEM_SIZE];
-} NE2000State;
-
-static void ne2000_reset(NE2000State *s)
-{
- int i;
-
- s->isr = ENISR_RESET;
- memcpy(s->mem, s->macaddr, 6);
- s->mem[14] = 0x57;
- s->mem[15] = 0x57;
-
- /* duplicate prom data */
- for(i = 15;i >= 0; i--) {
- s->mem[2 * i] = s->mem[i];
- s->mem[2 * i + 1] = s->mem[i];
- }
-}
-
-static void ne2000_update_irq(NE2000State *s)
-{
- 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);
-#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));
- }
-}
-
-#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);
-}
-
-static int ne2000_buffer_full(NE2000State *s)
-{
- int avail, index, boundary;
-
- index = s->curpag << 8;
- boundary = s->boundary << 8;
- if (index <= boundary)
- avail = boundary - index;
- else
- avail = (s->stop - s->start) - (index - boundary);
- if (avail < (MAX_ETH_FRAME_SIZE + 4))
- return 1;
- return 0;
-}
-
-static int ne2000_can_receive(void *opaque)
-{
- NE2000State *s = opaque;
-
- if (s->cmd & E8390_STOP)
- return 1;
- return !ne2000_buffer_full(s);
-}
-
-#define MIN_BUF_SIZE 60
-
-static void ne2000_receive(void *opaque, const uint8_t *buf, int size)
-{
- NE2000State *s = opaque;
- uint8_t *p;
- int total_len, next, avail, len, index, mcast_idx;
- uint8_t buf1[60];
- static const uint8_t broadcast_macaddr[6] =
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
-#if defined(DEBUG_NE2000)
- printf("NE2000: received len=%d\n", size);
-#endif
-
- if (s->cmd & E8390_STOP || ne2000_buffer_full(s))
- return;
-
- /* XXX: check this */
- if (s->rxcr & 0x10) {
- /* promiscuous: receive all */
- } else {
- if (!memcmp(buf, broadcast_macaddr, 6)) {
- /* broadcast address */
- if (!(s->rxcr & 0x04))
- return;
- } else if (buf[0] & 0x01) {
- /* multicast */
- if (!(s->rxcr & 0x08))
- return;
- mcast_idx = compute_mcast_idx(buf);
- if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
- return;
- } else if (s->mem[0] == buf[0] &&
- s->mem[2] == buf[1] &&
- s->mem[4] == buf[2] &&
- s->mem[6] == buf[3] &&
- s->mem[8] == buf[4] &&
- s->mem[10] == buf[5]) {
- /* match */
- } else {
- return;
- }
- }
-
-
- /* if too small buffer, then expand it */
- if (size < MIN_BUF_SIZE) {
- memcpy(buf1, buf, size);
- memset(buf1 + size, 0, MIN_BUF_SIZE - size);
- buf = buf1;
- size = MIN_BUF_SIZE;
- }
-
- index = s->curpag << 8;
- /* 4 bytes for header */
- total_len = size + 4;
- /* address for next packet (4 bytes for CRC) */
- next = index + ((total_len + 4 + 255) & ~0xff);
- if (next >= s->stop)
- next -= (s->stop - s->start);
- /* prepare packet header */
- p = s->mem + index;
- s->rsr = ENRSR_RXOK; /* receive status */
- /* XXX: check this */
- if (buf[0] & 0x01)
- s->rsr |= ENRSR_PHY;
- p[0] = s->rsr;
- p[1] = next >> 8;
- p[2] = total_len;
- p[3] = total_len >> 8;
- index += 4;
-
- /* write packet data */
- while (size > 0) {
- avail = s->stop - index;
- len = size;
- if (len > avail)
- len = avail;
- memcpy(s->mem + index, buf, len);
- buf += len;
- index += len;
- if (index == s->stop)
- index = s->start;
- size -= len;
- }
- s->curpag = next >> 8;
-
- /* now we can signal we have receive something */
- s->isr |= ENISR_RX;
- ne2000_update_irq(s);
-}
-
-static void ne2000_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- NE2000State *s = opaque;
- int offset, page, index;
-
- addr &= 0xf;
-#ifdef DEBUG_NE2000
- printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val);
-#endif
- if (addr == E8390_CMD) {
- /* control register */
- s->cmd = val;
- if (!(val & E8390_STOP)) { /* START bit makes no sense on RTL8029... */
- s->isr &= ~ENISR_RESET;
- /* test specific case: zero length transfert */
- if ((val & (E8390_RREAD | E8390_RWRITE)) &&
- s->rcnt == 0) {
- s->isr |= ENISR_RDC;
- ne2000_update_irq(s);
- }
- if (val & E8390_TRANS) {
- index = (s->tpsr << 8);
- /* XXX: next 2 lines are a hack to make netware 3.11 work */
- if (index >= NE2000_PMEM_END)
- index -= NE2000_PMEM_SIZE;
- /* fail safe: check range on the transmitted length */
- if (index + s->tcnt <= NE2000_PMEM_END) {
- qemu_send_packet(s->vc, s->mem + index, s->tcnt);
- }
- /* signal end of transfert */
- s->tsr = ENTSR_PTX;
- s->isr |= ENISR_TX;
- s->cmd &= ~E8390_TRANS;
- ne2000_update_irq(s);
- }
- }
- } else {
- page = s->cmd >> 6;
- offset = addr | (page << 4);
- switch(offset) {
- case EN0_STARTPG:
- s->start = val << 8;
- break;
- case EN0_STOPPG:
- s->stop = val << 8;
- break;
- case EN0_BOUNDARY:
- s->boundary = val;
- break;
- case EN0_IMR:
- s->imr = val;
- ne2000_update_irq(s);
- break;
- case EN0_TPSR:
- s->tpsr = val;
- break;
- case EN0_TCNTLO:
- s->tcnt = (s->tcnt & 0xff00) | val;
- break;
- case EN0_TCNTHI:
- s->tcnt = (s->tcnt & 0x00ff) | (val << 8);
- break;
- case EN0_RSARLO:
- s->rsar = (s->rsar & 0xff00) | val;
- break;
- case EN0_RSARHI:
- s->rsar = (s->rsar & 0x00ff) | (val << 8);
- break;
- case EN0_RCNTLO:
- s->rcnt = (s->rcnt & 0xff00) | val;
- break;
- case EN0_RCNTHI:
- s->rcnt = (s->rcnt & 0x00ff) | (val << 8);
- break;
- case EN0_RXCR:
- s->rxcr = val;
- break;
- case EN0_DCFG:
- s->dcfg = val;
- break;
- case EN0_ISR:
- s->isr &= ~(val & 0x7f);
- ne2000_update_irq(s);
- break;
- case EN1_PHYS ... EN1_PHYS + 5:
- s->phys[offset - EN1_PHYS] = val;
- break;
- case EN1_CURPAG:
- s->curpag = val;
- break;
- case EN1_MULT ... EN1_MULT + 7:
- s->mult[offset - EN1_MULT] = val;
- break;
- }
- }
-}
-
-static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
-{
- NE2000State *s = opaque;
- int offset, page, ret;
-
- addr &= 0xf;
- if (addr == E8390_CMD) {
- ret = s->cmd;
- } else {
- page = s->cmd >> 6;
- offset = addr | (page << 4);
- switch(offset) {
- case EN0_TSR:
- ret = s->tsr;
- break;
- case EN0_BOUNDARY:
- ret = s->boundary;
- break;
- case EN0_ISR:
- ret = s->isr;
- break;
- case EN0_RSARLO:
- ret = s->rsar & 0x00ff;
- break;
- case EN0_RSARHI:
- ret = s->rsar >> 8;
- break;
- case EN1_PHYS ... EN1_PHYS + 5:
- ret = s->phys[offset - EN1_PHYS];
- break;
- case EN1_CURPAG:
- ret = s->curpag;
- break;
- case EN1_MULT ... EN1_MULT + 7:
- ret = s->mult[offset - EN1_MULT];
- break;
- case EN0_RSR:
- ret = s->rsr;
- break;
- case EN2_STARTPG:
- ret = s->start >> 8;
- break;
- case EN2_STOPPG:
- ret = s->stop >> 8;
- break;
- case EN0_RTL8029ID0:
- ret = 0x50;
- break;
- case EN0_RTL8029ID1:
- ret = 0x43;
- break;
- case EN3_CONFIG0:
- ret = 0; /* 10baseT media */
- break;
- case EN3_CONFIG2:
- ret = 0x40; /* 10baseT active */
- break;
- case EN3_CONFIG3:
- ret = 0x40; /* Full duplex */
- break;
- default:
- ret = 0x00;
- break;
- }
- }
-#ifdef DEBUG_NE2000
- printf("NE2000: read addr=0x%x val=%02x\n", addr, ret);
-#endif
- return ret;
-}
-
-static inline void ne2000_mem_writeb(NE2000State *s, uint32_t addr,
- uint32_t val)
-{
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- s->mem[addr] = val;
- }
-}
-
-static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
- uint32_t val)
-{
- addr &= ~1; /* XXX: check exact behaviour if not even */
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- *(uint16_t *)(s->mem + addr) = cpu_to_le16(val);
- }
-}
-
-static inline void ne2000_mem_writel(NE2000State *s, uint32_t addr,
- uint32_t val)
-{
- addr &= ~1; /* XXX: check exact behaviour if not even */
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- cpu_to_le32wu((uint32_t *)(s->mem + addr), val);
- }
-}
-
-static inline uint32_t ne2000_mem_readb(NE2000State *s, uint32_t addr)
-{
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- return s->mem[addr];
- } else {
- return 0xff;
- }
-}
-
-static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
-{
- addr &= ~1; /* XXX: check exact behaviour if not even */
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- return le16_to_cpu(*(uint16_t *)(s->mem + addr));
- } else {
- return 0xffff;
- }
-}
-
-static inline uint32_t ne2000_mem_readl(NE2000State *s, uint32_t addr)
-{
- addr &= ~1; /* XXX: check exact behaviour if not even */
- if (addr < 32 ||
- (addr >= NE2000_PMEM_START && addr < NE2000_MEM_SIZE)) {
- return le32_to_cpupu((uint32_t *)(s->mem + addr));
- } else {
- return 0xffffffff;
- }
-}
-
-static inline void ne2000_dma_update(NE2000State *s, int len)
-{
- s->rsar += len;
- /* wrap */
- /* XXX: check what to do if rsar > stop */
- if (s->rsar == s->stop)
- s->rsar = s->start;
-
- if (s->rcnt <= len) {
- s->rcnt = 0;
- /* signal end of transfert */
- s->isr |= ENISR_RDC;
- ne2000_update_irq(s);
- } else {
- s->rcnt -= len;
- }
-}
-
-static void ne2000_asic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- NE2000State *s = opaque;
-
-#ifdef DEBUG_NE2000
- printf("NE2000: asic write val=0x%04x\n", val);
-#endif
- if (s->rcnt == 0)
- return;
- if (s->dcfg & 0x01) {
- /* 16 bit access */
- ne2000_mem_writew(s, s->rsar, val);
- ne2000_dma_update(s, 2);
- } else {
- /* 8 bit access */
- ne2000_mem_writeb(s, s->rsar, val);
- ne2000_dma_update(s, 1);
- }
-}
-
-static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
-{
- NE2000State *s = opaque;
- int ret;
-
- if (s->dcfg & 0x01) {
- /* 16 bit access */
- ret = ne2000_mem_readw(s, s->rsar);
- ne2000_dma_update(s, 2);
- } else {
- /* 8 bit access */
- ret = ne2000_mem_readb(s, s->rsar);
- ne2000_dma_update(s, 1);
- }
-#ifdef DEBUG_NE2000
- printf("NE2000: asic read val=0x%04x\n", ret);
-#endif
- return ret;
-}
-
-static void ne2000_asic_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- NE2000State *s = opaque;
-
-#ifdef DEBUG_NE2000
- printf("NE2000: asic writel val=0x%04x\n", val);
-#endif
- if (s->rcnt == 0)
- return;
- /* 32 bit access */
- ne2000_mem_writel(s, s->rsar, val);
- ne2000_dma_update(s, 4);
-}
-
-static uint32_t ne2000_asic_ioport_readl(void *opaque, uint32_t addr)
-{
- NE2000State *s = opaque;
- int ret;
-
- /* 32 bit access */
- ret = ne2000_mem_readl(s, s->rsar);
- ne2000_dma_update(s, 4);
-#ifdef DEBUG_NE2000
- printf("NE2000: asic readl val=0x%04x\n", ret);
-#endif
- return ret;
-}
-
-static void ne2000_reset_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- /* nothing to do (end of reset pulse) */
-}
-
-static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
-{
- NE2000State *s = opaque;
- ne2000_reset(s);
- return 0;
-}
-
-static void ne2000_save(QEMUFile* f,void* opaque)
-{
- NE2000State* s=(NE2000State*)opaque;
-
- 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_be32s(f, &s->irq);
- qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE);
-}
-
-static int ne2000_load(QEMUFile* f,void* opaque,int version_id)
-{
- NE2000State* s=(NE2000State*)opaque;
-
- if (version_id == 2) {
- qemu_get_8s(f, &s->rxcr);
- } else if (version_id == 1) {
- s->rxcr = 0x0c;
- } else {
- return -EINVAL;
- }
-
- 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_be32s(f, &s->irq);
- qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE);
-
- return 0;
-}
-
-void isa_ne2000_init(int base, int irq, NICInfo *nd)
-{
- NE2000State *s;
-
- s = qemu_mallocz(sizeof(NE2000State));
- if (!s)
- return;
-
- register_ioport_write(base, 16, 1, ne2000_ioport_write, s);
- register_ioport_read(base, 16, 1, ne2000_ioport_read, s);
-
- register_ioport_write(base + 0x10, 1, 1, ne2000_asic_ioport_write, s);
- register_ioport_read(base + 0x10, 1, 1, ne2000_asic_ioport_read, s);
- register_ioport_write(base + 0x10, 2, 2, ne2000_asic_ioport_write, s);
- register_ioport_read(base + 0x10, 2, 2, ne2000_asic_ioport_read, s);
-
- register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
- register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
- s->irq = irq;
- memcpy(s->macaddr, nd->macaddr, 6);
-
- ne2000_reset(s);
-
- s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive,
- ne2000_can_receive, s);
-
- snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "ne2000 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]);
-
- register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s);
-}
-
-/***********************************************************/
-/* PCI NE2000 definitions */
-
-typedef struct PCINE2000State {
- PCIDevice dev;
- NE2000State ne2000;
-} PCINE2000State;
-
-static void ne2000_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- PCINE2000State *d = (PCINE2000State *)pci_dev;
- NE2000State *s = &d->ne2000;
-
- register_ioport_write(addr, 16, 1, ne2000_ioport_write, s);
- register_ioport_read(addr, 16, 1, ne2000_ioport_read, s);
-
- register_ioport_write(addr + 0x10, 1, 1, ne2000_asic_ioport_write, s);
- register_ioport_read(addr + 0x10, 1, 1, ne2000_asic_ioport_read, s);
- register_ioport_write(addr + 0x10, 2, 2, ne2000_asic_ioport_write, s);
- register_ioport_read(addr + 0x10, 2, 2, ne2000_asic_ioport_read, s);
- register_ioport_write(addr + 0x10, 4, 4, ne2000_asic_ioport_writel, s);
- register_ioport_read(addr + 0x10, 4, 4, ne2000_asic_ioport_readl, s);
-
- register_ioport_write(addr + 0x1f, 1, 1, ne2000_reset_ioport_write, s);
- register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
-}
-
-void pci_ne2000_init(PCIBus *bus, NICInfo *nd)
-{
- PCINE2000State *d;
- NE2000State *s;
- uint8_t *pci_conf;
-
- d = (PCINE2000State *)pci_register_device(bus,
- "NE2000", sizeof(PCINE2000State),
- -1,
- NULL, NULL);
- pci_conf = d->dev.config;
- pci_conf[0x00] = 0xec; // Realtek 8029
- pci_conf[0x01] = 0x10;
- pci_conf[0x02] = 0x29;
- pci_conf[0x03] = 0x80;
- pci_conf[0x0a] = 0x00; // ethernet network controller
- pci_conf[0x0b] = 0x02;
- pci_conf[0x0e] = 0x00; // header_type
- pci_conf[0x3d] = 1; // interrupt pin 0
-
- pci_register_io_region(&d->dev, 0, 0x100,
- PCI_ADDRESS_SPACE_IO, ne2000_map);
- s = &d->ne2000;
- s->irq = 16; // PCI interrupt
- s->pci_dev = (PCIDevice *)d;
- memcpy(s->macaddr, nd->macaddr, 6);
- ne2000_reset(s);
- s->vc = qemu_new_vlan_client(nd->vlan, ne2000_receive,
- ne2000_can_receive, s);
-
- snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "ne2000 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]);
-
- /* XXX: instance number ? */
- register_savevm("ne2000", 0, 2, ne2000_save, ne2000_load, s);
- register_savevm("ne2000_pci", 0, 1, generic_pci_save, generic_pci_load,
- &d->dev);
-}
diff --git a/hw/openpic.c b/hw/openpic.c
deleted file mode 100644
index 3177337..0000000
--- a/hw/openpic.c
+++ /dev/null
@@ -1,1027 +0,0 @@
-/*
- * OpenPIC emulation
- *
- * Copyright (c) 2004 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.
- */
-/*
- *
- * Based on OpenPic implementations:
- * - Intel GW80314 I/O compagnion chip developper's manual
- * - Motorola MPC8245 & MPC8540 user manuals.
- * - Motorola MCP750 (aka Raven) programmer manual.
- * - Motorola Harrier programmer manuel
- *
- * Serial interrupts, as implemented in Raven chipset are not supported yet.
- *
- */
-#include "vl.h"
-
-//#define DEBUG_OPENPIC
-
-#ifdef DEBUG_OPENPIC
-#define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...) do { } while (0)
-#endif
-#define ERROR(fmr, args...) do { printf("ERROR: " fmr , ##args); } while (0)
-
-#define USE_MPCxxx /* Intel model is broken, for now */
-
-#if defined (USE_INTEL_GW80314)
-/* Intel GW80314 I/O Companion chip */
-
-#define MAX_CPU 4
-#define MAX_IRQ 32
-#define MAX_DBL 4
-#define MAX_MBX 4
-#define MAX_TMR 4
-#define VECTOR_BITS 8
-#define MAX_IPI 0
-
-#define VID (0x00000000)
-
-#define OPENPIC_LITTLE_ENDIAN 1
-#define OPENPIC_BIG_ENDIAN 0
-
-#elif defined(USE_MPCxxx)
-
-#define MAX_CPU 2
-#define MAX_IRQ 64
-#define EXT_IRQ 48
-#define MAX_DBL 0
-#define MAX_MBX 0
-#define MAX_TMR 4
-#define VECTOR_BITS 8
-#define MAX_IPI 4
-#define VID 0x03 /* MPIC version ID */
-#define VENI 0x00000000 /* Vendor ID */
-
-enum {
- IRQ_IPVP = 0,
- IRQ_IDE,
-};
-
-#define OPENPIC_LITTLE_ENDIAN 1
-#define OPENPIC_BIG_ENDIAN 0
-
-#else
-#error "Please select which OpenPic implementation is to be emulated"
-#endif
-
-#if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \
- (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN)
-#define OPENPIC_SWAP
-#endif
-
-/* Interrupt definitions */
-#define IRQ_FE (EXT_IRQ) /* Internal functional IRQ */
-#define IRQ_ERR (EXT_IRQ + 1) /* Error IRQ */
-#define IRQ_TIM0 (EXT_IRQ + 2) /* First timer IRQ */
-#if MAX_IPI > 0
-#define IRQ_IPI0 (IRQ_TIM0 + MAX_TMR) /* First IPI IRQ */
-#define IRQ_DBL0 (IRQ_IPI0 + (MAX_CPU * MAX_IPI)) /* First doorbell IRQ */
-#else
-#define IRQ_DBL0 (IRQ_TIM0 + MAX_TMR) /* First doorbell IRQ */
-#define IRQ_MBX0 (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */
-#endif
-
-#define BF_WIDTH(_bits_) \
-(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
-
-static inline void set_bit (uint32_t *field, int bit)
-{
- field[bit >> 5] |= 1 << (bit & 0x1F);
-}
-
-static inline void reset_bit (uint32_t *field, int bit)
-{
- field[bit >> 5] &= ~(1 << (bit & 0x1F));
-}
-
-static inline int test_bit (uint32_t *field, int bit)
-{
- return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
-}
-
-enum {
- IRQ_EXTERNAL = 0x01,
- IRQ_INTERNAL = 0x02,
- IRQ_TIMER = 0x04,
- IRQ_SPECIAL = 0x08,
-} IRQ_src_type;
-
-typedef struct IRQ_queue_t {
- uint32_t queue[BF_WIDTH(MAX_IRQ)];
- int next;
- int priority;
-} IRQ_queue_t;
-
-typedef struct IRQ_src_t {
- uint32_t ipvp; /* IRQ vector/priority register */
- uint32_t ide; /* IRQ destination register */
- int type;
- int last_cpu;
- int pending; /* TRUE if IRQ is pending */
-} IRQ_src_t;
-
-enum IPVP_bits {
- IPVP_MASK = 31,
- IPVP_ACTIVITY = 30,
- IPVP_MODE = 29,
- IPVP_POLARITY = 23,
- IPVP_SENSE = 22,
-};
-#define IPVP_PRIORITY_MASK (0x1F << 16)
-#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
-#define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1)
-#define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK)
-
-typedef struct IRQ_dst_t {
- uint32_t pctp; /* CPU current task priority */
- uint32_t pcsr; /* CPU sensitivity register */
- IRQ_queue_t raised;
- IRQ_queue_t servicing;
- CPUState *env;
-} IRQ_dst_t;
-
-struct openpic_t {
- PCIDevice pci_dev;
- int mem_index;
- /* Global registers */
- uint32_t frep; /* Feature reporting register */
- uint32_t glbc; /* Global configuration register */
- uint32_t micr; /* MPIC interrupt configuration register */
- uint32_t veni; /* Vendor identification register */
- uint32_t spve; /* Spurious vector register */
- uint32_t tifr; /* Timer frequency reporting register */
- /* Source registers */
- IRQ_src_t src[MAX_IRQ];
- /* Local registers per output pin */
- IRQ_dst_t dst[MAX_CPU];
- int nb_cpus;
- /* Timer registers */
- struct {
- uint32_t ticc; /* Global timer current count register */
- uint32_t tibc; /* Global timer base count register */
- } timers[MAX_TMR];
-#if MAX_DBL > 0
- /* Doorbell registers */
- uint32_t dar; /* Doorbell activate register */
- struct {
- uint32_t dmr; /* Doorbell messaging register */
- } doorbells[MAX_DBL];
-#endif
-#if MAX_MBX > 0
- /* Mailbox registers */
- struct {
- uint32_t mbr; /* Mailbox register */
- } mailboxes[MAX_MAILBOXES];
-#endif
-};
-
-static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
-{
- set_bit(q->queue, n_IRQ);
-}
-
-static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
-{
- reset_bit(q->queue, n_IRQ);
-}
-
-static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
-{
- return test_bit(q->queue, n_IRQ);
-}
-
-static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
-{
- int next, i;
- int priority;
-
- next = -1;
- priority = -1;
- for (i = 0; i < MAX_IRQ; i++) {
- if (IRQ_testbit(q, i)) {
- DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
- i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
- if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
- next = i;
- priority = IPVP_PRIORITY(opp->src[i].ipvp);
- }
- }
- }
- q->next = next;
- q->priority = priority;
-}
-
-static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
-{
- if (q->next == -1) {
- /* XXX: optimize */
- IRQ_check(opp, q);
- }
-
- return q->next;
-}
-
-static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
-{
- IRQ_dst_t *dst;
- IRQ_src_t *src;
- int priority;
-
- dst = &opp->dst[n_CPU];
- src = &opp->src[n_IRQ];
- priority = IPVP_PRIORITY(src->ipvp);
- if (priority <= dst->pctp) {
- /* Too low priority */
- return;
- }
- if (IRQ_testbit(&dst->raised, n_IRQ)) {
- /* Interrupt miss */
- 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);
- }
-}
-
-/* update pic state because registers for n_IRQ have changed value */
-static void openpic_update_irq(openpic_t *opp, int n_IRQ)
-{
- IRQ_src_t *src;
- int i;
-
- src = &opp->src[n_IRQ];
-
- if (!src->pending) {
- /* no irq pending */
- return;
- }
- if (test_bit(&src->ipvp, IPVP_MASK)) {
- /* Interrupt source is disabled */
- return;
- }
- if (IPVP_PRIORITY(src->ipvp) == 0) {
- /* Priority set to zero */
- return;
- }
- if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
- /* IRQ already active */
- return;
- }
- if (src->ide == 0x00000000) {
- /* No target */
- return;
- }
-
- if (!test_bit(&src->ipvp, IPVP_MODE) ||
- src->ide == (1 << src->last_cpu)) {
- /* Directed delivery mode */
- for (i = 0; i < opp->nb_cpus; i++) {
- if (test_bit(&src->ide, i))
- IRQ_local_pipe(opp, i, n_IRQ);
- }
- } else {
- /* Distributed delivery mode */
- /* XXX: incorrect code */
- for (i = src->last_cpu; i < src->last_cpu; i++) {
- if (i == MAX_IRQ)
- i = 0;
- if (test_bit(&src->ide, i)) {
- IRQ_local_pipe(opp, i, n_IRQ);
- src->last_cpu = i;
- break;
- }
- }
- }
-}
-
-void openpic_set_irq(void *opaque, int n_IRQ, int level)
-{
- openpic_t *opp = opaque;
- IRQ_src_t *src;
-
- src = &opp->src[n_IRQ];
- DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
- n_IRQ, level, src->ipvp);
- if (test_bit(&src->ipvp, IPVP_SENSE)) {
- /* level-sensitive irq */
- src->pending = level;
- if (!level)
- reset_bit(&src->ipvp, IPVP_ACTIVITY);
- } else {
- /* edge-sensitive irq */
- if (level)
- src->pending = 1;
- }
- openpic_update_irq(opp, n_IRQ);
-}
-
-static void openpic_reset (openpic_t *opp)
-{
- int i;
-
- opp->glbc = 0x80000000;
- /* Initialise controller registers */
- opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
- opp->veni = VENI;
- opp->spve = 0x000000FF;
- opp->tifr = 0x003F7A00;
- /* ? */
- opp->micr = 0x00000000;
- /* Initialise IRQ sources */
- for (i = 0; i < MAX_IRQ; i++) {
- opp->src[i].ipvp = 0xA0000000;
- opp->src[i].ide = 0x00000000;
- }
- /* Initialise IRQ destinations */
- for (i = 0; i < opp->nb_cpus; i++) {
- opp->dst[i].pctp = 0x0000000F;
- opp->dst[i].pcsr = 0x00000000;
- memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
- memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
- }
- /* Initialise timers */
- for (i = 0; i < MAX_TMR; i++) {
- opp->timers[i].ticc = 0x00000000;
- opp->timers[i].tibc = 0x80000000;
- }
- /* Initialise doorbells */
-#if MAX_DBL > 0
- opp->dar = 0x00000000;
- for (i = 0; i < MAX_DBL; i++) {
- opp->doorbells[i].dmr = 0x00000000;
- }
-#endif
- /* Initialise mailboxes */
-#if MAX_MBX > 0
- for (i = 0; i < MAX_MBX; i++) { /* ? */
- opp->mailboxes[i].mbr = 0x00000000;
- }
-#endif
- /* Go out of RESET state */
- opp->glbc = 0x00000000;
-}
-
-static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
-{
- uint32_t retval;
-
- switch (reg) {
- case IRQ_IPVP:
- retval = opp->src[n_IRQ].ipvp;
- break;
- case IRQ_IDE:
- retval = opp->src[n_IRQ].ide;
- break;
- }
-
- return retval;
-}
-
-static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
- uint32_t reg, uint32_t val)
-{
- uint32_t tmp;
-
- switch (reg) {
- case IRQ_IPVP:
- /* NOTE: not fully accurate for special IRQs, but simple and
- sufficient */
- /* ACTIVITY bit is read-only */
- opp->src[n_IRQ].ipvp =
- (opp->src[n_IRQ].ipvp & 0x40000000) |
- (val & 0x800F00FF);
- openpic_update_irq(opp, n_IRQ);
- DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
- n_IRQ, val, opp->src[n_IRQ].ipvp);
- break;
- case IRQ_IDE:
- tmp = val & 0xC0000000;
- tmp |= val & ((1 << MAX_CPU) - 1);
- opp->src[n_IRQ].ide = tmp;
- DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
- break;
- }
-}
-
-#if 0 // Code provision for Intel model
-#if MAX_DBL > 0
-static uint32_t read_doorbell_register (openpic_t *opp,
- int n_dbl, uint32_t offset)
-{
- uint32_t retval;
-
- switch (offset) {
- case DBL_IPVP_OFFSET:
- retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
- break;
- case DBL_IDE_OFFSET:
- retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
- break;
- case DBL_DMR_OFFSET:
- retval = opp->doorbells[n_dbl].dmr;
- break;
- }
-
- return retval;
-}
-
-static void write_doorbell_register (penpic_t *opp, int n_dbl,
- uint32_t offset, uint32_t value)
-{
- switch (offset) {
- case DBL_IVPR_OFFSET:
- write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
- break;
- case DBL_IDE_OFFSET:
- write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
- break;
- case DBL_DMR_OFFSET:
- opp->doorbells[n_dbl].dmr = value;
- break;
- }
-}
-#endif
-
-#if MAX_MBX > 0
-static uint32_t read_mailbox_register (openpic_t *opp,
- int n_mbx, uint32_t offset)
-{
- uint32_t retval;
-
- switch (offset) {
- case MBX_MBR_OFFSET:
- retval = opp->mailboxes[n_mbx].mbr;
- break;
- case MBX_IVPR_OFFSET:
- retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
- break;
- case MBX_DMR_OFFSET:
- retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
- break;
- }
-
- return retval;
-}
-
-static void write_mailbox_register (openpic_t *opp, int n_mbx,
- uint32_t address, uint32_t value)
-{
- switch (offset) {
- case MBX_MBR_OFFSET:
- opp->mailboxes[n_mbx].mbr = value;
- break;
- case MBX_IVPR_OFFSET:
- write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
- break;
- case MBX_DMR_OFFSET:
- write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
- break;
- }
-}
-#endif
-#endif /* 0 : Code provision for Intel model */
-
-static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
-{
- openpic_t *opp = opaque;
-
- DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
- if (addr & 0xF)
- return;
-#if defined OPENPIC_SWAP
- val = bswap32(val);
-#endif
- addr &= 0xFF;
- switch (addr) {
- case 0x00: /* FREP */
- break;
- case 0x20: /* GLBC */
- if (val & 0x80000000)
- openpic_reset(opp);
- opp->glbc = val & ~0x80000000;
- break;
- 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);
- }
- break;
-#if MAX_IPI > 0
- case 0xA0: /* IPI_IPVP */
- case 0xB0:
- case 0xC0:
- case 0xD0:
- {
- int idx;
- idx = (addr - 0xA0) >> 4;
- write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val);
- }
- break;
-#endif
- case 0xE0: /* SPVE */
- opp->spve = val & 0x000000FF;
- break;
- case 0xF0: /* TIFR */
- opp->tifr = val;
- break;
- default:
- break;
- }
-}
-
-static uint32_t openpic_gbl_read (void *opaque, uint32_t addr)
-{
- openpic_t *opp = opaque;
- uint32_t retval;
-
- DPRINTF("%s: addr %08x\n", __func__, addr);
- retval = 0xFFFFFFFF;
- if (addr & 0xF)
- return retval;
- addr &= 0xFF;
- switch (addr) {
- case 0x00: /* FREP */
- retval = opp->frep;
- break;
- case 0x20: /* GLBC */
- retval = opp->glbc;
- break;
- case 0x80: /* VENI */
- retval = opp->veni;
- break;
- case 0x90: /* PINT */
- retval = 0x00000000;
- break;
-#if MAX_IPI > 0
- case 0xA0: /* IPI_IPVP */
- case 0xB0:
- case 0xC0:
- case 0xD0:
- {
- int idx;
- idx = (addr - 0xA0) >> 4;
- retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP);
- }
- break;
-#endif
- case 0xE0: /* SPVE */
- retval = opp->spve;
- break;
- case 0xF0: /* TIFR */
- retval = opp->tifr;
- break;
- default:
- break;
- }
- DPRINTF("%s: => %08x\n", __func__, retval);
-#if defined OPENPIC_SWAP
- retval = bswap32(retval);
-#endif
-
- return retval;
-}
-
-static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
-{
- openpic_t *opp = opaque;
- int idx;
-
- DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
- if (addr & 0xF)
- return;
-#if defined OPENPIC_SWAP
- val = bswap32(val);
-#endif
- addr -= 0x1100;
- addr &= 0xFFFF;
- idx = (addr & 0xFFF0) >> 6;
- addr = addr & 0x30;
- switch (addr) {
- case 0x00: /* TICC */
- break;
- case 0x10: /* TIBC */
- if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
- (val & 0x80000000) == 0 &&
- (opp->timers[idx].tibc & 0x80000000) != 0)
- opp->timers[idx].ticc &= ~0x80000000;
- opp->timers[idx].tibc = val;
- break;
- case 0x20: /* TIVP */
- write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val);
- break;
- case 0x30: /* TIDE */
- write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val);
- break;
- }
-}
-
-static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
-{
- openpic_t *opp = opaque;
- uint32_t retval;
- int idx;
-
- DPRINTF("%s: addr %08x\n", __func__, addr);
- retval = 0xFFFFFFFF;
- if (addr & 0xF)
- return retval;
- addr -= 0x1100;
- addr &= 0xFFFF;
- idx = (addr & 0xFFF0) >> 6;
- addr = addr & 0x30;
- switch (addr) {
- case 0x00: /* TICC */
- retval = opp->timers[idx].ticc;
- break;
- case 0x10: /* TIBC */
- retval = opp->timers[idx].tibc;
- break;
- case 0x20: /* TIPV */
- retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP);
- break;
- case 0x30: /* TIDE */
- retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE);
- break;
- }
- DPRINTF("%s: => %08x\n", __func__, retval);
-#if defined OPENPIC_SWAP
- retval = bswap32(retval);
-#endif
-
- return retval;
-}
-
-static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
-{
- openpic_t *opp = opaque;
- int idx;
-
- DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
- if (addr & 0xF)
- return;
-#if defined OPENPIC_SWAP
- val = tswap32(val);
-#endif
- addr = addr & 0xFFF0;
- idx = addr >> 5;
- if (addr & 0x10) {
- /* EXDE / IFEDE / IEEDE */
- write_IRQreg(opp, idx, IRQ_IDE, val);
- } else {
- /* EXVP / IFEVP / IEEVP */
- write_IRQreg(opp, idx, IRQ_IPVP, val);
- }
-}
-
-static uint32_t openpic_src_read (void *opaque, uint32_t addr)
-{
- openpic_t *opp = opaque;
- uint32_t retval;
- int idx;
-
- DPRINTF("%s: addr %08x\n", __func__, addr);
- retval = 0xFFFFFFFF;
- if (addr & 0xF)
- return retval;
- addr = addr & 0xFFF0;
- idx = addr >> 5;
- if (addr & 0x10) {
- /* EXDE / IFEDE / IEEDE */
- retval = read_IRQreg(opp, idx, IRQ_IDE);
- } else {
- /* EXVP / IFEVP / IEEVP */
- retval = read_IRQreg(opp, idx, IRQ_IPVP);
- }
- DPRINTF("%s: => %08x\n", __func__, retval);
-#if defined OPENPIC_SWAP
- retval = tswap32(retval);
-#endif
-
- return retval;
-}
-
-static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val)
-{
- openpic_t *opp = opaque;
- IRQ_src_t *src;
- IRQ_dst_t *dst;
- int idx, n_IRQ;
-
- DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
- if (addr & 0xF)
- return;
-#if defined OPENPIC_SWAP
- val = bswap32(val);
-#endif
- addr &= 0x1FFF0;
- idx = addr / 0x1000;
- dst = &opp->dst[idx];
- addr &= 0xFF0;
- switch (addr) {
-#if MAX_IPI > 0
- case 0x40: /* PIPD */
- case 0x50:
- case 0x60:
- case 0x70:
- idx = (addr - 0x40) >> 4;
- write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val);
- openpic_set_irq(opp, IRQ_IPI0 + idx, 1);
- openpic_set_irq(opp, IRQ_IPI0 + idx, 0);
- break;
-#endif
- case 0x80: /* PCTP */
- dst->pctp = val & 0x0000000F;
- break;
- case 0x90: /* WHOAMI */
- /* Read-only register */
- break;
- case 0xA0: /* PIAC */
- /* Read-only register */
- break;
- case 0xB0: /* PEOI */
- DPRINTF("PEOI\n");
- n_IRQ = IRQ_get_next(opp, &dst->servicing);
- IRQ_resetbit(&dst->servicing, n_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);
- }
- }
- break;
- default:
- break;
- }
-}
-
-static uint32_t openpic_cpu_read (void *opaque, uint32_t addr)
-{
- openpic_t *opp = opaque;
- IRQ_src_t *src;
- IRQ_dst_t *dst;
- uint32_t retval;
- int idx, n_IRQ;
-
- DPRINTF("%s: addr %08x\n", __func__, addr);
- retval = 0xFFFFFFFF;
- if (addr & 0xF)
- return retval;
- addr &= 0x1FFF0;
- idx = addr / 0x1000;
- dst = &opp->dst[idx];
- addr &= 0xFF0;
- switch (addr) {
- case 0x80: /* PCTP */
- retval = dst->pctp;
- break;
- case 0x90: /* WHOAMI */
- retval = idx;
- break;
- case 0xA0: /* PIAC */
- 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;
- } else {
- src = &opp->src[n_IRQ];
- if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
- !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
- /* - Spurious level-sensitive IRQ
- * - Priorities has been changed
- * and the pending IRQ isn't allowed anymore
- */
- reset_bit(&src->ipvp, IPVP_ACTIVITY);
- retval = IPVP_VECTOR(opp->spve);
- } else {
- /* IRQ enter servicing state */
- IRQ_setbit(&dst->servicing, n_IRQ);
- retval = IPVP_VECTOR(src->ipvp);
- }
- IRQ_resetbit(&dst->raised, n_IRQ);
- dst->raised.next = -1;
- if (!test_bit(&src->ipvp, IPVP_SENSE)) {
- /* edge-sensitive IRQ */
- reset_bit(&src->ipvp, IPVP_ACTIVITY);
- src->pending = 0;
- }
- }
- break;
- case 0xB0: /* PEOI */
- retval = 0;
- break;
-#if MAX_IPI > 0
- case 0x40: /* IDE */
- case 0x50:
- idx = (addr - 0x40) >> 4;
- retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE);
- break;
-#endif
- default:
- break;
- }
- DPRINTF("%s: => %08x\n", __func__, retval);
-#if defined OPENPIC_SWAP
- retval= bswap32(retval);
-#endif
-
- return retval;
-}
-
-static void openpic_buggy_write (void *opaque,
- target_phys_addr_t addr, uint32_t val)
-{
- printf("Invalid OPENPIC write access !\n");
-}
-
-static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
-{
- printf("Invalid OPENPIC read access !\n");
-
- return -1;
-}
-
-static void openpic_writel (void *opaque,
- target_phys_addr_t addr, uint32_t val)
-{
- openpic_t *opp = opaque;
-
- addr &= 0x3FFFF;
- DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
- if (addr < 0x1100) {
- /* Global registers */
- openpic_gbl_write(opp, addr, val);
- } else if (addr < 0x10000) {
- /* Timers registers */
- openpic_timer_write(opp, addr, val);
- } else if (addr < 0x20000) {
- /* Source registers */
- openpic_src_write(opp, addr, val);
- } else {
- /* CPU registers */
- openpic_cpu_write(opp, addr, val);
- }
-}
-
-static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
-{
- openpic_t *opp = opaque;
- uint32_t retval;
-
- addr &= 0x3FFFF;
- DPRINTF("%s: offset %08x\n", __func__, (int)addr);
- if (addr < 0x1100) {
- /* Global registers */
- retval = openpic_gbl_read(opp, addr);
- } else if (addr < 0x10000) {
- /* Timers registers */
- retval = openpic_timer_read(opp, addr);
- } else if (addr < 0x20000) {
- /* Source registers */
- retval = openpic_src_read(opp, addr);
- } else {
- /* CPU registers */
- retval = openpic_cpu_read(opp, addr);
- }
-
- return retval;
-}
-
-static CPUWriteMemoryFunc *openpic_write[] = {
- &openpic_buggy_write,
- &openpic_buggy_write,
- &openpic_writel,
-};
-
-static CPUReadMemoryFunc *openpic_read[] = {
- &openpic_buggy_read,
- &openpic_buggy_read,
- &openpic_readl,
-};
-
-static void openpic_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- openpic_t *opp;
-
- DPRINTF("Map OpenPIC\n");
- opp = (openpic_t *)pci_dev;
- /* Global registers */
- DPRINTF("Register OPENPIC gbl %08x => %08x\n",
- addr + 0x1000, addr + 0x1000 + 0x100);
- /* Timer registers */
- DPRINTF("Register OPENPIC timer %08x => %08x\n",
- addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
- /* Interrupt source registers */
- DPRINTF("Register OPENPIC src %08x => %08x\n",
- addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2));
- /* Per CPU registers */
- DPRINTF("Register OPENPIC dst %08x => %08x\n",
- addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
- cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
-#if 0 // Don't implement ISU for now
- opp_io_memory = cpu_register_io_memory(0, openpic_src_read,
- openpic_src_write);
- cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
- opp_io_memory);
-#endif
-}
-
-openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
- CPUPPCState **envp)
-{
- openpic_t *opp;
- uint8_t *pci_conf;
- int i, m;
-
- /* XXX: for now, only one CPU is supported */
- if (nb_cpus != 1)
- return NULL;
- if (bus) {
- opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
- -1, NULL, NULL);
- if (opp == NULL)
- return NULL;
- pci_conf = opp->pci_dev.config;
- pci_conf[0x00] = 0x14; // IBM MPIC2
- pci_conf[0x01] = 0x10;
- pci_conf[0x02] = 0xFF;
- pci_conf[0x03] = 0xFF;
- pci_conf[0x0a] = 0x80; // PIC
- pci_conf[0x0b] = 0x08;
- pci_conf[0x0e] = 0x00; // header_type
- pci_conf[0x3d] = 0x00; // no interrupt pin
-
- /* Register I/O spaces */
- pci_register_io_region((PCIDevice *)opp, 0, 0x40000,
- PCI_ADDRESS_SPACE_MEM, &openpic_map);
- } else {
- opp = qemu_mallocz(sizeof(openpic_t));
- }
-
- opp->mem_index = cpu_register_io_memory(0, openpic_read,
- openpic_write, opp);
-
- // isu_base &= 0xFFFC0000;
- opp->nb_cpus = nb_cpus;
- /* Set IRQ types */
- for (i = 0; i < EXT_IRQ; i++) {
- opp->src[i].type = IRQ_EXTERNAL;
- }
- for (; i < IRQ_TIM0; i++) {
- opp->src[i].type = IRQ_SPECIAL;
- }
-#if MAX_IPI > 0
- m = IRQ_IPI0;
-#else
- m = IRQ_DBL0;
-#endif
- for (; i < m; i++) {
- opp->src[i].type = IRQ_TIMER;
- }
- for (; i < MAX_IRQ; i++) {
- opp->src[i].type = IRQ_INTERNAL;
- }
- for (i = 0; i < nb_cpus; i++)
- opp->dst[i].env = envp[i];
- openpic_reset(opp);
- if (pmem_index)
- *pmem_index = opp->mem_index;
- return opp;
-}
diff --git a/hw/parallel.c b/hw/parallel.c
deleted file mode 100644
index cba9561..0000000
--- a/hw/parallel.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * QEMU Parallel PORT emulation
- *
- * Copyright (c) 2003-2005 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"
-
-//#define DEBUG_PARALLEL
-
-/*
- * These are the definitions for the Printer Status Register
- */
-#define PARA_STS_BUSY 0x80 /* Busy complement */
-#define PARA_STS_ACK 0x40 /* Acknowledge */
-#define PARA_STS_PAPER 0x20 /* Out of paper */
-#define PARA_STS_ONLINE 0x10 /* Online */
-#define PARA_STS_ERROR 0x08 /* Error complement */
-
-/*
- * These are the definitions for the Printer Control Register
- */
-#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 */
-
-struct ParallelState {
- uint8_t data;
- uint8_t status; /* read only register */
- uint8_t control;
- int irq;
- int irq_pending;
- CharDriverState *chr;
- int hw_driver;
-};
-
-static void parallel_update_irq(ParallelState *s)
-{
- if (s->irq_pending)
- pic_set_irq(s->irq, 1);
- else
- pic_set_irq(s->irq, 0);
-}
-
-static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- ParallelState *s = opaque;
-
- 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);
- }
- 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;
- }
- break;
- }
-}
-
-static uint32_t parallel_ioport_read(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;
- 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);
- }
- break;
- case 2:
- if (s->hw_driver) {
- qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &s->control);
- }
- ret = s->control;
- break;
- }
-#ifdef DEBUG_PARALLEL
- printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret);
-#endif
- 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 *s;
- uint8_t dummy;
-
- 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->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;
-
- register_ioport_write(base, 8, 1, parallel_ioport_write, s);
- register_ioport_read(base, 8, 1, parallel_ioport_read, s);
- return s;
-}
diff --git a/hw/pc.c b/hw/pc.c
deleted file mode 100644
index 898d068..0000000
--- a/hw/pc.c
+++ /dev/null
@@ -1,911 +0,0 @@
-/*
- * QEMU PC System Emulator
- *
- * Copyright (c) 2003-2004 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"
-
-/* output Bochs bios info messages */
-//#define DEBUG_BIOS
-
-#define BIOS_FILENAME "bios.bin"
-#define VGABIOS_FILENAME "vgabios.bin"
-#define VGABIOS_CIRRUS_FILENAME "vgabios-cirrus.bin"
-#define LINUX_BOOT_FILENAME "linux_boot.bin"
-
-#define KERNEL_LOAD_ADDR 0x00100000
-#define INITRD_LOAD_ADDR 0x00600000
-#define KERNEL_PARAMS_ADDR 0x00090000
-#define KERNEL_CMDLINE_ADDR 0x00099000
-
-static fdctrl_t *floppy_controller;
-static RTCState *rtc_state;
-static PITState *pit;
-static IOAPICState *ioapic;
-
-static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
-{
-}
-
-/* MSDOS compatibility mode FPU exception support */
-/* XXX: add IGNNE support */
-void cpu_set_ferr(CPUX86State *s)
-{
- pic_set_irq(13, 1);
-}
-
-static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
-{
- pic_set_irq(13, 0);
-}
-
-/* TSC handling */
-uint64_t cpu_get_tsc(CPUX86State *env)
-{
- /* Note: when using kqemu, it is more logical to return the host TSC
- because kqemu does not trap the RDTSC instruction for
- performance reasons */
-#if USE_KQEMU
- if (env->kqemu_enabled) {
- return cpu_get_real_ticks();
- } else
-#endif
- {
- return cpu_get_ticks();
- }
-}
-
-/* IRQ handling */
-int cpu_get_pic_interrupt(CPUState *env)
-{
- int intno;
-
- intno = apic_get_interrupt(env);
- if (intno >= 0) {
- /* set irq request if a PIC irq is still pending */
- /* XXX: improve that */
- pic_update_irq(isa_pic);
- return intno;
- }
- /* read the irq from the PIC */
- intno = pic_read_irq(isa_pic);
- return intno;
-}
-
-static void pic_irq_request(void *opaque, int level)
-{
- CPUState *env = opaque;
- if (level)
- cpu_interrupt(env, CPU_INTERRUPT_HARD);
- else
- cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
-}
-
-/* PC cmos mappings */
-
-#define REG_EQUIPMENT_BYTE 0x14
-#define REG_IBM_CENTURY_BYTE 0x32
-#define REG_IBM_PS2_CENTURY_BYTE 0x37
-
-
-static inline int to_bcd(RTCState *s, int a)
-{
- return ((a / 10) << 4) | (a % 10);
-}
-
-static int cmos_get_fd_drive_type(int fd0)
-{
- int val;
-
- switch (fd0) {
- case 0:
- /* 1.44 Mb 3"5 drive */
- val = 4;
- break;
- case 1:
- /* 2.88 Mb 3"5 drive */
- val = 5;
- break;
- case 2:
- /* 1.2 Mb 5"5 drive */
- val = 2;
- break;
- default:
- val = 0;
- break;
- }
- return val;
-}
-
-static void cmos_init_hd(int type_ofs, int info_ofs, BlockDriverState *hd)
-{
- RTCState *s = rtc_state;
- int cylinders, heads, sectors;
- bdrv_get_geometry_hint(hd, &cylinders, &heads, &sectors);
- rtc_set_memory(s, type_ofs, 47);
- rtc_set_memory(s, info_ofs, cylinders);
- rtc_set_memory(s, info_ofs + 1, cylinders >> 8);
- rtc_set_memory(s, info_ofs + 2, heads);
- rtc_set_memory(s, info_ofs + 3, 0xff);
- rtc_set_memory(s, info_ofs + 4, 0xff);
- rtc_set_memory(s, info_ofs + 5, 0xc0 | ((heads > 8) << 3));
- rtc_set_memory(s, info_ofs + 6, cylinders);
- rtc_set_memory(s, info_ofs + 7, cylinders >> 8);
- rtc_set_memory(s, info_ofs + 8, sectors);
-}
-
-/* hd_table must contain 4 block drivers */
-static void cmos_init(int ram_size, int boot_device, BlockDriverState **hd_table)
-{
- RTCState *s = rtc_state;
- int val;
- int fd0, fd1, nb;
- time_t ti;
- struct tm *tm;
- int i;
-
- /* set the CMOS date */
- time(&ti);
- if (rtc_utc)
- tm = gmtime(&ti);
- else
- tm = localtime(&ti);
- rtc_set_date(s, tm);
-
- val = to_bcd(s, (tm->tm_year / 100) + 19);
- rtc_set_memory(s, REG_IBM_CENTURY_BYTE, val);
- rtc_set_memory(s, REG_IBM_PS2_CENTURY_BYTE, val);
-
- /* various important CMOS locations needed by PC/Bochs bios */
-
- /* memory size */
- val = 640; /* base memory in K */
- rtc_set_memory(s, 0x15, val);
- rtc_set_memory(s, 0x16, val >> 8);
-
- val = (ram_size / 1024) - 1024;
- if (val > 65535)
- val = 65535;
- rtc_set_memory(s, 0x17, val);
- rtc_set_memory(s, 0x18, val >> 8);
- rtc_set_memory(s, 0x30, val);
- rtc_set_memory(s, 0x31, val >> 8);
-
- if (ram_size > (16 * 1024 * 1024))
- val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536);
- else
- val = 0;
- if (val > 65535)
- val = 65535;
- rtc_set_memory(s, 0x34, val);
- rtc_set_memory(s, 0x35, val >> 8);
-
- switch(boot_device) {
- case 'a':
- case 'b':
- rtc_set_memory(s, 0x3d, 0x01); /* floppy boot */
- if (!fd_bootchk)
- rtc_set_memory(s, 0x38, 0x01); /* disable signature check */
- break;
- default:
- case 'c':
- rtc_set_memory(s, 0x3d, 0x02); /* hard drive boot */
- break;
- case 'd':
- rtc_set_memory(s, 0x3d, 0x03); /* CD-ROM boot */
- break;
- }
-
- /* floppy type */
-
- fd0 = fdctrl_get_drive_type(floppy_controller, 0);
- fd1 = fdctrl_get_drive_type(floppy_controller, 1);
-
- val = (cmos_get_fd_drive_type(fd0) << 4) | cmos_get_fd_drive_type(fd1);
- rtc_set_memory(s, 0x10, val);
-
- val = 0;
- nb = 0;
- if (fd0 < 3)
- nb++;
- if (fd1 < 3)
- nb++;
- switch (nb) {
- case 0:
- break;
- case 1:
- val |= 0x01; /* 1 drive, ready for boot */
- break;
- case 2:
- val |= 0x41; /* 2 drives, ready for boot */
- break;
- }
- val |= 0x02; /* FPU is there */
- val |= 0x04; /* PS/2 mouse installed */
- rtc_set_memory(s, REG_EQUIPMENT_BYTE, val);
-
- /* hard drives */
-
- rtc_set_memory(s, 0x12, (hd_table[0] ? 0xf0 : 0) | (hd_table[1] ? 0x0f : 0));
- if (hd_table[0])
- cmos_init_hd(0x19, 0x1b, hd_table[0]);
- if (hd_table[1])
- cmos_init_hd(0x1a, 0x24, hd_table[1]);
-
- val = 0;
- for (i = 0; i < 4; i++) {
- if (hd_table[i]) {
- int cylinders, heads, sectors, translation;
- /* NOTE: bdrv_get_geometry_hint() returns the physical
- geometry. It is always such that: 1 <= sects <= 63, 1
- <= heads <= 16, 1 <= cylinders <= 16383. The BIOS
- geometry can be different if a translation is done. */
- translation = bdrv_get_translation_hint(hd_table[i]);
- if (translation == BIOS_ATA_TRANSLATION_AUTO) {
- bdrv_get_geometry_hint(hd_table[i], &cylinders, &heads, &sectors);
- if (cylinders <= 1024 && heads <= 16 && sectors <= 63) {
- /* No translation. */
- translation = 0;
- } else {
- /* LBA translation. */
- translation = 1;
- }
- } else {
- translation--;
- }
- val |= translation << (i * 2);
- }
- }
- rtc_set_memory(s, 0x39, val);
-}
-
-void ioport_set_a20(int enable)
-{
- /* XXX: send to all CPUs ? */
- cpu_x86_set_a20(first_cpu, enable);
-}
-
-int ioport_get_a20(void)
-{
- return ((first_cpu->a20_mask >> 20) & 1);
-}
-
-static void ioport92_write(void *opaque, uint32_t addr, uint32_t val)
-{
- ioport_set_a20((val >> 1) & 1);
- /* XXX: bit 0 is fast reset */
-}
-
-static uint32_t ioport92_read(void *opaque, uint32_t addr)
-{
- return ioport_get_a20() << 1;
-}
-
-/***********************************************************/
-/* Bochs BIOS debug ports */
-
-void bochs_bios_write(void *opaque, uint32_t addr, uint32_t val)
-{
- static const char shutdown_str[8] = "Shutdown";
- static int shutdown_index = 0;
-
- switch(addr) {
- /* Bochs BIOS messages */
- case 0x400:
- case 0x401:
- fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val);
- exit(1);
- case 0x402:
- case 0x403:
-#ifdef DEBUG_BIOS
- fprintf(stderr, "%c", val);
-#endif
- break;
- case 0x8900:
- /* same as Bochs power off */
- if (val == shutdown_str[shutdown_index]) {
- shutdown_index++;
- if (shutdown_index == 8) {
- shutdown_index = 0;
- qemu_system_shutdown_request();
- }
- } else {
- shutdown_index = 0;
- }
- break;
-
- /* LGPL'ed VGA BIOS messages */
- case 0x501:
- case 0x502:
- fprintf(stderr, "VGA BIOS panic, line %d\n", val);
- exit(1);
- case 0x500:
- case 0x503:
-#ifdef DEBUG_BIOS
- fprintf(stderr, "%c", val);
-#endif
- break;
- }
-}
-
-void bochs_bios_init(void)
-{
- register_ioport_write(0x400, 1, 2, bochs_bios_write, NULL);
- register_ioport_write(0x401, 1, 2, bochs_bios_write, NULL);
- register_ioport_write(0x402, 1, 1, bochs_bios_write, NULL);
- register_ioport_write(0x403, 1, 1, bochs_bios_write, NULL);
- register_ioport_write(0x8900, 1, 1, bochs_bios_write, NULL);
-
- register_ioport_write(0x501, 1, 2, bochs_bios_write, NULL);
- register_ioport_write(0x502, 1, 2, bochs_bios_write, NULL);
- register_ioport_write(0x500, 1, 1, bochs_bios_write, NULL);
- register_ioport_write(0x503, 1, 1, bochs_bios_write, NULL);
-}
-
-
-int load_kernel(const char *filename, uint8_t *addr,
- uint8_t *real_addr)
-{
- int fd, size;
- int setup_sects;
-
- fd = open(filename, O_RDONLY | O_BINARY);
- if (fd < 0)
- return -1;
-
- /* load 16 bit code */
- if (read(fd, real_addr, 512) != 512)
- goto fail;
- setup_sects = real_addr[0x1F1];
- if (!setup_sects)
- setup_sects = 4;
- if (read(fd, real_addr + 512, setup_sects * 512) !=
- setup_sects * 512)
- goto fail;
-
- /* load 32 bit code */
- size = read(fd, addr, 16 * 1024 * 1024);
- if (size < 0)
- goto fail;
- close(fd);
- return size;
- fail:
- close(fd);
- return -1;
-}
-
-static void main_cpu_reset(void *opaque)
-{
- CPUState *env = opaque;
- cpu_reset(env);
-}
-
-/*************************************************/
-
-static void putb(uint8_t **pp, int val)
-{
- uint8_t *q;
- q = *pp;
- *q++ = val;
- *pp = q;
-}
-
-static void putstr(uint8_t **pp, const char *str)
-{
- uint8_t *q;
- q = *pp;
- while (*str)
- *q++ = *str++;
- *pp = q;
-}
-
-static void putle16(uint8_t **pp, int val)
-{
- uint8_t *q;
- q = *pp;
- *q++ = val;
- *q++ = val >> 8;
- *pp = q;
-}
-
-static void putle32(uint8_t **pp, int val)
-{
- uint8_t *q;
- q = *pp;
- *q++ = val;
- *q++ = val >> 8;
- *q++ = val >> 16;
- *q++ = val >> 24;
- *pp = q;
-}
-
-static int mpf_checksum(const uint8_t *data, int len)
-{
- int sum, i;
- sum = 0;
- for(i = 0; i < len; i++)
- sum += data[i];
- return sum & 0xff;
-}
-
-/* Build the Multi Processor table in the BIOS. Same values as Bochs. */
-static void bios_add_mptable(uint8_t *bios_data)
-{
- uint8_t *mp_config_table, *q, *float_pointer_struct;
- int ioapic_id, offset, i, len;
-
- if (smp_cpus <= 1)
- return;
-
- mp_config_table = bios_data + 0xb000;
- q = mp_config_table;
- putstr(&q, "PCMP"); /* "PCMP signature */
- putle16(&q, 0); /* table length (patched later) */
- putb(&q, 4); /* spec rev */
- putb(&q, 0); /* checksum (patched later) */
- putstr(&q, "QEMUCPU "); /* OEM id */
- putstr(&q, "0.1 "); /* vendor id */
- putle32(&q, 0); /* OEM table ptr */
- putle16(&q, 0); /* OEM table size */
- putle16(&q, 20); /* entry count */
- putle32(&q, 0xfee00000); /* local APIC addr */
- putle16(&q, 0); /* ext table length */
- putb(&q, 0); /* ext table checksum */
- putb(&q, 0); /* reserved */
-
- for(i = 0; i < smp_cpus; i++) {
- putb(&q, 0); /* entry type = processor */
- putb(&q, i); /* APIC id */
- putb(&q, 0x11); /* local APIC version number */
- if (i == 0)
- putb(&q, 3); /* cpu flags: enabled, bootstrap cpu */
- else
- putb(&q, 1); /* cpu flags: enabled */
- putb(&q, 0); /* cpu signature */
- putb(&q, 6);
- putb(&q, 0);
- putb(&q, 0);
- putle16(&q, 0x201); /* feature flags */
- putle16(&q, 0);
-
- putle16(&q, 0); /* reserved */
- putle16(&q, 0);
- putle16(&q, 0);
- putle16(&q, 0);
- }
-
- /* isa bus */
- putb(&q, 1); /* entry type = bus */
- putb(&q, 0); /* bus ID */
- putstr(&q, "ISA ");
-
- /* ioapic */
- ioapic_id = smp_cpus;
- putb(&q, 2); /* entry type = I/O APIC */
- putb(&q, ioapic_id); /* apic ID */
- putb(&q, 0x11); /* I/O APIC version number */
- putb(&q, 1); /* enable */
- putle32(&q, 0xfec00000); /* I/O APIC addr */
-
- /* irqs */
- for(i = 0; i < 16; i++) {
- putb(&q, 3); /* entry type = I/O interrupt */
- putb(&q, 0); /* interrupt type = vectored interrupt */
- putb(&q, 0); /* flags: po=0, el=0 */
- putb(&q, 0);
- putb(&q, 0); /* source bus ID = ISA */
- putb(&q, i); /* source bus IRQ */
- putb(&q, ioapic_id); /* dest I/O APIC ID */
- putb(&q, i); /* dest I/O APIC interrupt in */
- }
- /* patch length */
- len = q - mp_config_table;
- mp_config_table[4] = len;
- mp_config_table[5] = len >> 8;
-
- mp_config_table[7] = -mpf_checksum(mp_config_table, q - mp_config_table);
-
- /* align to 16 */
- offset = q - bios_data;
- offset = (offset + 15) & ~15;
- float_pointer_struct = bios_data + offset;
-
- /* floating pointer structure */
- q = float_pointer_struct;
- putstr(&q, "_MP_");
- /* pointer to MP config table */
- putle32(&q, mp_config_table - bios_data + 0x000f0000);
-
- putb(&q, 1); /* length in 16 byte units */
- putb(&q, 4); /* MP spec revision */
- putb(&q, 0); /* checksum (patched later) */
- putb(&q, 0); /* MP feature byte 1 */
-
- putb(&q, 0);
- putb(&q, 0);
- putb(&q, 0);
- putb(&q, 0);
- float_pointer_struct[10] =
- -mpf_checksum(float_pointer_struct, q - float_pointer_struct);
-}
-
-
-static const int ide_iobase[2] = { 0x1f0, 0x170 };
-static const int ide_iobase2[2] = { 0x3f6, 0x376 };
-static const int ide_irq[2] = { 14, 15 };
-
-#define NE2000_NB_MAX 6
-
-static int ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
-static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
-
-static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
-static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
-
-static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
-static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
-
-#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) {
- c->init.init_isa (s);
- }
- else {
- if (pci_bus) {
- c->init.init_pci (pci_bus, s);
- }
- }
- }
- }
- }
- }
-}
-#endif
-
-static void pc_init_ne2k_isa(NICInfo *nd)
-{
- static int nb_ne2k = 0;
-
- if (nb_ne2k == NE2000_NB_MAX)
- return;
- isa_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd);
- nb_ne2k++;
-}
-
-/* PC hardware initialisation */
-static void pc_init1(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 pci_enabled)
-{
- char buf[1024];
- int ret, linux_boot, initrd_size, i;
- unsigned long bios_offset, vga_bios_offset;
- int bios_size, isa_bios_size;
- PCIBus *pci_bus;
- int piix3_devfn = -1;
- CPUState *env;
- NICInfo *nd;
-
- linux_boot = (kernel_filename != NULL);
-
- /* init CPUs */
- for(i = 0; i < smp_cpus; i++) {
- env = cpu_init();
- if (i != 0)
- env->hflags |= HF_HALTED_MASK;
- if (smp_cpus > 1) {
- /* XXX: enable it in all cases */
- env->cpuid_features |= CPUID_APIC;
- }
- register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
- qemu_register_reset(main_cpu_reset, env);
- if (pci_enabled) {
- apic_init(env);
- }
- }
-
- /* allocate RAM */
- cpu_register_physical_memory(0, ram_size, 0);
-
- /* 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)) {
- goto bios_error;
- }
- 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);
- exit(1);
- }
- if (bios_size == 65536) {
- bios_add_mptable(phys_ram_base + bios_offset);
- }
-
- /* VGA BIOS load */
- if (cirrus_vga_enabled) {
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_CIRRUS_FILENAME);
- } else {
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
- }
- ret = load_image(buf, phys_ram_base + vga_bios_offset);
-
- /* setup basic memory access */
- cpu_register_physical_memory(0xc0000, 0x10000,
- vga_bios_offset | IO_MEM_ROM);
-
- /* map the last 128KB of the BIOS in ISA space */
- isa_bios_size = bios_size;
- if (isa_bios_size > (128 * 1024))
- isa_bios_size = 128 * 1024;
- cpu_register_physical_memory(0xd0000, (192 * 1024) - isa_bios_size,
- IO_MEM_UNASSIGNED);
- cpu_register_physical_memory(0x100000 - isa_bios_size,
- isa_bios_size,
- (bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
- /* map all the bios at the top of memory */
- cpu_register_physical_memory((uint32_t)(-bios_size),
- bios_size, bios_offset | IO_MEM_ROM);
-
- bochs_bios_init();
-
- if (linux_boot) {
- uint8_t bootsect[512];
- uint8_t old_bootsect[512];
-
- if (bs_table[0] == NULL) {
- fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n");
- exit(1);
- }
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME);
- ret = load_image(buf, bootsect);
- if (ret != sizeof(bootsect)) {
- fprintf(stderr, "qemu: could not load linux boot sector '%s'\n",
- buf);
- exit(1);
- }
-
- if (bdrv_read(bs_table[0], 0, old_bootsect, 1) >= 0) {
- /* copy the MSDOS partition table */
- memcpy(bootsect + 0x1be, old_bootsect + 0x1be, 0x40);
- }
-
- bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect));
-
- /* now we can load the kernel */
- ret = load_kernel(kernel_filename,
- phys_ram_base + KERNEL_LOAD_ADDR,
- phys_ram_base + KERNEL_PARAMS_ADDR);
- if (ret < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
-
- /* load initrd */
- initrd_size = 0;
- 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 initial ram disk '%s'\n",
- initrd_filename);
- exit(1);
- }
- }
- if (initrd_size > 0) {
- stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR);
- stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size);
- }
- pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096,
- kernel_cmdline);
- stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F);
- stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22,
- KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR);
- /* loader type */
- stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01);
- }
-
- if (pci_enabled) {
- pci_bus = i440fx_init();
- piix3_devfn = piix3_init(pci_bus);
- } else {
- pci_bus = NULL;
- }
-
- /* init basic PC hardware */
- register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
-
- register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
-
- if (cirrus_vga_enabled) {
- if (pci_enabled) {
- pci_cirrus_vga_init(pci_bus,
- ds, phys_ram_base + ram_size, ram_size,
- vga_ram_size);
- } else {
- isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size,
- vga_ram_size);
- }
- } else {
- vga_initialize(pci_bus, ds, phys_ram_base + ram_size, ram_size,
- vga_ram_size, 0, 0);
- }
-
- rtc_state = rtc_init(0x70, 8);
-
- register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
- register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
-
- if (pci_enabled) {
- ioapic = ioapic_init();
- }
- isa_pic = pic_init(pic_irq_request, first_cpu);
- pit = pit_init(0x40, 0);
- pcspk_init(pit);
- if (pci_enabled) {
- pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
- }
-
- 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]);
- }
- }
-
- for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
- if (parallel_hds[i]) {
- parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
- }
- }
-
- for(i = 0; i < nb_nics; i++) {
- nd = &nd_table[i];
- if (!nd->model) {
- if (pci_enabled) {
- nd->model = "ne2k_pci";
- } else {
- nd->model = "ne2k_isa";
- }
- }
- if (strcmp(nd->model, "ne2k_isa") == 0) {
- pc_init_ne2k_isa(nd);
- } else if (pci_enabled) {
- pci_nic_init(pci_bus, nd);
- } else {
- fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
- exit(1);
- }
- }
-
- if (pci_enabled) {
- pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
- } else {
- for(i = 0; i < 2; i++) {
- isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
- bs_table[2 * i], bs_table[2 * i + 1]);
- }
- }
-
- kbd_init();
- DMA_init(0);
-#ifdef HAS_AUDIO
- audio_init(pci_enabled ? pci_bus : NULL);
-#endif
-
- floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
-
- cmos_init(ram_size, boot_device, bs_table);
-
- if (pci_enabled && usb_enabled) {
- usb_uhci_init(pci_bus, piix3_devfn + 2);
- }
-
- if (pci_enabled && acpi_enabled) {
- piix4_pm_init(pci_bus, piix3_devfn + 3);
- }
-
-#if 0
- /* ??? Need to figure out some way for the user to
- specify SCSI devices. */
- if (pci_enabled) {
- void *scsi;
- BlockDriverState *bdrv;
-
- scsi = lsi_scsi_init(pci_bus, -1);
- bdrv = bdrv_new("scsidisk");
- bdrv_open(bdrv, "scsi_disk.img", 0);
- lsi_scsi_attach(scsi, bdrv, -1);
- bdrv = bdrv_new("scsicd");
- bdrv_open(bdrv, "scsi_cd.iso", 0);
- bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);
- lsi_scsi_attach(scsi, bdrv, -1);
- }
-#endif
- /* must be done after all PCI devices are instanciated */
- /* XXX: should be done in the Bochs BIOS */
- if (pci_enabled) {
- pci_bios_init();
- if (acpi_enabled)
- acpi_bios_init();
- }
-}
-
-static void pc_init_pci(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)
-{
- pc_init1(ram_size, vga_ram_size, boot_device,
- ds, fd_filename, snapshot,
- kernel_filename, kernel_cmdline,
- initrd_filename, 1);
-}
-
-static void pc_init_isa(int ram_size, int vga_ram_size, int boot_device,
- DisplayState *ds, const char **fd_filename,
- int snapshot,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename)
-{
- pc_init1(ram_size, vga_ram_size, boot_device,
- ds, fd_filename, snapshot,
- kernel_filename, kernel_cmdline,
- initrd_filename, 0);
-}
-
-QEMUMachine pc_machine = {
- "pc",
- "Standard PC",
- pc_init_pci,
-};
-
-QEMUMachine isapc_machine = {
- "isapc",
- "ISA-only PC",
- pc_init_isa,
-};
diff --git a/hw/pci.c b/hw/pci.c
index f58f6fd..d8cbc2b 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -2,7 +2,7 @@
* QEMU PCI bus manager
*
* Copyright (c) 2004 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
@@ -75,16 +75,16 @@ int generic_pci_load(QEMUFile* f, void *opaque, int version_id)
}
/* -1 for devfn means auto assign */
-PCIDevice *pci_register_device(PCIBus *bus, const char *name,
+PCIDevice *pci_register_device(PCIBus *bus, const char *name,
int instance_size, int devfn,
- PCIConfigReadFunc *config_read,
+ PCIConfigReadFunc *config_read,
PCIConfigWriteFunc *config_write)
{
PCIDevice *pci_dev;
if (pci_irq_index >= PCI_DEVICES_MAX)
return NULL;
-
+
if (devfn < 0) {
for(devfn = bus->devfn_min ; devfn < 256; devfn += 8) {
if (!bus->devices[devfn])
@@ -111,8 +111,8 @@ PCIDevice *pci_register_device(PCIBus *bus, const char *name,
return pci_dev;
}
-void pci_register_io_region(PCIDevice *pci_dev, int region_num,
- uint32_t size, int type,
+void pci_register_io_region(PCIDevice *pci_dev, int region_num,
+ uint32_t size, int type,
PCIMapIORegionFunc *map_func)
{
PCIIORegion *r;
@@ -143,7 +143,7 @@ static void pci_update_mappings(PCIDevice *d)
PCIIORegion *r;
int cmd, i;
uint32_t last_addr, new_addr, config_ofs;
-
+
cmd = le16_to_cpu(*(uint16_t *)(d->config + PCI_COMMAND));
for(i = 0; i < PCI_NUM_REGIONS; i++) {
r = &d->io_regions[i];
@@ -155,7 +155,7 @@ static void pci_update_mappings(PCIDevice *d)
if (r->size != 0) {
if (r->type & PCI_ADDRESS_SPACE_IO) {
if (cmd & PCI_COMMAND_IO) {
- new_addr = le32_to_cpu(*(uint32_t *)(d->config +
+ new_addr = le32_to_cpu(*(uint32_t *)(d->config +
config_ofs));
new_addr = new_addr & ~(r->size - 1);
last_addr = new_addr + r->size - 1;
@@ -169,7 +169,7 @@ static void pci_update_mappings(PCIDevice *d)
}
} else {
if (cmd & PCI_COMMAND_MEMORY) {
- new_addr = le32_to_cpu(*(uint32_t *)(d->config +
+ new_addr = le32_to_cpu(*(uint32_t *)(d->config +
config_ofs));
/* the ROM slot has a specific enable bit */
if (i == PCI_ROM_SLOT && !(new_addr & 1))
@@ -204,7 +204,7 @@ static void pci_update_mappings(PCIDevice *d)
}
} else {
cpu_register_physical_memory(pci_to_cpu_addr(r->addr),
- r->size,
+ r->size,
IO_MEM_UNASSIGNED);
}
}
@@ -217,7 +217,7 @@ static void pci_update_mappings(PCIDevice *d)
}
}
-uint32_t pci_default_read_config(PCIDevice *d,
+uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len)
{
uint32_t val;
@@ -236,13 +236,13 @@ uint32_t pci_default_read_config(PCIDevice *d,
return val;
}
-void pci_default_write_config(PCIDevice *d,
+void pci_default_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len)
{
int can_write, i;
uint32_t end, addr;
- if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
+ if (len == 4 && ((address >= 0x10 && address < 0x10 + 4 * 6) ||
(address >= 0x30 && address < 0x34))) {
PCIIORegion *r;
int reg;
@@ -336,7 +336,7 @@ void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len)
PCIBus *s = opaque;
PCIDevice *pci_dev;
int config_addr, bus_num;
-
+
#if defined(DEBUG_PCI) && 0
printf("pci_data_write: addr=%08x val=%08x len=%d\n",
addr, val, len);
@@ -414,7 +414,7 @@ typedef struct {
const char *desc;
} pci_class_desc;
-static pci_class_desc pci_class_descriptions[] =
+static pci_class_desc pci_class_descriptions[] =
{
{ 0x0101, "IDE controller"},
{ 0x0200, "Ethernet controller"},
@@ -456,10 +456,10 @@ static void pci_info_device(PCIDevice *d)
if (r->size != 0) {
term_printf(" BAR%d: ", i);
if (r->type & PCI_ADDRESS_SPACE_IO) {
- term_printf("I/O at 0x%04x [0x%04x].\n",
+ term_printf("I/O at 0x%04x [0x%04x].\n",
r->addr, r->addr + r->size - 1);
} else {
- term_printf("32 bit memory at 0x%08x [0x%08x].\n",
+ term_printf("32 bit memory at 0x%08x [0x%08x].\n",
r->addr, r->addr + r->size - 1);
}
}
@@ -471,7 +471,7 @@ void pci_for_each_device(void (*fn)(PCIDevice *d))
PCIBus *bus = first_bus;
PCIDevice *d;
int devfn;
-
+
if (bus) {
for(devfn = 0; devfn < 256; devfn++) {
d = bus->devices[devfn];
@@ -489,6 +489,7 @@ void pci_info(void)
/* Initialize a PCI NIC. */
void pci_nic_init(PCIBus *bus, NICInfo *nd)
{
+#if 0 /* ANDROID */
if (strcmp(nd->model, "ne2k_pci") == 0) {
pci_ne2000_init(bus, nd);
} else if (strcmp(nd->model, "rtl8139") == 0) {
@@ -496,6 +497,9 @@ void pci_nic_init(PCIBus *bus, NICInfo *nd)
} else if (strcmp(nd->model, "pcnet") == 0) {
pci_pcnet_init(bus, nd);
} else {
+#else
+ {
+#endif
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
exit (1);
}
diff --git a/hw/pckbd.c b/hw/pckbd.c
deleted file mode 100644
index 3c41e5f..0000000
--- a/hw/pckbd.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * QEMU PC keyboard emulation
- *
- * 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"
-
-/* debug PC keyboard */
-//#define DEBUG_KBD
-
-/* debug PC keyboard : only mouse */
-//#define DEBUG_MOUSE
-
-/* Keyboard Controller Commands */
-#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
-#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
-#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
-#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
-#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
-#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
-#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
-#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
-#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
-#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
-#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
-#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
-#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
-#define KBD_CCMD_WRITE_OBUF 0xD2
-#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
- initiated by the auxiliary device */
-#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
-#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
-#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
-#define KBD_CCMD_RESET 0xFE
-
-/* Keyboard Commands */
-#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
-#define KBD_CMD_ECHO 0xEE
-#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
-#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
-#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
-#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
-#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
-#define KBD_CMD_RESET 0xFF /* Reset */
-
-/* Keyboard Replies */
-#define KBD_REPLY_POR 0xAA /* Power on reset */
-#define KBD_REPLY_ACK 0xFA /* Command ACK */
-#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
-
-/* Status Register Bits */
-#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
-#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
-#define KBD_STAT_SELFTEST 0x04 /* Self test successful */
-#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
-#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
-#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
-#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
-#define KBD_STAT_PERR 0x80 /* Parity error */
-
-/* Controller Mode Register Bits */
-#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
-#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
-#define KBD_MODE_SYS 0x04 /* The system flag (?) */
-#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
-#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
-#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
-#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
-#define KBD_MODE_RFU 0x80
-
-/* Mouse Commands */
-#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
-#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
-#define AUX_SET_RES 0xE8 /* Set resolution */
-#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
-#define AUX_SET_STREAM 0xEA /* Set stream mode */
-#define AUX_POLL 0xEB /* Poll */
-#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
-#define AUX_SET_WRAP 0xEE /* Set wrap mode */
-#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
-#define AUX_GET_TYPE 0xF2 /* Get type */
-#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
-#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
-#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
-#define AUX_SET_DEFAULT 0xF6
-#define AUX_RESET 0xFF /* Reset aux device */
-#define AUX_ACK 0xFA /* Command byte ACK. */
-
-#define MOUSE_STATUS_REMOTE 0x40
-#define MOUSE_STATUS_ENABLED 0x20
-#define MOUSE_STATUS_SCALE21 0x10
-
-#define KBD_QUEUE_SIZE 256
-
-#define KBD_PENDING_KBD 1
-#define KBD_PENDING_AUX 2
-
-typedef struct KBDState {
- uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
- uint8_t status;
- uint8_t mode;
- /* Bitmask of devices with data available. */
- uint8_t pending;
- void *kbd;
- void *mouse;
-} KBDState;
-
-KBDState kbd_state;
-
-/* update irq and KBD_STAT_[MOUSE_]OBF */
-/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
- incorrect, but it avoids having to simulate exact delays */
-static void kbd_update_irq(KBDState *s)
-{
- int irq12_level, irq1_level;
-
- irq1_level = 0;
- irq12_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. */
- if (s->pending == KBD_PENDING_AUX) {
- s->status |= KBD_STAT_MOUSE_OBF;
- if (s->mode & KBD_MODE_MOUSE_INT)
- irq12_level = 1;
- } else {
- if ((s->mode & KBD_MODE_KBD_INT) &&
- !(s->mode & KBD_MODE_DISABLE_KBD))
- irq1_level = 1;
- }
- }
- pic_set_irq(1, irq1_level);
- pic_set_irq(12, irq12_level);
-}
-
-static void kbd_update_kbd_irq(void *opaque, int level)
-{
- KBDState *s = (KBDState *)opaque;
-
- if (level)
- s->pending |= KBD_PENDING_KBD;
- else
- s->pending &= ~KBD_PENDING_KBD;
- kbd_update_irq(s);
-}
-
-static void kbd_update_aux_irq(void *opaque, int level)
-{
- KBDState *s = (KBDState *)opaque;
-
- if (level)
- s->pending |= KBD_PENDING_AUX;
- else
- s->pending &= ~KBD_PENDING_AUX;
- kbd_update_irq(s);
-}
-
-static uint32_t kbd_read_status(void *opaque, uint32_t addr)
-{
- KBDState *s = opaque;
- int val;
- val = s->status;
-#if defined(DEBUG_KBD)
- printf("kbd: read status=0x%02x\n", val);
-#endif
- return val;
-}
-
-static void kbd_queue(KBDState *s, int b, int aux)
-{
- if (aux)
- ps2_queue(s->mouse, b);
- else
- ps2_queue(s->kbd, b);
-}
-
-static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
-{
- KBDState *s = opaque;
-
-#ifdef DEBUG_KBD
- printf("kbd: write cmd=0x%02x\n", val);
-#endif
- switch(val) {
- case KBD_CCMD_READ_MODE:
- kbd_queue(s, s->mode, 0);
- break;
- case KBD_CCMD_WRITE_MODE:
- case KBD_CCMD_WRITE_OBUF:
- case KBD_CCMD_WRITE_AUX_OBUF:
- case KBD_CCMD_WRITE_MOUSE:
- case KBD_CCMD_WRITE_OUTPORT:
- s->write_cmd = val;
- break;
- case KBD_CCMD_MOUSE_DISABLE:
- s->mode |= KBD_MODE_DISABLE_MOUSE;
- break;
- case KBD_CCMD_MOUSE_ENABLE:
- s->mode &= ~KBD_MODE_DISABLE_MOUSE;
- break;
- case KBD_CCMD_TEST_MOUSE:
- kbd_queue(s, 0x00, 0);
- break;
- case KBD_CCMD_SELF_TEST:
- s->status |= KBD_STAT_SELFTEST;
- kbd_queue(s, 0x55, 0);
- break;
- case KBD_CCMD_KBD_TEST:
- kbd_queue(s, 0x00, 0);
- break;
- case KBD_CCMD_KBD_DISABLE:
- s->mode |= KBD_MODE_DISABLE_KBD;
- kbd_update_irq(s);
- break;
- case KBD_CCMD_KBD_ENABLE:
- s->mode &= ~KBD_MODE_DISABLE_KBD;
- kbd_update_irq(s);
- break;
- case KBD_CCMD_READ_INPORT:
- kbd_queue(s, 0x00, 0);
- break;
- case KBD_CCMD_READ_OUTPORT:
- /* XXX: check that */
-#ifdef TARGET_I386
- val = 0x01 | (ioport_get_a20() << 1);
-#else
- val = 0x01;
-#endif
- if (s->status & KBD_STAT_OBF)
- val |= 0x10;
- if (s->status & KBD_STAT_MOUSE_OBF)
- val |= 0x20;
- kbd_queue(s, val, 0);
- break;
-#ifdef TARGET_I386
- case KBD_CCMD_ENABLE_A20:
- ioport_set_a20(1);
- break;
- case KBD_CCMD_DISABLE_A20:
- ioport_set_a20(0);
- break;
-#endif
- case KBD_CCMD_RESET:
- qemu_system_reset_request();
- break;
- case 0xff:
- /* ignore that - I don't know what is its use */
- break;
- default:
- fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
- break;
- }
-}
-
-static uint32_t kbd_read_data(void *opaque, uint32_t addr)
-{
- KBDState *s = opaque;
-
- if (s->pending == KBD_PENDING_AUX)
- return ps2_read_data(s->mouse);
-
- return ps2_read_data(s->kbd);
-}
-
-void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
-{
- KBDState *s = opaque;
-
-#ifdef DEBUG_KBD
- printf("kbd: write data=0x%02x\n", val);
-#endif
-
- switch(s->write_cmd) {
- case 0:
- ps2_write_keyboard(s->kbd, val);
- break;
- case KBD_CCMD_WRITE_MODE:
- s->mode = val;
- ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
- /* ??? */
- kbd_update_irq(s);
- break;
- case KBD_CCMD_WRITE_OBUF:
- kbd_queue(s, val, 0);
- break;
- case KBD_CCMD_WRITE_AUX_OBUF:
- kbd_queue(s, val, 1);
- break;
- case KBD_CCMD_WRITE_OUTPORT:
-#ifdef TARGET_I386
- ioport_set_a20((val >> 1) & 1);
-#endif
- if (!(val & 1)) {
- qemu_system_reset_request();
- }
- break;
- case KBD_CCMD_WRITE_MOUSE:
- ps2_write_mouse(s->mouse, val);
- break;
- default:
- break;
- }
- s->write_cmd = 0;
-}
-
-static void kbd_reset(void *opaque)
-{
- KBDState *s = opaque;
-
- s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
- s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
-}
-
-static void kbd_save(QEMUFile* f, void* opaque)
-{
- KBDState *s = (KBDState*)opaque;
-
- qemu_put_8s(f, &s->write_cmd);
- qemu_put_8s(f, &s->status);
- qemu_put_8s(f, &s->mode);
- qemu_put_8s(f, &s->pending);
-}
-
-static int kbd_load(QEMUFile* f, void* opaque, int version_id)
-{
- KBDState *s = (KBDState*)opaque;
-
- if (version_id != 3)
- return -EINVAL;
- qemu_get_8s(f, &s->write_cmd);
- qemu_get_8s(f, &s->status);
- qemu_get_8s(f, &s->mode);
- qemu_get_8s(f, &s->pending);
- return 0;
-}
-
-void kbd_init(void)
-{
- KBDState *s = &kbd_state;
-
- 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);
-
- s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
- s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
- qemu_register_reset(kbd_reset, s);
-}
diff --git a/hw/pcnet.c b/hw/pcnet.c
deleted file mode 100644
index 0845cdc..0000000
--- a/hw/pcnet.c
+++ /dev/null
@@ -1,1789 +0,0 @@
-/*
- * QEMU AMD PC-Net II (Am79C970A) emulation
- *
- * Copyright (c) 2004 Antony T Curtis
- *
- * 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.
- */
-
-/* This software was written to be compatible with the specification:
- * AMD Am79C970A PCnet-PCI II Ethernet Controller Data-Sheet
- * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000
- */
-
-#include "vl.h"
-
-//#define PCNET_DEBUG
-//#define PCNET_DEBUG_IO
-//#define PCNET_DEBUG_BCR
-//#define PCNET_DEBUG_CSR
-//#define PCNET_DEBUG_RMD
-//#define PCNET_DEBUG_TMD
-//#define PCNET_DEBUG_MATCH
-
-
-#define PCNET_IOPORT_SIZE 0x20
-#define PCNET_PNPMMIO_SIZE 0x20
-
-
-typedef struct PCNetState_st PCNetState;
-
-struct PCNetState_st {
- PCIDevice dev;
- VLANClientState *vc;
- NICInfo *nd;
- QEMUTimer *poll_timer;
- int mmio_io_addr, rap, isr, lnkst;
- target_phys_addr_t rdra, tdra;
- uint8_t prom[16];
- uint16_t csr[128];
- uint16_t bcr[32];
- uint64_t timer;
- int xmit_pos, recv_pos;
- uint8_t buffer[4096];
- int tx_busy;
-};
-
-/* 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];
- uint16_t ether_type;
-};
-
-/* BUS CONFIGURATION REGISTERS */
-#define BCR_MSRDA 0
-#define BCR_MSWRA 1
-#define BCR_MC 2
-#define BCR_LNKST 4
-#define BCR_LED1 5
-#define BCR_LED2 6
-#define BCR_LED3 7
-#define BCR_FDC 9
-#define BCR_BSBC 18
-#define BCR_EECAS 19
-#define BCR_SWS 20
-#define BCR_PLAT 22
-
-#define BCR_DWIO(S) !!((S)->bcr[BCR_BSBC] & 0x0080)
-#define BCR_SSIZE32(S) !!((S)->bcr[BCR_SWS ] & 0x0100)
-#define BCR_SWSTYLE(S) ((S)->bcr[BCR_SWS ] & 0x00FF)
-
-#define CSR_INIT(S) !!(((S)->csr[0])&0x0001)
-#define CSR_STRT(S) !!(((S)->csr[0])&0x0002)
-#define CSR_STOP(S) !!(((S)->csr[0])&0x0004)
-#define CSR_TDMD(S) !!(((S)->csr[0])&0x0008)
-#define CSR_TXON(S) !!(((S)->csr[0])&0x0010)
-#define CSR_RXON(S) !!(((S)->csr[0])&0x0020)
-#define CSR_INEA(S) !!(((S)->csr[0])&0x0040)
-#define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020)
-#define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040)
-#define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800)
-#define CSR_DPOLL(S) !!(((S)->csr[4])&0x1000)
-#define CSR_SPND(S) !!(((S)->csr[5])&0x0001)
-#define CSR_LTINTEN(S) !!(((S)->csr[5])&0x4000)
-#define CSR_TOKINTD(S) !!(((S)->csr[5])&0x8000)
-#define CSR_DRX(S) !!(((S)->csr[15])&0x0001)
-#define CSR_DTX(S) !!(((S)->csr[15])&0x0002)
-#define CSR_LOOP(S) !!(((S)->csr[15])&0x0004)
-#define CSR_DRCVPA(S) !!(((S)->csr[15])&0x2000)
-#define CSR_DRCVBC(S) !!(((S)->csr[15])&0x4000)
-#define CSR_PROM(S) !!(((S)->csr[15])&0x8000)
-
-#define CSR_CRBC(S) ((S)->csr[40])
-#define CSR_CRST(S) ((S)->csr[41])
-#define CSR_CXBC(S) ((S)->csr[42])
-#define CSR_CXST(S) ((S)->csr[43])
-#define CSR_NRBC(S) ((S)->csr[44])
-#define CSR_NRST(S) ((S)->csr[45])
-#define CSR_POLL(S) ((S)->csr[46])
-#define CSR_PINT(S) ((S)->csr[47])
-#define CSR_RCVRC(S) ((S)->csr[72])
-#define CSR_XMTRC(S) ((S)->csr[74])
-#define CSR_RCVRL(S) ((S)->csr[76])
-#define CSR_XMTRL(S) ((S)->csr[78])
-#define CSR_MISSC(S) ((S)->csr[112])
-
-#define CSR_IADR(S) ((S)->csr[ 1] | ((S)->csr[ 2] << 16))
-#define CSR_CRBA(S) ((S)->csr[18] | ((S)->csr[19] << 16))
-#define CSR_CXBA(S) ((S)->csr[20] | ((S)->csr[21] << 16))
-#define CSR_NRBA(S) ((S)->csr[22] | ((S)->csr[23] << 16))
-#define CSR_BADR(S) ((S)->csr[24] | ((S)->csr[25] << 16))
-#define CSR_NRDA(S) ((S)->csr[26] | ((S)->csr[27] << 16))
-#define CSR_CRDA(S) ((S)->csr[28] | ((S)->csr[29] << 16))
-#define CSR_BADX(S) ((S)->csr[30] | ((S)->csr[31] << 16))
-#define CSR_NXDA(S) ((S)->csr[32] | ((S)->csr[33] << 16))
-#define CSR_CXDA(S) ((S)->csr[34] | ((S)->csr[35] << 16))
-#define CSR_NNRD(S) ((S)->csr[36] | ((S)->csr[37] << 16))
-#define CSR_NNXD(S) ((S)->csr[38] | ((S)->csr[39] << 16))
-#define CSR_PXDA(S) ((S)->csr[60] | ((S)->csr[61] << 16))
-#define CSR_NXBA(S) ((S)->csr[64] | ((S)->csr[65] << 16))
-
-#define PHYSADDR(S,A) \
- (BCR_SSIZE32(S) ? (A) : (A) | ((0xff00 & (uint32_t)(s)->csr[2])<<16))
-
-struct pcnet_initblk16 {
- uint16_t mode;
- uint16_t padr1;
- uint16_t padr2;
- uint16_t padr3;
- uint16_t ladrf1;
- uint16_t ladrf2;
- uint16_t ladrf3;
- uint16_t ladrf4;
- unsigned PACKED_FIELD(rdra:24);
- unsigned PACKED_FIELD(res1:5);
- unsigned PACKED_FIELD(rlen:3);
- unsigned PACKED_FIELD(tdra:24);
- unsigned PACKED_FIELD(res2:5);
- unsigned PACKED_FIELD(tlen:3);
-};
-
-struct pcnet_initblk32 {
- uint16_t mode;
- unsigned PACKED_FIELD(res1:4);
- unsigned PACKED_FIELD(rlen:4);
- unsigned PACKED_FIELD(res2:4);
- unsigned PACKED_FIELD(tlen:4);
- uint16_t padr1;
- uint16_t padr2;
- uint16_t padr3;
- uint16_t _res;
- uint16_t ladrf1;
- uint16_t ladrf2;
- uint16_t ladrf3;
- uint16_t ladrf4;
- uint32_t rdra;
- uint32_t tdra;
-};
-
-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;
-};
-
-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;
-};
-
-
-#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)
-
-#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" \
- "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)
-
-static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
-{
- if (!BCR_SWSTYLE(s)) {
- uint16_t xda[4];
- cpu_physical_memory_read(addr,
- (void *)&xda[0], sizeof(xda));
- ((uint32_t *)tmd)[0] = (xda[0]&0xffff) |
- ((xda[1]&0x00ff) << 16);
- ((uint32_t *)tmd)[1] = (xda[2]&0xffff)|
- ((xda[1] & 0xff00) << 16);
- ((uint32_t *)tmd)[2] =
- (xda[3] & 0xffff) << 16;
- ((uint32_t *)tmd)[3] = 0;
- }
- else
- if (BCR_SWSTYLE(s) != 3)
- cpu_physical_memory_read(addr, (void *)tmd, 16);
- else {
- uint32_t xda[4];
- cpu_physical_memory_read(addr,
- (void *)&xda[0], sizeof(xda));
- ((uint32_t *)tmd)[0] = xda[2];
- ((uint32_t *)tmd)[1] = xda[1];
- ((uint32_t *)tmd)[2] = xda[0];
- ((uint32_t *)tmd)[3] = xda[3];
- }
-}
-
-static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_phys_addr_t addr)
-{
- if (!BCR_SWSTYLE(s)) {
- uint16_t xda[4];
- xda[0] = ((uint32_t *)tmd)[0] & 0xffff;
- xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) |
- ((((uint32_t *)tmd)[1]>>16)&0xff00);
- xda[2] = ((uint32_t *)tmd)[1] & 0xffff;
- xda[3] = ((uint32_t *)tmd)[2] >> 16;
- cpu_physical_memory_write(addr,
- (void *)&xda[0], sizeof(xda));
- }
- else {
- if (BCR_SWSTYLE(s) != 3)
- cpu_physical_memory_write(addr, (void *)tmd, 16);
- else {
- uint32_t xda[4];
- xda[0] = ((uint32_t *)tmd)[2];
- xda[1] = ((uint32_t *)tmd)[1];
- xda[2] = ((uint32_t *)tmd)[0];
- xda[3] = ((uint32_t *)tmd)[3];
- cpu_physical_memory_write(addr,
- (void *)&xda[0], sizeof(xda));
- }
- }
-}
-
-static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr)
-{
- if (!BCR_SWSTYLE(s)) {
- uint16_t rda[4];
- cpu_physical_memory_read(addr,
- (void *)&rda[0], sizeof(rda));
- ((uint32_t *)rmd)[0] = (rda[0]&0xffff)|
- ((rda[1] & 0x00ff) << 16);
- ((uint32_t *)rmd)[1] = (rda[2]&0xffff)|
- ((rda[1] & 0xff00) << 16);
- ((uint32_t *)rmd)[2] = rda[3] & 0xffff;
- ((uint32_t *)rmd)[3] = 0;
- }
- else
- if (BCR_SWSTYLE(s) != 3)
- cpu_physical_memory_read(addr, (void *)rmd, 16);
- else {
- uint32_t rda[4];
- cpu_physical_memory_read(addr,
- (void *)&rda[0], sizeof(rda));
- ((uint32_t *)rmd)[0] = rda[2];
- ((uint32_t *)rmd)[1] = rda[1];
- ((uint32_t *)rmd)[2] = rda[0];
- ((uint32_t *)rmd)[3] = rda[3];
- }
-}
-
-static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr)
-{
- if (!BCR_SWSTYLE(s)) {
- uint16_t rda[4]; \
- rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \
- rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\
- ((((uint32_t *)rmd)[1]>>16)&0xff00);\
- rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \
- rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \
- cpu_physical_memory_write(addr, \
- (void *)&rda[0], sizeof(rda)); \
- }
- else {
- if (BCR_SWSTYLE(s) != 3)
- cpu_physical_memory_write(addr, (void *)rmd, 16);
- else {
- uint32_t rda[4];
- rda[0] = ((uint32_t *)rmd)[2];
- rda[1] = ((uint32_t *)rmd)[1];
- rda[2] = ((uint32_t *)rmd)[0];
- rda[3] = ((uint32_t *)rmd)[3];
- cpu_physical_memory_write(addr,
- (void *)&rda[0], sizeof(rda));
- }
- }
-}
-
-
-#define TMDLOAD(TMD,ADDR) pcnet_tmd_load(s,TMD,ADDR)
-
-#define TMDSTORE(TMD,ADDR) pcnet_tmd_store(s,TMD,ADDR)
-
-#define RMDLOAD(RMD,ADDR) pcnet_rmd_load(s,RMD,ADDR)
-
-#define RMDSTORE(RMD,ADDR) pcnet_rmd_store(s,RMD,ADDR)
-
-#if 1
-
-#define CHECK_RMD(ADDR,RES) do { \
- struct pcnet_RMD rmd; \
- RMDLOAD(&rmd,(ADDR)); \
- (RES) |= (rmd.rmd1.ones != 15) \
- || (rmd.rmd2.zeros != 0); \
-} while (0)
-
-#define CHECK_TMD(ADDR,RES) do { \
- struct pcnet_TMD tmd; \
- TMDLOAD(&tmd,(ADDR)); \
- (RES) |= (tmd.tmd1.ones != 15); \
-} while (0)
-
-#else
-
-#define CHECK_RMD(ADDR,RES) do { \
- switch (BCR_SWSTYLE(s)) { \
- case 0x00: \
- do { \
- uint16_t rda[4]; \
- cpu_physical_memory_read((ADDR), \
- (void *)&rda[0], sizeof(rda)); \
- (RES) |= (rda[2] & 0xf000)!=0xf000; \
- (RES) |= (rda[3] & 0xf000)!=0x0000; \
- } while (0); \
- break; \
- case 0x01: \
- case 0x02: \
- do { \
- uint32_t rda[4]; \
- cpu_physical_memory_read((ADDR), \
- (void *)&rda[0], sizeof(rda)); \
- (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
- (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
- } while (0); \
- break; \
- case 0x03: \
- do { \
- uint32_t rda[4]; \
- cpu_physical_memory_read((ADDR), \
- (void *)&rda[0], sizeof(rda)); \
- (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
- (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
- } while (0); \
- break; \
- } \
-} while (0)
-
-#define CHECK_TMD(ADDR,RES) do { \
- switch (BCR_SWSTYLE(s)) { \
- case 0x00: \
- do { \
- uint16_t xda[4]; \
- cpu_physical_memory_read((ADDR), \
- (void *)&xda[0], sizeof(xda)); \
- (RES) |= (xda[2] & 0xf000)!=0xf000;\
- } while (0); \
- break; \
- case 0x01: \
- case 0x02: \
- case 0x03: \
- do { \
- uint32_t xda[4]; \
- cpu_physical_memory_read((ADDR), \
- (void *)&xda[0], sizeof(xda)); \
- (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
- } while (0); \
- break; \
- } \
-} while (0)
-
-#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 (bcast=%d)\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), \
- !!ETHER_IS_MULTICAST(hdr->ether_dhost)); \
-} while (0)
-
-#define MULTICAST_FILTER_LEN 8
-
-static inline uint32_t lnc_mchash(const uint8_t *ether_addr)
-{
-#define LNC_POLYNOMIAL 0xEDB88320UL
- uint32_t crc = 0xFFFFFFFF;
- int idx, bit;
- uint8_t data;
-
- for (idx = 0; idx < 6; idx++) {
- for (data = *ether_addr++, bit = 0; bit < MULTICAST_FILTER_LEN; bit++) {
- crc = (crc >> 1) ^ (((crc ^ data) & 1) ? LNC_POLYNOMIAL : 0);
- data >>= 1;
- }
- }
- return crc;
-#undef LNC_POLYNOMIAL
-}
-
-#define CRC(crc, ch) (crc = (crc >> 8) ^ crctab[(crc ^ (ch)) & 0xff])
-
-/* generated using the AUTODIN II polynomial
- * x^32 + x^26 + x^23 + x^22 + x^16 +
- * x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
- */
-static const uint32_t crctab[256] = {
- 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
- 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
- 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
- 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
- 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
- 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
- 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
- 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
- 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
- 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
- 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
- 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
- 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
- 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
- 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
- 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
- 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
- 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
- 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
- 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
- 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
- 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
- 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
- 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
- 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
- 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
- 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
- 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
- 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
- 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
- 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
- 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
- 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
- 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
- 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
- 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
- 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
- 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
- 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
- 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
- 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
- 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
- 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
- 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
- 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
- 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
- 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
- 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
- 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
- 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
- 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
- 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
- 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
- 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
- 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
- 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
- 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
- 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
- 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
- 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
- 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
- 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
- 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
- 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
-};
-
-static inline int padr_match(PCNetState *s, const uint8_t *buf, int size)
-{
- struct qemu_ether_header *hdr = (void *)buf;
- uint8_t padr[6] = {
- s->csr[12] & 0xff, s->csr[12] >> 8,
- s->csr[13] & 0xff, s->csr[13] >> 8,
- s->csr[14] & 0xff, s->csr[14] >> 8
- };
- int result = (!CSR_DRCVPA(s)) && !memcmp(hdr->ether_dhost, padr, 6);
-#ifdef PCNET_DEBUG_MATCH
- printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, "
- "padr=%02x:%02x:%02x:%02x:%02x:%02x\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],
- padr[0],padr[1],padr[2],padr[3],padr[4],padr[5]);
- printf("padr_match result=%d\n", result);
-#endif
- return result;
-}
-
-static inline int padr_bcast(PCNetState *s, const uint8_t *buf, int size)
-{
- static uint8_t BCAST[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- struct qemu_ether_header *hdr = (void *)buf;
- int result = !CSR_DRCVBC(s) && !memcmp(hdr->ether_dhost, BCAST, 6);
-#ifdef PCNET_DEBUG_MATCH
- printf("padr_bcast result=%d\n", result);
-#endif
- return result;
-}
-
-static inline int ladr_match(PCNetState *s, const uint8_t *buf, int size)
-{
- struct qemu_ether_header *hdr = (void *)buf;
- if ((*(hdr->ether_dhost)&0x01) &&
- ((uint64_t *)&s->csr[8])[0] != 0LL) {
- uint8_t ladr[8] = {
- s->csr[8] & 0xff, s->csr[8] >> 8,
- s->csr[9] & 0xff, s->csr[9] >> 8,
- s->csr[10] & 0xff, s->csr[10] >> 8,
- s->csr[11] & 0xff, s->csr[11] >> 8
- };
- int index = lnc_mchash(hdr->ether_dhost) >> 26;
- return !!(ladr[index >> 3] & (1 << (index & 7)));
- }
- return 0;
-}
-
-static inline target_phys_addr_t pcnet_rdra_addr(PCNetState *s, int idx)
-{
- while (idx < 1) idx += CSR_RCVRL(s);
- return s->rdra + ((CSR_RCVRL(s) - idx) * (BCR_SWSTYLE(s) ? 16 : 8));
-}
-
-static inline int64_t pcnet_get_next_poll_time(PCNetState *s, int64_t current_time)
-{
- int64_t next_time = current_time +
- muldiv64(65536 - (CSR_SPND(s) ? 0 : CSR_POLL(s)),
- ticks_per_sec, 33000000L);
- if (next_time <= current_time)
- next_time = current_time + 1;
- return next_time;
-}
-
-static void pcnet_poll(PCNetState *s);
-static void pcnet_poll_timer(void *opaque);
-
-static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
-static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
-static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
-static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
-
-static void pcnet_s_reset(PCNetState *s)
-{
-#ifdef PCNET_DEBUG
- printf("pcnet_s_reset\n");
-#endif
-
- s->lnkst = 0x40;
- s->rdra = 0;
- s->tdra = 0;
- s->rap = 0;
-
- s->bcr[BCR_BSBC] &= ~0x0080;
-
- s->csr[0] = 0x0004;
- s->csr[3] = 0x0000;
- s->csr[4] = 0x0115;
- s->csr[5] = 0x0000;
- s->csr[6] = 0x0000;
- s->csr[8] = 0;
- s->csr[9] = 0;
- s->csr[10] = 0;
- s->csr[11] = 0;
- s->csr[12] = le16_to_cpu(((uint16_t *)&s->prom[0])[0]);
- s->csr[13] = le16_to_cpu(((uint16_t *)&s->prom[0])[1]);
- s->csr[14] = le16_to_cpu(((uint16_t *)&s->prom[0])[2]);
- s->csr[15] &= 0x21c4;
- s->csr[72] = 1;
- s->csr[74] = 1;
- s->csr[76] = 1;
- s->csr[78] = 1;
- s->csr[80] = 0x1410;
- s->csr[88] = 0x1003;
- s->csr[89] = 0x0262;
- s->csr[94] = 0x0000;
- s->csr[100] = 0x0200;
- s->csr[103] = 0x0105;
- s->csr[103] = 0x0105;
- s->csr[112] = 0x0000;
- s->csr[114] = 0x0000;
- s->csr[122] = 0x0000;
- s->csr[124] = 0x0000;
-
- s->tx_busy = 0;
-}
-
-static void pcnet_update_irq(PCNetState *s)
-{
- int isr = 0;
- s->csr[0] &= ~0x0080;
-
-#if 1
- if (((s->csr[0] & ~s->csr[3]) & 0x5f00) ||
- (((s->csr[4]>>1) & ~s->csr[4]) & 0x0115) ||
- (((s->csr[5]>>1) & s->csr[5]) & 0x0048))
-#else
- if ((!(s->csr[3] & 0x4000) && !!(s->csr[0] & 0x4000)) /* BABL */ ||
- (!(s->csr[3] & 0x1000) && !!(s->csr[0] & 0x1000)) /* MISS */ ||
- (!(s->csr[3] & 0x0100) && !!(s->csr[0] & 0x0100)) /* IDON */ ||
- (!(s->csr[3] & 0x0200) && !!(s->csr[0] & 0x0200)) /* TINT */ ||
- (!(s->csr[3] & 0x0400) && !!(s->csr[0] & 0x0400)) /* RINT */ ||
- (!(s->csr[3] & 0x0800) && !!(s->csr[0] & 0x0800)) /* MERR */ ||
- (!(s->csr[4] & 0x0001) && !!(s->csr[4] & 0x0002)) /* JAB */ ||
- (!(s->csr[4] & 0x0004) && !!(s->csr[4] & 0x0008)) /* TXSTRT */ ||
- (!(s->csr[4] & 0x0010) && !!(s->csr[4] & 0x0020)) /* RCVO */ ||
- (!(s->csr[4] & 0x0100) && !!(s->csr[4] & 0x0200)) /* MFCO */ ||
- (!!(s->csr[5] & 0x0040) && !!(s->csr[5] & 0x0080)) /* EXDINT */ ||
- (!!(s->csr[5] & 0x0008) && !!(s->csr[5] & 0x0010)) /* MPINT */)
-#endif
- {
-
- isr = CSR_INEA(s);
- s->csr[0] |= 0x0080;
- }
-
- if (!!(s->csr[4] & 0x0080) && CSR_INEA(s)) { /* UINT */
- s->csr[4] &= ~0x0080;
- s->csr[4] |= 0x0040;
- s->csr[0] |= 0x0080;
- isr = 1;
-#ifdef PCNET_DEBUG
- printf("pcnet user int\n");
-#endif
- }
-
-#if 1
- if (((s->csr[5]>>1) & s->csr[5]) & 0x0500)
-#else
- if ((!!(s->csr[5] & 0x0400) && !!(s->csr[5] & 0x0800)) /* SINT */ ||
- (!!(s->csr[5] & 0x0100) && !!(s->csr[5] & 0x0200)) /* SLPINT */ )
-#endif
- {
- isr = 1;
- s->csr[0] |= 0x0080;
- }
-
- if (isr != s->isr) {
-#ifdef PCNET_DEBUG
- printf("pcnet: INTA=%d\n", isr);
-#endif
- }
- pci_set_irq(&s->dev, 0, isr);
- s->isr = isr;
-}
-
-static void pcnet_init(PCNetState *s)
-{
-#ifdef PCNET_DEBUG
- printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s)));
-#endif
-
-#define PCNET_INIT() do { \
- cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \
- (uint8_t *)&initblk, sizeof(initblk)); \
- s->csr[15] = le16_to_cpu(initblk.mode); \
- CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \
- CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \
- s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \
- s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \
- s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \
- s->csr[10] = le16_to_cpu(initblk.ladrf3); \
- s->csr[11] = le16_to_cpu(initblk.ladrf4); \
- s->csr[12] = le16_to_cpu(initblk.padr1); \
- s->csr[13] = le16_to_cpu(initblk.padr2); \
- s->csr[14] = le16_to_cpu(initblk.padr3); \
- s->rdra = PHYSADDR(s,initblk.rdra); \
- s->tdra = PHYSADDR(s,initblk.tdra); \
-} while (0)
-
- if (BCR_SSIZE32(s)) {
- struct pcnet_initblk32 initblk;
- PCNET_INIT();
-#ifdef PCNET_DEBUG
- printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
- initblk.rlen, initblk.tlen);
-#endif
- } else {
- struct pcnet_initblk16 initblk;
- PCNET_INIT();
-#ifdef PCNET_DEBUG
- printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n",
- initblk.rlen, initblk.tlen);
-#endif
- }
-
-#undef PCNET_INIT
-
- CSR_RCVRC(s) = CSR_RCVRL(s);
- CSR_XMTRC(s) = CSR_XMTRL(s);
-
-#ifdef PCNET_DEBUG
- printf("pcnet ss32=%d rdra=0x%08x[%d] tdra=0x%08x[%d]\n",
- BCR_SSIZE32(s),
- s->rdra, CSR_RCVRL(s), s->tdra, CSR_XMTRL(s));
-#endif
-
- s->csr[0] |= 0x0101;
- s->csr[0] &= ~0x0004; /* clear STOP bit */
-}
-
-static void pcnet_start(PCNetState *s)
-{
-#ifdef PCNET_DEBUG
- printf("pcnet_start\n");
-#endif
-
- if (!CSR_DTX(s))
- s->csr[0] |= 0x0010; /* set TXON */
-
- if (!CSR_DRX(s))
- s->csr[0] |= 0x0020; /* set RXON */
-
- s->csr[0] &= ~0x0004; /* clear STOP bit */
- s->csr[0] |= 0x0002;
-}
-
-static void pcnet_stop(PCNetState *s)
-{
-#ifdef PCNET_DEBUG
- printf("pcnet_stop\n");
-#endif
- s->csr[0] &= ~0x7feb;
- s->csr[0] |= 0x0014;
- s->csr[4] &= ~0x02c2;
- s->csr[5] &= ~0x0011;
- pcnet_poll_timer(s);
-}
-
-static void pcnet_rdte_poll(PCNetState *s)
-{
- s->csr[28] = s->csr[29] = 0;
- if (s->rdra) {
- int bad = 0;
-#if 1
- target_phys_addr_t crda = pcnet_rdra_addr(s, CSR_RCVRC(s));
- target_phys_addr_t nrda = pcnet_rdra_addr(s, -1 + CSR_RCVRC(s));
- target_phys_addr_t nnrd = pcnet_rdra_addr(s, -2 + CSR_RCVRC(s));
-#else
- target_phys_addr_t crda = s->rdra +
- (CSR_RCVRL(s) - CSR_RCVRC(s)) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
- int nrdc = CSR_RCVRC(s)<=1 ? CSR_RCVRL(s) : CSR_RCVRC(s)-1;
- target_phys_addr_t nrda = s->rdra +
- (CSR_RCVRL(s) - nrdc) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
- int nnrc = nrdc<=1 ? CSR_RCVRL(s) : nrdc-1;
- target_phys_addr_t nnrd = s->rdra +
- (CSR_RCVRL(s) - nnrc) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
-#endif
-
- CHECK_RMD(PHYSADDR(s,crda), bad);
- if (!bad) {
- CHECK_RMD(PHYSADDR(s,nrda), bad);
- if (bad || (nrda == crda)) nrda = 0;
- CHECK_RMD(PHYSADDR(s,nnrd), bad);
- if (bad || (nnrd == crda)) nnrd = 0;
-
- s->csr[28] = crda & 0xffff;
- s->csr[29] = crda >> 16;
- s->csr[26] = nrda & 0xffff;
- s->csr[27] = nrda >> 16;
- s->csr[36] = nnrd & 0xffff;
- s->csr[37] = nnrd >> 16;
-#ifdef PCNET_DEBUG
- if (bad) {
- printf("pcnet: BAD RMD RECORDS AFTER 0x%08x\n",
- PHYSADDR(s,crda));
- }
- } else {
- printf("pcnet: BAD RMD RDA=0x%08x\n", PHYSADDR(s,crda));
-#endif
- }
- }
-
- 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;
-#ifdef PCNET_DEBUG_RMD_X
- printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n",
- PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
- ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]);
- PRINT_RMD(&rmd);
-#endif
- } else {
- CSR_CRBC(s) = CSR_CRST(s) = 0;
- }
-
- 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;
- } else {
- CSR_NRBC(s) = CSR_NRST(s) = 0;
- }
-
-}
-
-static int pcnet_tdte_poll(PCNetState *s)
-{
- s->csr[34] = s->csr[35] = 0;
- if (s->tdra) {
- target_phys_addr_t cxda = s->tdra +
- (CSR_XMTRL(s) - CSR_XMTRC(s)) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
- int bad = 0;
- CHECK_TMD(PHYSADDR(s, cxda),bad);
- if (!bad) {
- if (CSR_CXDA(s) != cxda) {
- s->csr[60] = s->csr[34];
- s->csr[61] = s->csr[35];
- s->csr[62] = CSR_CXBC(s);
- s->csr[63] = CSR_CXST(s);
- }
- s->csr[34] = cxda & 0xffff;
- s->csr[35] = cxda >> 16;
-#ifdef PCNET_DEBUG
- } else {
- printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda));
-#endif
- }
- }
-
- if (CSR_CXDA(s)) {
- struct pcnet_TMD tmd;
-
- TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
-
- CSR_CXBC(s) = tmd.tmd1.bcnt;
- CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16;
- } else {
- CSR_CXBC(s) = CSR_CXST(s) = 0;
- }
-
- return !!(CSR_CXST(s) & 0x8000);
-}
-
-static int pcnet_can_receive(void *opaque)
-{
- PCNetState *s = opaque;
- if (CSR_STOP(s) || CSR_SPND(s))
- return 0;
-
- if (s->recv_pos > 0)
- return 0;
-
- return sizeof(s->buffer)-16;
-}
-
-#define MIN_BUF_SIZE 60
-
-static void pcnet_receive(void *opaque, const uint8_t *buf, int size)
-{
- PCNetState *s = opaque;
- int is_padr = 0, is_bcast = 0, is_ladr = 0;
- uint8_t buf1[60];
-
- if (CSR_DRX(s) || CSR_STOP(s) || CSR_SPND(s) || !size)
- return;
-
-#ifdef PCNET_DEBUG
- printf("pcnet_receive size=%d\n", size);
-#endif
-
- /* if too small buffer, then expand it */
- if (size < MIN_BUF_SIZE) {
- memcpy(buf1, buf, size);
- memset(buf1 + size, 0, MIN_BUF_SIZE - size);
- buf = buf1;
- size = MIN_BUF_SIZE;
- }
-
- if (CSR_PROM(s)
- || (is_padr=padr_match(s, buf, size))
- || (is_bcast=padr_bcast(s, buf, size))
- || (is_ladr=ladr_match(s, buf, size))) {
-
- pcnet_rdte_poll(s);
-
- if (!(CSR_CRST(s) & 0x8000) && s->rdra) {
- struct pcnet_RMD rmd;
- int rcvrc = CSR_RCVRC(s)-1,i;
- target_phys_addr_t nrda;
- for (i = CSR_RCVRL(s)-1; i > 0; i--, rcvrc--) {
- if (rcvrc <= 1)
- rcvrc = CSR_RCVRL(s);
- nrda = s->rdra +
- (CSR_RCVRL(s) - rcvrc) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
- RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (rmd.rmd1.own) {
-#ifdef PCNET_DEBUG_RMD
- printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
- rcvrc, CSR_RCVRC(s));
-#endif
- CSR_RCVRC(s) = rcvrc;
- pcnet_rdte_poll(s);
- break;
- }
- }
- }
-
- if (!(CSR_CRST(s) & 0x8000)) {
-#ifdef PCNET_DEBUG_RMD
- printf("pcnet - no buffer: RCVRC=%d\n", CSR_RCVRC(s));
-#endif
- s->csr[0] |= 0x1000; /* Set MISS flag */
- CSR_MISSC(s)++;
- } else {
- uint8_t *src = &s->buffer[8];
- target_phys_addr_t crda = CSR_CRDA(s);
- struct pcnet_RMD rmd;
- int pktcount = 0;
-
- memcpy(src, buf, size);
-
-#if 1
- /* no need to compute the CRC */
- src[size] = 0;
- src[size + 1] = 0;
- src[size + 2] = 0;
- src[size + 3] = 0;
- size += 4;
-#else
- /* XXX: avoid CRC generation */
- if (!CSR_ASTRP_RCV(s)) {
- uint32_t fcs = ~0;
- uint8_t *p = src;
-
- while (size < 46) {
- src[size++] = 0;
- }
-
- while (p != &src[size]) {
- CRC(fcs, *p++);
- }
- ((uint32_t *)&src[size])[0] = htonl(fcs);
- size += 4; /* FCS at end of packet */
- } else size += 4;
-#endif
-
-#ifdef PCNET_DEBUG_MATCH
- PRINT_PKTHDR(buf);
-#endif
-
- RMDLOAD(&rmd, PHYSADDR(s,crda));
- /*if (!CSR_LAPPEN(s))*/
- rmd.rmd1.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); \
- cpu_physical_memory_write(rbadr, src, count); \
- src += count; size -= count; \
- rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \
- RMDSTORE(&rmd, PHYSADDR(s,crda)); \
- pktcount++; \
-} while (0)
-
- PCNET_RECV_STORE();
- if ((size > 0) && CSR_NRDA(s)) {
- target_phys_addr_t nrda = CSR_NRDA(s);
- RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (rmd.rmd1.own) {
- crda = nrda;
- PCNET_RECV_STORE();
- if ((size > 0) && (nrda=CSR_NNRD(s))) {
- RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (rmd.rmd1.own) {
- crda = nrda;
- PCNET_RECV_STORE();
- }
- }
- }
- }
-
-#undef PCNET_RECV_STORE
-
- 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;
- } else {
- rmd.rmd1.oflo = 1;
- rmd.rmd1.buff = 1;
- rmd.rmd1.err = 1;
- }
- RMDSTORE(&rmd, PHYSADDR(s,crda));
- s->csr[0] |= 0x0400;
-
-#ifdef PCNET_DEBUG
- printf("RCVRC=%d CRDA=0x%08x BLKS=%d\n",
- CSR_RCVRC(s), PHYSADDR(s,CSR_CRDA(s)), pktcount);
-#endif
-#ifdef PCNET_DEBUG_RMD
- PRINT_RMD(&rmd);
-#endif
-
- while (pktcount--) {
- if (CSR_RCVRC(s) <= 1)
- CSR_RCVRC(s) = CSR_RCVRL(s);
- else
- CSR_RCVRC(s)--;
- }
-
- pcnet_rdte_poll(s);
-
- }
- }
-
- pcnet_poll(s);
- pcnet_update_irq(s);
-}
-
-static void pcnet_transmit(PCNetState *s)
-{
- target_phys_addr_t xmit_cxda = 0;
- int count = CSR_XMTRL(s)-1;
- s->xmit_pos = -1;
-
- if (!CSR_TXON(s)) {
- s->csr[0] &= ~0x0008;
- return;
- }
-
- s->tx_busy = 1;
-
- txagain:
- if (pcnet_tdte_poll(s)) {
- struct pcnet_TMD tmd;
-
- 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) {
- cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
- s->buffer, 4096 - tmd.tmd1.bcnt);
- s->xmit_pos += 4096 - tmd.tmd1.bcnt;
- }
- xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
- }
- if (tmd.tmd1.enp && (s->xmit_pos >= 0)) {
- cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
- s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt);
- s->xmit_pos += 4096 - tmd.tmd1.bcnt;
-#ifdef PCNET_DEBUG
- printf("pcnet_transmit size=%d\n", s->xmit_pos);
-#endif
- if (CSR_LOOP(s))
- pcnet_receive(s, s->buffer, s->xmit_pos);
- else
- qemu_send_packet(s->vc, s->buffer, s->xmit_pos);
-
- s->csr[0] &= ~0x0008; /* clear TDMD */
- s->csr[4] |= 0x0004; /* set TXSTRT */
- s->xmit_pos = -1;
- }
-
- tmd.tmd1.own = 0;
- TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
- if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint))
- s->csr[0] |= 0x0200; /* set TINT */
-
- if (CSR_XMTRC(s)<=1)
- CSR_XMTRC(s) = CSR_XMTRL(s);
- else
- CSR_XMTRC(s)--;
- if (count--)
- goto txagain;
-
- } 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;
- TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda));
- s->csr[0] |= 0x0200; /* set TINT */
- if (!CSR_DXSUFLO(s)) {
- s->csr[0] &= ~0x0010;
- } else
- if (count--)
- goto txagain;
- }
-
- s->tx_busy = 0;
-}
-
-static void pcnet_poll(PCNetState *s)
-{
- if (CSR_RXON(s)) {
- pcnet_rdte_poll(s);
- }
-
- if (CSR_TDMD(s) ||
- (CSR_TXON(s) && !CSR_DPOLL(s) && pcnet_tdte_poll(s)))
- {
- /* prevent recursion */
- if (s->tx_busy)
- return;
-
- pcnet_transmit(s);
- }
-}
-
-static void pcnet_poll_timer(void *opaque)
-{
- PCNetState *s = opaque;
-
- qemu_del_timer(s->poll_timer);
-
- if (CSR_TDMD(s)) {
- pcnet_transmit(s);
- }
-
- pcnet_update_irq(s);
-
- if (!CSR_STOP(s) && !CSR_SPND(s) && !CSR_DPOLL(s)) {
- uint64_t now = qemu_get_clock(vm_clock) * 33;
- if (!s->timer || !now)
- s->timer = now;
- else {
- uint64_t t = now - s->timer + CSR_POLL(s);
- if (t > 0xffffLL) {
- pcnet_poll(s);
- CSR_POLL(s) = CSR_PINT(s);
- } else
- CSR_POLL(s) = t;
- }
- qemu_mod_timer(s->poll_timer,
- pcnet_get_next_poll_time(s,qemu_get_clock(vm_clock)));
- }
-}
-
-
-static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value)
-{
- uint16_t val = new_value;
-#ifdef PCNET_DEBUG_CSR
- printf("pcnet_csr_writew rap=%d val=0x%04x\n", rap, val);
-#endif
- switch (rap) {
- case 0:
- s->csr[0] &= ~(val & 0x7f00); /* Clear any interrupt flags */
-
- s->csr[0] = (s->csr[0] & ~0x0040) | (val & 0x0048);
-
- val = (val & 0x007f) | (s->csr[0] & 0x7f00);
-
- /* IFF STOP, STRT and INIT are set, clear STRT and INIT */
- if ((val&7) == 7)
- val &= ~3;
-
- if (!CSR_STOP(s) && (val & 4))
- pcnet_stop(s);
-
- if (!CSR_INIT(s) && (val & 1))
- pcnet_init(s);
-
- if (!CSR_STRT(s) && (val & 2))
- pcnet_start(s);
-
- if (CSR_TDMD(s))
- pcnet_transmit(s);
-
- return;
- case 1:
- case 2:
- case 8:
- case 9:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 15:
- case 18: /* CRBAL */
- case 19: /* CRBAU */
- case 20: /* CXBAL */
- case 21: /* CXBAU */
- case 22: /* NRBAU */
- case 23: /* NRBAU */
- case 24:
- case 25:
- case 26:
- case 27:
- case 28:
- case 29:
- case 30:
- case 31:
- case 32:
- case 33:
- case 34:
- case 35:
- case 36:
- case 37:
- case 38:
- case 39:
- case 40: /* CRBC */
- case 41:
- case 42: /* CXBC */
- case 43:
- case 44:
- case 45:
- case 46: /* POLL */
- case 47: /* POLLINT */
- case 72:
- case 74:
- case 76: /* RCVRL */
- case 78: /* XMTRL */
- case 112:
- if (CSR_STOP(s) || CSR_SPND(s))
- break;
- return;
- case 3:
- break;
- case 4:
- s->csr[4] &= ~(val & 0x026a);
- val &= ~0x026a; val |= s->csr[4] & 0x026a;
- break;
- case 5:
- s->csr[5] &= ~(val & 0x0a90);
- val &= ~0x0a90; val |= s->csr[5] & 0x0a90;
- break;
- case 16:
- pcnet_csr_writew(s,1,val);
- return;
- case 17:
- pcnet_csr_writew(s,2,val);
- return;
- case 58:
- pcnet_bcr_writew(s,BCR_SWS,val);
- break;
- default:
- return;
- }
- s->csr[rap] = val;
-}
-
-static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap)
-{
- uint32_t val;
- switch (rap) {
- case 0:
- pcnet_update_irq(s);
- val = s->csr[0];
- val |= (val & 0x7800) ? 0x8000 : 0;
- break;
- case 16:
- return pcnet_csr_readw(s,1);
- case 17:
- return pcnet_csr_readw(s,2);
- case 58:
- return pcnet_bcr_readw(s,BCR_SWS);
- case 88:
- val = s->csr[89];
- val <<= 16;
- val |= s->csr[88];
- break;
- default:
- val = s->csr[rap];
- }
-#ifdef PCNET_DEBUG_CSR
- printf("pcnet_csr_readw rap=%d val=0x%04x\n", rap, val);
-#endif
- return val;
-}
-
-static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
-{
- rap &= 127;
-#ifdef PCNET_DEBUG_BCR
- printf("pcnet_bcr_writew rap=%d val=0x%04x\n", rap, val);
-#endif
- switch (rap) {
- case BCR_SWS:
- if (!(CSR_STOP(s) || CSR_SPND(s)))
- return;
- val &= ~0x0300;
- switch (val & 0x00ff) {
- case 0:
- val |= 0x0200;
- break;
- case 1:
- val |= 0x0100;
- break;
- case 2:
- case 3:
- val |= 0x0300;
- break;
- default:
- printf("Bad SWSTYLE=0x%02x\n", val & 0xff);
- val = 0x0200;
- break;
- }
-#ifdef PCNET_DEBUG
- printf("BCR_SWS=0x%04x\n", val);
-#endif
- case BCR_LNKST:
- case BCR_LED1:
- case BCR_LED2:
- case BCR_LED3:
- case BCR_MC:
- case BCR_FDC:
- case BCR_BSBC:
- case BCR_EECAS:
- case BCR_PLAT:
- s->bcr[rap] = val;
- break;
- default:
- break;
- }
-}
-
-static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
-{
- uint32_t val;
- rap &= 127;
- switch (rap) {
- case BCR_LNKST:
- case BCR_LED1:
- case BCR_LED2:
- case BCR_LED3:
- val = s->bcr[rap] & ~0x8000;
- val |= (val & 0x017f & s->lnkst) ? 0x8000 : 0;
- break;
- default:
- val = rap < 32 ? s->bcr[rap] : 0;
- break;
- }
-#ifdef PCNET_DEBUG_BCR
- printf("pcnet_bcr_readw rap=%d val=0x%04x\n", rap, val);
-#endif
- return val;
-}
-
-static void pcnet_h_reset(PCNetState *s)
-{
- int i;
- uint16_t checksum;
-
- /* Initialize the PROM */
-
- memcpy(s->prom, s->nd->macaddr, 6);
- s->prom[12] = s->prom[13] = 0x00;
- s->prom[14] = s->prom[15] = 0x57;
-
- for (i = 0,checksum = 0; i < 16; i++)
- checksum += s->prom[i];
- *(uint16_t *)&s->prom[12] = cpu_to_le16(checksum);
-
-
- s->bcr[BCR_MSRDA] = 0x0005;
- s->bcr[BCR_MSWRA] = 0x0005;
- s->bcr[BCR_MC ] = 0x0002;
- s->bcr[BCR_LNKST] = 0x00c0;
- s->bcr[BCR_LED1 ] = 0x0084;
- s->bcr[BCR_LED2 ] = 0x0088;
- s->bcr[BCR_LED3 ] = 0x0090;
- s->bcr[BCR_FDC ] = 0x0000;
- s->bcr[BCR_BSBC ] = 0x9001;
- s->bcr[BCR_EECAS] = 0x0002;
- s->bcr[BCR_SWS ] = 0x0200;
- s->bcr[BCR_PLAT ] = 0xff06;
-
- pcnet_s_reset(s);
-}
-
-static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- PCNetState *s = opaque;
-#ifdef PCNET_DEBUG
- printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
- /* Check APROMWE bit to enable write access */
- if (pcnet_bcr_readw(s,2) & 0x80)
- s->prom[addr & 15] = val;
-}
-
-static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
-{
- PCNetState *s = opaque;
- uint32_t val = s->prom[addr &= 15];
-#ifdef PCNET_DEBUG
- printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
- return val;
-}
-
-static void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- PCNetState *s = opaque;
- pcnet_poll_timer(s);
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_writew addr=0x%08x val=0x%04x\n", addr, val);
-#endif
- if (!BCR_DWIO(s)) {
- switch (addr & 0x0f) {
- case 0x00: /* RDP */
- pcnet_csr_writew(s, s->rap, val);
- break;
- case 0x02:
- s->rap = val & 0x7f;
- break;
- case 0x06:
- pcnet_bcr_writew(s, s->rap, val);
- break;
- }
- }
- pcnet_update_irq(s);
-}
-
-static uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
-{
- PCNetState *s = opaque;
- uint32_t val = -1;
- pcnet_poll_timer(s);
- if (!BCR_DWIO(s)) {
- switch (addr & 0x0f) {
- case 0x00: /* RDP */
- val = pcnet_csr_readw(s, s->rap);
- break;
- case 0x02:
- val = s->rap;
- break;
- case 0x04:
- pcnet_s_reset(s);
- val = 0;
- break;
- case 0x06:
- val = pcnet_bcr_readw(s, s->rap);
- break;
- }
- }
- pcnet_update_irq(s);
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_readw addr=0x%08x val=0x%04x\n", addr, val & 0xffff);
-#endif
- return val;
-}
-
-static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- PCNetState *s = opaque;
- pcnet_poll_timer(s);
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_writel addr=0x%08x val=0x%08x\n", addr, val);
-#endif
- if (BCR_DWIO(s)) {
- switch (addr & 0x0f) {
- case 0x00: /* RDP */
- pcnet_csr_writew(s, s->rap, val & 0xffff);
- break;
- case 0x04:
- s->rap = val & 0x7f;
- break;
- case 0x0c:
- pcnet_bcr_writew(s, s->rap, val & 0xffff);
- break;
- }
- } else
- if ((addr & 0x0f) == 0) {
- /* switch device to dword i/o mode */
- pcnet_bcr_writew(s, BCR_BSBC, pcnet_bcr_readw(s, BCR_BSBC) | 0x0080);
-#ifdef PCNET_DEBUG_IO
- printf("device switched into dword i/o mode\n");
-#endif
- }
- pcnet_update_irq(s);
-}
-
-static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
-{
- PCNetState *s = opaque;
- uint32_t val = -1;
- pcnet_poll_timer(s);
- if (BCR_DWIO(s)) {
- switch (addr & 0x0f) {
- case 0x00: /* RDP */
- val = pcnet_csr_readw(s, s->rap);
- break;
- case 0x04:
- val = s->rap;
- break;
- case 0x08:
- pcnet_s_reset(s);
- val = 0;
- break;
- case 0x0c:
- val = pcnet_bcr_readw(s, s->rap);
- break;
- }
- }
- pcnet_update_irq(s);
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_readl addr=0x%08x val=0x%08x\n", addr, val);
-#endif
- return val;
-}
-
-static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- PCNetState *d = (PCNetState *)pci_dev;
-
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_map addr=0x%04x size=0x%04x\n", addr, size);
-#endif
-
- register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
- register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
-
- register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
- register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
- register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
- register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
-}
-
-static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_writeb addr=0x%08x val=0x%02x\n", addr, val);
-#endif
- if (!(addr & 0x10))
- pcnet_aprom_writeb(d, addr & 0x0f, val);
-}
-
-static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
-{
- PCNetState *d = opaque;
- uint32_t val = -1;
- if (!(addr & 0x10))
- val = pcnet_aprom_readb(d, addr & 0x0f);
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_readb addr=0x%08x val=0x%02x\n", addr, val & 0xff);
-#endif
- return val;
-}
-
-static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_writew addr=0x%08x val=0x%04x\n", addr, val);
-#endif
- if (addr & 0x10)
- pcnet_ioport_writew(d, addr & 0x0f, val);
- else {
- addr &= 0x0f;
- pcnet_aprom_writeb(d, addr, val & 0xff);
- pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
- }
-}
-
-static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
- PCNetState *d = opaque;
- uint32_t val = -1;
- if (addr & 0x10)
- val = pcnet_ioport_readw(d, addr & 0x0f);
- else {
- addr &= 0x0f;
- val = pcnet_aprom_readb(d, addr+1);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr);
- }
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_readw addr=0x%08x val = 0x%04x\n", addr, val & 0xffff);
-#endif
- return val;
-}
-
-static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PCNetState *d = opaque;
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_writel addr=0x%08x val=0x%08x\n", addr, val);
-#endif
- if (addr & 0x10)
- pcnet_ioport_writel(d, addr & 0x0f, val);
- else {
- addr &= 0x0f;
- pcnet_aprom_writeb(d, addr, val & 0xff);
- pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
- pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
- pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
- }
-}
-
-static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
- PCNetState *d = opaque;
- uint32_t val;
- if (addr & 0x10)
- val = pcnet_ioport_readl(d, addr & 0x0f);
- else {
- addr &= 0x0f;
- val = pcnet_aprom_readb(d, addr+3);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr+2);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr+1);
- val <<= 8;
- val |= pcnet_aprom_readb(d, addr);
- }
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_mmio_readl addr=0x%08x val=0x%08x\n", addr, val);
-#endif
- return val;
-}
-
-
-static CPUWriteMemoryFunc *pcnet_mmio_write[] = {
- (CPUWriteMemoryFunc *)&pcnet_mmio_writeb,
- (CPUWriteMemoryFunc *)&pcnet_mmio_writew,
- (CPUWriteMemoryFunc *)&pcnet_mmio_writel
-};
-
-static CPUReadMemoryFunc *pcnet_mmio_read[] = {
- (CPUReadMemoryFunc *)&pcnet_mmio_readb,
- (CPUReadMemoryFunc *)&pcnet_mmio_readw,
- (CPUReadMemoryFunc *)&pcnet_mmio_readl
-};
-
-static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- PCNetState *d = (PCNetState *)pci_dev;
-
-#ifdef PCNET_DEBUG_IO
- printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size);
-#endif
-
- cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr);
-}
-
-void pci_pcnet_init(PCIBus *bus, NICInfo *nd)
-{
- PCNetState *d;
- uint8_t *pci_conf;
-
-#if 0
- printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
- sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
-#endif
-
- d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState),
- -1, NULL, NULL);
-
- pci_conf = d->dev.config;
-
- *(uint16_t *)&pci_conf[0x00] = cpu_to_le16(0x1022);
- *(uint16_t *)&pci_conf[0x02] = cpu_to_le16(0x2000);
- *(uint16_t *)&pci_conf[0x04] = cpu_to_le16(0x0007);
- *(uint16_t *)&pci_conf[0x06] = cpu_to_le16(0x0280);
- pci_conf[0x08] = 0x10;
- pci_conf[0x09] = 0x00;
- pci_conf[0x0a] = 0x00; // ethernet network controller
- pci_conf[0x0b] = 0x02;
- pci_conf[0x0e] = 0x00; // header_type
-
- *(uint32_t *)&pci_conf[0x10] = cpu_to_le32(0x00000001);
- *(uint32_t *)&pci_conf[0x14] = cpu_to_le32(0x00000000);
-
- pci_conf[0x3d] = 1; // interrupt pin 0
- pci_conf[0x3e] = 0x06;
- pci_conf[0x3f] = 0xff;
-
- /* Handler for memory-mapped I/O */
- d->mmio_io_addr =
- cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d);
-
- pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE,
- PCI_ADDRESS_SPACE_IO, pcnet_ioport_map);
-
- pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
- PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map);
-
- d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d);
-
- d->nd = nd;
-
- d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive,
- pcnet_can_receive, d);
-
- snprintf(d->vc->info_str, sizeof(d->vc->info_str),
- "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
- d->nd->macaddr[0],
- d->nd->macaddr[1],
- d->nd->macaddr[2],
- d->nd->macaddr[3],
- d->nd->macaddr[4],
- d->nd->macaddr[5]);
-
- pcnet_h_reset(d);
-}
diff --git a/hw/pcspk.c b/hw/pcspk.c
deleted file mode 100644
index 0d52b31..0000000
--- a/hw/pcspk.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * QEMU PC speaker emulation
- *
- * Copyright (c) 2006 Joachim Henke
- *
- * 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 PCSPK_BUF_LEN 1792
-#define PCSPK_SAMPLE_RATE 32000
-#define PCSPK_MAX_FREQ (PCSPK_SAMPLE_RATE >> 1)
-#define PCSPK_MIN_COUNT ((PIT_FREQ + PCSPK_MAX_FREQ - 1) / PCSPK_MAX_FREQ)
-
-typedef struct {
- uint8_t sample_buf[PCSPK_BUF_LEN];
- QEMUSoundCard card;
- SWVoiceOut *voice;
- PITState *pit;
- unsigned int pit_count;
- unsigned int samples;
- unsigned int play_pos;
- int data_on;
- int dummy_refresh_clock;
-} PCSpkState;
-
-static const char *s_spk = "pcspk";
-static PCSpkState pcspk_state;
-
-static inline void generate_samples(PCSpkState *s)
-{
- unsigned int i;
-
- if (s->pit_count) {
- const uint32_t m = PCSPK_SAMPLE_RATE * s->pit_count;
- const uint32_t n = ((uint64_t)PIT_FREQ << 32) / m;
-
- /* multiple of wavelength for gapless looping */
- s->samples = (PCSPK_BUF_LEN * PIT_FREQ / m * m / (PIT_FREQ >> 1) + 1) >> 1;
- for (i = 0; i < s->samples; ++i)
- s->sample_buf[i] = (64 & (n * i >> 25)) - 32;
- } else {
- s->samples = PCSPK_BUF_LEN;
- for (i = 0; i < PCSPK_BUF_LEN; ++i)
- s->sample_buf[i] = 128; /* silence */
- }
-}
-
-static void pcspk_callback(void *opaque, int free)
-{
- PCSpkState *s = opaque;
- unsigned int n;
-
- if (pit_get_mode(s->pit, 2) != 3)
- return;
-
- n = pit_get_initial_count(s->pit, 2);
- /* avoid frequencies that are not reproducible with sample rate */
- if (n < PCSPK_MIN_COUNT)
- n = 0;
-
- if (s->pit_count != n) {
- s->pit_count = n;
- s->play_pos = 0;
- generate_samples(s);
- }
-
- while (free > 0) {
- n = audio_MIN(s->samples - s->play_pos, (unsigned int)free);
- n = AUD_write(s->voice, &s->sample_buf[s->play_pos], n);
- if (!n)
- break;
- s->play_pos = (s->play_pos + n) % s->samples;
- free -= n;
- }
-}
-
-int pcspk_audio_init(AudioState *audio)
-{
- PCSpkState *s = &pcspk_state;
- audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
-
- if (!audio) {
- AUD_log(s_spk, "No audio state\n");
- return -1;
- }
- AUD_register_card(audio, s_spk, &s->card);
-
- s->voice = AUD_open_out(&s->card, s->voice, s_spk, s, pcspk_callback, &as);
- if (!s->voice) {
- AUD_log(s_spk, "Could not open voice\n");
- return -1;
- }
-
- return 0;
-}
-
-static uint32_t pcspk_ioport_read(void *opaque, uint32_t addr)
-{
- PCSpkState *s = opaque;
- int out;
-
- s->dummy_refresh_clock ^= (1 << 4);
- out = pit_get_out(s->pit, 2, qemu_get_clock(vm_clock)) << 5;
-
- return pit_get_gate(s->pit, 2) | (s->data_on << 1) | s->dummy_refresh_clock | out;
-}
-
-static void pcspk_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- PCSpkState *s = opaque;
- const int gate = val & 1;
-
- s->data_on = (val >> 1) & 1;
- pit_set_gate(s->pit, 2, gate);
- if (s->voice) {
- if (gate) /* restart */
- s->play_pos = 0;
- AUD_set_active_out(s->voice, gate & s->data_on);
- }
-}
-
-void pcspk_init(PITState *pit)
-{
- PCSpkState *s = &pcspk_state;
-
- s->pit = pit;
- register_ioport_read(0x61, 1, 1, pcspk_ioport_read, s);
- register_ioport_write(0x61, 1, 1, pcspk_ioport_write, s);
-}
diff --git a/hw/pflash_cfi02.c b/hw/pflash_cfi02.c
deleted file mode 100644
index ee2f63a..0000000
--- a/hw/pflash_cfi02.c
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- * CFI parallel flash with AMD command set emulation
- *
- * Copyright (c) 2005 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
- */
-
-/*
- * For now, this code can emulate flashes of 1, 2 or 4 bytes width.
- * Supported commands/modes are:
- * - flash read
- * - flash write
- * - flash ID read
- * - sector erase
- * - chip erase
- * - unlock bypass command
- * - CFI queries
- *
- * It does not support flash interleaving.
- * It does not implement boot blocs with reduced size
- * It does not implement software data protection as found in many real chips
- * It does not implement erase suspend/resume commands
- * It does not implement multiple sectors erase
- */
-
-#include "vl.h"
-
-//#define PFLASH_DEBUG
-#ifdef PFLASH_DEBUG
-#define DPRINTF(fmt, args...) \
-do { \
- printf("PFLASH: " fmt , ##args); \
-} while (0)
-#else
-#define DPRINTF(fmt, args...) do { } while (0)
-#endif
-
-struct pflash_t {
- BlockDriverState *bs;
- target_ulong base;
- target_ulong sector_len;
- target_ulong total_len;
- int width;
- int wcycle; /* if 0, the flash is read normally */
- int bypass;
- int ro;
- uint8_t cmd;
- uint8_t status;
- uint16_t ident[4];
- uint8_t cfi_len;
- uint8_t cfi_table[0x52];
- QEMUTimer *timer;
- ram_addr_t off;
- int fl_mem;
- void *storage;
-};
-
-static void pflash_timer (void *opaque)
-{
- pflash_t *pfl = opaque;
-
- DPRINTF("%s: command %02x done\n", __func__, pfl->cmd);
- /* Reset flash */
- pfl->status ^= 0x80;
- if (pfl->bypass) {
- pfl->wcycle = 2;
- } else {
- cpu_register_physical_memory(pfl->base, pfl->total_len,
- pfl->off | IO_MEM_ROMD | pfl->fl_mem);
- pfl->wcycle = 0;
- }
- pfl->cmd = 0;
-}
-
-static uint32_t pflash_read (pflash_t *pfl, target_ulong offset, int width)
-{
- target_ulong boff;
- uint32_t ret;
- uint8_t *p;
-
- DPRINTF("%s: offset %08x\n", __func__, offset);
- ret = -1;
- offset -= pfl->base;
- boff = offset & 0xFF;
- if (pfl->width == 2)
- boff = boff >> 1;
- else if (pfl->width == 4)
- boff = boff >> 2;
- switch (pfl->cmd) {
- default:
- /* This should never happen : reset state & treat it as a read*/
- DPRINTF("%s: unknown command state: %x\n", __func__, pfl->cmd);
- pfl->wcycle = 0;
- pfl->cmd = 0;
- case 0x80:
- /* We accept reads during second unlock sequence... */
- case 0x00:
- flash_read:
- /* Flash area read */
- p = pfl->storage;
- switch (width) {
- case 1:
- ret = p[offset];
-// DPRINTF("%s: data offset %08x %02x\n", __func__, offset, ret);
- break;
- case 2:
-#if defined(TARGET_WORDS_BIGENDIAN)
- ret = p[offset] << 8;
- ret |= p[offset + 1];
-#else
- ret = p[offset];
- ret |= p[offset + 1] << 8;
-#endif
-// DPRINTF("%s: data offset %08x %04x\n", __func__, offset, ret);
- break;
- case 4:
-#if defined(TARGET_WORDS_BIGENDIAN)
- ret = p[offset] << 24;
- ret |= p[offset + 1] << 16;
- ret |= p[offset + 2] << 8;
- ret |= p[offset + 3];
-#else
- ret = p[offset];
- ret |= p[offset + 1] << 8;
- ret |= p[offset + 1] << 8;
- ret |= p[offset + 2] << 16;
- ret |= p[offset + 3] << 24;
-#endif
-// DPRINTF("%s: data offset %08x %08x\n", __func__, offset, ret);
- break;
- }
- break;
- case 0x90:
- /* flash ID read */
- switch (boff) {
- case 0x00:
- case 0x01:
- ret = pfl->ident[boff & 0x01];
- break;
- case 0x02:
- ret = 0x00; /* Pretend all sectors are unprotected */
- break;
- case 0x0E:
- case 0x0F:
- if (pfl->ident[2 + (boff & 0x01)] == (uint8_t)-1)
- goto flash_read;
- ret = pfl->ident[2 + (boff & 0x01)];
- break;
- default:
- goto flash_read;
- }
- DPRINTF("%s: ID %d %x\n", __func__, boff, ret);
- break;
- case 0xA0:
- case 0x10:
- case 0x30:
- /* Status register read */
- ret = pfl->status;
- DPRINTF("%s: status %x\n", __func__, ret);
- /* Toggle bit 6 */
- pfl->status ^= 0x40;
- break;
- case 0x98:
- /* CFI query mode */
- if (boff > pfl->cfi_len)
- ret = 0;
- else
- ret = pfl->cfi_table[boff];
- break;
- }
-
- return ret;
-}
-
-/* update flash content on disk */
-static void pflash_update(pflash_t *pfl, int offset,
- int size)
-{
- int offset_end;
- if (pfl->bs) {
- offset_end = offset + size;
- /* round to sectors */
- offset = offset >> 9;
- offset_end = (offset_end + 511) >> 9;
- bdrv_write(pfl->bs, offset, pfl->storage + (offset << 9),
- offset_end - offset);
- }
-}
-
-static void pflash_write (pflash_t *pfl, target_ulong offset, uint32_t value,
- int width)
-{
- target_ulong boff;
- uint8_t *p;
- uint8_t cmd;
-
- /* 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) {
- DPRINTF("%s: flash reset asked (%02x %02x)\n",
- __func__, pfl->cmd, cmd);
- goto reset_flash;
- }
- /* 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);
- if (pfl->width == 2)
- boff = boff >> 1;
- else if (pfl->width == 4)
- boff = boff >> 2;
- switch (pfl->wcycle) {
- case 0:
- /* We're in read mode */
- check_unlock0:
- if (boff == 0x55 && cmd == 0x98) {
- enter_CFI_mode:
- /* Enter CFI query mode */
- pfl->wcycle = 7;
- pfl->cmd = 0x98;
- return;
- }
- if (boff != 0x555 || cmd != 0xAA) {
- DPRINTF("%s: unlock0 failed %04x %02x %04x\n",
- __func__, boff, cmd, 0x555);
- goto reset_flash;
- }
- DPRINTF("%s: unlock sequence started\n", __func__);
- break;
- case 1:
- /* We started an unlock sequence */
- check_unlock1:
- if (boff != 0x2AA || cmd != 0x55) {
- DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd);
- goto reset_flash;
- }
- DPRINTF("%s: unlock sequence done\n", __func__);
- break;
- case 2:
- /* We finished an unlock sequence */
- if (!pfl->bypass && boff != 0x555) {
- DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd);
- goto reset_flash;
- }
- switch (cmd) {
- case 0x20:
- pfl->bypass = 1;
- goto do_bypass;
- case 0x80:
- case 0x90:
- case 0xA0:
- pfl->cmd = cmd;
- DPRINTF("%s: starting command %02x\n", __func__, cmd);
- break;
- default:
- DPRINTF("%s: unknown command %02x\n", __func__, cmd);
- goto reset_flash;
- }
- break;
- case 3:
- switch (pfl->cmd) {
- case 0x80:
- /* We need another unlock sequence */
- goto check_unlock0;
- case 0xA0:
- DPRINTF("%s: write data offset %08x %08x %d\n",
- __func__, offset, value, width);
- p = pfl->storage;
- switch (width) {
- case 1:
- p[offset] &= value;
- pflash_update(pfl, offset, 1);
- break;
- case 2:
-#if defined(TARGET_WORDS_BIGENDIAN)
- p[offset] &= value >> 8;
- p[offset + 1] &= value;
-#else
- p[offset] &= value;
- p[offset + 1] &= value >> 8;
-#endif
- pflash_update(pfl, offset, 2);
- break;
- case 4:
-#if defined(TARGET_WORDS_BIGENDIAN)
- p[offset] &= value >> 24;
- p[offset + 1] &= value >> 16;
- p[offset + 2] &= value >> 8;
- p[offset + 3] &= value;
-#else
- p[offset] &= value;
- p[offset + 1] &= value >> 8;
- p[offset + 2] &= value >> 16;
- p[offset + 3] &= value >> 24;
-#endif
- pflash_update(pfl, offset, 4);
- break;
- }
- pfl->status = 0x00 | ~(value & 0x80);
- /* Let's pretend write is immediate */
- if (pfl->bypass)
- goto do_bypass;
- goto reset_flash;
- case 0x90:
- if (pfl->bypass && cmd == 0x00) {
- /* Unlock bypass reset */
- goto reset_flash;
- }
- /* We can enter CFI query mode from autoselect mode */
- if (boff == 0x55 && cmd == 0x98)
- goto enter_CFI_mode;
- /* No break here */
- default:
- DPRINTF("%s: invalid write for command %02x\n",
- __func__, pfl->cmd);
- goto reset_flash;
- }
- case 4:
- switch (pfl->cmd) {
- case 0xA0:
- /* Ignore writes while flash data write is occuring */
- /* As we suppose write is immediate, this should never happen */
- return;
- case 0x80:
- goto check_unlock1;
- default:
- /* Should never happen */
- DPRINTF("%s: invalid command state %02x (wc 4)\n",
- __func__, pfl->cmd);
- goto reset_flash;
- }
- break;
- case 5:
- switch (cmd) {
- case 0x10:
- if (boff != 0x555) {
- DPRINTF("%s: chip erase: invalid address %04x\n",
- __func__, offset);
- goto reset_flash;
- }
- /* Chip erase */
- DPRINTF("%s: start chip erase\n", __func__);
- memset(pfl->storage, 0xFF, pfl->total_len);
- pfl->status = 0x00;
- pflash_update(pfl, 0, pfl->total_len);
- /* Let's wait 5 seconds before chip erase is done */
- qemu_mod_timer(pfl->timer,
- qemu_get_clock(vm_clock) + (ticks_per_sec * 5));
- break;
- case 0x30:
- /* Sector erase */
- p = pfl->storage;
- offset &= ~(pfl->sector_len - 1);
- DPRINTF("%s: start sector erase at %08x\n", __func__, offset);
- memset(p + offset, 0xFF, pfl->sector_len);
- pflash_update(pfl, offset, pfl->sector_len);
- pfl->status = 0x00;
- /* Let's wait 1/2 second before sector erase is done */
- qemu_mod_timer(pfl->timer,
- qemu_get_clock(vm_clock) + (ticks_per_sec / 2));
- break;
- default:
- DPRINTF("%s: invalid command %02x (wc 5)\n", __func__, cmd);
- goto reset_flash;
- }
- pfl->cmd = cmd;
- break;
- case 6:
- switch (pfl->cmd) {
- case 0x10:
- /* Ignore writes during chip erase */
- return;
- case 0x30:
- /* Ignore writes during sector erase */
- return;
- default:
- /* Should never happen */
- DPRINTF("%s: invalid command state %02x (wc 6)\n",
- __func__, pfl->cmd);
- goto reset_flash;
- }
- break;
- case 7: /* Special value for CFI queries */
- DPRINTF("%s: invalid write in CFI query mode\n", __func__);
- goto reset_flash;
- default:
- /* Should never happen */
- DPRINTF("%s: invalid write state (wc 7)\n", __func__);
- goto reset_flash;
- }
- pfl->wcycle++;
-
- return;
-
- /* 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);
- }
- pfl->bypass = 0;
- pfl->wcycle = 0;
- pfl->cmd = 0;
- return;
-
- do_bypass:
- pfl->wcycle = 2;
- pfl->cmd = 0;
- return;
-}
-
-
-static uint32_t pflash_readb (void *opaque, target_phys_addr_t addr)
-{
- return pflash_read(opaque, addr, 1);
-}
-
-static uint32_t pflash_readw (void *opaque, target_phys_addr_t addr)
-{
- pflash_t *pfl = opaque;
-
- return pflash_read(pfl, addr, 2);
-}
-
-static uint32_t pflash_readl (void *opaque, target_phys_addr_t addr)
-{
- pflash_t *pfl = opaque;
-
- return pflash_read(pfl, addr, 4);
-}
-
-static void pflash_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- pflash_write(opaque, addr, value, 1);
-}
-
-static void pflash_writew (void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- pflash_t *pfl = opaque;
-
- pflash_write(pfl, addr, value, 2);
-}
-
-static void pflash_writel (void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- pflash_t *pfl = opaque;
-
- pflash_write(pfl, addr, value, 4);
-}
-
-static CPUWriteMemoryFunc *pflash_write_ops[] = {
- &pflash_writeb,
- &pflash_writew,
- &pflash_writel,
-};
-
-static CPUReadMemoryFunc *pflash_read_ops[] = {
- &pflash_readb,
- &pflash_readw,
- &pflash_readl,
-};
-
-/* Count trailing zeroes of a 32 bits quantity */
-static int ctz32 (uint32_t n)
-{
- int ret;
-
- ret = 0;
- if (!(n & 0xFFFF)) {
- ret += 16;
- n = n >> 16;
- }
- if (!(n & 0xFF)) {
- ret += 8;
- n = n >> 8;
- }
- if (!(n & 0xF)) {
- ret += 4;
- n = n >> 4;
- }
- if (!(n & 0x3)) {
- ret += 2;
- n = n >> 2;
- }
- if (!(n & 0x1)) {
- ret++;
- n = n >> 1;
- }
-#if 0 /* This is not necessary as n is never 0 */
- if (!n)
- ret++;
-#endif
-
- return ret;
-}
-
-pflash_t *pflash_register (target_ulong base, ram_addr_t off,
- BlockDriverState *bs,
- target_ulong sector_len, int nb_blocs, int width,
- uint16_t id0, uint16_t id1,
- uint16_t id2, uint16_t id3)
-{
- pflash_t *pfl;
- target_long total_len;
-
- total_len = sector_len * nb_blocs;
- /* XXX: to be fixed */
- if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
- total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
- return NULL;
- 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->off = off;
- cpu_register_physical_memory(base, total_len,
- off | pfl->fl_mem | IO_MEM_ROMD);
- pfl->bs = bs;
- if (pfl->bs) {
- /* read the initial flash content */
- bdrv_read(pfl->bs, 0, pfl->storage, total_len >> 9);
- }
-#if 0 /* XXX: there should be a bit to set up read-only,
- * the same way the hardware does (with WP pin).
- */
- pfl->ro = 1;
-#else
- pfl->ro = 0;
-#endif
- pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);
- pfl->base = base;
- pfl->sector_len = sector_len;
- pfl->total_len = total_len;
- pfl->width = width;
- pfl->wcycle = 0;
- pfl->cmd = 0;
- pfl->status = 0;
- pfl->ident[0] = id0;
- pfl->ident[1] = id1;
- pfl->ident[2] = id2;
- pfl->ident[3] = id3;
- /* Hardcoded CFI table (mostly from SG29 Spansion flash) */
- pfl->cfi_len = 0x52;
- /* Standard "QRY" string */
- pfl->cfi_table[0x10] = 'Q';
- pfl->cfi_table[0x11] = 'R';
- pfl->cfi_table[0x12] = 'Y';
- /* Command set (AMD/Fujitsu) */
- pfl->cfi_table[0x13] = 0x02;
- pfl->cfi_table[0x14] = 0x00;
- /* Primary extended table address (none) */
- pfl->cfi_table[0x15] = 0x00;
- pfl->cfi_table[0x16] = 0x00;
- /* Alternate command set (none) */
- pfl->cfi_table[0x17] = 0x00;
- pfl->cfi_table[0x18] = 0x00;
- /* Alternate extended table (none) */
- pfl->cfi_table[0x19] = 0x00;
- pfl->cfi_table[0x1A] = 0x00;
- /* Vcc min */
- pfl->cfi_table[0x1B] = 0x27;
- /* Vcc max */
- pfl->cfi_table[0x1C] = 0x36;
- /* Vpp min (no Vpp pin) */
- pfl->cfi_table[0x1D] = 0x00;
- /* Vpp max (no Vpp pin) */
- pfl->cfi_table[0x1E] = 0x00;
- /* Reserved */
- pfl->cfi_table[0x1F] = 0x07;
- /* Timeout for min size buffer write (16 µs) */
- pfl->cfi_table[0x20] = 0x04;
- /* Typical timeout for block erase (512 ms) */
- pfl->cfi_table[0x21] = 0x09;
- /* Typical timeout for full chip erase (4096 ms) */
- pfl->cfi_table[0x22] = 0x0C;
- /* Reserved */
- pfl->cfi_table[0x23] = 0x01;
- /* Max timeout for buffer write */
- pfl->cfi_table[0x24] = 0x04;
- /* Max timeout for block erase */
- pfl->cfi_table[0x25] = 0x0A;
- /* Max timeout for chip erase */
- pfl->cfi_table[0x26] = 0x0D;
- /* Device size */
- pfl->cfi_table[0x27] = ctz32(total_len) + 1;
- /* Flash device interface (8 & 16 bits) */
- pfl->cfi_table[0x28] = 0x02;
- pfl->cfi_table[0x29] = 0x00;
- /* Max number of bytes in multi-bytes write */
- pfl->cfi_table[0x2A] = 0x05;
- pfl->cfi_table[0x2B] = 0x00;
- /* Number of erase block regions (uniform) */
- pfl->cfi_table[0x2C] = 0x01;
- /* Erase block region 1 */
- pfl->cfi_table[0x2D] = nb_blocs - 1;
- pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;
- pfl->cfi_table[0x2F] = sector_len >> 8;
- pfl->cfi_table[0x30] = sector_len >> 16;
-
- return pfl;
-}
diff --git a/hw/piix_pci.c b/hw/piix_pci.c
deleted file mode 100644
index 1f7ad94..0000000
--- a/hw/piix_pci.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * QEMU i440FX/PIIX3 PCI Bridge Emulation
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "vl.h"
-typedef uint32_t pci_addr_t;
-#include "pci_host.h"
-
-typedef PCIHostState I440FXState;
-
-static void i440fx_addr_writel(void* opaque, uint32_t addr, uint32_t val)
-{
- I440FXState *s = opaque;
- s->config_reg = val;
-}
-
-static uint32_t i440fx_addr_readl(void* opaque, uint32_t addr)
-{
- I440FXState *s = opaque;
- return s->config_reg;
-}
-
-static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level);
-
-PCIBus *i440fx_init(void)
-{
- PCIBus *b;
- PCIDevice *d;
- I440FXState *s;
-
- s = qemu_mallocz(sizeof(I440FXState));
- b = pci_register_bus(piix3_set_irq, NULL, 0);
- s->bus = b;
-
- register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
- register_ioport_read(0xcf8, 4, 4, i440fx_addr_readl, s);
-
- register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
- register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
- register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
- register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
- register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
- register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
-
- d = pci_register_device(b, "i440FX", sizeof(PCIDevice), 0,
- NULL, NULL);
-
- d->config[0x00] = 0x86; // vendor_id
- d->config[0x01] = 0x80;
- d->config[0x02] = 0x37; // device_id
- d->config[0x03] = 0x12;
- d->config[0x08] = 0x02; // revision
- d->config[0x0a] = 0x00; // class_sub = host2pci
- d->config[0x0b] = 0x06; // class_base = PCI_bridge
- d->config[0x0e] = 0x00; // header_type
- return b;
-}
-
-/* PIIX3 PCI to ISA bridge */
-
-static PCIDevice *piix3_dev;
-
-/* just used for simpler irq handling. */
-#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
-
-static uint32_t pci_irq_levels[4][PCI_IRQ_WORDS];
-
-/* return the global irq number corresponding to a given device irq
- pin. We could also use the bus number to have a more precise
- mapping. */
-static inline int pci_slot_get_pirq(PCIDevice *pci_dev, int irq_num)
-{
- int slot_addend;
- slot_addend = (pci_dev->devfn >> 3) - 1;
- return (irq_num + slot_addend) & 3;
-}
-
-static inline int get_pci_irq_level(int irq_num)
-{
- int pic_level;
-#if (PCI_IRQ_WORDS == 2)
- pic_level = ((pci_irq_levels[irq_num][0] |
- pci_irq_levels[irq_num][1]) != 0);
-#else
- {
- int i;
- pic_level = 0;
- for(i = 0; i < PCI_IRQ_WORDS; i++) {
- if (pci_irq_levels[irq_num][i]) {
- pic_level = 1;
- break;
- }
- }
- }
-#endif
- return pic_level;
-}
-
-static void piix3_set_irq(PCIDevice *pci_dev, void *pic, int irq_num, int level)
-{
- int irq_index, shift, pic_irq, pic_level;
- uint32_t *p;
-
- irq_num = pci_slot_get_pirq(pci_dev, irq_num);
- irq_index = pci_dev->irq_index;
- p = &pci_irq_levels[irq_num][irq_index >> 5];
- shift = (irq_index & 0x1f);
- *p = (*p & ~(1 << shift)) | (level << shift);
-
- /* now we change the pic irq level according to the piix irq mappings */
- /* XXX: optimize */
- pic_irq = piix3_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;
- if (pic_irq == piix3_dev->config[0x60])
- pic_level |= get_pci_irq_level(0);
- if (pic_irq == piix3_dev->config[0x61])
- pic_level |= get_pci_irq_level(1);
- if (pic_irq == piix3_dev->config[0x62])
- pic_level |= get_pci_irq_level(2);
- if (pic_irq == piix3_dev->config[0x63])
- pic_level |= get_pci_irq_level(3);
- pic_set_irq(pic_irq, pic_level);
- }
-}
-
-static void piix3_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] = 0x80;
- 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[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;
-}
-
-int piix3_init(PCIBus *bus)
-{
- PCIDevice *d;
- uint8_t *pci_conf;
-
- d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
- -1, NULL, NULL);
- register_savevm("PIIX3", 0, 1, generic_pci_save, generic_pci_load, d);
-
- piix3_dev = d;
- pci_conf = d->config;
-
- pci_conf[0x00] = 0x86; // Intel
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x00; // 82371SB PIIX3 PCI-to-ISA bridge (Step A1)
- pci_conf[0x03] = 0x70;
- 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;
-}
-
-/***********************************************************/
-/* XXX: the following should be moved to the PC BIOS */
-
-static __attribute__((unused)) uint32_t isa_inb(uint32_t addr)
-{
- return cpu_inb(NULL, addr);
-}
-
-static void isa_outb(uint32_t val, uint32_t addr)
-{
- cpu_outb(NULL, addr, val);
-}
-
-static __attribute__((unused)) uint32_t isa_inw(uint32_t addr)
-{
- return cpu_inw(NULL, addr);
-}
-
-static __attribute__((unused)) void isa_outw(uint32_t val, uint32_t addr)
-{
- cpu_outw(NULL, addr, val);
-}
-
-static __attribute__((unused)) uint32_t isa_inl(uint32_t addr)
-{
- return cpu_inl(NULL, addr);
-}
-
-static __attribute__((unused)) void isa_outl(uint32_t val, uint32_t addr)
-{
- cpu_outl(NULL, addr, val);
-}
-
-static uint32_t pci_bios_io_addr;
-static uint32_t pci_bios_mem_addr;
-/* host irqs corresponding to PCI irqs A-D */
-static uint8_t pci_irqs[4] = { 11, 9, 11, 9 };
-
-static void pci_config_writel(PCIDevice *d, uint32_t addr, uint32_t val)
-{
- PCIBus *s = d->bus;
- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
- pci_data_write(s, addr, val, 4);
-}
-
-static void pci_config_writew(PCIDevice *d, uint32_t addr, uint32_t val)
-{
- PCIBus *s = d->bus;
- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
- pci_data_write(s, addr, val, 2);
-}
-
-static void pci_config_writeb(PCIDevice *d, uint32_t addr, uint32_t val)
-{
- PCIBus *s = d->bus;
- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
- pci_data_write(s, addr, val, 1);
-}
-
-static __attribute__((unused)) uint32_t pci_config_readl(PCIDevice *d, uint32_t addr)
-{
- PCIBus *s = d->bus;
- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
- return pci_data_read(s, addr, 4);
-}
-
-static uint32_t pci_config_readw(PCIDevice *d, uint32_t addr)
-{
- PCIBus *s = d->bus;
- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
- return pci_data_read(s, addr, 2);
-}
-
-static uint32_t pci_config_readb(PCIDevice *d, uint32_t addr)
-{
- PCIBus *s = d->bus;
- addr |= (pci_bus_num(s) << 16) | (d->devfn << 8);
- return pci_data_read(s, addr, 1);
-}
-
-static void pci_set_io_region_addr(PCIDevice *d, int region_num, uint32_t addr)
-{
- PCIIORegion *r;
- uint16_t cmd;
- uint32_t ofs;
-
- if ( region_num == PCI_ROM_SLOT ) {
- ofs = 0x30;
- }else{
- ofs = 0x10 + region_num * 4;
- }
-
- pci_config_writel(d, ofs, addr);
- r = &d->io_regions[region_num];
-
- /* enable memory mappings */
- cmd = pci_config_readw(d, PCI_COMMAND);
- if ( region_num == PCI_ROM_SLOT )
- cmd |= 2;
- else if (r->type & PCI_ADDRESS_SPACE_IO)
- cmd |= 1;
- else
- cmd |= 2;
- pci_config_writew(d, PCI_COMMAND, cmd);
-}
-
-static void pci_bios_init_device(PCIDevice *d)
-{
- int class;
- PCIIORegion *r;
- uint32_t *paddr;
- int i, pin, pic_irq, vendor_id, device_id;
-
- class = pci_config_readw(d, PCI_CLASS_DEVICE);
- vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
- device_id = pci_config_readw(d, PCI_DEVICE_ID);
- switch(class) {
- case 0x0101:
- if (vendor_id == 0x8086 && device_id == 0x7010) {
- /* PIIX3 IDE */
- pci_config_writew(d, 0x40, 0x8000); // enable IDE0
- pci_config_writew(d, 0x42, 0x8000); // enable IDE1
- goto default_map;
- } else {
- /* IDE: we map it as in ISA mode */
- pci_set_io_region_addr(d, 0, 0x1f0);
- pci_set_io_region_addr(d, 1, 0x3f4);
- pci_set_io_region_addr(d, 2, 0x170);
- pci_set_io_region_addr(d, 3, 0x374);
- }
- break;
- case 0x0300:
- if (vendor_id != 0x1234)
- goto default_map;
- /* VGA: map frame buffer to default Bochs VBE address */
- pci_set_io_region_addr(d, 0, 0xE0000000);
- break;
- case 0x0800:
- /* PIC */
- vendor_id = pci_config_readw(d, PCI_VENDOR_ID);
- device_id = pci_config_readw(d, PCI_DEVICE_ID);
- if (vendor_id == 0x1014) {
- /* IBM */
- if (device_id == 0x0046 || device_id == 0xFFFF) {
- /* MPIC & MPIC2 */
- pci_set_io_region_addr(d, 0, 0x80800000 + 0x00040000);
- }
- }
- break;
- case 0xff00:
- if (vendor_id == 0x0106b &&
- (device_id == 0x0017 || device_id == 0x0022)) {
- /* macio bridge */
- pci_set_io_region_addr(d, 0, 0x80800000);
- }
- break;
- default:
- default_map:
- /* default memory mappings */
- for(i = 0; i < PCI_NUM_REGIONS; i++) {
- r = &d->io_regions[i];
- if (r->size) {
- if (r->type & PCI_ADDRESS_SPACE_IO)
- paddr = &pci_bios_io_addr;
- else
- paddr = &pci_bios_mem_addr;
- *paddr = (*paddr + r->size - 1) & ~(r->size - 1);
- pci_set_io_region_addr(d, i, *paddr);
- *paddr += r->size;
- }
- }
- break;
- }
-
- /* map the interrupt */
- pin = pci_config_readb(d, PCI_INTERRUPT_PIN);
- if (pin != 0) {
- pin = pci_slot_get_pirq(d, pin - 1);
- pic_irq = pci_irqs[pin];
- pci_config_writeb(d, PCI_INTERRUPT_LINE, pic_irq);
- }
-}
-
-/*
- * This function initializes the PCI devices as a normal PCI BIOS
- * would do. It is provided just in case the BIOS has no support for
- * PCI.
- */
-void pci_bios_init(void)
-{
- int i, irq;
- uint8_t elcr[2];
-
- pci_bios_io_addr = 0xc000;
- pci_bios_mem_addr = 0xf0000000;
-
- /* activate IRQ mappings */
- elcr[0] = 0x00;
- elcr[1] = 0x00;
- for(i = 0; i < 4; i++) {
- irq = pci_irqs[i];
- /* set to trigger level */
- elcr[irq >> 3] |= (1 << (irq & 7));
- /* activate irq remapping in PIIX */
- pci_config_writeb(piix3_dev, 0x60 + i, irq);
- }
- isa_outb(elcr[0], 0x4d0);
- isa_outb(elcr[1], 0x4d1);
-
- pci_for_each_device(pci_bios_init_device);
-}
-
diff --git a/hw/pl011.c b/hw/pl011.c
deleted file mode 100644
index 657f03b..0000000
--- a/hw/pl011.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Arm PrimeCell PL011 UART
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the GPL.
- */
-
-#include "vl.h"
-
-typedef struct {
- uint32_t base;
- uint32_t readbuff;
- uint32_t flags;
- uint32_t lcr;
- uint32_t cr;
- uint32_t dmacr;
- uint32_t int_enabled;
- uint32_t int_level;
- uint32_t read_fifo[16];
- uint32_t ilpr;
- uint32_t ibrd;
- uint32_t fbrd;
- uint32_t ifl;
- int read_pos;
- int read_count;
- int read_trigger;
- CharDriverState *chr;
- void *pic;
- int irq;
-} pl011_state;
-
-#define PL011_INT_TX 0x20
-#define PL011_INT_RX 0x10
-
-#define PL011_FLAG_TXFE 0x80
-#define PL011_FLAG_RXFF 0x40
-#define PL011_FLAG_TXFF 0x20
-#define PL011_FLAG_RXFE 0x10
-
-static const unsigned char pl011_id[] =
-{ 0x11, 0x10, 0x14, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl011_update(pl011_state *s)
-{
- uint32_t flags;
-
- flags = s->int_level & s->int_enabled;
- pic_set_irq_new(s->pic, s->irq, flags != 0);
-}
-
-static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
-{
- pl011_state *s = (pl011_state *)opaque;
- uint32_t c;
-
- offset -= s->base;
- if (offset >= 0xfe0 && offset < 0x1000) {
- return pl011_id[(offset - 0xfe0) >> 2];
- }
- switch (offset >> 2) {
- case 0: /* UARTDR */
- s->flags &= ~PL011_FLAG_RXFF;
- c = s->read_fifo[s->read_pos];
- if (s->read_count > 0) {
- s->read_count--;
- if (++s->read_pos == 16)
- s->read_pos = 0;
- }
- if (s->read_count == 0) {
- s->flags |= PL011_FLAG_RXFE;
- }
- if (s->read_count == s->read_trigger - 1)
- s->int_level &= ~ PL011_INT_RX;
- pl011_update(s);
- return c;
- case 1: /* UARTCR */
- return 0;
- case 6: /* UARTFR */
- return s->flags;
- case 8: /* UARTILPR */
- return s->ilpr;
- case 9: /* UARTIBRD */
- return s->ibrd;
- case 10: /* UARTFBRD */
- return s->fbrd;
- case 11: /* UARTLCR_H */
- return s->lcr;
- case 12: /* UARTCR */
- return s->cr;
- case 13: /* UARTIFLS */
- return s->ifl;
- case 14: /* UARTIMSC */
- return s->int_enabled;
- case 15: /* UARTRIS */
- return s->int_level;
- case 16: /* UARTMIS */
- return s->int_level & s->int_enabled;
- case 18: /* UARTDMACR */
- return s->dmacr;
- default:
- cpu_abort (cpu_single_env, "pl011_read: Bad offset %x\n", offset);
- return 0;
- }
-}
-
-static void pl011_set_read_trigger(pl011_state *s)
-{
-#if 0
- /* The docs say the RX interrupt is triggered when the FIFO exceeds
- the threshold. However linux only reads the FIFO in response to an
- interrupt. Triggering the interrupt when the FIFO is non-empty seems
- to make things work. */
- if (s->lcr & 0x10)
- s->read_trigger = (s->ifl >> 1) & 0x1c;
- else
-#endif
- s->read_trigger = 1;
-}
-
-static void pl011_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- pl011_state *s = (pl011_state *)opaque;
- unsigned char ch;
-
- offset -= s->base;
- switch (offset >> 2) {
- case 0: /* UARTDR */
- /* ??? Check if transmitter is enabled. */
- ch = value;
- if (s->chr)
- qemu_chr_write(s->chr, &ch, 1);
- s->int_level |= PL011_INT_TX;
- pl011_update(s);
- break;
- case 1: /* UARTCR */
- s->cr = value;
- break;
- case 8: /* UARTUARTILPR */
- s->ilpr = value;
- break;
- case 9: /* UARTIBRD */
- s->ibrd = value;
- break;
- case 10: /* UARTFBRD */
- s->fbrd = value;
- break;
- case 11: /* UARTLCR_H */
- s->lcr = value;
- pl011_set_read_trigger(s);
- break;
- case 12: /* UARTCR */
- /* ??? Need to implement the enable and loopback bits. */
- s->cr = value;
- break;
- case 13: /* UARTIFS */
- s->ifl = value;
- pl011_set_read_trigger(s);
- break;
- case 14: /* UARTIMSC */
- s->int_enabled = value;
- pl011_update(s);
- break;
- case 17: /* UARTICR */
- s->int_level &= ~value;
- pl011_update(s);
- break;
- case 18: /* UARTDMACR */
- s->dmacr = value;
- if (value & 3)
- cpu_abort(cpu_single_env, "PL011: DMA not implemented\n");
- break;
- default:
- cpu_abort (cpu_single_env, "pl011_write: Bad offset %x\n", offset);
- }
-}
-
-static int pl011_can_recieve(void *opaque)
-{
- pl011_state *s = (pl011_state *)opaque;
-
- if (s->lcr & 0x10)
- return s->read_count < 16;
- else
- return s->read_count < 1;
-}
-
-static void pl011_recieve(void *opaque, const uint8_t *buf, int size)
-{
- pl011_state *s = (pl011_state *)opaque;
- int slot;
-
- slot = s->read_pos + s->read_count;
- if (slot >= 16)
- slot -= 16;
- s->read_fifo[slot] = *buf;
- s->read_count++;
- s->flags &= ~PL011_FLAG_RXFE;
- if (s->cr & 0x10 || s->read_count == 16) {
- s->flags |= PL011_FLAG_RXFF;
- }
- if (s->read_count == s->read_trigger) {
- s->int_level |= PL011_INT_RX;
- pl011_update(s);
- }
-}
-
-static void pl011_event(void *opaque, int event)
-{
- /* ??? Should probably implement break. */
-}
-
-static CPUReadMemoryFunc *pl011_readfn[] = {
- pl011_read,
- pl011_read,
- pl011_read
-};
-
-static CPUWriteMemoryFunc *pl011_writefn[] = {
- pl011_write,
- pl011_write,
- pl011_write
-};
-
-void pl011_init(uint32_t base, void *pic, int irq,
- CharDriverState *chr)
-{
- int iomemtype;
- pl011_state *s;
-
- s = (pl011_state *)qemu_mallocz(sizeof(pl011_state));
- iomemtype = cpu_register_io_memory(0, pl011_readfn,
- 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;
- s->ifl = 0x12;
- 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);
- }
- /* ??? Save/restore. */
-}
-
diff --git a/hw/pl050.c b/hw/pl050.c
deleted file mode 100644
index 20451e5..0000000
--- a/hw/pl050.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Arm PrimeCell PL050 Keyboard / Mouse Interface
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the GPL.
- */
-
-#include "vl.h"
-
-typedef struct {
- void *dev;
- uint32_t base;
- uint32_t cr;
- uint32_t clk;
- uint32_t last;
- void *pic;
- int pending;
- int irq;
- int is_mouse;
-} pl050_state;
-
-static const unsigned char pl050_id[] =
-{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl050_update(void *opaque, int level)
-{
- pl050_state *s = (pl050_state *)opaque;
- int raise;
-
- s->pending = level;
- raise = (s->pending && (s->cr & 0x10) != 0)
- || (s->cr & 0x08) != 0;
- pic_set_irq_new(s->pic, s->irq, raise);
-}
-
-static uint32_t pl050_read(void *opaque, target_phys_addr_t offset)
-{
- pl050_state *s = (pl050_state *)opaque;
- offset -= s->base;
- if (offset >= 0xfe0 && offset < 0x1000)
- return pl050_id[(offset - 0xfe0) >> 2];
-
- switch (offset >> 2) {
- case 0: /* KMICR */
- return s->cr;
- case 1: /* KMISTAT */
- /* KMIC and KMID bits not implemented. */
- if (s->pending) {
- return 0x10;
- } else {
- return 0;
- }
- case 2: /* KMIDATA */
- if (s->pending)
- s->last = ps2_read_data(s->dev);
- return s->last;
- case 3: /* KMICLKDIV */
- return s->clk;
- case 4: /* KMIIR */
- return s->pending | 2;
- default:
- cpu_abort (cpu_single_env, "pl050_read: Bad offset %x\n", offset);
- return 0;
- }
-}
-
-static void pl050_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- pl050_state *s = (pl050_state *)opaque;
- offset -= s->base;
- switch (offset >> 2) {
- case 0: /* KMICR */
- s->cr = value;
- pl050_update(s, s->pending);
- /* ??? Need to implement the enable/disable bit. */
- break;
- case 2: /* KMIDATA */
- /* ??? This should toggle the TX interrupt line. */
- /* ??? This means kbd/mouse can block each other. */
- if (s->is_mouse) {
- ps2_write_mouse(s->dev, value);
- } else {
- ps2_write_keyboard(s->dev, value);
- }
- break;
- case 3: /* KMICLKDIV */
- s->clk = value;
- return;
- default:
- cpu_abort (cpu_single_env, "pl050_write: Bad offset %x\n", offset);
- }
-}
-static CPUReadMemoryFunc *pl050_readfn[] = {
- pl050_read,
- pl050_read,
- pl050_read
-};
-
-static CPUWriteMemoryFunc *pl050_writefn[] = {
- pl050_write,
- pl050_write,
- pl050_write
-};
-
-void pl050_init(uint32_t base, void *pic, int irq, int is_mouse)
-{
- int iomemtype;
- pl050_state *s;
-
- s = (pl050_state *)qemu_mallocz(sizeof(pl050_state));
- iomemtype = cpu_register_io_memory(0, pl050_readfn,
- 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)
- s->dev = ps2_mouse_init(pl050_update, s);
- else
- s->dev = ps2_kbd_init(pl050_update, s);
- /* ??? Save/restore. */
-}
-
diff --git a/hw/pl080.c b/hw/pl080.c
deleted file mode 100644
index 49996ca..0000000
--- a/hw/pl080.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Arm PrimeCell PL080 DMA controller
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the GPL.
- */
-
-#include "vl.h"
-
-#define PL080_NUM_CHANNELS 8
-#define PL080_CONF_E 0x1
-#define PL080_CONF_M1 0x2
-#define PL080_CONF_M2 0x4
-
-#define PL080_CCONF_H 0x40000
-#define PL080_CCONF_A 0x20000
-#define PL080_CCONF_L 0x10000
-#define PL080_CCONF_ITC 0x08000
-#define PL080_CCONF_IE 0x04000
-#define PL080_CCONF_E 0x00001
-
-#define PL080_CCTRL_I 0x80000000
-#define PL080_CCTRL_DI 0x08000000
-#define PL080_CCTRL_SI 0x04000000
-#define PL080_CCTRL_D 0x02000000
-#define PL080_CCTRL_S 0x01000000
-
-typedef struct {
- uint32_t src;
- uint32_t dest;
- uint32_t lli;
- uint32_t ctrl;
- uint32_t conf;
-} pl080_channel;
-
-typedef struct {
- uint32_t base;
- uint8_t tc_int;
- uint8_t tc_mask;
- uint8_t err_int;
- uint8_t err_mask;
- uint32_t conf;
- uint32_t sync;
- uint32_t req_single;
- uint32_t req_burst;
- pl080_channel chan[PL080_NUM_CHANNELS];
- /* Flag to avoid recursive DMA invocations. */
- int running;
- void *pic;
- int irq;
-} pl080_state;
-
-static const unsigned char pl080_id[] =
-{ 0x80, 0x10, 0x04, 0x0a, 0x0d, 0xf0, 0x05, 0xb1 };
-
-static void pl080_update(pl080_state *s)
-{
- if ((s->tc_int & s->tc_mask)
- || (s->err_int & s->err_mask))
- pic_set_irq_new(s->pic, s->irq, 1);
- else
- pic_set_irq_new(s->pic, s->irq, 1);
-}
-
-static void pl080_run(pl080_state *s)
-{
- int c;
- int flow;
- pl080_channel *ch;
- int swidth;
- int dwidth;
- int xsize;
- int n;
- int src_id;
- int dest_id;
- int size;
- char buff[4];
- uint32_t req;
-
- s->tc_mask = 0;
- for (c = 0; c < PL080_NUM_CHANNELS; c++) {
- if (s->chan[c].conf & PL080_CCONF_ITC)
- s->tc_mask |= 1 << c;
- if (s->chan[c].conf & PL080_CCONF_IE)
- s->err_mask |= 1 << c;
- }
-
- if ((s->conf & PL080_CONF_E) == 0)
- return;
-
-cpu_abort(cpu_single_env, "DMA active\n");
- /* If we are already in the middle of a DMA operation then indicate that
- there may be new DMA requests and return immediately. */
- if (s->running) {
- s->running++;
- return;
- }
- s->running = 1;
- while (s->running) {
- for (c = 0; c < PL080_NUM_CHANNELS; c++) {
- ch = &s->chan[c];
-again:
- /* Test if thiws channel has any pending DMA requests. */
- if ((ch->conf & (PL080_CCONF_H | PL080_CCONF_E))
- != PL080_CCONF_E)
- continue;
- flow = (ch->conf >> 11) & 7;
- if (flow >= 4) {
- cpu_abort(cpu_single_env,
- "pl080_run: Peripheral flow control not implemented\n");
- }
- src_id = (ch->conf >> 1) & 0x1f;
- dest_id = (ch->conf >> 6) & 0x1f;
- size = ch->ctrl & 0xfff;
- req = s->req_single | s->req_burst;
- switch (flow) {
- case 0:
- break;
- case 1:
- if ((req & (1u << dest_id)) == 0)
- size = 0;
- break;
- case 2:
- if ((req & (1u << src_id)) == 0)
- size = 0;
- break;
- case 3:
- if ((req & (1u << src_id)) == 0
- || (req & (1u << dest_id)) == 0)
- size = 0;
- break;
- }
- if (!size)
- continue;
-
- /* Transfer one element. */
- /* ??? Should transfer multiple elements for a burst request. */
- /* ??? Unclear what the proper behavior is when source and
- destination widths are different. */
- swidth = 1 << ((ch->ctrl >> 18) & 7);
- dwidth = 1 << ((ch->ctrl >> 21) & 7);
- for (n = 0; n < dwidth; n+= swidth) {
- cpu_physical_memory_read(ch->src, buff + n, swidth);
- if (ch->ctrl & PL080_CCTRL_SI)
- ch->src += swidth;
- }
- xsize = (dwidth < swidth) ? swidth : dwidth;
- /* ??? This may pad the value incorrectly for dwidth < 32. */
- for (n = 0; n < xsize; n += dwidth) {
- cpu_physical_memory_write(ch->dest + n, buff + n, dwidth);
- if (ch->ctrl & PL080_CCTRL_DI)
- ch->dest += swidth;
- }
-
- size--;
- ch->ctrl = (ch->ctrl & 0xfffff000) | size;
- if (size == 0) {
- /* Transfer complete. */
- if (ch->lli) {
- ch->src = ldl_phys(ch->lli);
- ch->dest = ldl_phys(ch->lli + 4);
- ch->ctrl = ldl_phys(ch->lli + 12);
- ch->lli = ldl_phys(ch->lli + 8);
- } else {
- ch->conf &= ~PL080_CCONF_E;
- }
- if (ch->ctrl & PL080_CCTRL_I) {
- s->tc_int |= 1 << c;
- }
- }
- goto again;
- }
- if (--s->running)
- s->running = 1;
- }
-}
-
-static uint32_t pl080_read(void *opaque, target_phys_addr_t offset)
-{
- pl080_state *s = (pl080_state *)opaque;
- uint32_t i;
- uint32_t mask;
-
- offset -= s->base;
- if (offset >= 0xfe0 && offset < 0x1000) {
- return pl080_id[(offset - 0xfe0) >> 2];
- }
- if (offset >= 0x100 && offset < 0x200) {
- i = (offset & 0xe0) >> 5;
- switch (offset >> 2) {
- case 0: /* SrcAddr */
- return s->chan[i].src;
- case 1: /* DestAddr */
- return s->chan[i].dest;
- case 2: /* LLI */
- return s->chan[i].lli;
- case 3: /* Control */
- return s->chan[i].ctrl;
- case 4: /* Configuration */
- return s->chan[i].conf;
- default:
- goto bad_offset;
- }
- }
- switch (offset >> 2) {
- case 0: /* IntStatus */
- return (s->tc_int & s->tc_mask) | (s->err_int & s->err_mask);
- case 1: /* IntTCStatus */
- return (s->tc_int & s->tc_mask);
- case 3: /* IntErrorStatus */
- return (s->err_int & s->err_mask);
- case 5: /* RawIntTCStatus */
- return s->tc_int;
- case 6: /* RawIntErrorStatus */
- return s->err_int;
- case 7: /* EnbldChns */
- mask = 0;
- for (i = 0; i < PL080_NUM_CHANNELS; i++) {
- if (s->chan[i].conf & PL080_CCONF_E)
- mask |= 1 << i;
- }
- return mask;
- case 8: /* SoftBReq */
- case 9: /* SoftSReq */
- case 10: /* SoftLBReq */
- case 11: /* SoftLSReq */
- /* ??? Implement these. */
- return 0;
- case 12: /* Configuration */
- return s->conf;
- case 13: /* Sync */
- return s->sync;
- default:
- bad_offset:
- cpu_abort(cpu_single_env, "pl080_read: Bad offset %x\n", offset);
- return 0;
- }
-}
-
-static void pl080_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- pl080_state *s = (pl080_state *)opaque;
- int i;
-
- offset -= s->base;
- if (offset >= 0x100 && offset < 0x200) {
- i = (offset & 0xe0) >> 5;
- switch (offset >> 2) {
- case 0: /* SrcAddr */
- s->chan[i].src = value;
- break;
- case 1: /* DestAddr */
- s->chan[i].dest = value;
- break;
- case 2: /* LLI */
- s->chan[i].lli = value;
- break;
- case 3: /* Control */
- s->chan[i].ctrl = value;
- break;
- case 4: /* Configuration */
- s->chan[i].conf = value;
- pl080_run(s);
- break;
- }
- }
- switch (offset >> 2) {
- case 2: /* IntTCClear */
- s->tc_int &= ~value;
- break;
- case 4: /* IntErrorClear */
- s->err_int &= ~value;
- break;
- case 8: /* SoftBReq */
- case 9: /* SoftSReq */
- case 10: /* SoftLBReq */
- case 11: /* SoftLSReq */
- /* ??? Implement these. */
- cpu_abort(cpu_single_env, "pl080_write: Soft DMA not implemented\n");
- break;
- case 12: /* Configuration */
- s->conf = value;
- if (s->conf & (PL080_CONF_M1 | PL080_CONF_M1)) {
- cpu_abort(cpu_single_env,
- "pl080_write: Big-endian DMA not implemented\n");
- }
- pl080_run(s);
- break;
- case 13: /* Sync */
- s->sync = value;
- break;
- default:
- cpu_abort(cpu_single_env, "pl080_write: Bad offset %x\n", offset);
- }
- pl080_update(s);
-}
-
-static CPUReadMemoryFunc *pl080_readfn[] = {
- pl080_read,
- pl080_read,
- pl080_read
-};
-
-static CPUWriteMemoryFunc *pl080_writefn[] = {
- pl080_write,
- pl080_write,
- pl080_write
-};
-
-void *pl080_init(uint32_t base, void *pic, int irq)
-{
- int iomemtype;
- pl080_state *s;
-
- s = (pl080_state *)qemu_mallocz(sizeof(pl080_state));
- iomemtype = cpu_register_io_memory(0, pl080_readfn,
- pl080_writefn, s);
- cpu_register_physical_memory(base, 0x00000fff, iomemtype);
- s->base = base;
- s->pic = pic;
- s->irq = irq;
- /* ??? Save/restore. */
- return s;
-}
-
diff --git a/hw/pl110.c b/hw/pl110.c
deleted file mode 100644
index ecebe35..0000000
--- a/hw/pl110.c
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
- * Arm PrimeCell PL110 Color LCD Controller
- *
- * Copyright (c) 2005-2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the GNU LGPL
- */
-
-#include "vl.h"
-
-#define PL110_CR_EN 0x001
-#define PL110_CR_BEBO 0x200
-#define PL110_CR_BEPO 0x400
-#define PL110_CR_PWR 0x800
-
-enum pl110_bppmode
-{
- BPP_1,
- BPP_2,
- BPP_4,
- BPP_8,
- BPP_16,
- BPP_32
-};
-
-typedef struct {
- uint32_t base;
- 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;
- uint32_t lpbase;
- uint32_t int_status;
- uint32_t int_mask;
- int cols;
- int rows;
- enum pl110_bppmode bpp;
- int invalidate;
- uint32_t pallette[256];
- uint32_t raw_pallette[128];
- int irq;
-} pl110_state;
-
-static const unsigned char pl110_id[] =
-{ 0x10, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-
-/* The Arm documentation (DDI0224C) says the CLDC on the Versatile board
- has a different ID. However Linux only looks for the normal ID. */
-#if 0
-static const unsigned char pl110_versatile_id[] =
-{ 0x93, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
-#else
-#define pl110_versatile_id pl110_id
-#endif
-
-static inline uint32_t rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
-{
- return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
-}
-
-static inline uint32_t rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
-{
- return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
-}
-
-static inline uint32_t rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
-{
- return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
-}
-
-static inline uint32_t rgb_to_pixel24(unsigned int r, unsigned int g, unsigned b)
-{
- return (r << 16) | (g << 8) | b;
-}
-
-static inline uint32_t rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
-{
- return (r << 16) | (g << 8) | b;
-}
-
-typedef void (*drawfn)(uint32_t *, uint8_t *, const uint8_t *, int);
-
-#define BITS 8
-#include "pl110_template.h"
-#define BITS 15
-#include "pl110_template.h"
-#define BITS 16
-#include "pl110_template.h"
-#define BITS 24
-#include "pl110_template.h"
-#define BITS 32
-#include "pl110_template.h"
-
-static int pl110_enabled(pl110_state *s)
-{
- return (s->cr & PL110_CR_EN) && (s->cr & PL110_CR_PWR);
-}
-
-static void pl110_update_display(void *opaque)
-{
- pl110_state *s = (pl110_state *)opaque;
- drawfn* fntable;
- drawfn fn;
- uint32_t *pallette;
- uint32_t addr;
- uint32_t base;
- int dest_width;
- int src_width;
- uint8_t *dest;
- uint8_t *src;
- int first, last = 0;
- int dirty, new_dirty;
- int i;
-
- if (!pl110_enabled(s))
- return;
-
- switch (s->ds->depth) {
- case 0:
- return;
- case 8:
- fntable = pl110_draw_fn_8;
- dest_width = 1;
- break;
- case 15:
- fntable = pl110_draw_fn_15;
- dest_width = 2;
- break;
- case 16:
- fntable = pl110_draw_fn_16;
- dest_width = 2;
- break;
- case 24:
- fntable = pl110_draw_fn_24;
- dest_width = 3;
- break;
- case 32:
- fntable = pl110_draw_fn_32;
- dest_width = 4;
- break;
- default:
- fprintf(stderr, "pl110: Bad color depth\n");
- exit(1);
- }
- if (s->cr & PL110_CR_BEBO)
- fn = fntable[s->bpp + 6];
- else if (s->cr & PL110_CR_BEPO)
- fn = fntable[s->bpp + 12];
- else
- fn = fntable[s->bpp];
-
- src_width = s->cols;
- switch (s->bpp) {
- case BPP_1:
- src_width >>= 3;
- break;
- case BPP_2:
- src_width >>= 2;
- break;
- case BPP_4:
- src_width >>= 1;
- break;
- case BPP_8:
- break;
- case BPP_16:
- src_width <<= 1;
- break;
- case BPP_32:
- src_width <<= 2;
- break;
- }
- dest_width *= s->cols;
- pallette = s->pallette;
- base = s->upbase;
- /* HACK: Arm aliases physical memory at 0x80000000. */
- if (base > 0x80000000)
- base -= 0x80000000;
- src = phys_ram_base + base;
- dest = s->ds->data;
- first = -1;
- addr = base;
-
- dirty = cpu_physical_memory_get_dirty(addr, VGA_DIRTY_FLAG);
- for (i = 0; i < s->rows; i++) {
- new_dirty = 0;
- if ((addr & TARGET_PAGE_MASK) + src_width >= TARGET_PAGE_SIZE) {
- uint32_t tmp;
- for (tmp = 0; tmp < src_width; tmp += TARGET_PAGE_SIZE) {
- new_dirty |= cpu_physical_memory_get_dirty(addr + tmp,
- VGA_DIRTY_FLAG);
- }
- }
-
- if (dirty || new_dirty || s->invalidate) {
- fn(pallette, dest, src, s->cols);
- if (first == -1)
- first = i;
- last = i;
- }
- dirty = new_dirty;
- addr += src_width;
- dest += dest_width;
- src += src_width;
- }
- if (first < 0)
- return;
-
- s->invalidate = 0;
- cpu_physical_memory_reset_dirty(base + first * src_width,
- base + (last + 1) * src_width,
- VGA_DIRTY_FLAG);
- dpy_update(s->ds, 0, first, s->cols, last - first + 1);
-}
-
-static void pl110_invalidate_display(void * opaque)
-{
- pl110_state *s = (pl110_state *)opaque;
- s->invalidate = 1;
-}
-
-static void pl110_update_pallette(pl110_state *s, int n)
-{
- int i;
- uint32_t raw;
- unsigned int r, g, b;
-
- raw = s->raw_pallette[n];
- n <<= 1;
- for (i = 0; i < 2; i++) {
- r = (raw & 0x1f) << 3;
- raw >>= 5;
- g = (raw & 0x1f) << 3;
- raw >>= 5;
- b = (raw & 0x1f) << 3;
- /* The I bit is ignored. */
- raw >>= 6;
- switch (s->ds->depth) {
- case 8:
- s->pallette[n] = rgb_to_pixel8(r, g, b);
- break;
- case 15:
- s->pallette[n] = rgb_to_pixel15(r, g, b);
- break;
- case 16:
- s->pallette[n] = rgb_to_pixel16(r, g, b);
- break;
- case 24:
- case 32:
- s->pallette[n] = rgb_to_pixel32(r, g, b);
- break;
- }
- n++;
- }
-}
-
-static void pl110_resize(pl110_state *s, int width, int height)
-{
- if (width != s->cols || height != s->rows) {
- if (pl110_enabled(s)) {
- dpy_resize(s->ds, width, height);
- }
- }
- s->cols = width;
- s->rows = height;
-}
-
-/* Update interrupts. */
-static void pl110_update(pl110_state *s)
-{
- /* TODO: Implement interrupts. */
-}
-
-static uint32_t pl110_read(void *opaque, target_phys_addr_t offset)
-{
- pl110_state *s = (pl110_state *)opaque;
-
- offset -= s->base;
- if (offset >= 0xfe0 && offset < 0x1000) {
- if (s->versatile)
- return pl110_versatile_id[(offset - 0xfe0) >> 2];
- else
- return pl110_id[(offset - 0xfe0) >> 2];
- }
- if (offset >= 0x200 && offset < 0x400) {
- return s->raw_pallette[(offset - 0x200) >> 2];
- }
- switch (offset >> 2) {
- case 0: /* LCDTiming0 */
- return s->timing[0];
- case 1: /* LCDTiming1 */
- return s->timing[1];
- case 2: /* LCDTiming2 */
- return s->timing[2];
- case 3: /* LCDTiming3 */
- return s->timing[3];
- case 4: /* LCDUPBASE */
- return s->upbase;
- case 5: /* LCDLPBASE */
- return s->lpbase;
- case 6: /* LCDIMSC */
- return s->int_mask;
- case 7: /* LCDControl */
- return s->cr;
- case 8: /* LCDRIS */
- return s->int_status;
- case 9: /* LCDMIS */
- return s->int_status & s->int_mask;
- case 11: /* LCDUPCURR */
- /* TODO: Implement vertical refresh. */
- return s->upbase;
- case 12: /* LCDLPCURR */
- return s->lpbase;
- default:
- cpu_abort (cpu_single_env, "pl110_read: Bad offset %x\n", offset);
- return 0;
- }
-}
-
-static void pl110_write(void *opaque, target_phys_addr_t offset,
- uint32_t val)
-{
- pl110_state *s = (pl110_state *)opaque;
- int n;
-
- /* For simplicity invalidate the display whenever a control register
- is writen to. */
- s->invalidate = 1;
- offset -= s->base;
- if (offset >= 0x200 && offset < 0x400) {
- /* Pallette. */
- n = (offset - 0x200) >> 2;
- s->raw_pallette[(offset - 0x200) >> 2] = val;
- pl110_update_pallette(s, n);
- return;
- }
- switch (offset >> 2) {
- case 0: /* LCDTiming0 */
- s->timing[0] = val;
- n = ((val & 0xfc) + 4) * 4;
- pl110_resize(s, n, s->rows);
- break;
- case 1: /* LCDTiming1 */
- s->timing[1] = val;
- n = (val & 0x3ff) + 1;
- pl110_resize(s, s->cols, n);
- break;
- case 2: /* LCDTiming2 */
- s->timing[2] = val;
- break;
- case 3: /* LCDTiming3 */
- s->timing[3] = val;
- break;
- case 4: /* LCDUPBASE */
- s->upbase = val;
- break;
- case 5: /* LCDLPBASE */
- s->lpbase = val;
- break;
- case 6: /* LCDIMSC */
- if (s->versatile)
- goto control;
- imsc:
- s->int_mask = val;
- pl110_update(s);
- break;
- case 7: /* LCDControl */
- if (s->versatile)
- goto imsc;
- control:
- s->cr = val;
- s->bpp = (val >> 1) & 7;
- if (pl110_enabled(s)) {
- dpy_resize(s->ds, s->cols, s->rows);
- }
- break;
- case 10: /* LCDICR */
- s->int_status &= ~val;
- pl110_update(s);
- break;
- default:
- cpu_abort (cpu_single_env, "pl110_write: Bad offset %x\n", offset);
- }
-}
-
-static CPUReadMemoryFunc *pl110_readfn[] = {
- pl110_read,
- pl110_read,
- pl110_read
-};
-
-static CPUWriteMemoryFunc *pl110_writefn[] = {
- pl110_write,
- pl110_write,
- pl110_write
-};
-
-void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq,
- int versatile)
-{
- pl110_state *s;
- int iomemtype;
-
- s = (pl110_state *)qemu_mallocz(sizeof(pl110_state));
- iomemtype = cpu_register_io_memory(0, pl110_readfn,
- pl110_writefn, s);
- cpu_register_physical_memory(base, 0x00000fff, iomemtype);
- 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);
- /* ??? Save/restore. */
- return s;
-}
diff --git a/hw/pl110_template.h b/hw/pl110_template.h
deleted file mode 100644
index db05035..0000000
--- a/hw/pl110_template.h
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Arm PrimeCell PL110 Color LCD Controller
- *
- * Copyright (c) 2005 CodeSourcery, LLC.
- * Written by Paul Brook
- *
- * This code is licenced under the GNU LGPL
- *
- * Framebuffer format conversion routines.
- */
-
-#ifndef ORDER
-
-#if BITS == 8
-#define COPY_PIXEL(to, from) *(to++) = from
-#elif BITS == 15 || BITS == 16
-#define COPY_PIXEL(to, from) *(uint16_t *)to = from; to += 2;
-#elif BITS == 24
-#define COPY_PIXEL(to, from) \
- *(to++) = from; *(to++) = (from) >> 8; *(to++) = (from) >> 16
-#elif BITS == 32
-#define COPY_PIXEL(to, from) *(uint32_t *)to = from; to += 4;
-#else
-#error unknown bit depth
-#endif
-
-#define ORDER 0
-#include "pl110_template.h"
-#define ORDER 1
-#include "pl110_template.h"
-#define ORDER 2
-#include "pl110_template.h"
-
-static drawfn glue(pl110_draw_fn_,BITS)[18] =
-{
- glue(pl110_draw_line1_lblp,BITS),
- glue(pl110_draw_line2_lblp,BITS),
- glue(pl110_draw_line4_lblp,BITS),
- glue(pl110_draw_line8_lblp,BITS),
- glue(pl110_draw_line16_lblp,BITS),
- glue(pl110_draw_line32_lblp,BITS),
-
- glue(pl110_draw_line1_bbbp,BITS),
- glue(pl110_draw_line2_bbbp,BITS),
- glue(pl110_draw_line4_bbbp,BITS),
- glue(pl110_draw_line8_bbbp,BITS),
- glue(pl110_draw_line16_bbbp,BITS),
- glue(pl110_draw_line32_bbbp,BITS),
-
- glue(pl110_draw_line1_lbbp,BITS),
- glue(pl110_draw_line2_lbbp,BITS),
- glue(pl110_draw_line4_lbbp,BITS),
- glue(pl110_draw_line8_lbbp,BITS),
- glue(pl110_draw_line16_lbbp,BITS),
- glue(pl110_draw_line32_lbbp,BITS)
-};
-
-#undef BITS
-#undef COPY_PIXEL
-
-#else
-
-#if ORDER == 0
-#define NAME glue(lblp, BITS)
-#ifdef WORDS_BIGENDIAN
-#define SWAP_WORDS 1
-#endif
-#elif ORDER == 1
-#define NAME glue(bbbp, BITS)
-#ifndef WORDS_BIGENDIAN
-#define SWAP_WORDS 1
-#endif
-#else
-#define SWAP_PIXELS 1
-#define NAME glue(lbbp, BITS)
-#ifdef WORDS_BIGENDIAN
-#define SWAP_WORDS 1
-#endif
-#endif
-
-#define FN_2(x, y) FN(x, y) FN(x+1, y)
-#define FN_4(x, y) FN_2(x, y) FN_2(x+1, y)
-#define FN_8(y) FN_4(0, y) FN_4(4, y)
-
-static void glue(pl110_draw_line1_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
-{
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 7 - (x))) & 1]);
-#else
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x) + y)) & 1]);
-#endif
-#ifdef SWAP_WORDS
- FN_8(24)
- FN_8(16)
- FN_8(8)
- FN_8(0)
-#else
- FN_8(0)
- FN_8(8)
- FN_8(16)
- FN_8(24)
-#endif
-#undef FN
- width -= 32;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line2_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
-{
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 6 - (x)*2)) & 3]);
-#else
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*2 + y)) & 3]);
-#endif
-#ifdef SWAP_WORDS
- FN_4(0, 24)
- FN_4(0, 16)
- FN_4(0, 8)
- FN_4(0, 0)
-#else
- FN_4(0, 0)
- FN_4(0, 8)
- FN_4(0, 16)
- FN_4(0, 24)
-#endif
-#undef FN
- width -= 16;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line4_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
-{
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_PIXELS
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> (y + 4 - (x)*4)) & 0xf]);
-#else
-#define FN(x, y) COPY_PIXEL(d, pallette[(data >> ((x)*4 + y)) & 0xf]);
-#endif
-#ifdef SWAP_WORDS
- FN_2(0, 24)
- FN_2(0, 16)
- FN_2(0, 8)
- FN_2(0, 0)
-#else
- FN_2(0, 0)
- FN_2(0, 8)
- FN_2(0, 16)
- FN_2(0, 24)
-#endif
-#undef FN
- width -= 8;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line8_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
-{
- uint32_t data;
- while (width > 0) {
- data = *(uint32_t *)src;
-#define FN(x) COPY_PIXEL(d, pallette[(data >> (x)) & 0xff]);
-#ifdef SWAP_WORDS
- FN(24)
- FN(16)
- FN(8)
- FN(0)
-#else
- FN(0)
- FN(8)
- FN(16)
- FN(24)
-#endif
-#undef FN
- width -= 4;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line16_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_WORDS
- data = bswap32(data);
-#endif
-#if 0
- r = data & 0x1f;
- data >>= 5;
- g = data & 0x3f;
- data >>= 6;
- b = data & 0x1f;
- data >>= 5;
-#else
- r = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- b = (data & 0x1f) << 3;
- data >>= 5;
-#endif
- COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
- r = (data & 0x1f) << 3;
- data >>= 5;
- g = (data & 0x3f) << 2;
- data >>= 6;
- b = (data & 0x1f) << 3;
- data >>= 5;
- COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
- width -= 2;
- src += 4;
- }
-}
-
-static void glue(pl110_draw_line32_,NAME)(uint32_t *pallette, uint8_t *d, const uint8_t *src, int width)
-{
- uint32_t data;
- unsigned int r, g, b;
- while (width > 0) {
- data = *(uint32_t *)src;
-#ifdef SWAP_WORDS
- r = data & 0xff;
- g = (data >> 8) & 0xff;
- b = (data >> 16) & 0xff;
-#else
- r = (data >> 24) & 0xff;
- g = (data >> 16) & 0xff;
- b = (data >> 8) & 0xff;
-#endif
- COPY_PIXEL(d, glue(rgb_to_pixel,BITS)(r, g, b));
- width--;
- src += 4;
- }
-}
-
-#undef SWAP_PIXELS
-#undef NAME
-#undef SWAP_WORDS
-#undef ORDER
-
-#endif
diff --git a/hw/pl190.c b/hw/pl190.c
deleted file mode 100644
index 55c7180..0000000
--- a/hw/pl190.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Arm PrimeCell PL190 Vector Interrupt Controller
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the GPL.
- */
-
-#include "vl.h"
-#include "arm_pic.h"
-
-/* The number of virtual priority levels. 16 user vectors plus the
- unvectored IRQ. Chained interrupts would require an additional level
- if implemented. */
-
-#define PL190_NUM_PRIO 17
-
-typedef struct {
- arm_pic_handler handler;
- uint32_t base;
- DisplayState *ds;
- uint32_t level;
- uint32_t soft_level;
- uint32_t irq_enable;
- uint32_t fiq_select;
- uint32_t default_addr;
- uint8_t vect_control[16];
- uint32_t vect_addr[PL190_NUM_PRIO];
- /* Mask containing interrupts with higher priority than this one. */
- uint32_t prio_mask[PL190_NUM_PRIO + 1];
- int protected;
- /* Current priority level. */
- int priority;
- int prev_prio[PL190_NUM_PRIO];
- void *parent;
- int irq;
- int fiq;
-} pl190_state;
-
-static const unsigned char pl190_id[] =
-{ 0x90, 0x11, 0x04, 0x00, 0x0D, 0xf0, 0x05, 0xb1 };
-
-static inline uint32_t pl190_irq_level(pl190_state *s)
-{
- return (s->level | s->soft_level) & s->irq_enable & ~s->fiq_select;
-}
-
-/* Update interrupts. */
-static void pl190_update(pl190_state *s)
-{
- uint32_t level = pl190_irq_level(s);
- int set;
-
- set = (level & s->prio_mask[s->priority]) != 0;
- pic_set_irq_new(s->parent, s->irq, set);
- set = ((s->level | s->soft_level) & s->fiq_select) != 0;
- pic_set_irq_new(s->parent, s->fiq, set);
-}
-
-static void pl190_set_irq(void *opaque, int irq, int level)
-{
- pl190_state *s = (pl190_state *)opaque;
-
- if (level)
- s->level |= 1u << irq;
- else
- s->level &= ~(1u << irq);
- pl190_update(s);
-}
-
-static void pl190_update_vectors(pl190_state *s)
-{
- uint32_t mask;
- int i;
- int n;
-
- mask = 0;
- for (i = 0; i < 16; i++)
- {
- s->prio_mask[i] = mask;
- if (s->vect_control[i] & 0x20)
- {
- n = s->vect_control[i] & 0x1f;
- mask |= 1 << n;
- }
- }
- s->prio_mask[16] = mask;
- pl190_update(s);
-}
-
-static uint32_t pl190_read(void *opaque, target_phys_addr_t offset)
-{
- pl190_state *s = (pl190_state *)opaque;
- int i;
-
- offset -= s->base;
- if (offset >= 0xfe0 && offset < 0x1000) {
- return pl190_id[(offset - 0xfe0) >> 2];
- }
- if (offset >= 0x100 && offset < 0x140) {
- return s->vect_addr[(offset - 0x100) >> 2];
- }
- if (offset >= 0x200 && offset < 0x240) {
- return s->vect_control[(offset - 0x200) >> 2];
- }
- switch (offset >> 2) {
- case 0: /* IRQSTATUS */
- return pl190_irq_level(s);
- case 1: /* FIQSATUS */
- return (s->level | s->soft_level) & s->fiq_select;
- case 2: /* RAWINTR */
- return s->level | s->soft_level;
- case 3: /* INTSELECT */
- return s->fiq_select;
- case 4: /* INTENABLE */
- return s->irq_enable;
- case 6: /* SOFTINT */
- return s->soft_level;
- case 8: /* PROTECTION */
- return s->protected;
- case 12: /* VECTADDR */
- /* Read vector address at the start of an ISR. Increases the
- current priority level to that of the current interrupt. */
- for (i = 0; i < s->priority; i++)
- {
- if ((s->level | s->soft_level) & s->prio_mask[i])
- break;
- }
- /* Reading this value with no pending interrupts is undefined.
- We return the default address. */
- if (i == PL190_NUM_PRIO)
- return s->vect_addr[16];
- if (i < s->priority)
- {
- s->prev_prio[i] = s->priority;
- s->priority = i;
- pl190_update(s);
- }
- return s->vect_addr[s->priority];
- case 13: /* DEFVECTADDR */
- return s->vect_addr[16];
- default:
- cpu_abort (cpu_single_env, "pl190_read: Bad offset %x\n", offset);
- return 0;
- }
-}
-
-static void pl190_write(void *opaque, target_phys_addr_t offset, uint32_t val)
-{
- pl190_state *s = (pl190_state *)opaque;
-
- offset -= s->base;
- if (offset >= 0x100 && offset < 0x140) {
- s->vect_addr[(offset - 0x100) >> 2] = val;
- pl190_update_vectors(s);
- return;
- }
- if (offset >= 0x200 && offset < 0x240) {
- s->vect_control[(offset - 0x200) >> 2] = val;
- pl190_update_vectors(s);
- return;
- }
- switch (offset >> 2) {
- case 0: /* SELECT */
- /* This is a readonly register, but linux tries to write to it
- anyway. Ignore the write. */
- break;
- case 3: /* INTSELECT */
- s->fiq_select = val;
- break;
- case 4: /* INTENABLE */
- s->irq_enable |= val;
- break;
- case 5: /* INTENCLEAR */
- s->irq_enable &= ~val;
- break;
- case 6: /* SOFTINT */
- s->soft_level |= val;
- break;
- case 7: /* SOFTINTCLEAR */
- s->soft_level &= ~val;
- break;
- case 8: /* PROTECTION */
- /* TODO: Protection (supervisor only access) is not implemented. */
- s->protected = val & 1;
- break;
- case 12: /* VECTADDR */
- /* Restore the previous priority level. The value written is
- ignored. */
- if (s->priority < PL190_NUM_PRIO)
- s->priority = s->prev_prio[s->priority];
- break;
- case 13: /* DEFVECTADDR */
- s->default_addr = val;
- break;
- case 0xc0: /* ITCR */
- if (val)
- cpu_abort(cpu_single_env, "pl190: Test mode not implemented\n");
- break;
- default:
- cpu_abort(cpu_single_env, "pl190_write: Bad offset %x\n", offset);
- return;
- }
- pl190_update(s);
-}
-
-static CPUReadMemoryFunc *pl190_readfn[] = {
- pl190_read,
- pl190_read,
- pl190_read
-};
-
-static CPUWriteMemoryFunc *pl190_writefn[] = {
- pl190_write,
- pl190_write,
- pl190_write
-};
-
-void pl190_reset(pl190_state *s)
-{
- int i;
-
- for (i = 0; i < 16; i++)
- {
- s->vect_addr[i] = 0;
- s->vect_control[i] = 0;
- }
- s->vect_addr[16] = 0;
- s->prio_mask[17] = 0xffffffff;
- s->priority = PL190_NUM_PRIO;
- pl190_update_vectors(s);
-}
-
-void *pl190_init(uint32_t base, void *parent, int irq, int fiq)
-{
- pl190_state *s;
- 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;
- s->base = base;
- s->parent = parent;
- s->irq = irq;
- s->fiq = fiq;
- pl190_reset(s);
- /* ??? Save/restore. */
- return s;
-}
diff --git a/hw/power_supply.h b/hw/power_supply.h
new file mode 100644
index 0000000..b85edc7
--- /dev/null
+++ b/hw/power_supply.h
@@ -0,0 +1,109 @@
+/*
+ * Universal power supply monitor class
+ *
+ * Copyright © 2007 Anton Vorontsov <cbou@mail.ru>
+ * Copyright © 2004 Szabolcs Gyurko
+ * Copyright © 2003 Ian Molton <spyro@f2s.com>
+ *
+ * Modified: 2004, Oct Szabolcs Gyurko
+ *
+ * You may use this code as per GPL version 2
+ */
+
+#ifndef __LINUX_POWER_SUPPLY_H__
+#define __LINUX_POWER_SUPPLY_H__
+
+/*
+ * All voltages, currents, charges, energies, time and temperatures in uV,
+ * µA, µAh, µWh, seconds and tenths of degree Celsius unless otherwise
+ * stated. It's driver's job to convert its raw values to units in which
+ * this class operates.
+ */
+
+/*
+ * For systems where the charger determines the maximum battery capacity
+ * the min and max fields should be used to present these values to user
+ * space. Unused/unknown fields will not appear in sysfs.
+ */
+
+enum {
+ POWER_SUPPLY_STATUS_UNKNOWN = 0,
+ POWER_SUPPLY_STATUS_CHARGING,
+ POWER_SUPPLY_STATUS_DISCHARGING,
+ POWER_SUPPLY_STATUS_NOT_CHARGING,
+ POWER_SUPPLY_STATUS_FULL,
+};
+
+enum {
+ POWER_SUPPLY_HEALTH_UNKNOWN = 0,
+ POWER_SUPPLY_HEALTH_GOOD,
+ POWER_SUPPLY_HEALTH_OVERHEAT,
+ POWER_SUPPLY_HEALTH_DEAD,
+ POWER_SUPPLY_HEALTH_OVERVOLTAGE,
+ POWER_SUPPLY_HEALTH_UNSPEC_FAILURE,
+};
+
+enum {
+ POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0,
+ POWER_SUPPLY_TECHNOLOGY_NiMH,
+ POWER_SUPPLY_TECHNOLOGY_LION,
+ POWER_SUPPLY_TECHNOLOGY_LIPO,
+ POWER_SUPPLY_TECHNOLOGY_LiFe,
+ POWER_SUPPLY_TECHNOLOGY_NiCd,
+};
+
+enum {
+ POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0,
+ POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL,
+ POWER_SUPPLY_CAPACITY_LEVEL_LOW,
+ POWER_SUPPLY_CAPACITY_LEVEL_NORMAL,
+ POWER_SUPPLY_CAPACITY_LEVEL_HIGH,
+ POWER_SUPPLY_CAPACITY_LEVEL_FULL,
+};
+
+enum power_supply_property {
+ /* Properties of type `int' */
+ POWER_SUPPLY_PROP_STATUS = 0,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_TECHNOLOGY,
+ POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_CURRENT_AVG,
+ POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN,
+ POWER_SUPPLY_PROP_CHARGE_FULL,
+ POWER_SUPPLY_PROP_CHARGE_EMPTY,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_CHARGE_AVG,
+ POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
+ POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN,
+ POWER_SUPPLY_PROP_ENERGY_FULL,
+ POWER_SUPPLY_PROP_ENERGY_EMPTY,
+ POWER_SUPPLY_PROP_ENERGY_NOW,
+ POWER_SUPPLY_PROP_ENERGY_AVG,
+ POWER_SUPPLY_PROP_CAPACITY, /* in percents! */
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
+ POWER_SUPPLY_PROP_TEMP,
+ POWER_SUPPLY_PROP_TEMP_AMBIENT,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+ POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG,
+ POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
+ POWER_SUPPLY_PROP_TIME_TO_FULL_AVG,
+ /* Properties of type `const char *' */
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+enum power_supply_type {
+ POWER_SUPPLY_TYPE_BATTERY = 0,
+ POWER_SUPPLY_TYPE_UPS,
+ POWER_SUPPLY_TYPE_MAINS,
+ POWER_SUPPLY_TYPE_USB,
+};
+
+#endif /* __LINUX_POWER_SUPPLY_H__ */
diff --git a/hw/ppc.c b/hw/ppc.c
deleted file mode 100644
index 3743ad7..0000000
--- a/hw/ppc.c
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * QEMU generic PPC hardware System Emulator
- *
- * Copyright (c) 2003-2004 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 "m48t59.h"
-
-/*****************************************************************************/
-/* PPC time base and decrementer emulation */
-//#define DEBUG_TB
-
-struct ppc_tb_t {
- /* Time base management */
- int64_t tb_offset; /* Compensation */
- uint32_t tb_freq; /* TB frequency */
- /* Decrementer management */
- uint64_t decr_next; /* Tick for next decr interrupt */
- struct QEMUTimer *decr_timer;
-};
-
-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);
-}
-
-uint32_t cpu_ppc_load_tbl (CPUState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb;
-
- tb = cpu_ppc_get_tb(tb_env);
-#ifdef 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);
- }
- }
-#endif
-
- return tb & 0xFFFFFFFF;
-}
-
-uint32_t cpu_ppc_load_tbu (CPUState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint64_t tb;
-
- tb = cpu_ppc_get_tb(tb_env);
-#ifdef DEBUG_TB
- printf("%s: tb=0x%016lx\n", __func__, tb);
-#endif
- return tb >> 32;
-}
-
-static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value)
-{
- 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);
-#endif
-}
-
-void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
-{
- ppc_tb_t *tb_env = env->tb_env;
-
- cpu_ppc_store_tb(tb_env,
- ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
-}
-
-void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
-{
- ppc_tb_t *tb_env = env->tb_env;
-
- cpu_ppc_store_tb(tb_env,
- ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value);
-}
-
-uint32_t cpu_ppc_load_decr (CPUState *env)
-{
- ppc_tb_t *tb_env = env->tb_env;
- uint32_t decr;
- int64_t diff;
-
- diff = tb_env->decr_next - qemu_get_clock(vm_clock);
- if (diff >= 0)
- 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);
-#endif
- return decr;
-}
-
-/* When decrementer expires,
- * all we need to do is generate or queue a CPU exception
- */
-static inline void cpu_ppc_decr_excp (CPUState *env)
-{
- /* Raise it */
-#ifdef DEBUG_TB
- printf("raise decrementer exception\n");
-#endif
- cpu_interrupt(env, CPU_INTERRUPT_TIMER);
-}
-
-static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
- uint32_t value, int is_excp)
-{
- 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);
-#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++;
- tb_env->decr_next = next;
- /* Adjust timer */
- qemu_mod_timer(tb_env->decr_timer, next);
- /* If we set a negative value and the decrementer was positive,
- * raise an exception.
- */
- if ((value & 0x80000000) && !(decr & 0x80000000))
- cpu_ppc_decr_excp(env);
-}
-
-void cpu_ppc_store_decr (CPUState *env, uint32_t value)
-{
- _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0);
-}
-
-static void cpu_ppc_decr_cb (void *opaque)
-{
- _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
-}
-
-/* Set up (once) timebase frequency (in Hz) */
-ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
-{
- ppc_tb_t *tb_env;
-
- tb_env = qemu_mallocz(sizeof(ppc_tb_t));
- 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);
- }
-
- return tb_env;
-}
-
-#if 0
-/*****************************************************************************/
-/* Handle system reset (for now, just stop emulation) */
-void cpu_ppc_reset (CPUState *env)
-{
- printf("Reset asked... Stop emulation\n");
- abort();
-}
-#endif
-
-static void PPC_io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
- cpu_outb(NULL, addr & 0xffff, value);
-}
-
-static uint32_t PPC_io_readb (void *opaque, target_phys_addr_t addr)
-{
- uint32_t ret = cpu_inb(NULL, addr & 0xffff);
- return ret;
-}
-
-static void PPC_io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- value = bswap16(value);
-#endif
- cpu_outw(NULL, addr & 0xffff, value);
-}
-
-static uint32_t PPC_io_readw (void *opaque, target_phys_addr_t addr)
-{
- uint32_t ret = cpu_inw(NULL, addr & 0xffff);
-#ifdef TARGET_WORDS_BIGENDIAN
- ret = bswap16(ret);
-#endif
- return ret;
-}
-
-static void PPC_io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- value = bswap32(value);
-#endif
- cpu_outl(NULL, addr & 0xffff, value);
-}
-
-static uint32_t PPC_io_readl (void *opaque, target_phys_addr_t addr)
-{
- uint32_t ret = cpu_inl(NULL, addr & 0xffff);
-
-#ifdef TARGET_WORDS_BIGENDIAN
- ret = bswap32(ret);
-#endif
- return ret;
-}
-
-CPUWriteMemoryFunc *PPC_io_write[] = {
- &PPC_io_writeb,
- &PPC_io_writew,
- &PPC_io_writel,
-};
-
-CPUReadMemoryFunc *PPC_io_read[] = {
- &PPC_io_readb,
- &PPC_io_readw,
- &PPC_io_readl,
-};
-
-/*****************************************************************************/
-/* Debug port */
-void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
-{
- addr &= 0xF;
- switch (addr) {
- case 0:
- printf("%c", val);
- break;
- case 1:
- printf("\n");
- fflush(stdout);
- break;
- case 2:
- printf("Set loglevel to %04x\n", val);
- cpu_set_log(val | 0x100);
- break;
- }
-}
-
-/*****************************************************************************/
-/* NVRAM helpers */
-void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
-{
- m48t59_write(nvram, addr, value);
-}
-
-uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
-{
- return m48t59_read(nvram, addr);
-}
-
-void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
-{
- m48t59_write(nvram, addr, value >> 8);
- m48t59_write(nvram, addr + 1, value & 0xFF);
-}
-
-uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
-{
- uint16_t tmp;
-
- tmp = m48t59_read(nvram, addr) << 8;
- tmp |= m48t59_read(nvram, addr + 1);
- return tmp;
-}
-
-void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
-{
- m48t59_write(nvram, addr, value >> 24);
- m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
- m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
- m48t59_write(nvram, addr + 3, value & 0xFF);
-}
-
-uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
-{
- uint32_t tmp;
-
- tmp = m48t59_read(nvram, addr) << 24;
- tmp |= m48t59_read(nvram, addr + 1) << 16;
- tmp |= m48t59_read(nvram, addr + 2) << 8;
- tmp |= m48t59_read(nvram, addr + 3);
- return tmp;
-}
-
-void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
- const unsigned char *str, uint32_t max)
-{
- int i;
-
- for (i = 0; i < max && str[i] != '\0'; i++) {
- m48t59_write(nvram, addr + i, str[i]);
- }
- m48t59_write(nvram, addr + max - 1, '\0');
-}
-
-int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
-{
- int i;
-
- memset(dst, 0, max);
- for (i = 0; i < max; i++) {
- dst[i] = NVRAM_get_byte(nvram, addr + i);
- if (dst[i] == '\0')
- break;
- }
-
- return i;
-}
-
-static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
-{
- uint16_t tmp;
- uint16_t pd, pd1, pd2;
-
- tmp = prev >> 8;
- pd = prev ^ value;
- pd1 = pd & 0x000F;
- pd2 = ((pd >> 4) & 0x000F) ^ pd1;
- tmp ^= (pd1 << 3) | (pd1 << 8);
- tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
-
- return tmp;
-}
-
-uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
-{
- uint32_t i;
- uint16_t crc = 0xFFFF;
- int odd;
-
- odd = count & 1;
- count &= ~1;
- for (i = 0; i != count; 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);
- }
-
- return crc;
-}
-
-#define CMDLINE_ADDR 0x017ff000
-
-int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
- const unsigned char *arch,
- uint32_t RAM_size, int boot_device,
- uint32_t kernel_image, uint32_t kernel_size,
- const char *cmdline,
- uint32_t initrd_image, uint32_t initrd_size,
- uint32_t NVRAM_image,
- int width, int height, int depth)
-{
- uint16_t crc;
-
- /* Set parameters for Open Hack'Ware BIOS */
- NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
- NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
- NVRAM_set_word(nvram, 0x14, NVRAM_size);
- NVRAM_set_string(nvram, 0x20, arch, 16);
- NVRAM_set_lword(nvram, 0x30, RAM_size);
- NVRAM_set_byte(nvram, 0x34, boot_device);
- NVRAM_set_lword(nvram, 0x38, kernel_image);
- NVRAM_set_lword(nvram, 0x3C, kernel_size);
- if (cmdline) {
- /* XXX: put the cmdline in NVRAM too ? */
- strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
- NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
- NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
- } else {
- NVRAM_set_lword(nvram, 0x40, 0);
- NVRAM_set_lword(nvram, 0x44, 0);
- }
- NVRAM_set_lword(nvram, 0x48, initrd_image);
- NVRAM_set_lword(nvram, 0x4C, initrd_size);
- NVRAM_set_lword(nvram, 0x50, NVRAM_image);
-
- NVRAM_set_word(nvram, 0x54, width);
- NVRAM_set_word(nvram, 0x56, height);
- NVRAM_set_word(nvram, 0x58, depth);
- crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
- NVRAM_set_word(nvram, 0xFC, crc);
-
- return 0;
-}
diff --git a/hw/ppc_chrp.c b/hw/ppc_chrp.c
deleted file mode 100644
index 42d5995..0000000
--- a/hw/ppc_chrp.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * QEMU PPC CHRP/PMAC hardware System Emulator
- *
- * Copyright (c) 2004 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"
-
-#define BIOS_FILENAME "ppc_rom.bin"
-#define VGABIOS_FILENAME "video.x"
-#define NVRAM_SIZE 0x2000
-
-#define KERNEL_LOAD_ADDR 0x01000000
-#define INITRD_LOAD_ADDR 0x01800000
-
-/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA,
- NVRAM */
-
-static int dbdma_mem_index;
-static int cuda_mem_index;
-static int ide0_mem_index = -1;
-static int ide1_mem_index = -1;
-static int openpic_mem_index = -1;
-static int heathrow_pic_mem_index = -1;
-static int macio_nvram_mem_index = -1;
-
-/* DBDMA: currently no op - should suffice right now */
-
-static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
- printf("%s: 0x%08x <= 0x%08x\n", __func__, addr, value);
-}
-
-static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-}
-
-static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-}
-
-static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr)
-{
- printf("%s: 0x%08x => 0x00000000\n", __func__, addr);
- return 0;
-}
-
-static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr)
-{
- return 0;
-}
-
-static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr)
-{
- return 0;
-}
-
-static CPUWriteMemoryFunc *dbdma_write[] = {
- &dbdma_writeb,
- &dbdma_writew,
- &dbdma_writel,
-};
-
-static CPUReadMemoryFunc *dbdma_read[] = {
- &dbdma_readb,
- &dbdma_readw,
- &dbdma_readl,
-};
-
-/* macio style NVRAM device */
-typedef struct MacIONVRAMState {
- uint8_t data[0x2000];
-} MacIONVRAMState;
-
-static void macio_nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
- MacIONVRAMState *s = opaque;
- addr = (addr >> 4) & 0x1fff;
- s->data[addr] = value;
- // printf("macio_nvram_writeb %04x = %02x\n", addr, value);
-}
-
-static uint32_t macio_nvram_readb (void *opaque, target_phys_addr_t addr)
-{
- MacIONVRAMState *s = opaque;
- uint32_t value;
-
- addr = (addr >> 4) & 0x1fff;
- value = s->data[addr];
- // printf("macio_nvram_readb %04x = %02x\n", addr, value);
- return value;
-}
-
-static CPUWriteMemoryFunc *macio_nvram_write[] = {
- &macio_nvram_writeb,
- &macio_nvram_writeb,
- &macio_nvram_writeb,
-};
-
-static CPUReadMemoryFunc *macio_nvram_read[] = {
- &macio_nvram_readb,
- &macio_nvram_readb,
- &macio_nvram_readb,
-};
-
-static MacIONVRAMState *macio_nvram_init(void)
-{
- MacIONVRAMState *s;
- s = qemu_mallocz(sizeof(MacIONVRAMState));
- if (!s)
- return NULL;
- macio_nvram_mem_index = cpu_register_io_memory(0, macio_nvram_read,
- macio_nvram_write, s);
- return s;
-}
-
-static void macio_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- if (heathrow_pic_mem_index >= 0) {
- cpu_register_physical_memory(addr + 0x00000, 0x1000,
- heathrow_pic_mem_index);
- }
- cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index);
- cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index);
- if (ide0_mem_index >= 0)
- cpu_register_physical_memory(addr + 0x1f000, 0x1000, ide0_mem_index);
- if (ide1_mem_index >= 0)
- cpu_register_physical_memory(addr + 0x20000, 0x1000, ide1_mem_index);
- if (openpic_mem_index >= 0) {
- cpu_register_physical_memory(addr + 0x40000, 0x40000,
- openpic_mem_index);
- }
- if (macio_nvram_mem_index >= 0)
- cpu_register_physical_memory(addr + 0x60000, 0x20000, macio_nvram_mem_index);
-}
-
-static void macio_init(PCIBus *bus, int device_id)
-{
- PCIDevice *d;
-
- d = pci_register_device(bus, "macio", sizeof(PCIDevice),
- -1, NULL, NULL);
- /* Note: this code is strongly inspirated from the corresponding code
- in PearPC */
- d->config[0x00] = 0x6b; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = device_id;
- d->config[0x03] = device_id >> 8;
-
- d->config[0x0a] = 0x00; // class_sub = pci2pci
- d->config[0x0b] = 0xff; // class_base = bridge
- d->config[0x0e] = 0x00; // header_type
-
- d->config[0x3d] = 0x01; // interrupt on pin 1
-
- dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL);
-
- pci_register_io_region(d, 0, 0x80000,
- PCI_ADDRESS_SPACE_MEM, macio_map);
-}
-
-/* UniN device */
-static void unin_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-}
-
-static uint32_t unin_readl (void *opaque, target_phys_addr_t addr)
-{
- return 0;
-}
-
-static CPUWriteMemoryFunc *unin_write[] = {
- &unin_writel,
- &unin_writel,
- &unin_writel,
-};
-
-static CPUReadMemoryFunc *unin_read[] = {
- &unin_readl,
- &unin_readl,
- &unin_readl,
-};
-
-/* temporary frame buffer OSI calls for the video.x driver. The right
- solution is to modify the driver to use VGA PCI I/Os */
-static int vga_osi_call(CPUState *env)
-{
- static int vga_vbl_enabled;
- int linesize;
-
- // printf("osi_call R5=%d\n", env->gpr[5]);
-
- /* same handler as PearPC, coming from the original MOL video
- driver. */
- switch(env->gpr[5]) {
- case 4:
- break;
- case 28: /* set_vmode */
- if (env->gpr[6] != 1 || env->gpr[7] != 0)
- env->gpr[3] = 1;
- else
- env->gpr[3] = 0;
- break;
- case 29: /* get_vmode_info */
- if (env->gpr[6] != 0) {
- if (env->gpr[6] != 1 || env->gpr[7] != 0) {
- env->gpr[3] = 1;
- break;
- }
- }
- env->gpr[3] = 0;
- env->gpr[4] = (1 << 16) | 1; /* num_vmodes, cur_vmode */
- env->gpr[5] = (1 << 16) | 0; /* num_depths, cur_depth_mode */
- env->gpr[6] = (graphic_width << 16) | graphic_height; /* w, h */
- env->gpr[7] = 85 << 16; /* refresh rate */
- env->gpr[8] = (graphic_depth + 7) & ~7; /* depth (round to byte) */
- linesize = ((graphic_depth + 7) >> 3) * graphic_width;
- linesize = (linesize + 3) & ~3;
- env->gpr[9] = (linesize << 16) | 0; /* row_bytes, offset */
- break;
- case 31: /* set_video power */
- env->gpr[3] = 0;
- break;
- case 39: /* video_ctrl */
- if (env->gpr[6] == 0 || env->gpr[6] == 1)
- vga_vbl_enabled = env->gpr[6];
- env->gpr[3] = 0;
- break;
- case 47:
- break;
- case 59: /* set_color */
- /* R6 = index, R7 = RGB */
- env->gpr[3] = 0;
- break;
- case 64: /* get color */
- /* R6 = index */
- env->gpr[3] = 0;
- break;
- case 116: /* set hwcursor */
- /* R6 = x, R7 = y, R8 = visible, R9 = data */
- break;
- default:
- fprintf(stderr, "unsupported OSI call R5=%08x\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;
- sum = 0;
- for(i = 0; i < n; i++)
- sum += buf[i];
- return (sum & 0xff) + (sum >> 8);
-}
-
-/* set a free Mac OS NVRAM partition */
-void pmac_format_nvram_partition(uint8_t *buf, int len)
-{
- char partition_name[12] = "wwwwwwwwwwww";
-
- buf[0] = 0x7f; /* free partition magic */
- buf[1] = 0; /* checksum */
- buf[2] = len >> 8;
- buf[3] = len;
- memcpy(buf + 4, partition_name, 12);
- buf[1] = nvram_chksum(buf, 16);
-}
-
-/* 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)
-{
- CPUState *env;
- char buf[1024];
- SetIRQFunc *set_irq;
- void *pic;
- m48t59_t *nvram;
- int PPC_io_memory, unin_memory;
- int linux_boot, i;
- unsigned long bios_offset, vga_bios_offset;
- uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
- ppc_def_t *def;
- PCIBus *pci_bus;
- const char *arch_name;
- int vga_bios_size, bios_size;
-
- linux_boot = (kernel_filename != NULL);
-
- /* init CPUs */
- env = cpu_init();
- register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
-
- /* Register CPU as a 74x/75x */
- /* 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);
- if (def == NULL) {
- cpu_abort(env, "Unable to find PowerPC CPU definition\n");
- }
- 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;
-
- /* allocate RAM */
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
-
- /* allocate and load BIOS */
- 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) {
- 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);
-
- /* allocate and load VGA BIOS */
- vga_bios_offset = bios_offset + bios_size;
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
- vga_bios_size = load_image(buf, phys_ram_base + vga_bios_offset + 8);
- if (vga_bios_size < 0) {
- /* if no bios is present, we can still work */
- fprintf(stderr, "qemu: warning: could not load VGA bios '%s'\n", buf);
- vga_bios_size = 0;
- } else {
- /* set a specific header (XXX: find real Apple format for NDRV
- drivers) */
- phys_ram_base[vga_bios_offset] = 'N';
- phys_ram_base[vga_bios_offset + 1] = 'D';
- phys_ram_base[vga_bios_offset + 2] = 'R';
- phys_ram_base[vga_bios_offset + 3] = 'V';
- cpu_to_be32w((uint32_t *)(phys_ram_base + vga_bios_offset + 4),
- vga_bios_size);
- vga_bios_size += 8;
- }
- vga_bios_size = (vga_bios_size + 0xfff) & ~0xfff;
-
- if (linux_boot) {
- 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;
- }
-
- if (is_heathrow) {
- isa_mem_base = 0x80000000;
-
- /* Register 2 MB of ISA IO space */
- PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
- cpu_register_physical_memory(0xfe000000, 0x00200000, PPC_io_memory);
-
- /* init basic PC hardware */
- pic = heathrow_pic_init(&heathrow_pic_mem_index);
- set_irq = heathrow_pic_set_irq;
- pci_bus = pci_grackle_init(0xfec00000, pic);
- vga_initialize(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);
-
- /* XXX: use Mac Serial port */
- serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 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_cmd646_ide_init(pci_bus, &bs_table[0], 0);
-
- /* cuda also initialize ADB */
- cuda_mem_index = cuda_init(set_irq, pic, 0x12);
-
- adb_kbd_init(&adb_bus);
- adb_mouse_init(&adb_bus);
-
- {
- MacIONVRAMState *nvr;
- nvr = macio_nvram_init();
- pmac_format_nvram_partition(nvr->data, 0x2000);
- }
-
- macio_init(pci_bus, 0x0017);
-
- nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
-
- arch_name = "HEATHROW";
- } else {
- isa_mem_base = 0x80000000;
-
- /* Register 8 MB of ISA IO space */
- PPC_io_memory = cpu_register_io_memory(0, PPC_io_read, PPC_io_write, NULL);
- cpu_register_physical_memory(0xF2000000, 0x00800000, PPC_io_memory);
-
- /* 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;
- pci_bus = pci_pmac_init(pic);
- /* init basic PC hardware */
- vga_initialize(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);
-
- /* XXX: use Mac Serial port */
- serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
-
- for(i = 0; i < nb_nics; i++) {
- pci_ne2000_init(pci_bus, &nd_table[i]);
- }
-
-#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);
-#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);
-
- adb_kbd_init(&adb_bus);
- adb_mouse_init(&adb_bus);
-
- macio_init(pci_bus, 0x0022);
-
- nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
-
- arch_name = "MAC99";
- }
-
- if (usb_enabled) {
- usb_ohci_init(pci_bus, 3, -1);
- }
-
- if (graphic_depth != 15 && graphic_depth != 32 && graphic_depth != 8)
- graphic_depth = 15;
-
- PPC_NVRAM_set_params(nvram, NVRAM_SIZE, arch_name, ram_size, boot_device,
- kernel_base, kernel_size,
- kernel_cmdline,
- initrd_base, initrd_size,
- /* XXX: need an option to load a NVRAM image */
- 0,
- graphic_width, graphic_height, graphic_depth);
- /* No PCI init: the BIOS will do it */
-
- /* Special port to get debug messages from Open-Firmware */
- 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)
-{
- ppc_chrp_init(ram_size, vga_ram_size, boot_device,
- ds, fd_filename, snapshot,
- kernel_filename, kernel_cmdline,
- initrd_filename, 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)
-{
- ppc_chrp_init(ram_size, vga_ram_size, boot_device,
- ds, fd_filename, snapshot,
- kernel_filename, kernel_cmdline,
- initrd_filename, 1);
-}
-
-QEMUMachine core99_machine = {
- "mac99",
- "Mac99 based PowerMAC",
- ppc_core99_init,
-};
-
-QEMUMachine heathrow_machine = {
- "g3bw",
- "Heathrow based PowerMAC",
- ppc_heathrow_init,
-};
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
deleted file mode 100644
index a4d7ddf..0000000
--- a/hw/ppc_prep.c
+++ /dev/null
@@ -1,694 +0,0 @@
-/*
- * QEMU PPC PREP hardware System Emulator
- *
- * Copyright (c) 2003-2004 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"
-
-//#define HARD_DEBUG_PPC_IO
-//#define DEBUG_PPC_IO
-
-#define BIOS_FILENAME "ppc_rom.bin"
-#define KERNEL_LOAD_ADDR 0x01000000
-#define INITRD_LOAD_ADDR 0x01800000
-
-extern int loglevel;
-extern FILE *logfile;
-
-#if defined (HARD_DEBUG_PPC_IO) && !defined (DEBUG_PPC_IO)
-#define DEBUG_PPC_IO
-#endif
-
-#if defined (HARD_DEBUG_PPC_IO)
-#define PPC_IO_DPRINTF(fmt, args...) \
-do { \
- if (loglevel & CPU_LOG_IOPORT) { \
- fprintf(logfile, "%s: " fmt, __func__ , ##args); \
- } else { \
- printf("%s : " fmt, __func__ , ##args); \
- } \
-} while (0)
-#elif defined (DEBUG_PPC_IO)
-#define PPC_IO_DPRINTF(fmt, args...) \
-do { \
- if (loglevel & CPU_LOG_IOPORT) { \
- fprintf(logfile, "%s: " fmt, __func__ , ##args); \
- } \
-} while (0)
-#else
-#define PPC_IO_DPRINTF(fmt, args...) do { } while (0)
-#endif
-
-/* Constants for devices init */
-static const int ide_iobase[2] = { 0x1f0, 0x170 };
-static const int ide_iobase2[2] = { 0x3f6, 0x376 };
-static const int ide_irq[2] = { 13, 13 };
-
-#define NE2000_NB_MAX 6
-
-static uint32_t ne2000_io[NE2000_NB_MAX] = { 0x300, 0x320, 0x340, 0x360, 0x280, 0x380 };
-static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 };
-
-//static PITState *pit;
-
-/* ISA IO ports bridge */
-#define PPC_IO_BASE 0x80000000
-
-/* Speaker port 0x61 */
-int speaker_data_on;
-int dummy_refresh_clock;
-
-static void speaker_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
-#if 0
- speaker_data_on = (val >> 1) & 1;
- pit_set_gate(pit, 2, val & 1);
-#endif
-}
-
-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);
-#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)
-{
- // printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value);
-}
-
-static inline uint32_t _PPC_intack_read (target_phys_addr_t addr)
-{
- uint32_t retval = 0;
-
- if (addr == 0xBFFFFFF0)
- retval = pic_intack_read(isa_pic);
- // printf("%s: 0x%08x <= %d\n", __func__, addr, retval);
-
- return retval;
-}
-
-static uint32_t PPC_intack_readb (void *opaque, target_phys_addr_t addr)
-{
- return _PPC_intack_read(addr);
-}
-
-static uint32_t PPC_intack_readw (void *opaque, target_phys_addr_t addr)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- return bswap16(_PPC_intack_read(addr));
-#else
- return _PPC_intack_read(addr);
-#endif
-}
-
-static uint32_t PPC_intack_readl (void *opaque, target_phys_addr_t addr)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- return bswap32(_PPC_intack_read(addr));
-#else
- return _PPC_intack_read(addr);
-#endif
-}
-
-static CPUWriteMemoryFunc *PPC_intack_write[] = {
- &_PPC_intack_write,
- &_PPC_intack_write,
- &_PPC_intack_write,
-};
-
-static CPUReadMemoryFunc *PPC_intack_read[] = {
- &PPC_intack_readb,
- &PPC_intack_readw,
- &PPC_intack_readl,
-};
-
-/* PowerPC control and status registers */
-#if 0 // Not used
-static struct {
- /* IDs */
- uint32_t veni_devi;
- uint32_t revi;
- /* Control and status */
- uint32_t gcsr;
- uint32_t xcfr;
- uint32_t ct32;
- uint32_t mcsr;
- /* General purpose registers */
- uint32_t gprg[6];
- /* Exceptions */
- uint32_t feen;
- uint32_t fest;
- uint32_t fema;
- uint32_t fecl;
- uint32_t eeen;
- uint32_t eest;
- uint32_t eecl;
- uint32_t eeint;
- uint32_t eemck0;
- uint32_t eemck1;
- /* Error diagnostic */
-} XCSR;
-
-static void PPC_XCSR_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
- printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
-}
-
-static void PPC_XCSR_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- value = bswap16(value);
-#endif
- printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
-}
-
-static void PPC_XCSR_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- value = bswap32(value);
-#endif
- printf("%s: 0x%08lx => 0x%08x\n", __func__, (long)addr, value);
-}
-
-static uint32_t PPC_XCSR_readb (void *opaque, target_phys_addr_t addr)
-{
- uint32_t retval = 0;
-
- printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
-
- return retval;
-}
-
-static uint32_t PPC_XCSR_readw (void *opaque, target_phys_addr_t addr)
-{
- uint32_t retval = 0;
-
- printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
-#ifdef TARGET_WORDS_BIGENDIAN
- retval = bswap16(retval);
-#endif
-
- return retval;
-}
-
-static uint32_t PPC_XCSR_readl (void *opaque, target_phys_addr_t addr)
-{
- uint32_t retval = 0;
-
- printf("%s: 0x%08lx <= %d\n", __func__, (long)addr, retval);
-#ifdef TARGET_WORDS_BIGENDIAN
- retval = bswap32(retval);
-#endif
-
- return retval;
-}
-
-static CPUWriteMemoryFunc *PPC_XCSR_write[] = {
- &PPC_XCSR_writeb,
- &PPC_XCSR_writew,
- &PPC_XCSR_writel,
-};
-
-static CPUReadMemoryFunc *PPC_XCSR_read[] = {
- &PPC_XCSR_readb,
- &PPC_XCSR_readw,
- &PPC_XCSR_readl,
-};
-#endif
-
-/* Fake super-io ports for PREP platform (Intel 82378ZB) */
-typedef struct sysctrl_t {
- m48t59_t *nvram;
- uint8_t state;
- uint8_t syscontrol;
- uint8_t fake_io[2];
- int contiguous_map;
- int endian;
-} sysctrl_t;
-
-enum {
- STATE_HARDFILE = 0x01,
-};
-
-static sysctrl_t *sysctrl;
-
-static void PREP_io_write (void *opaque, uint32_t addr, uint32_t val)
-{
- sysctrl_t *sysctrl = opaque;
-
- PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val);
- sysctrl->fake_io[addr - 0x0398] = val;
-}
-
-static uint32_t PREP_io_read (void *opaque, uint32_t addr)
-{
- sysctrl_t *sysctrl = opaque;
-
- PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE,
- sysctrl->fake_io[addr - 0x0398]);
- return sysctrl->fake_io[addr - 0x0398];
-}
-
-static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
-{
- sysctrl_t *sysctrl = opaque;
-
- PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr - PPC_IO_BASE, val);
- switch (addr) {
- case 0x0092:
- /* Special port 92 */
- /* Check soft reset asked */
- if (val & 0x01) {
- // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
- }
- /* Check LE mode */
- if (val & 0x02) {
- sysctrl->endian = 1;
- } else {
- sysctrl->endian = 0;
- }
- break;
- case 0x0800:
- /* Motorola CPU configuration register : read-only */
- break;
- case 0x0802:
- /* Motorola base module feature register : read-only */
- break;
- case 0x0803:
- /* Motorola base module status register : read-only */
- break;
- case 0x0808:
- /* Hardfile light register */
- if (val & 1)
- sysctrl->state |= STATE_HARDFILE;
- else
- sysctrl->state &= ~STATE_HARDFILE;
- break;
- case 0x0810:
- /* Password protect 1 register */
- if (sysctrl->nvram != NULL)
- m48t59_toggle_lock(sysctrl->nvram, 1);
- break;
- case 0x0812:
- /* Password protect 2 register */
- if (sysctrl->nvram != NULL)
- m48t59_toggle_lock(sysctrl->nvram, 2);
- break;
- case 0x0814:
- /* L2 invalidate register */
- // tlb_flush(first_cpu, 1);
- break;
- case 0x081C:
- /* system control register */
- sysctrl->syscontrol = val & 0x0F;
- break;
- case 0x0850:
- /* I/O map type register */
- sysctrl->contiguous_map = val & 0x01;
- break;
- default:
- printf("ERROR: unaffected IO port write: %04lx => %02x\n",
- (long)addr, val);
- break;
- }
-}
-
-static uint32_t PREP_io_800_readb (void *opaque, uint32_t addr)
-{
- sysctrl_t *sysctrl = opaque;
- uint32_t retval = 0xFF;
-
- switch (addr) {
- case 0x0092:
- /* Special port 92 */
- retval = 0x00;
- break;
- case 0x0800:
- /* Motorola CPU configuration register */
- retval = 0xEF; /* MPC750 */
- break;
- case 0x0802:
- /* Motorola Base module feature register */
- retval = 0xAD; /* No ESCC, PMC slot neither ethernet */
- break;
- case 0x0803:
- /* Motorola base module status register */
- retval = 0xE0; /* Standard MPC750 */
- break;
- case 0x080C:
- /* Equipment present register:
- * no L2 cache
- * no upgrade processor
- * no cards in PCI slots
- * SCSI fuse is bad
- */
- retval = 0x3C;
- break;
- case 0x0810:
- /* Motorola base module extended feature register */
- retval = 0x39; /* No USB, CF and PCI bridge. NVRAM present */
- break;
- case 0x0814:
- /* L2 invalidate: don't care */
- break;
- case 0x0818:
- /* Keylock */
- retval = 0x00;
- break;
- case 0x081C:
- /* system control register
- * 7 - 6 / 1 - 0: L2 cache enable
- */
- retval = sysctrl->syscontrol;
- break;
- case 0x0823:
- /* */
- retval = 0x03; /* no L2 cache */
- break;
- case 0x0850:
- /* I/O map type register */
- retval = sysctrl->contiguous_map;
- break;
- default:
- printf("ERROR: unaffected IO port: %04lx read\n", (long)addr);
- break;
- }
- PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr - PPC_IO_BASE, retval);
-
- return retval;
-}
-
-static inline target_phys_addr_t prep_IO_address (sysctrl_t *sysctrl,
- target_phys_addr_t addr)
-{
- if (sysctrl->contiguous_map == 0) {
- /* 64 KB contiguous space for IOs */
- addr &= 0xFFFF;
- } else {
- /* 8 MB non-contiguous space for IOs */
- addr = (addr & 0x1F) | ((addr & 0x007FFF000) >> 7);
- }
-
- return addr;
-}
-
-static void PPC_prep_io_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- sysctrl_t *sysctrl = opaque;
-
- addr = prep_IO_address(sysctrl, addr);
- cpu_outb(NULL, addr, value);
-}
-
-static uint32_t PPC_prep_io_readb (void *opaque, target_phys_addr_t addr)
-{
- sysctrl_t *sysctrl = opaque;
- uint32_t ret;
-
- addr = prep_IO_address(sysctrl, addr);
- ret = cpu_inb(NULL, addr);
-
- return ret;
-}
-
-static void PPC_prep_io_writew (void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- sysctrl_t *sysctrl = opaque;
-
- addr = prep_IO_address(sysctrl, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
- value = bswap16(value);
-#endif
- PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value);
- cpu_outw(NULL, addr, value);
-}
-
-static uint32_t PPC_prep_io_readw (void *opaque, target_phys_addr_t addr)
-{
- sysctrl_t *sysctrl = opaque;
- uint32_t ret;
-
- addr = prep_IO_address(sysctrl, addr);
- ret = cpu_inw(NULL, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
- ret = bswap16(ret);
-#endif
- PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret);
-
- return ret;
-}
-
-static void PPC_prep_io_writel (void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- sysctrl_t *sysctrl = opaque;
-
- addr = prep_IO_address(sysctrl, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
- value = bswap32(value);
-#endif
- PPC_IO_DPRINTF("0x%08lx => 0x%08x\n", (long)addr, value);
- cpu_outl(NULL, addr, value);
-}
-
-static uint32_t PPC_prep_io_readl (void *opaque, target_phys_addr_t addr)
-{
- sysctrl_t *sysctrl = opaque;
- uint32_t ret;
-
- addr = prep_IO_address(sysctrl, addr);
- ret = cpu_inl(NULL, addr);
-#ifdef TARGET_WORDS_BIGENDIAN
- ret = bswap32(ret);
-#endif
- PPC_IO_DPRINTF("0x%08lx <= 0x%08x\n", (long)addr, ret);
-
- return ret;
-}
-
-CPUWriteMemoryFunc *PPC_prep_io_write[] = {
- &PPC_prep_io_writeb,
- &PPC_prep_io_writew,
- &PPC_prep_io_writel,
-};
-
-CPUReadMemoryFunc *PPC_prep_io_read[] = {
- &PPC_prep_io_readb,
- &PPC_prep_io_readw,
- &PPC_prep_io_readl,
-};
-
-#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)
-{
- CPUState *env;
- char buf[1024];
- SetIRQFunc *set_irq;
- m48t59_t *nvram;
- int PPC_io_memory;
- int linux_boot, i, nb_nics1, bios_size;
- unsigned long bios_offset;
- uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
- ppc_def_t *def;
- PCIBus *pci_bus;
-
- sysctrl = qemu_mallocz(sizeof(sysctrl_t));
- if (sysctrl == NULL)
- return;
-
- linux_boot = (kernel_filename != NULL);
-
- /* init CPUs */
-
- env = cpu_init();
- 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);
- if (def == NULL) {
- cpu_abort(env, "Unable to find PowerPC CPU definition\n");
- }
- cpu_ppc_register(env, def);
- /* Set time-base frequency to 100 Mhz */
- cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
-
- /* allocate RAM */
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
-
- /* allocate and load BIOS */
- 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) {
- fprintf(stderr, "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),
- bios_size, bios_offset | IO_MEM_ROM);
-
- if (linux_boot) {
- 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;
- }
-
- isa_mem_base = 0xc0000000;
- pci_bus = pci_prep_init();
- // 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,
- PPC_prep_io_write, sysctrl);
- cpu_register_physical_memory(0x80000000, 0x00800000, PPC_io_memory);
-
- /* init basic PC hardware */
- vga_initialize(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);
-
- serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 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]);
- } else {
- fprintf(stderr, "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],
- bs_table[2 * i], bs_table[2 * i + 1]);
- }
- kbd_init();
- DMA_init(1);
- // AUD_init();
- // SB16_init();
-
- fdctrl_init(6, 2, 0, 0x3f0, fd_table);
-
- /* Register speaker port */
- register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
- register_ioport_write(0x61, 1, 1, speaker_ioport_write, NULL);
- /* Register fake IO ports for PREP */
- register_ioport_read(0x398, 2, 1, &PREP_io_read, sysctrl);
- register_ioport_write(0x398, 2, 1, &PREP_io_write, sysctrl);
- /* System control ports */
- register_ioport_read(0x0092, 0x01, 1, &PREP_io_800_readb, sysctrl);
- register_ioport_write(0x0092, 0x01, 1, &PREP_io_800_writeb, sysctrl);
- register_ioport_read(0x0800, 0x52, 1, &PREP_io_800_readb, sysctrl);
- register_ioport_write(0x0800, 0x52, 1, &PREP_io_800_writeb, sysctrl);
- /* PCI intack location */
- PPC_io_memory = cpu_register_io_memory(0, PPC_intack_read,
- PPC_intack_write, NULL);
- cpu_register_physical_memory(0xBFFFFFF0, 0x4, PPC_io_memory);
- /* PowerPC control and status register group */
-#if 0
- PPC_io_memory = cpu_register_io_memory(0, PPC_XCSR_read, PPC_XCSR_write, NULL);
- cpu_register_physical_memory(0xFEFF0000, 0x1000, PPC_io_memory);
-#endif
-
- if (usb_enabled) {
- usb_ohci_init(pci_bus, 3, -1);
- }
-
- nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
- if (nvram == NULL)
- return;
- sysctrl->nvram = nvram;
-
- /* Initialise NVRAM */
- PPC_NVRAM_set_params(nvram, NVRAM_SIZE, "PREP", ram_size, boot_device,
- kernel_base, kernel_size,
- kernel_cmdline,
- initrd_base, initrd_size,
- /* XXX: need an option to load a NVRAM image */
- 0,
- graphic_width, graphic_height, graphic_depth);
-
- /* Special port to get debug messages from Open-Firmware */
- register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
-}
-
-QEMUMachine prep_machine = {
- "prep",
- "PowerPC PREP platform",
- ppc_prep_init,
-};
diff --git a/hw/prep_pci.c b/hw/prep_pci.c
deleted file mode 100644
index a31b74c..0000000
--- a/hw/prep_pci.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * QEMU PREP PCI host
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-#include "vl.h"
-typedef uint32_t pci_addr_t;
-#include "pci_host.h"
-
-typedef PCIHostState PREPPCIState;
-
-static void pci_prep_addr_writel(void* opaque, uint32_t addr, uint32_t val)
-{
- PREPPCIState *s = opaque;
- s->config_reg = val;
-}
-
-static uint32_t pci_prep_addr_readl(void* opaque, uint32_t addr)
-{
- PREPPCIState *s = opaque;
- return s->config_reg;
-}
-
-static inline uint32_t PPC_PCIIO_config(target_phys_addr_t addr)
-{
- int i;
-
- for(i = 0; i < 11; i++) {
- if ((addr & (1 << (11 + i))) != 0)
- break;
- }
- return (addr & 0x7ff) | (i << 11);
-}
-
-static void PPC_PCIIO_writeb (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PREPPCIState *s = opaque;
- pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 1);
-}
-
-static void PPC_PCIIO_writew (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PREPPCIState *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 2);
-}
-
-static void PPC_PCIIO_writel (void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- PREPPCIState *s = opaque;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- pci_data_write(s->bus, PPC_PCIIO_config(addr), val, 4);
-}
-
-static uint32_t PPC_PCIIO_readb (void *opaque, target_phys_addr_t addr)
-{
- PREPPCIState *s = opaque;
- uint32_t val;
- val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 1);
- return val;
-}
-
-static uint32_t PPC_PCIIO_readw (void *opaque, target_phys_addr_t addr)
-{
- PREPPCIState *s = opaque;
- uint32_t val;
- val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 2);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- return val;
-}
-
-static uint32_t PPC_PCIIO_readl (void *opaque, target_phys_addr_t addr)
-{
- PREPPCIState *s = opaque;
- uint32_t val;
- val = pci_data_read(s->bus, PPC_PCIIO_config(addr), 4);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- return val;
-}
-
-static CPUWriteMemoryFunc *PPC_PCIIO_write[] = {
- &PPC_PCIIO_writeb,
- &PPC_PCIIO_writew,
- &PPC_PCIIO_writel,
-};
-
-static CPUReadMemoryFunc *PPC_PCIIO_read[] = {
- &PPC_PCIIO_readb,
- &PPC_PCIIO_readw,
- &PPC_PCIIO_readl,
-};
-
-static void prep_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
-{
- /* XXX: we do not simulate the hardware - we rely on the BIOS to
- set correctly for irq line field */
- pic_set_irq(d->config[PCI_INTERRUPT_LINE], level);
-}
-
-PCIBus *pci_prep_init(void)
-{
- PREPPCIState *s;
- PCIDevice *d;
- int PPC_io_memory;
-
- s = qemu_mallocz(sizeof(PREPPCIState));
- s->bus = pci_register_bus(prep_set_irq, NULL, 0);
-
- register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
- register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
-
- register_ioport_write(0xcfc, 4, 1, pci_host_data_writeb, s);
- register_ioport_write(0xcfc, 4, 2, pci_host_data_writew, s);
- register_ioport_write(0xcfc, 4, 4, pci_host_data_writel, s);
- register_ioport_read(0xcfc, 4, 1, pci_host_data_readb, s);
- register_ioport_read(0xcfc, 4, 2, pci_host_data_readw, s);
- register_ioport_read(0xcfc, 4, 4, pci_host_data_readl, s);
-
- PPC_io_memory = cpu_register_io_memory(0, PPC_PCIIO_read,
- PPC_PCIIO_write, s);
- cpu_register_physical_memory(0x80800000, 0x00400000, PPC_io_memory);
-
- /* PCI host bridge */
- d = pci_register_device(s->bus, "PREP Host Bridge - Motorola Raven",
- sizeof(PCIDevice), 0, NULL, NULL);
- d->config[0x00] = 0x57; // vendor_id : Motorola
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x01; // device_id : Raven
- d->config[0x03] = 0x48;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- d->config[0x34] = 0x00; // capabilities_pointer
-
- return s->bus;
-}
-
diff --git a/hw/ps2.c b/hw/ps2.c
deleted file mode 100644
index 8438a5e..0000000
--- a/hw/ps2.c
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * QEMU PS/2 keyboard/mouse emulation
- *
- * 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"
-
-/* debug PC keyboard */
-//#define DEBUG_KBD
-
-/* debug PC keyboard : only mouse */
-//#define DEBUG_MOUSE
-
-/* Keyboard Commands */
-#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
-#define KBD_CMD_ECHO 0xEE
-#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
-#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
-#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
-#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
-#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
-#define KBD_CMD_RESET 0xFF /* Reset */
-
-/* Keyboard Replies */
-#define KBD_REPLY_POR 0xAA /* Power on reset */
-#define KBD_REPLY_ACK 0xFA /* Command ACK */
-#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
-
-/* Mouse Commands */
-#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
-#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
-#define AUX_SET_RES 0xE8 /* Set resolution */
-#define AUX_GET_SCALE 0xE9 /* Get scaling factor */
-#define AUX_SET_STREAM 0xEA /* Set stream mode */
-#define AUX_POLL 0xEB /* Poll */
-#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
-#define AUX_SET_WRAP 0xEE /* Set wrap mode */
-#define AUX_SET_REMOTE 0xF0 /* Set remote mode */
-#define AUX_GET_TYPE 0xF2 /* Get type */
-#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
-#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
-#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
-#define AUX_SET_DEFAULT 0xF6
-#define AUX_RESET 0xFF /* Reset aux device */
-#define AUX_ACK 0xFA /* Command byte ACK. */
-
-#define MOUSE_STATUS_REMOTE 0x40
-#define MOUSE_STATUS_ENABLED 0x20
-#define MOUSE_STATUS_SCALE21 0x10
-
-#define PS2_QUEUE_SIZE 256
-
-typedef struct {
- uint8_t data[PS2_QUEUE_SIZE];
- int rptr, wptr, count;
-} PS2Queue;
-
-typedef struct {
- PS2Queue queue;
- int32_t write_cmd;
- void (*update_irq)(void *, int);
- void *update_arg;
-} PS2State;
-
-typedef struct {
- PS2State common;
- int scan_enabled;
- /* Qemu uses translated PC scancodes internally. To avoid multiple
- conversions we do the translation (if any) in the PS/2 emulation
- not the keyboard controller. */
- int translate;
-} PS2KbdState;
-
-typedef struct {
- PS2State common;
- uint8_t mouse_status;
- uint8_t mouse_resolution;
- uint8_t mouse_sample_rate;
- uint8_t mouse_wrap;
- uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
- uint8_t mouse_detect_state;
- int mouse_dx; /* current values, needed for 'poll' mode */
- int mouse_dy;
- int mouse_dz;
- uint8_t mouse_buttons;
-} PS2MouseState;
-
-/* Table to convert from PC scancodes to raw scancodes. */
-static const unsigned char ps2_raw_keycode[128] = {
- 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
- 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
- 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
- 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
- 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
- 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
- 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
- 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
-};
-
-void ps2_queue(void *opaque, int b)
-{
- PS2State *s = (PS2State *)opaque;
- PS2Queue *q = &s->queue;
-
- if (q->count >= PS2_QUEUE_SIZE)
- return;
- q->data[q->wptr] = b;
- if (++q->wptr == PS2_QUEUE_SIZE)
- q->wptr = 0;
- q->count++;
- s->update_irq(s->update_arg, 1);
-}
-
-static void ps2_put_keycode(void *opaque, int keycode)
-{
- PS2KbdState *s = opaque;
- if (!s->translate && keycode < 0xe0)
- {
- if (keycode & 0x80)
- ps2_queue(&s->common, 0xf0);
- keycode = ps2_raw_keycode[keycode & 0x7f];
- }
- ps2_queue(&s->common, keycode);
-}
-
-uint32_t ps2_read_data(void *opaque)
-{
- PS2State *s = (PS2State *)opaque;
- PS2Queue *q;
- int val, index;
-
- q = &s->queue;
- if (q->count == 0) {
- /* NOTE: if no data left, we return the last keyboard one
- (needed for EMM386) */
- /* XXX: need a timer to do things correctly */
- index = q->rptr - 1;
- if (index < 0)
- index = PS2_QUEUE_SIZE - 1;
- val = q->data[index];
- } else {
- val = q->data[q->rptr];
- if (++q->rptr == PS2_QUEUE_SIZE)
- q->rptr = 0;
- q->count--;
- /* reading deasserts IRQ */
- s->update_irq(s->update_arg, 0);
- /* reassert IRQs if data left */
- s->update_irq(s->update_arg, q->count != 0);
- }
- return val;
-}
-
-static void ps2_reset_keyboard(PS2KbdState *s)
-{
- s->scan_enabled = 1;
-}
-
-void ps2_write_keyboard(void *opaque, int val)
-{
- PS2KbdState *s = (PS2KbdState *)opaque;
-
- switch(s->common.write_cmd) {
- default:
- case -1:
- switch(val) {
- case 0x00:
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- case 0x05:
- ps2_queue(&s->common, KBD_REPLY_RESEND);
- break;
- case KBD_CMD_GET_ID:
- ps2_queue(&s->common, KBD_REPLY_ACK);
- ps2_queue(&s->common, 0xab);
- ps2_queue(&s->common, 0x83);
- break;
- case KBD_CMD_ECHO:
- ps2_queue(&s->common, KBD_CMD_ECHO);
- break;
- case KBD_CMD_ENABLE:
- s->scan_enabled = 1;
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- case KBD_CMD_SET_LEDS:
- case KBD_CMD_SET_RATE:
- s->common.write_cmd = val;
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- case KBD_CMD_RESET_DISABLE:
- ps2_reset_keyboard(s);
- s->scan_enabled = 0;
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- case KBD_CMD_RESET_ENABLE:
- ps2_reset_keyboard(s);
- s->scan_enabled = 1;
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- case KBD_CMD_RESET:
- ps2_reset_keyboard(s);
- ps2_queue(&s->common, KBD_REPLY_ACK);
- ps2_queue(&s->common, KBD_REPLY_POR);
- break;
- default:
- ps2_queue(&s->common, KBD_REPLY_ACK);
- break;
- }
- break;
- case KBD_CMD_SET_LEDS:
- ps2_queue(&s->common, KBD_REPLY_ACK);
- s->common.write_cmd = -1;
- break;
- case KBD_CMD_SET_RATE:
- ps2_queue(&s->common, KBD_REPLY_ACK);
- s->common.write_cmd = -1;
- break;
- }
-}
-
-/* Set the scancode translation mode.
- 0 = raw scancodes.
- 1 = translated scancodes (used by qemu internally). */
-
-void ps2_keyboard_set_translation(void *opaque, int mode)
-{
- PS2KbdState *s = (PS2KbdState *)opaque;
- s->translate = mode;
-}
-
-static void ps2_mouse_send_packet(PS2MouseState *s)
-{
- unsigned int b;
- int dx1, dy1, dz1;
-
- dx1 = s->mouse_dx;
- dy1 = s->mouse_dy;
- dz1 = s->mouse_dz;
- /* XXX: increase range to 8 bits ? */
- if (dx1 > 127)
- dx1 = 127;
- else if (dx1 < -127)
- dx1 = -127;
- if (dy1 > 127)
- dy1 = 127;
- else if (dy1 < -127)
- dy1 = -127;
- b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
- ps2_queue(&s->common, b);
- ps2_queue(&s->common, dx1 & 0xff);
- ps2_queue(&s->common, dy1 & 0xff);
- /* extra byte for IMPS/2 or IMEX */
- switch(s->mouse_type) {
- default:
- break;
- case 3:
- if (dz1 > 127)
- dz1 = 127;
- else if (dz1 < -127)
- dz1 = -127;
- ps2_queue(&s->common, dz1 & 0xff);
- break;
- case 4:
- if (dz1 > 7)
- dz1 = 7;
- else if (dz1 < -7)
- dz1 = -7;
- b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
- ps2_queue(&s->common, b);
- break;
- }
-
- /* update deltas */
- s->mouse_dx -= dx1;
- s->mouse_dy -= dy1;
- s->mouse_dz -= dz1;
-}
-
-static void ps2_mouse_event(void *opaque,
- int dx, int dy, int dz, int buttons_state)
-{
- PS2MouseState *s = opaque;
-
- /* check if deltas are recorded when disabled */
- if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
- return;
-
- s->mouse_dx += dx;
- s->mouse_dy -= dy;
- s->mouse_dz += dz;
- /* XXX: SDL sometimes generates nul events: we delete them */
- if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
- s->mouse_buttons == buttons_state)
- return;
- s->mouse_buttons = buttons_state;
-
- if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
- (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
- for(;;) {
- /* if not remote, send event. Multiple events are sent if
- too big deltas */
- ps2_mouse_send_packet(s);
- if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
- break;
- }
- }
-}
-
-void ps2_write_mouse(void *opaque, int val)
-{
- PS2MouseState *s = (PS2MouseState *)opaque;
-#ifdef DEBUG_MOUSE
- printf("kbd: write mouse 0x%02x\n", val);
-#endif
- switch(s->common.write_cmd) {
- default:
- case -1:
- /* mouse command */
- if (s->mouse_wrap) {
- if (val == AUX_RESET_WRAP) {
- s->mouse_wrap = 0;
- ps2_queue(&s->common, AUX_ACK);
- return;
- } else if (val != AUX_RESET) {
- ps2_queue(&s->common, val);
- return;
- }
- }
- switch(val) {
- case AUX_SET_SCALE11:
- s->mouse_status &= ~MOUSE_STATUS_SCALE21;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_SET_SCALE21:
- s->mouse_status |= MOUSE_STATUS_SCALE21;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_SET_STREAM:
- s->mouse_status &= ~MOUSE_STATUS_REMOTE;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_SET_WRAP:
- s->mouse_wrap = 1;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_SET_REMOTE:
- s->mouse_status |= MOUSE_STATUS_REMOTE;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_GET_TYPE:
- ps2_queue(&s->common, AUX_ACK);
- ps2_queue(&s->common, s->mouse_type);
- break;
- case AUX_SET_RES:
- case AUX_SET_SAMPLE:
- s->common.write_cmd = val;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_GET_SCALE:
- ps2_queue(&s->common, AUX_ACK);
- ps2_queue(&s->common, s->mouse_status);
- ps2_queue(&s->common, s->mouse_resolution);
- ps2_queue(&s->common, s->mouse_sample_rate);
- break;
- case AUX_POLL:
- ps2_queue(&s->common, AUX_ACK);
- ps2_mouse_send_packet(s);
- break;
- case AUX_ENABLE_DEV:
- s->mouse_status |= MOUSE_STATUS_ENABLED;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_DISABLE_DEV:
- s->mouse_status &= ~MOUSE_STATUS_ENABLED;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_SET_DEFAULT:
- s->mouse_sample_rate = 100;
- s->mouse_resolution = 2;
- s->mouse_status = 0;
- ps2_queue(&s->common, AUX_ACK);
- break;
- case AUX_RESET:
- s->mouse_sample_rate = 100;
- s->mouse_resolution = 2;
- s->mouse_status = 0;
- s->mouse_type = 0;
- ps2_queue(&s->common, AUX_ACK);
- ps2_queue(&s->common, 0xaa);
- ps2_queue(&s->common, s->mouse_type);
- break;
- default:
- break;
- }
- break;
- case AUX_SET_SAMPLE:
- s->mouse_sample_rate = val;
- /* detect IMPS/2 or IMEX */
- switch(s->mouse_detect_state) {
- default:
- case 0:
- if (val == 200)
- s->mouse_detect_state = 1;
- break;
- case 1:
- if (val == 100)
- s->mouse_detect_state = 2;
- else if (val == 200)
- s->mouse_detect_state = 3;
- else
- s->mouse_detect_state = 0;
- break;
- case 2:
- if (val == 80)
- s->mouse_type = 3; /* IMPS/2 */
- s->mouse_detect_state = 0;
- break;
- case 3:
- if (val == 80)
- s->mouse_type = 4; /* IMEX */
- s->mouse_detect_state = 0;
- break;
- }
- ps2_queue(&s->common, AUX_ACK);
- s->common.write_cmd = -1;
- break;
- case AUX_SET_RES:
- s->mouse_resolution = val;
- ps2_queue(&s->common, AUX_ACK);
- s->common.write_cmd = -1;
- break;
- }
-}
-
-static void ps2_reset(void *opaque)
-{
- PS2State *s = (PS2State *)opaque;
- PS2Queue *q;
- s->write_cmd = -1;
- q = &s->queue;
- q->rptr = 0;
- q->wptr = 0;
- q->count = 0;
-}
-
-static void ps2_common_save (QEMUFile *f, PS2State *s)
-{
- qemu_put_be32s (f, &s->write_cmd);
- qemu_put_be32s (f, &s->queue.rptr);
- qemu_put_be32s (f, &s->queue.wptr);
- qemu_put_be32s (f, &s->queue.count);
- qemu_put_buffer (f, s->queue.data, sizeof (s->queue.data));
-}
-
-static void ps2_common_load (QEMUFile *f, PS2State *s)
-{
- qemu_get_be32s (f, &s->write_cmd);
- qemu_get_be32s (f, &s->queue.rptr);
- qemu_get_be32s (f, &s->queue.wptr);
- qemu_get_be32s (f, &s->queue.count);
- qemu_get_buffer (f, s->queue.data, sizeof (s->queue.data));
-}
-
-static void ps2_kbd_save(QEMUFile* f, void* opaque)
-{
- PS2KbdState *s = (PS2KbdState*)opaque;
-
- ps2_common_save (f, &s->common);
- qemu_put_be32s(f, &s->scan_enabled);
- qemu_put_be32s(f, &s->translate);
-}
-
-static void ps2_mouse_save(QEMUFile* f, void* opaque)
-{
- PS2MouseState *s = (PS2MouseState*)opaque;
-
- ps2_common_save (f, &s->common);
- qemu_put_8s(f, &s->mouse_status);
- qemu_put_8s(f, &s->mouse_resolution);
- qemu_put_8s(f, &s->mouse_sample_rate);
- qemu_put_8s(f, &s->mouse_wrap);
- qemu_put_8s(f, &s->mouse_type);
- qemu_put_8s(f, &s->mouse_detect_state);
- qemu_put_be32s(f, &s->mouse_dx);
- qemu_put_be32s(f, &s->mouse_dy);
- qemu_put_be32s(f, &s->mouse_dz);
- qemu_put_8s(f, &s->mouse_buttons);
-}
-
-static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id)
-{
- PS2KbdState *s = (PS2KbdState*)opaque;
-
- if (version_id != 2)
- return -EINVAL;
-
- ps2_common_load (f, &s->common);
- qemu_get_be32s(f, &s->scan_enabled);
- qemu_get_be32s(f, &s->translate);
- return 0;
-}
-
-static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id)
-{
- PS2MouseState *s = (PS2MouseState*)opaque;
-
- if (version_id != 2)
- return -EINVAL;
-
- ps2_common_load (f, &s->common);
- qemu_get_8s(f, &s->mouse_status);
- qemu_get_8s(f, &s->mouse_resolution);
- qemu_get_8s(f, &s->mouse_sample_rate);
- qemu_get_8s(f, &s->mouse_wrap);
- qemu_get_8s(f, &s->mouse_type);
- qemu_get_8s(f, &s->mouse_detect_state);
- qemu_get_be32s(f, &s->mouse_dx);
- qemu_get_be32s(f, &s->mouse_dy);
- qemu_get_be32s(f, &s->mouse_dz);
- qemu_get_8s(f, &s->mouse_buttons);
- return 0;
-}
-
-void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
-{
- PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
-
- s->common.update_irq = update_irq;
- s->common.update_arg = update_arg;
- ps2_reset(&s->common);
- register_savevm("ps2kbd", 0, 2, ps2_kbd_save, ps2_kbd_load, s);
- qemu_add_kbd_event_handler(ps2_put_keycode, s);
- qemu_register_reset(ps2_reset, &s->common);
- return s;
-}
-
-void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
-{
- PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
-
- s->common.update_irq = update_irq;
- s->common.update_arg = update_arg;
- ps2_reset(&s->common);
- register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s);
- qemu_add_mouse_event_handler(ps2_mouse_event, s, 0);
- qemu_register_reset(ps2_reset, &s->common);
- return s;
-}
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
deleted file mode 100644
index 9c613a8..0000000
--- a/hw/rtl8139.c
+++ /dev/null
@@ -1,3471 +0,0 @@
-/**
- * QEMU RTL8139 emulation
- *
- * Copyright (c) 2006 Igor Kovalenko
- *
- * 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.
-
- * Modifications:
- * 2006-Jan-28 Mark Malakanov : TSAD and CSCR implementation (for Windows driver)
- *
- * 2006-Apr-28 Juergen Lock : EEPROM emulation changes for FreeBSD driver
- * HW revision ID changes for FreeBSD driver
- *
- * 2006-Jul-01 Igor Kovalenko : Implemented loopback mode for FreeBSD driver
- * Corrected packet transfer reassembly routine for 8139C+ mode
- * Rearranged debugging print statements
- * Implemented PCI timer interrupt (disabled by default)
- * Implemented Tally Counters, increased VM load/save version
- * Implemented IP/TCP/UDP checksum task offloading
- *
- * 2006-Jul-04 Igor Kovalenko : Implemented TCP segmentation offloading
- * Fixed MTU=1500 for produced ethernet frames
- *
- * 2006-Jul-09 Igor Kovalenko : Fixed TCP header length calculation while processing
- * segmentation offloading
- * Removed slirp.h dependency
- * Added rx/tx buffer reset when enabling rx/tx operation
- */
-
-#include "vl.h"
-
-/* debug RTL8139 card */
-//#define DEBUG_RTL8139 1
-
-#define PCI_FREQUENCY 33000000L
-
-/* debug RTL8139 card C+ mode only */
-//#define DEBUG_RTL8139CP 1
-
-/* RTL8139 provides frame CRC with received packet, this feature seems to be
- ignored by most drivers, disabled by default */
-//#define RTL8139_CALCULATE_RXCRC 1
-
-/* Uncomment to enable on-board timer interrupts */
-//#define RTL8139_ONBOARD_TIMER 1
-
-#if defined(RTL8139_CALCULATE_RXCRC)
-/* For crc32 */
-#include <zlib.h>
-#endif
-
-#define SET_MASKED(input, mask, curr) \
- ( ( (input) & ~(mask) ) | ( (curr) & (mask) ) )
-
-/* arg % size for size which is a power of 2 */
-#define MOD2(input, size) \
- ( ( input ) & ( size - 1 ) )
-
-#if defined (DEBUG_RTL8139)
-# define DEBUG_PRINT(x) do { printf x ; } while (0)
-#else
-# define DEBUG_PRINT(x)
-#endif
-
-/* Symbolic offsets to registers. */
-enum RTL8139_registers {
- MAC0 = 0, /* Ethernet hardware address. */
- MAR0 = 8, /* Multicast filter. */
- TxStatus0 = 0x10,/* Transmit status (Four 32bit registers). C mode only */
- /* Dump Tally Conter control register(64bit). C+ mode only */
- TxAddr0 = 0x20, /* Tx descriptors (also four 32bit). */
- RxBuf = 0x30,
- ChipCmd = 0x37,
- RxBufPtr = 0x38,
- RxBufAddr = 0x3A,
- IntrMask = 0x3C,
- IntrStatus = 0x3E,
- TxConfig = 0x40,
- RxConfig = 0x44,
- Timer = 0x48, /* A general-purpose counter. */
- RxMissed = 0x4C, /* 24 bits valid, write clears. */
- Cfg9346 = 0x50,
- Config0 = 0x51,
- Config1 = 0x52,
- FlashReg = 0x54,
- MediaStatus = 0x58,
- Config3 = 0x59,
- Config4 = 0x5A, /* absent on RTL-8139A */
- HltClk = 0x5B,
- MultiIntr = 0x5C,
- PCIRevisionID = 0x5E,
- TxSummary = 0x60, /* TSAD register. Transmit Status of All Descriptors*/
- BasicModeCtrl = 0x62,
- BasicModeStatus = 0x64,
- NWayAdvert = 0x66,
- NWayLPAR = 0x68,
- NWayExpansion = 0x6A,
- /* Undocumented registers, but required for proper operation. */
- FIFOTMS = 0x70, /* FIFO Control and test. */
- CSCR = 0x74, /* Chip Status and Configuration Register. */
- PARA78 = 0x78,
- PARA7c = 0x7c, /* Magic transceiver parameter register. */
- Config5 = 0xD8, /* absent on RTL-8139A */
- /* C+ mode */
- TxPoll = 0xD9, /* Tell chip to check Tx descriptors for work */
- RxMaxSize = 0xDA, /* Max size of an Rx packet (8169 only) */
- CpCmd = 0xE0, /* C+ Command register (C+ mode only) */
- IntrMitigate = 0xE2, /* rx/tx interrupt mitigation control */
- RxRingAddrLO = 0xE4, /* 64-bit start addr of Rx ring */
- RxRingAddrHI = 0xE8, /* 64-bit start addr of Rx ring */
- TxThresh = 0xEC, /* Early Tx threshold */
-};
-
-enum ClearBitMasks {
- MultiIntrClear = 0xF000,
- ChipCmdClear = 0xE2,
- Config1Clear = (1<<7)|(1<<6)|(1<<3)|(1<<2)|(1<<1),
-};
-
-enum ChipCmdBits {
- CmdReset = 0x10,
- CmdRxEnb = 0x08,
- CmdTxEnb = 0x04,
- RxBufEmpty = 0x01,
-};
-
-/* C+ mode */
-enum CplusCmdBits {
- CPlusRxVLAN = 0x0040, /* enable receive VLAN detagging */
- CPlusRxChkSum = 0x0020, /* enable receive checksum offloading */
- CPlusRxEnb = 0x0002,
- CPlusTxEnb = 0x0001,
-};
-
-/* Interrupt register bits, using my own meaningful names. */
-enum IntrStatusBits {
- PCIErr = 0x8000,
- PCSTimeout = 0x4000,
- RxFIFOOver = 0x40,
- RxUnderrun = 0x20,
- RxOverflow = 0x10,
- TxErr = 0x08,
- TxOK = 0x04,
- RxErr = 0x02,
- RxOK = 0x01,
-
- RxAckBits = RxFIFOOver | RxOverflow | RxOK,
-};
-
-enum TxStatusBits {
- TxHostOwns = 0x2000,
- TxUnderrun = 0x4000,
- TxStatOK = 0x8000,
- TxOutOfWindow = 0x20000000,
- TxAborted = 0x40000000,
- TxCarrierLost = 0x80000000,
-};
-enum RxStatusBits {
- RxMulticast = 0x8000,
- RxPhysical = 0x4000,
- RxBroadcast = 0x2000,
- RxBadSymbol = 0x0020,
- RxRunt = 0x0010,
- RxTooLong = 0x0008,
- RxCRCErr = 0x0004,
- RxBadAlign = 0x0002,
- RxStatusOK = 0x0001,
-};
-
-/* Bits in RxConfig. */
-enum rx_mode_bits {
- AcceptErr = 0x20,
- AcceptRunt = 0x10,
- AcceptBroadcast = 0x08,
- AcceptMulticast = 0x04,
- AcceptMyPhys = 0x02,
- AcceptAllPhys = 0x01,
-};
-
-/* Bits in TxConfig. */
-enum tx_config_bits {
-
- /* Interframe Gap Time. Only TxIFG96 doesn't violate IEEE 802.3 */
- TxIFGShift = 24,
- TxIFG84 = (0 << TxIFGShift), /* 8.4us / 840ns (10 / 100Mbps) */
- TxIFG88 = (1 << TxIFGShift), /* 8.8us / 880ns (10 / 100Mbps) */
- TxIFG92 = (2 << TxIFGShift), /* 9.2us / 920ns (10 / 100Mbps) */
- TxIFG96 = (3 << TxIFGShift), /* 9.6us / 960ns (10 / 100Mbps) */
-
- TxLoopBack = (1 << 18) | (1 << 17), /* enable loopback test mode */
- TxCRC = (1 << 16), /* DISABLE appending CRC to end of Tx packets */
- TxClearAbt = (1 << 0), /* Clear abort (WO) */
- TxDMAShift = 8, /* DMA burst value (0-7) is shifted this many bits */
- TxRetryShift = 4, /* TXRR value (0-15) is shifted this many bits */
-
- TxVersionMask = 0x7C800000, /* mask out version bits 30-26, 23 */
-};
-
-
-/* Transmit Status of All Descriptors (TSAD) Register */
-enum TSAD_bits {
- TSAD_TOK3 = 1<<15, // TOK bit of Descriptor 3
- TSAD_TOK2 = 1<<14, // TOK bit of Descriptor 2
- TSAD_TOK1 = 1<<13, // TOK bit of Descriptor 1
- TSAD_TOK0 = 1<<12, // TOK bit of Descriptor 0
- TSAD_TUN3 = 1<<11, // TUN bit of Descriptor 3
- TSAD_TUN2 = 1<<10, // TUN bit of Descriptor 2
- TSAD_TUN1 = 1<<9, // TUN bit of Descriptor 1
- TSAD_TUN0 = 1<<8, // TUN bit of Descriptor 0
- TSAD_TABT3 = 1<<07, // TABT bit of Descriptor 3
- TSAD_TABT2 = 1<<06, // TABT bit of Descriptor 2
- TSAD_TABT1 = 1<<05, // TABT bit of Descriptor 1
- TSAD_TABT0 = 1<<04, // TABT bit of Descriptor 0
- TSAD_OWN3 = 1<<03, // OWN bit of Descriptor 3
- TSAD_OWN2 = 1<<02, // OWN bit of Descriptor 2
- TSAD_OWN1 = 1<<01, // OWN bit of Descriptor 1
- TSAD_OWN0 = 1<<00, // OWN bit of Descriptor 0
-};
-
-
-/* Bits in Config1 */
-enum Config1Bits {
- Cfg1_PM_Enable = 0x01,
- Cfg1_VPD_Enable = 0x02,
- Cfg1_PIO = 0x04,
- Cfg1_MMIO = 0x08,
- LWAKE = 0x10, /* not on 8139, 8139A */
- Cfg1_Driver_Load = 0x20,
- Cfg1_LED0 = 0x40,
- Cfg1_LED1 = 0x80,
- SLEEP = (1 << 1), /* only on 8139, 8139A */
- PWRDN = (1 << 0), /* only on 8139, 8139A */
-};
-
-/* Bits in Config3 */
-enum Config3Bits {
- Cfg3_FBtBEn = (1 << 0), /* 1 = Fast Back to Back */
- Cfg3_FuncRegEn = (1 << 1), /* 1 = enable CardBus Function registers */
- Cfg3_CLKRUN_En = (1 << 2), /* 1 = enable CLKRUN */
- Cfg3_CardB_En = (1 << 3), /* 1 = enable CardBus registers */
- Cfg3_LinkUp = (1 << 4), /* 1 = wake up on link up */
- Cfg3_Magic = (1 << 5), /* 1 = wake up on Magic Packet (tm) */
- Cfg3_PARM_En = (1 << 6), /* 0 = software can set twister parameters */
- Cfg3_GNTSel = (1 << 7), /* 1 = delay 1 clock from PCI GNT signal */
-};
-
-/* Bits in Config4 */
-enum Config4Bits {
- LWPTN = (1 << 2), /* not on 8139, 8139A */
-};
-
-/* Bits in Config5 */
-enum Config5Bits {
- Cfg5_PME_STS = (1 << 0), /* 1 = PCI reset resets PME_Status */
- Cfg5_LANWake = (1 << 1), /* 1 = enable LANWake signal */
- Cfg5_LDPS = (1 << 2), /* 0 = save power when link is down */
- Cfg5_FIFOAddrPtr = (1 << 3), /* Realtek internal SRAM testing */
- Cfg5_UWF = (1 << 4), /* 1 = accept unicast wakeup frame */
- Cfg5_MWF = (1 << 5), /* 1 = accept multicast wakeup frame */
- Cfg5_BWF = (1 << 6), /* 1 = accept broadcast wakeup frame */
-};
-
-enum RxConfigBits {
- /* rx fifo threshold */
- RxCfgFIFOShift = 13,
- RxCfgFIFONone = (7 << RxCfgFIFOShift),
-
- /* Max DMA burst */
- RxCfgDMAShift = 8,
- RxCfgDMAUnlimited = (7 << RxCfgDMAShift),
-
- /* rx ring buffer length */
- RxCfgRcv8K = 0,
- RxCfgRcv16K = (1 << 11),
- RxCfgRcv32K = (1 << 12),
- RxCfgRcv64K = (1 << 11) | (1 << 12),
-
- /* Disable packet wrap at end of Rx buffer. (not possible with 64k) */
- RxNoWrap = (1 << 7),
-};
-
-/* Twister tuning parameters from RealTek.
- Completely undocumented, but required to tune bad links on some boards. */
-/*
-enum CSCRBits {
- CSCR_LinkOKBit = 0x0400,
- CSCR_LinkChangeBit = 0x0800,
- CSCR_LinkStatusBits = 0x0f000,
- CSCR_LinkDownOffCmd = 0x003c0,
- CSCR_LinkDownCmd = 0x0f3c0,
-*/
-enum CSCRBits {
- CSCR_Testfun = 1<<15, /* 1 = Auto-neg speeds up internal timer, WO, def 0 */
- CSCR_LD = 1<<9, /* Active low TPI link disable signal. When low, TPI still transmits link pulses and TPI stays in good link state. def 1*/
- CSCR_HEART_BIT = 1<<8, /* 1 = HEART BEAT enable, 0 = HEART BEAT disable. HEART BEAT function is only valid in 10Mbps mode. def 1*/
- CSCR_JBEN = 1<<7, /* 1 = enable jabber function. 0 = disable jabber function, def 1*/
- CSCR_F_LINK_100 = 1<<6, /* Used to login force good link in 100Mbps for diagnostic purposes. 1 = DISABLE, 0 = ENABLE. def 1*/
- CSCR_F_Connect = 1<<5, /* Assertion of this bit forces the disconnect function to be bypassed. def 0*/
- CSCR_Con_status = 1<<3, /* This bit indicates the status of the connection. 1 = valid connected link detected; 0 = disconnected link detected. RO def 0*/
- CSCR_Con_status_En = 1<<2, /* Assertion of this bit configures LED1 pin to indicate connection status. def 0*/
- CSCR_PASS_SCR = 1<<0, /* Bypass Scramble, def 0*/
-};
-
-enum Cfg9346Bits {
- Cfg9346_Lock = 0x00,
- Cfg9346_Unlock = 0xC0,
-};
-
-typedef enum {
- CH_8139 = 0,
- CH_8139_K,
- CH_8139A,
- CH_8139A_G,
- CH_8139B,
- CH_8130,
- CH_8139C,
- CH_8100,
- CH_8100B_8139D,
- CH_8101,
-} chip_t;
-
-enum chip_flags {
- HasHltClk = (1 << 0),
- HasLWake = (1 << 1),
-};
-
-#define HW_REVID(b30, b29, b28, b27, b26, b23, b22) \
- (b30<<30 | b29<<29 | b28<<28 | b27<<27 | b26<<26 | b23<<23 | b22<<22)
-#define HW_REVID_MASK HW_REVID(1, 1, 1, 1, 1, 1, 1)
-
-#define RTL8139_PCI_REVID_8139 0x10
-#define RTL8139_PCI_REVID_8139CPLUS 0x20
-
-#define RTL8139_PCI_REVID RTL8139_PCI_REVID_8139CPLUS
-
-/* Size is 64 * 16bit words */
-#define EEPROM_9346_ADDR_BITS 6
-#define EEPROM_9346_SIZE (1 << EEPROM_9346_ADDR_BITS)
-#define EEPROM_9346_ADDR_MASK (EEPROM_9346_SIZE - 1)
-
-enum Chip9346Operation
-{
- Chip9346_op_mask = 0xc0, /* 10 zzzzzz */
- Chip9346_op_read = 0x80, /* 10 AAAAAA */
- Chip9346_op_write = 0x40, /* 01 AAAAAA D(15)..D(0) */
- Chip9346_op_ext_mask = 0xf0, /* 11 zzzzzz */
- Chip9346_op_write_enable = 0x30, /* 00 11zzzz */
- Chip9346_op_write_all = 0x10, /* 00 01zzzz */
- Chip9346_op_write_disable = 0x00, /* 00 00zzzz */
-};
-
-enum Chip9346Mode
-{
- Chip9346_none = 0,
- Chip9346_enter_command_mode,
- Chip9346_read_command,
- Chip9346_data_read, /* from output register */
- Chip9346_data_write, /* to input register, then to contents at specified address */
- Chip9346_data_write_all, /* to input register, then filling contents */
-};
-
-typedef struct EEprom9346
-{
- uint16_t contents[EEPROM_9346_SIZE];
- int mode;
- uint32_t tick;
- uint8_t address;
- uint16_t input;
- uint16_t output;
-
- uint8_t eecs;
- uint8_t eesk;
- uint8_t eedi;
- uint8_t eedo;
-} EEprom9346;
-
-typedef struct RTL8139TallyCounters
-{
- /* Tally counters */
- uint64_t TxOk;
- uint64_t RxOk;
- uint64_t TxERR;
- uint32_t RxERR;
- uint16_t MissPkt;
- uint16_t FAE;
- uint32_t Tx1Col;
- uint32_t TxMCol;
- uint64_t RxOkPhy;
- uint64_t RxOkBrd;
- uint32_t RxOkMul;
- uint16_t TxAbt;
- uint16_t TxUndrn;
-} RTL8139TallyCounters;
-
-/* Clears all tally counters */
-static void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters);
-
-/* Writes tally counters to specified physical memory address */
-static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* counters);
-
-/* Loads values of tally counters from VM state file */
-static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters);
-
-/* Saves values of tally counters to VM state file */
-static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters);
-
-typedef struct RTL8139State {
- uint8_t phys[8]; /* mac address */
- uint8_t mult[8]; /* multicast mask array */
-
- uint32_t TxStatus[4]; /* TxStatus0 in C mode*/ /* also DTCCR[0] and DTCCR[1] in C+ mode */
- uint32_t TxAddr[4]; /* TxAddr0 */
- uint32_t RxBuf; /* Receive buffer */
- uint32_t RxBufferSize;/* internal variable, receive ring buffer size in C mode */
- uint32_t RxBufPtr;
- uint32_t RxBufAddr;
-
- uint16_t IntrStatus;
- uint16_t IntrMask;
-
- uint32_t TxConfig;
- uint32_t RxConfig;
- uint32_t RxMissed;
-
- uint16_t CSCR;
-
- uint8_t Cfg9346;
- uint8_t Config0;
- uint8_t Config1;
- uint8_t Config3;
- uint8_t Config4;
- uint8_t Config5;
-
- uint8_t clock_enabled;
- uint8_t bChipCmdState;
-
- uint16_t MultiIntr;
-
- uint16_t BasicModeCtrl;
- uint16_t BasicModeStatus;
- uint16_t NWayAdvert;
- uint16_t NWayLPAR;
- uint16_t NWayExpansion;
-
- uint16_t CpCmd;
- uint8_t TxThresh;
-
- int irq;
- PCIDevice *pci_dev;
- VLANClientState *vc;
- uint8_t macaddr[6];
- int rtl8139_mmio_io_addr;
-
- /* C ring mode */
- uint32_t currTxDesc;
-
- /* C+ mode */
- uint32_t currCPlusRxDesc;
- uint32_t currCPlusTxDesc;
-
- uint32_t RxRingAddrLO;
- uint32_t RxRingAddrHI;
-
- EEprom9346 eeprom;
-
- uint32_t TCTR;
- uint32_t TimerInt;
- int64_t TCTR_base;
-
- /* Tally counters */
- RTL8139TallyCounters tally_counters;
-
- /* Non-persistent data */
- uint8_t *cplus_txbuffer;
- int cplus_txbuffer_len;
- int cplus_txbuffer_offset;
-
- /* PCI interrupt timer */
- QEMUTimer *timer;
-
-} RTL8139State;
-
-void prom9346_decode_command(EEprom9346 *eeprom, uint8_t command)
-{
- DEBUG_PRINT(("RTL8139: eeprom command 0x%02x\n", command));
-
- switch (command & Chip9346_op_mask)
- {
- case Chip9346_op_read:
- {
- eeprom->address = command & EEPROM_9346_ADDR_MASK;
- eeprom->output = eeprom->contents[eeprom->address];
- eeprom->eedo = 0;
- eeprom->tick = 0;
- eeprom->mode = Chip9346_data_read;
- DEBUG_PRINT(("RTL8139: eeprom read from address 0x%02x data=0x%04x\n",
- eeprom->address, eeprom->output));
- }
- break;
-
- case Chip9346_op_write:
- {
- eeprom->address = command & EEPROM_9346_ADDR_MASK;
- eeprom->input = 0;
- eeprom->tick = 0;
- eeprom->mode = Chip9346_none; /* Chip9346_data_write */
- DEBUG_PRINT(("RTL8139: eeprom begin write to address 0x%02x\n",
- eeprom->address));
- }
- break;
- default:
- eeprom->mode = Chip9346_none;
- switch (command & Chip9346_op_ext_mask)
- {
- case Chip9346_op_write_enable:
- DEBUG_PRINT(("RTL8139: eeprom write enabled\n"));
- break;
- case Chip9346_op_write_all:
- DEBUG_PRINT(("RTL8139: eeprom begin write all\n"));
- break;
- case Chip9346_op_write_disable:
- DEBUG_PRINT(("RTL8139: eeprom write disabled\n"));
- break;
- }
- break;
- }
-}
-
-void prom9346_shift_clock(EEprom9346 *eeprom)
-{
- int bit = eeprom->eedi?1:0;
-
- ++ eeprom->tick;
-
- DEBUG_PRINT(("eeprom: tick %d eedi=%d eedo=%d\n", eeprom->tick, eeprom->eedi, eeprom->eedo));
-
- switch (eeprom->mode)
- {
- case Chip9346_enter_command_mode:
- if (bit)
- {
- eeprom->mode = Chip9346_read_command;
- eeprom->tick = 0;
- eeprom->input = 0;
- DEBUG_PRINT(("eeprom: +++ synchronized, begin command read\n"));
- }
- break;
-
- case Chip9346_read_command:
- eeprom->input = (eeprom->input << 1) | (bit & 1);
- if (eeprom->tick == 8)
- {
- prom9346_decode_command(eeprom, eeprom->input & 0xff);
- }
- break;
-
- case Chip9346_data_read:
- eeprom->eedo = (eeprom->output & 0x8000)?1:0;
- eeprom->output <<= 1;
- if (eeprom->tick == 16)
- {
-#if 1
- // the FreeBSD drivers (rl and re) don't explicitly toggle
- // CS between reads (or does setting Cfg9346 to 0 count too?),
- // so we need to enter wait-for-command state here
- eeprom->mode = Chip9346_enter_command_mode;
- eeprom->input = 0;
- eeprom->tick = 0;
-
- DEBUG_PRINT(("eeprom: +++ end of read, awaiting next command\n"));
-#else
- // original behaviour
- ++eeprom->address;
- eeprom->address &= EEPROM_9346_ADDR_MASK;
- eeprom->output = eeprom->contents[eeprom->address];
- eeprom->tick = 0;
-
- DEBUG_PRINT(("eeprom: +++ read next address 0x%02x data=0x%04x\n",
- eeprom->address, eeprom->output));
-#endif
- }
- break;
-
- case Chip9346_data_write:
- eeprom->input = (eeprom->input << 1) | (bit & 1);
- if (eeprom->tick == 16)
- {
- DEBUG_PRINT(("RTL8139: eeprom write to address 0x%02x data=0x%04x\n",
- eeprom->address, eeprom->input));
-
- eeprom->contents[eeprom->address] = eeprom->input;
- eeprom->mode = Chip9346_none; /* waiting for next command after CS cycle */
- eeprom->tick = 0;
- eeprom->input = 0;
- }
- break;
-
- case Chip9346_data_write_all:
- eeprom->input = (eeprom->input << 1) | (bit & 1);
- if (eeprom->tick == 16)
- {
- int i;
- for (i = 0; i < EEPROM_9346_SIZE; i++)
- {
- eeprom->contents[i] = eeprom->input;
- }
- DEBUG_PRINT(("RTL8139: eeprom filled with data=0x%04x\n",
- eeprom->input));
-
- eeprom->mode = Chip9346_enter_command_mode;
- eeprom->tick = 0;
- eeprom->input = 0;
- }
- break;
-
- default:
- break;
- }
-}
-
-int prom9346_get_wire(RTL8139State *s)
-{
- EEprom9346 *eeprom = &s->eeprom;
- if (!eeprom->eecs)
- return 0;
-
- return eeprom->eedo;
-}
-
-void prom9346_set_wire(RTL8139State *s, int eecs, int eesk, int eedi)
-{
- EEprom9346 *eeprom = &s->eeprom;
- uint8_t old_eecs = eeprom->eecs;
- uint8_t old_eesk = eeprom->eesk;
-
- eeprom->eecs = eecs;
- eeprom->eesk = eesk;
- eeprom->eedi = eedi;
-
- DEBUG_PRINT(("eeprom: +++ wires CS=%d SK=%d DI=%d DO=%d\n",
- eeprom->eecs, eeprom->eesk, eeprom->eedi, eeprom->eedo));
-
- if (!old_eecs && eecs)
- {
- /* Synchronize start */
- eeprom->tick = 0;
- eeprom->input = 0;
- eeprom->output = 0;
- eeprom->mode = Chip9346_enter_command_mode;
-
- DEBUG_PRINT(("=== eeprom: begin access, enter command mode\n"));
- }
-
- if (!eecs)
- {
- DEBUG_PRINT(("=== eeprom: end access\n"));
- return;
- }
-
- if (!old_eesk && eesk)
- {
- /* SK front rules */
- prom9346_shift_clock(eeprom);
- }
-}
-
-static void rtl8139_update_irq(RTL8139State *s)
-{
- 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));
-
- 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));
- }
-}
-
-#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);
-}
-
-static int rtl8139_RxWrap(RTL8139State *s)
-{
- /* wrapping enabled; assume 1.5k more buffer space if size < 65536 */
- return (s->RxConfig & (1 << 7));
-}
-
-static int rtl8139_receiver_enabled(RTL8139State *s)
-{
- return s->bChipCmdState & CmdRxEnb;
-}
-
-static int rtl8139_transmitter_enabled(RTL8139State *s)
-{
- return s->bChipCmdState & CmdTxEnb;
-}
-
-static int rtl8139_cp_receiver_enabled(RTL8139State *s)
-{
- return s->CpCmd & CPlusRxEnb;
-}
-
-static int rtl8139_cp_transmitter_enabled(RTL8139State *s)
-{
- return s->CpCmd & CPlusTxEnb;
-}
-
-static void rtl8139_write_buffer(RTL8139State *s, const void *buf, int size)
-{
- if (s->RxBufAddr + size > s->RxBufferSize)
- {
- int wrapped = MOD2(s->RxBufAddr + size, s->RxBufferSize);
-
- /* write packet data */
- if (wrapped && s->RxBufferSize < 65536 && !rtl8139_RxWrap(s))
- {
- DEBUG_PRINT((">>> RTL8139: rx packet wrapped in buffer at %d\n", size-wrapped));
-
- if (size > wrapped)
- {
- cpu_physical_memory_write( s->RxBuf + s->RxBufAddr,
- buf, size-wrapped );
- }
-
- /* reset buffer pointer */
- s->RxBufAddr = 0;
-
- cpu_physical_memory_write( s->RxBuf + s->RxBufAddr,
- buf + (size-wrapped), wrapped );
-
- s->RxBufAddr = wrapped;
-
- return;
- }
- }
-
- /* non-wrapping path or overwrapping enabled */
- cpu_physical_memory_write( s->RxBuf + s->RxBufAddr, buf, size );
-
- s->RxBufAddr += size;
-}
-
-#define MIN_BUF_SIZE 60
-static inline target_phys_addr_t rtl8139_addr64(uint32_t low, uint32_t high)
-{
-#if TARGET_PHYS_ADDR_BITS > 32
- return low | ((target_phys_addr_t)high << 32);
-#else
- return low;
-#endif
-}
-
-static int rtl8139_can_receive(void *opaque)
-{
- RTL8139State *s = opaque;
- int avail;
-
- /* Recieve (drop) packets if card is disabled. */
- if (!s->clock_enabled)
- return 1;
- if (!rtl8139_receiver_enabled(s))
- return 1;
-
- if (rtl8139_cp_receiver_enabled(s)) {
- /* ??? Flow control not implemented in c+ mode.
- This is a hack to work around slirp deficiencies anyway. */
- return 1;
- } else {
- avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr,
- s->RxBufferSize);
- return (avail == 0 || avail >= 1514);
- }
-}
-
-static void rtl8139_do_receive(void *opaque, const uint8_t *buf, int size, int do_interrupt)
-{
- RTL8139State *s = opaque;
-
- uint32_t packet_header = 0;
-
- uint8_t buf1[60];
- static const uint8_t broadcast_macaddr[6] =
- { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
- DEBUG_PRINT((">>> RTL8139: received len=%d\n", size));
-
- /* test if board clock is stopped */
- if (!s->clock_enabled)
- {
- DEBUG_PRINT(("RTL8139: stopped ==========================\n"));
- return;
- }
-
- /* first check if receiver is enabled */
-
- if (!rtl8139_receiver_enabled(s))
- {
- DEBUG_PRINT(("RTL8139: receiver disabled ================\n"));
- return;
- }
-
- /* XXX: check this */
- if (s->RxConfig & AcceptAllPhys) {
- /* promiscuous: receive all */
- DEBUG_PRINT((">>> RTL8139: packet received in promiscuous mode\n"));
-
- } else {
- if (!memcmp(buf, broadcast_macaddr, 6)) {
- /* broadcast address */
- if (!(s->RxConfig & AcceptBroadcast))
- {
- DEBUG_PRINT((">>> RTL8139: broadcast packet rejected\n"));
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
-
- return;
- }
-
- packet_header |= RxBroadcast;
-
- DEBUG_PRINT((">>> RTL8139: broadcast packet received\n"));
-
- /* update tally counter */
- ++s->tally_counters.RxOkBrd;
-
- } else if (buf[0] & 0x01) {
- /* multicast */
- if (!(s->RxConfig & AcceptMulticast))
- {
- DEBUG_PRINT((">>> RTL8139: multicast packet rejected\n"));
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
-
- return;
- }
-
- int mcast_idx = compute_mcast_idx(buf);
-
- if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7))))
- {
- DEBUG_PRINT((">>> RTL8139: multicast address mismatch\n"));
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
-
- return;
- }
-
- packet_header |= RxMulticast;
-
- DEBUG_PRINT((">>> RTL8139: multicast packet received\n"));
-
- /* update tally counter */
- ++s->tally_counters.RxOkMul;
-
- } else if (s->phys[0] == buf[0] &&
- s->phys[1] == buf[1] &&
- s->phys[2] == buf[2] &&
- s->phys[3] == buf[3] &&
- s->phys[4] == buf[4] &&
- s->phys[5] == buf[5]) {
- /* match */
- if (!(s->RxConfig & AcceptMyPhys))
- {
- DEBUG_PRINT((">>> RTL8139: rejecting physical address matching packet\n"));
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
-
- return;
- }
-
- packet_header |= RxPhysical;
-
- DEBUG_PRINT((">>> RTL8139: physical address matching packet received\n"));
-
- /* update tally counter */
- ++s->tally_counters.RxOkPhy;
-
- } else {
-
- DEBUG_PRINT((">>> RTL8139: unknown packet\n"));
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
-
- return;
- }
- }
-
- /* if too small buffer, then expand it */
- if (size < MIN_BUF_SIZE) {
- memcpy(buf1, buf, size);
- memset(buf1 + size, 0, MIN_BUF_SIZE - size);
- buf = buf1;
- size = MIN_BUF_SIZE;
- }
-
- if (rtl8139_cp_receiver_enabled(s))
- {
- DEBUG_PRINT(("RTL8139: in C+ Rx mode ================\n"));
-
- /* begin C+ receiver mode */
-
-/* w0 ownership flag */
-#define CP_RX_OWN (1<<31)
-/* w0 end of ring flag */
-#define CP_RX_EOR (1<<30)
-/* w0 bits 0...12 : buffer size */
-#define CP_RX_BUFFER_SIZE_MASK ((1<<13) - 1)
-/* w1 tag available flag */
-#define CP_RX_TAVA (1<<16)
-/* w1 bits 0...15 : VLAN tag */
-#define CP_RX_VLAN_TAG_MASK ((1<<16) - 1)
-/* w2 low 32bit of Rx buffer ptr */
-/* w3 high 32bit of Rx buffer ptr */
-
- int descriptor = s->currCPlusRxDesc;
- target_phys_addr_t cplus_rx_ring_desc;
-
- cplus_rx_ring_desc = rtl8139_addr64(s->RxRingAddrLO, s->RxRingAddrHI);
- cplus_rx_ring_desc += 16 * descriptor;
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode reading RX descriptor %d from host memory at %08x %08x = %016" PRIx64 "\n",
- descriptor, s->RxRingAddrHI, s->RxRingAddrLO, (uint64_t)cplus_rx_ring_desc));
-
- uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
-
- cpu_physical_memory_read(cplus_rx_ring_desc, (uint8_t *)&val, 4);
- rxdw0 = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
- rxdw1 = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_rx_ring_desc+8, (uint8_t *)&val, 4);
- rxbufLO = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_rx_ring_desc+12, (uint8_t *)&val, 4);
- rxbufHI = le32_to_cpu(val);
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
- descriptor,
- rxdw0, rxdw1, rxbufLO, rxbufHI));
-
- if (!(rxdw0 & CP_RX_OWN))
- {
- DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d is owned by host\n", descriptor));
-
- s->IntrStatus |= RxOverflow;
- ++s->RxMissed;
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
- ++s->tally_counters.MissPkt;
-
- rtl8139_update_irq(s);
- return;
- }
-
- uint32_t rx_space = rxdw0 & CP_RX_BUFFER_SIZE_MASK;
-
- /* TODO: scatter the packet over available receive ring descriptors space */
-
- if (size+4 > rx_space)
- {
- DEBUG_PRINT(("RTL8139: C+ Rx mode : descriptor %d size %d received %d + 4\n",
- descriptor, rx_space, size));
-
- s->IntrStatus |= RxOverflow;
- ++s->RxMissed;
-
- /* update tally counter */
- ++s->tally_counters.RxERR;
- ++s->tally_counters.MissPkt;
-
- rtl8139_update_irq(s);
- return;
- }
-
- target_phys_addr_t rx_addr = rtl8139_addr64(rxbufLO, rxbufHI);
-
- /* receive/copy to target memory */
- cpu_physical_memory_write( rx_addr, buf, size );
-
- if (s->CpCmd & CPlusRxChkSum)
- {
- /* do some packet checksumming */
- }
-
- /* write checksum */
-#if defined (RTL8139_CALCULATE_RXCRC)
- val = cpu_to_le32(crc32(~0, buf, size));
-#else
- val = 0;
-#endif
- cpu_physical_memory_write( rx_addr+size, (uint8_t *)&val, 4);
-
-/* first segment of received packet flag */
-#define CP_RX_STATUS_FS (1<<29)
-/* last segment of received packet flag */
-#define CP_RX_STATUS_LS (1<<28)
-/* multicast packet flag */
-#define CP_RX_STATUS_MAR (1<<26)
-/* physical-matching packet flag */
-#define CP_RX_STATUS_PAM (1<<25)
-/* broadcast packet flag */
-#define CP_RX_STATUS_BAR (1<<24)
-/* runt packet flag */
-#define CP_RX_STATUS_RUNT (1<<19)
-/* crc error flag */
-#define CP_RX_STATUS_CRC (1<<18)
-/* IP checksum error flag */
-#define CP_RX_STATUS_IPF (1<<15)
-/* UDP checksum error flag */
-#define CP_RX_STATUS_UDPF (1<<14)
-/* TCP checksum error flag */
-#define CP_RX_STATUS_TCPF (1<<13)
-
- /* transfer ownership to target */
- rxdw0 &= ~CP_RX_OWN;
-
- /* set first segment bit */
- rxdw0 |= CP_RX_STATUS_FS;
-
- /* set last segment bit */
- rxdw0 |= CP_RX_STATUS_LS;
-
- /* set received packet type flags */
- if (packet_header & RxBroadcast)
- rxdw0 |= CP_RX_STATUS_BAR;
- if (packet_header & RxMulticast)
- rxdw0 |= CP_RX_STATUS_MAR;
- if (packet_header & RxPhysical)
- rxdw0 |= CP_RX_STATUS_PAM;
-
- /* set received size */
- rxdw0 &= ~CP_RX_BUFFER_SIZE_MASK;
- rxdw0 |= (size+4);
-
- /* reset VLAN tag flag */
- rxdw1 &= ~CP_RX_TAVA;
-
- /* update ring data */
- val = cpu_to_le32(rxdw0);
- cpu_physical_memory_write(cplus_rx_ring_desc, (uint8_t *)&val, 4);
- val = cpu_to_le32(rxdw1);
- cpu_physical_memory_write(cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
-
- /* update tally counter */
- ++s->tally_counters.RxOk;
-
- /* seek to next Rx descriptor */
- if (rxdw0 & CP_RX_EOR)
- {
- s->currCPlusRxDesc = 0;
- }
- else
- {
- ++s->currCPlusRxDesc;
- }
-
- DEBUG_PRINT(("RTL8139: done C+ Rx mode ----------------\n"));
-
- }
- else
- {
- DEBUG_PRINT(("RTL8139: in ring Rx mode ================\n"));
-
- /* begin ring receiver mode */
- int avail = MOD2(s->RxBufferSize + s->RxBufPtr - s->RxBufAddr, s->RxBufferSize);
-
- /* if receiver buffer is empty then avail == 0 */
-
- if (avail != 0 && size + 8 >= avail)
- {
- DEBUG_PRINT(("rx overflow: rx buffer length %d head 0x%04x read 0x%04x === available 0x%04x need 0x%04x\n",
- s->RxBufferSize, s->RxBufAddr, s->RxBufPtr, avail, size + 8));
-
- s->IntrStatus |= RxOverflow;
- ++s->RxMissed;
- rtl8139_update_irq(s);
- return;
- }
-
- packet_header |= RxStatusOK;
-
- packet_header |= (((size+4) << 16) & 0xffff0000);
-
- /* write header */
- uint32_t val = cpu_to_le32(packet_header);
-
- rtl8139_write_buffer(s, (uint8_t *)&val, 4);
-
- rtl8139_write_buffer(s, buf, size);
-
- /* write checksum */
-#if defined (RTL8139_CALCULATE_RXCRC)
- val = cpu_to_le32(crc32(~0, buf, size));
-#else
- val = 0;
-#endif
-
- rtl8139_write_buffer(s, (uint8_t *)&val, 4);
-
- /* correct buffer write pointer */
- s->RxBufAddr = MOD2((s->RxBufAddr + 3) & ~0x3, s->RxBufferSize);
-
- /* now we can signal we have received something */
-
- DEBUG_PRINT((" received: rx buffer length %d head 0x%04x read 0x%04x\n",
- s->RxBufferSize, s->RxBufAddr, s->RxBufPtr));
- }
-
- s->IntrStatus |= RxOK;
-
- if (do_interrupt)
- {
- rtl8139_update_irq(s);
- }
-}
-
-static void rtl8139_receive(void *opaque, const uint8_t *buf, int size)
-{
- rtl8139_do_receive(opaque, buf, size, 1);
-}
-
-static void rtl8139_reset_rxring(RTL8139State *s, uint32_t bufferSize)
-{
- s->RxBufferSize = bufferSize;
- s->RxBufPtr = 0;
- s->RxBufAddr = 0;
-}
-
-static void rtl8139_reset(RTL8139State *s)
-{
- int i;
-
- /* restore MAC address */
- memcpy(s->phys, s->macaddr, 6);
-
- /* reset interrupt mask */
- s->IntrStatus = 0;
- s->IntrMask = 0;
-
- rtl8139_update_irq(s);
-
- /* prepare eeprom */
- s->eeprom.contents[0] = 0x8129;
-#if 1
- // PCI vendor and device ID should be mirrored here
- s->eeprom.contents[1] = 0x10ec;
- s->eeprom.contents[2] = 0x8139;
-#endif
- memcpy(&s->eeprom.contents[7], s->macaddr, 6);
-
- /* mark all status registers as owned by host */
- for (i = 0; i < 4; ++i)
- {
- s->TxStatus[i] = TxHostOwns;
- }
-
- s->currTxDesc = 0;
- s->currCPlusRxDesc = 0;
- s->currCPlusTxDesc = 0;
-
- s->RxRingAddrLO = 0;
- s->RxRingAddrHI = 0;
-
- s->RxBuf = 0;
-
- rtl8139_reset_rxring(s, 8192);
-
- /* ACK the reset */
- s->TxConfig = 0;
-
-#if 0
-// s->TxConfig |= HW_REVID(1, 0, 0, 0, 0, 0, 0); // RTL-8139 HasHltClk
- s->clock_enabled = 0;
-#else
- s->TxConfig |= HW_REVID(1, 1, 1, 0, 1, 1, 0); // RTL-8139C+ HasLWake
- s->clock_enabled = 1;
-#endif
-
- s->bChipCmdState = CmdReset; /* RxBufEmpty bit is calculated on read from ChipCmd */;
-
- /* set initial state data */
- s->Config0 = 0x0; /* No boot ROM */
- s->Config1 = 0xC; /* IO mapped and MEM mapped registers available */
- s->Config3 = 0x1; /* fast back-to-back compatible */
- s->Config5 = 0x0;
-
- s->CSCR = CSCR_F_LINK_100 | CSCR_HEART_BIT | CSCR_LD;
-
- s->CpCmd = 0x0; /* reset C+ mode */
-
-// s->BasicModeCtrl = 0x3100; // 100Mbps, full duplex, autonegotiation
-// s->BasicModeCtrl = 0x2100; // 100Mbps, full duplex
- s->BasicModeCtrl = 0x1000; // autonegotiation
-
- s->BasicModeStatus = 0x7809;
- //s->BasicModeStatus |= 0x0040; /* UTP medium */
- s->BasicModeStatus |= 0x0020; /* autonegotiation completed */
- s->BasicModeStatus |= 0x0004; /* link is up */
-
- s->NWayAdvert = 0x05e1; /* all modes, full duplex */
- s->NWayLPAR = 0x05e1; /* all modes, full duplex */
- s->NWayExpansion = 0x0001; /* autonegotiation supported */
-
- /* also reset timer and disable timer interrupt */
- s->TCTR = 0;
- s->TimerInt = 0;
- s->TCTR_base = 0;
-
- /* reset tally counters */
- RTL8139TallyCounters_clear(&s->tally_counters);
-}
-
-void RTL8139TallyCounters_clear(RTL8139TallyCounters* counters)
-{
- counters->TxOk = 0;
- counters->RxOk = 0;
- counters->TxERR = 0;
- counters->RxERR = 0;
- counters->MissPkt = 0;
- counters->FAE = 0;
- counters->Tx1Col = 0;
- counters->TxMCol = 0;
- counters->RxOkPhy = 0;
- counters->RxOkBrd = 0;
- counters->RxOkMul = 0;
- counters->TxAbt = 0;
- counters->TxUndrn = 0;
-}
-
-static void RTL8139TallyCounters_physical_memory_write(target_phys_addr_t tc_addr, RTL8139TallyCounters* tally_counters)
-{
- uint16_t val16;
- uint32_t val32;
- uint64_t val64;
-
- val64 = cpu_to_le64(tally_counters->TxOk);
- cpu_physical_memory_write(tc_addr + 0, (uint8_t *)&val64, 8);
-
- val64 = cpu_to_le64(tally_counters->RxOk);
- cpu_physical_memory_write(tc_addr + 8, (uint8_t *)&val64, 8);
-
- val64 = cpu_to_le64(tally_counters->TxERR);
- cpu_physical_memory_write(tc_addr + 16, (uint8_t *)&val64, 8);
-
- val32 = cpu_to_le32(tally_counters->RxERR);
- cpu_physical_memory_write(tc_addr + 24, (uint8_t *)&val32, 4);
-
- val16 = cpu_to_le16(tally_counters->MissPkt);
- cpu_physical_memory_write(tc_addr + 28, (uint8_t *)&val16, 2);
-
- val16 = cpu_to_le16(tally_counters->FAE);
- cpu_physical_memory_write(tc_addr + 30, (uint8_t *)&val16, 2);
-
- val32 = cpu_to_le32(tally_counters->Tx1Col);
- cpu_physical_memory_write(tc_addr + 32, (uint8_t *)&val32, 4);
-
- val32 = cpu_to_le32(tally_counters->TxMCol);
- cpu_physical_memory_write(tc_addr + 36, (uint8_t *)&val32, 4);
-
- val64 = cpu_to_le64(tally_counters->RxOkPhy);
- cpu_physical_memory_write(tc_addr + 40, (uint8_t *)&val64, 8);
-
- val64 = cpu_to_le64(tally_counters->RxOkBrd);
- cpu_physical_memory_write(tc_addr + 48, (uint8_t *)&val64, 8);
-
- val32 = cpu_to_le32(tally_counters->RxOkMul);
- cpu_physical_memory_write(tc_addr + 56, (uint8_t *)&val32, 4);
-
- val16 = cpu_to_le16(tally_counters->TxAbt);
- cpu_physical_memory_write(tc_addr + 60, (uint8_t *)&val16, 2);
-
- val16 = cpu_to_le16(tally_counters->TxUndrn);
- cpu_physical_memory_write(tc_addr + 62, (uint8_t *)&val16, 2);
-}
-
-/* Loads values of tally counters from VM state file */
-static void RTL8139TallyCounters_load(QEMUFile* f, RTL8139TallyCounters *tally_counters)
-{
- qemu_get_be64s(f, &tally_counters->TxOk);
- qemu_get_be64s(f, &tally_counters->RxOk);
- qemu_get_be64s(f, &tally_counters->TxERR);
- qemu_get_be32s(f, &tally_counters->RxERR);
- qemu_get_be16s(f, &tally_counters->MissPkt);
- qemu_get_be16s(f, &tally_counters->FAE);
- qemu_get_be32s(f, &tally_counters->Tx1Col);
- qemu_get_be32s(f, &tally_counters->TxMCol);
- qemu_get_be64s(f, &tally_counters->RxOkPhy);
- qemu_get_be64s(f, &tally_counters->RxOkBrd);
- qemu_get_be32s(f, &tally_counters->RxOkMul);
- qemu_get_be16s(f, &tally_counters->TxAbt);
- qemu_get_be16s(f, &tally_counters->TxUndrn);
-}
-
-/* Saves values of tally counters to VM state file */
-static void RTL8139TallyCounters_save(QEMUFile* f, RTL8139TallyCounters *tally_counters)
-{
- qemu_put_be64s(f, &tally_counters->TxOk);
- qemu_put_be64s(f, &tally_counters->RxOk);
- qemu_put_be64s(f, &tally_counters->TxERR);
- qemu_put_be32s(f, &tally_counters->RxERR);
- qemu_put_be16s(f, &tally_counters->MissPkt);
- qemu_put_be16s(f, &tally_counters->FAE);
- qemu_put_be32s(f, &tally_counters->Tx1Col);
- qemu_put_be32s(f, &tally_counters->TxMCol);
- qemu_put_be64s(f, &tally_counters->RxOkPhy);
- qemu_put_be64s(f, &tally_counters->RxOkBrd);
- qemu_put_be32s(f, &tally_counters->RxOkMul);
- qemu_put_be16s(f, &tally_counters->TxAbt);
- qemu_put_be16s(f, &tally_counters->TxUndrn);
-}
-
-static void rtl8139_ChipCmd_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DEBUG_PRINT(("RTL8139: ChipCmd write val=0x%08x\n", val));
-
- if (val & CmdReset)
- {
- DEBUG_PRINT(("RTL8139: ChipCmd reset\n"));
- rtl8139_reset(s);
- }
- if (val & CmdRxEnb)
- {
- DEBUG_PRINT(("RTL8139: ChipCmd enable receiver\n"));
-
- s->currCPlusRxDesc = 0;
- }
- if (val & CmdTxEnb)
- {
- DEBUG_PRINT(("RTL8139: ChipCmd enable transmitter\n"));
-
- s->currCPlusTxDesc = 0;
- }
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0xe3, s->bChipCmdState);
-
- /* Deassert reset pin before next read */
- val &= ~CmdReset;
-
- s->bChipCmdState = val;
-}
-
-static int rtl8139_RxBufferEmpty(RTL8139State *s)
-{
- int unread = MOD2(s->RxBufferSize + s->RxBufAddr - s->RxBufPtr, s->RxBufferSize);
-
- if (unread != 0)
- {
- DEBUG_PRINT(("RTL8139: receiver buffer data available 0x%04x\n", unread));
- return 0;
- }
-
- DEBUG_PRINT(("RTL8139: receiver buffer is empty\n"));
-
- return 1;
-}
-
-static uint32_t rtl8139_ChipCmd_read(RTL8139State *s)
-{
- uint32_t ret = s->bChipCmdState;
-
- if (rtl8139_RxBufferEmpty(s))
- ret |= RxBufEmpty;
-
- DEBUG_PRINT(("RTL8139: ChipCmd read val=0x%04x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_CpCmd_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xffff;
-
- DEBUG_PRINT(("RTL8139C+ command register write(w) val=0x%04x\n", val));
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0xff84, s->CpCmd);
-
- s->CpCmd = val;
-}
-
-static uint32_t rtl8139_CpCmd_read(RTL8139State *s)
-{
- uint32_t ret = s->CpCmd;
-
- DEBUG_PRINT(("RTL8139C+ command register read(w) val=0x%04x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_IntrMitigate_write(RTL8139State *s, uint32_t val)
-{
- DEBUG_PRINT(("RTL8139C+ IntrMitigate register write(w) val=0x%04x\n", val));
-}
-
-static uint32_t rtl8139_IntrMitigate_read(RTL8139State *s)
-{
- uint32_t ret = 0;
-
- DEBUG_PRINT(("RTL8139C+ IntrMitigate register read(w) val=0x%04x\n", ret));
-
- return ret;
-}
-
-int rtl8139_config_writeable(RTL8139State *s)
-{
- if (s->Cfg9346 & Cfg9346_Unlock)
- {
- return 1;
- }
-
- DEBUG_PRINT(("RTL8139: Configuration registers are write-protected\n"));
-
- return 0;
-}
-
-static void rtl8139_BasicModeCtrl_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xffff;
-
- DEBUG_PRINT(("RTL8139: BasicModeCtrl register write(w) val=0x%04x\n", val));
-
- /* mask unwriteable bits */
- uint32 mask = 0x4cff;
-
- if (1 || !rtl8139_config_writeable(s))
- {
- /* Speed setting and autonegotiation enable bits are read-only */
- mask |= 0x3000;
- /* Duplex mode setting is read-only */
- mask |= 0x0100;
- }
-
- val = SET_MASKED(val, mask, s->BasicModeCtrl);
-
- s->BasicModeCtrl = val;
-}
-
-static uint32_t rtl8139_BasicModeCtrl_read(RTL8139State *s)
-{
- uint32_t ret = s->BasicModeCtrl;
-
- DEBUG_PRINT(("RTL8139: BasicModeCtrl register read(w) val=0x%04x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_BasicModeStatus_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xffff;
-
- DEBUG_PRINT(("RTL8139: BasicModeStatus register write(w) val=0x%04x\n", val));
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0xff3f, s->BasicModeStatus);
-
- s->BasicModeStatus = val;
-}
-
-static uint32_t rtl8139_BasicModeStatus_read(RTL8139State *s)
-{
- uint32_t ret = s->BasicModeStatus;
-
- DEBUG_PRINT(("RTL8139: BasicModeStatus register read(w) val=0x%04x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_Cfg9346_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DEBUG_PRINT(("RTL8139: Cfg9346 write val=0x%02x\n", val));
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0x31, s->Cfg9346);
-
- uint32_t opmode = val & 0xc0;
- uint32_t eeprom_val = val & 0xf;
-
- if (opmode == 0x80) {
- /* eeprom access */
- int eecs = (eeprom_val & 0x08)?1:0;
- int eesk = (eeprom_val & 0x04)?1:0;
- int eedi = (eeprom_val & 0x02)?1:0;
- prom9346_set_wire(s, eecs, eesk, eedi);
- } else if (opmode == 0x40) {
- /* Reset. */
- val = 0;
- rtl8139_reset(s);
- }
-
- s->Cfg9346 = val;
-}
-
-static uint32_t rtl8139_Cfg9346_read(RTL8139State *s)
-{
- uint32_t ret = s->Cfg9346;
-
- uint32_t opmode = ret & 0xc0;
-
- if (opmode == 0x80)
- {
- /* eeprom access */
- int eedo = prom9346_get_wire(s);
- if (eedo)
- {
- ret |= 0x01;
- }
- else
- {
- ret &= ~0x01;
- }
- }
-
- DEBUG_PRINT(("RTL8139: Cfg9346 read val=0x%02x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_Config0_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DEBUG_PRINT(("RTL8139: Config0 write val=0x%02x\n", val));
-
- if (!rtl8139_config_writeable(s))
- return;
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0xf8, s->Config0);
-
- s->Config0 = val;
-}
-
-static uint32_t rtl8139_Config0_read(RTL8139State *s)
-{
- uint32_t ret = s->Config0;
-
- DEBUG_PRINT(("RTL8139: Config0 read val=0x%02x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_Config1_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DEBUG_PRINT(("RTL8139: Config1 write val=0x%02x\n", val));
-
- if (!rtl8139_config_writeable(s))
- return;
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0xC, s->Config1);
-
- s->Config1 = val;
-}
-
-static uint32_t rtl8139_Config1_read(RTL8139State *s)
-{
- uint32_t ret = s->Config1;
-
- DEBUG_PRINT(("RTL8139: Config1 read val=0x%02x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_Config3_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DEBUG_PRINT(("RTL8139: Config3 write val=0x%02x\n", val));
-
- if (!rtl8139_config_writeable(s))
- return;
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0x8F, s->Config3);
-
- s->Config3 = val;
-}
-
-static uint32_t rtl8139_Config3_read(RTL8139State *s)
-{
- uint32_t ret = s->Config3;
-
- DEBUG_PRINT(("RTL8139: Config3 read val=0x%02x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_Config4_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DEBUG_PRINT(("RTL8139: Config4 write val=0x%02x\n", val));
-
- if (!rtl8139_config_writeable(s))
- return;
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0x0a, s->Config4);
-
- s->Config4 = val;
-}
-
-static uint32_t rtl8139_Config4_read(RTL8139State *s)
-{
- uint32_t ret = s->Config4;
-
- DEBUG_PRINT(("RTL8139: Config4 read val=0x%02x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_Config5_write(RTL8139State *s, uint32_t val)
-{
- val &= 0xff;
-
- DEBUG_PRINT(("RTL8139: Config5 write val=0x%02x\n", val));
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0x80, s->Config5);
-
- s->Config5 = val;
-}
-
-static uint32_t rtl8139_Config5_read(RTL8139State *s)
-{
- uint32_t ret = s->Config5;
-
- DEBUG_PRINT(("RTL8139: Config5 read val=0x%02x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_TxConfig_write(RTL8139State *s, uint32_t val)
-{
- if (!rtl8139_transmitter_enabled(s))
- {
- DEBUG_PRINT(("RTL8139: transmitter disabled; no TxConfig write val=0x%08x\n", val));
- return;
- }
-
- DEBUG_PRINT(("RTL8139: TxConfig write val=0x%08x\n", val));
-
- val = SET_MASKED(val, TxVersionMask | 0x8070f80f, s->TxConfig);
-
- s->TxConfig = val;
-}
-
-static void rtl8139_TxConfig_writeb(RTL8139State *s, uint32_t val)
-{
- DEBUG_PRINT(("RTL8139C TxConfig via write(b) val=0x%02x\n", val));
-
- uint32_t tc = s->TxConfig;
- tc &= 0xFFFFFF00;
- tc |= (val & 0x000000FF);
- rtl8139_TxConfig_write(s, tc);
-}
-
-static uint32_t rtl8139_TxConfig_read(RTL8139State *s)
-{
- uint32_t ret = s->TxConfig;
-
- DEBUG_PRINT(("RTL8139: TxConfig read val=0x%04x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_RxConfig_write(RTL8139State *s, uint32_t val)
-{
- DEBUG_PRINT(("RTL8139: RxConfig write val=0x%08x\n", val));
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0xf0fc0040, s->RxConfig);
-
- s->RxConfig = val;
-
- /* reset buffer size and read/write pointers */
- rtl8139_reset_rxring(s, 8192 << ((s->RxConfig >> 11) & 0x3));
-
- DEBUG_PRINT(("RTL8139: RxConfig write reset buffer size to %d\n", s->RxBufferSize));
-}
-
-static uint32_t rtl8139_RxConfig_read(RTL8139State *s)
-{
- uint32_t ret = s->RxConfig;
-
- DEBUG_PRINT(("RTL8139: RxConfig read val=0x%08x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_transfer_frame(RTL8139State *s, const uint8_t *buf, int size, int do_interrupt)
-{
- if (!size)
- {
- DEBUG_PRINT(("RTL8139: +++ empty ethernet frame\n"));
- return;
- }
-
- if (TxLoopBack == (s->TxConfig & TxLoopBack))
- {
- DEBUG_PRINT(("RTL8139: +++ transmit loopback mode\n"));
- rtl8139_do_receive(s, buf, size, do_interrupt);
- }
- else
- {
- qemu_send_packet(s->vc, buf, size);
- }
-}
-
-static int rtl8139_transmit_one(RTL8139State *s, int descriptor)
-{
- if (!rtl8139_transmitter_enabled(s))
- {
- DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: transmitter disabled\n",
- descriptor));
- return 0;
- }
-
- if (s->TxStatus[descriptor] & TxHostOwns)
- {
- DEBUG_PRINT(("RTL8139: +++ cannot transmit from descriptor %d: owned by host (%08x)\n",
- descriptor, s->TxStatus[descriptor]));
- return 0;
- }
-
- DEBUG_PRINT(("RTL8139: +++ transmitting from descriptor %d\n", descriptor));
-
- int txsize = s->TxStatus[descriptor] & 0x1fff;
- uint8_t txbuffer[0x2000];
-
- DEBUG_PRINT(("RTL8139: +++ transmit reading %d bytes from host memory at 0x%08x\n",
- txsize, s->TxAddr[descriptor]));
-
- cpu_physical_memory_read(s->TxAddr[descriptor], txbuffer, txsize);
-
- /* Mark descriptor as transferred */
- s->TxStatus[descriptor] |= TxHostOwns;
- s->TxStatus[descriptor] |= TxStatOK;
-
- rtl8139_transfer_frame(s, txbuffer, txsize, 0);
-
- DEBUG_PRINT(("RTL8139: +++ transmitted %d bytes from descriptor %d\n", txsize, descriptor));
-
- /* update interrupt */
- s->IntrStatus |= TxOK;
- rtl8139_update_irq(s);
-
- return 1;
-}
-
-/* structures and macros for task offloading */
-typedef struct ip_header
-{
- uint8_t ip_ver_len; /* version and header length */
- uint8_t ip_tos; /* type of service */
- uint16_t ip_len; /* total length */
- uint16_t ip_id; /* identification */
- uint16_t ip_off; /* fragment offset field */
- uint8_t ip_ttl; /* time to live */
- uint8_t ip_p; /* protocol */
- uint16_t ip_sum; /* checksum */
- uint32_t ip_src,ip_dst; /* source and dest address */
-} ip_header;
-
-#define IP_HEADER_VERSION_4 4
-#define IP_HEADER_VERSION(ip) ((ip->ip_ver_len >> 4)&0xf)
-#define IP_HEADER_LENGTH(ip) (((ip->ip_ver_len)&0xf) << 2)
-
-typedef struct tcp_header
-{
- uint16_t th_sport; /* source port */
- uint16_t th_dport; /* destination port */
- uint32_t th_seq; /* sequence number */
- uint32_t th_ack; /* acknowledgement number */
- uint16_t th_offset_flags; /* data offset, reserved 6 bits, TCP protocol flags */
- uint16_t th_win; /* window */
- uint16_t th_sum; /* checksum */
- uint16_t th_urp; /* urgent pointer */
-} tcp_header;
-
-typedef struct udp_header
-{
- uint16_t uh_sport; /* source port */
- uint16_t uh_dport; /* destination port */
- uint16_t uh_ulen; /* udp length */
- uint16_t uh_sum; /* udp checksum */
-} udp_header;
-
-typedef struct ip_pseudo_header
-{
- uint32_t ip_src;
- uint32_t ip_dst;
- uint8_t zeros;
- uint8_t ip_proto;
- uint16_t ip_payload;
-} ip_pseudo_header;
-
-#define IP_PROTO_TCP 6
-#define IP_PROTO_UDP 17
-
-#define TCP_HEADER_DATA_OFFSET(tcp) (((be16_to_cpu(tcp->th_offset_flags) >> 12)&0xf) << 2)
-#define TCP_FLAGS_ONLY(flags) ((flags)&0x3f)
-#define TCP_HEADER_FLAGS(tcp) TCP_FLAGS_ONLY(be16_to_cpu(tcp->th_offset_flags))
-
-#define TCP_HEADER_CLEAR_FLAGS(tcp, off) ((tcp)->th_offset_flags &= cpu_to_be16(~TCP_FLAGS_ONLY(off)))
-
-#define TCP_FLAG_FIN 0x01
-#define TCP_FLAG_PUSH 0x08
-
-/* produces ones' complement sum of data */
-static uint16_t ones_complement_sum(uint8_t *data, size_t len)
-{
- uint32_t result = 0;
-
- for (; len > 1; data+=2, len-=2)
- {
- result += *(uint16_t*)data;
- }
-
- /* add the remainder byte */
- if (len)
- {
- uint8_t odd[2] = {*data, 0};
- result += *(uint16_t*)odd;
- }
-
- while (result>>16)
- result = (result & 0xffff) + (result >> 16);
-
- return result;
-}
-
-static uint16_t ip_checksum(void *data, size_t len)
-{
- return ~ones_complement_sum((uint8_t*)data, len);
-}
-
-static int rtl8139_cplus_transmit_one(RTL8139State *s)
-{
- if (!rtl8139_transmitter_enabled(s))
- {
- DEBUG_PRINT(("RTL8139: +++ C+ mode: transmitter disabled\n"));
- return 0;
- }
-
- if (!rtl8139_cp_transmitter_enabled(s))
- {
- DEBUG_PRINT(("RTL8139: +++ C+ mode: C+ transmitter disabled\n"));
- return 0 ;
- }
-
- int descriptor = s->currCPlusTxDesc;
-
- target_phys_addr_t cplus_tx_ring_desc =
- rtl8139_addr64(s->TxAddr[0], s->TxAddr[1]);
-
- /* Normal priority ring */
- cplus_tx_ring_desc += 16 * descriptor;
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode reading TX descriptor %d from host memory at %08x0x%08x = 0x%8lx\n",
- descriptor, s->TxAddr[1], s->TxAddr[0], cplus_tx_ring_desc));
-
- uint32_t val, txdw0,txdw1,txbufLO,txbufHI;
-
- cpu_physical_memory_read(cplus_tx_ring_desc, (uint8_t *)&val, 4);
- txdw0 = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_tx_ring_desc+4, (uint8_t *)&val, 4);
- txdw1 = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_tx_ring_desc+8, (uint8_t *)&val, 4);
- txbufLO = le32_to_cpu(val);
- cpu_physical_memory_read(cplus_tx_ring_desc+12, (uint8_t *)&val, 4);
- txbufHI = le32_to_cpu(val);
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode TX descriptor %d %08x %08x %08x %08x\n",
- descriptor,
- txdw0, txdw1, txbufLO, txbufHI));
-
-/* w0 ownership flag */
-#define CP_TX_OWN (1<<31)
-/* w0 end of ring flag */
-#define CP_TX_EOR (1<<30)
-/* first segment of received packet flag */
-#define CP_TX_FS (1<<29)
-/* last segment of received packet flag */
-#define CP_TX_LS (1<<28)
-/* large send packet flag */
-#define CP_TX_LGSEN (1<<27)
-/* large send MSS mask, bits 16...25 */
-#define CP_TC_LGSEN_MSS_MASK ((1 << 12) - 1)
-
-/* IP checksum offload flag */
-#define CP_TX_IPCS (1<<18)
-/* UDP checksum offload flag */
-#define CP_TX_UDPCS (1<<17)
-/* TCP checksum offload flag */
-#define CP_TX_TCPCS (1<<16)
-
-/* w0 bits 0...15 : buffer size */
-#define CP_TX_BUFFER_SIZE (1<<16)
-#define CP_TX_BUFFER_SIZE_MASK (CP_TX_BUFFER_SIZE - 1)
-/* w1 tag available flag */
-#define CP_RX_TAGC (1<<17)
-/* w1 bits 0...15 : VLAN tag */
-#define CP_TX_VLAN_TAG_MASK ((1<<16) - 1)
-/* w2 low 32bit of Rx buffer ptr */
-/* w3 high 32bit of Rx buffer ptr */
-
-/* set after transmission */
-/* FIFO underrun flag */
-#define CP_TX_STATUS_UNF (1<<25)
-/* transmit error summary flag, valid if set any of three below */
-#define CP_TX_STATUS_TES (1<<23)
-/* out-of-window collision flag */
-#define CP_TX_STATUS_OWC (1<<22)
-/* link failure flag */
-#define CP_TX_STATUS_LNKF (1<<21)
-/* excessive collisions flag */
-#define CP_TX_STATUS_EXC (1<<20)
-
- if (!(txdw0 & CP_TX_OWN))
- {
- DEBUG_PRINT(("RTL8139: C+ Tx mode : descriptor %d is owned by host\n", descriptor));
- return 0 ;
- }
-
- DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : transmitting from descriptor %d\n", descriptor));
-
- if (txdw0 & CP_TX_FS)
- {
- DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is first segment descriptor\n", descriptor));
-
- /* reset internal buffer offset */
- s->cplus_txbuffer_offset = 0;
- }
-
- int txsize = txdw0 & CP_TX_BUFFER_SIZE_MASK;
- target_phys_addr_t tx_addr = rtl8139_addr64(txbufLO, txbufHI);
-
- /* make sure we have enough space to assemble the packet */
- if (!s->cplus_txbuffer)
- {
- s->cplus_txbuffer_len = CP_TX_BUFFER_SIZE;
- s->cplus_txbuffer = malloc(s->cplus_txbuffer_len);
- s->cplus_txbuffer_offset = 0;
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer allocated space %d\n", s->cplus_txbuffer_len));
- }
-
- while (s->cplus_txbuffer && s->cplus_txbuffer_offset + txsize >= s->cplus_txbuffer_len)
- {
- s->cplus_txbuffer_len += CP_TX_BUFFER_SIZE;
- s->cplus_txbuffer = realloc(s->cplus_txbuffer, s->cplus_txbuffer_len);
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode transmission buffer space changed to %d\n", s->cplus_txbuffer_len));
- }
-
- if (!s->cplus_txbuffer)
- {
- /* out of memory */
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode transmiter failed to reallocate %d bytes\n", s->cplus_txbuffer_len));
-
- /* update tally counter */
- ++s->tally_counters.TxERR;
- ++s->tally_counters.TxAbt;
-
- return 0;
- }
-
- /* append more data to the packet */
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode transmit reading %d bytes from host memory at %016" PRIx64 " to offset %d\n",
- txsize, (uint64_t)tx_addr, s->cplus_txbuffer_offset));
-
- cpu_physical_memory_read(tx_addr, s->cplus_txbuffer + s->cplus_txbuffer_offset, txsize);
- s->cplus_txbuffer_offset += txsize;
-
- /* seek to next Rx descriptor */
- if (txdw0 & CP_TX_EOR)
- {
- s->currCPlusTxDesc = 0;
- }
- else
- {
- ++s->currCPlusTxDesc;
- if (s->currCPlusTxDesc >= 64)
- s->currCPlusTxDesc = 0;
- }
-
- /* transfer ownership to target */
- txdw0 &= ~CP_RX_OWN;
-
- /* reset error indicator bits */
- txdw0 &= ~CP_TX_STATUS_UNF;
- txdw0 &= ~CP_TX_STATUS_TES;
- txdw0 &= ~CP_TX_STATUS_OWC;
- txdw0 &= ~CP_TX_STATUS_LNKF;
- txdw0 &= ~CP_TX_STATUS_EXC;
-
- /* update ring data */
- val = cpu_to_le32(txdw0);
- cpu_physical_memory_write(cplus_tx_ring_desc, (uint8_t *)&val, 4);
-// val = cpu_to_le32(txdw1);
-// cpu_physical_memory_write(cplus_tx_ring_desc+4, &val, 4);
-
- /* Now decide if descriptor being processed is holding the last segment of packet */
- if (txdw0 & CP_TX_LS)
- {
- DEBUG_PRINT(("RTL8139: +++ C+ Tx mode : descriptor %d is last segment descriptor\n", descriptor));
-
- /* can transfer fully assembled packet */
-
- uint8_t *saved_buffer = s->cplus_txbuffer;
- int saved_size = s->cplus_txbuffer_offset;
- int saved_buffer_len = s->cplus_txbuffer_len;
-
- /* reset the card space to protect from recursive call */
- s->cplus_txbuffer = NULL;
- s->cplus_txbuffer_offset = 0;
- s->cplus_txbuffer_len = 0;
-
- if (txdw0 & (CP_TX_IPCS | CP_TX_UDPCS | CP_TX_TCPCS | CP_TX_LGSEN))
- {
- DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task checksum\n"));
-
- #define ETH_P_IP 0x0800 /* Internet Protocol packet */
- #define ETH_HLEN 14
- #define ETH_MTU 1500
-
- /* ip packet header */
- ip_header *ip = 0;
- int hlen = 0;
- uint8_t ip_protocol = 0;
- uint16_t ip_data_len = 0;
-
- uint8_t *eth_payload_data = 0;
- size_t eth_payload_len = 0;
-
- int proto = be16_to_cpu(*(uint16_t *)(saved_buffer + 12));
- if (proto == ETH_P_IP)
- {
- DEBUG_PRINT(("RTL8139: +++ C+ mode has IP packet\n"));
-
- /* not aligned */
- eth_payload_data = saved_buffer + ETH_HLEN;
- eth_payload_len = saved_size - ETH_HLEN;
-
- ip = (ip_header*)eth_payload_data;
-
- if (IP_HEADER_VERSION(ip) != IP_HEADER_VERSION_4) {
- DEBUG_PRINT(("RTL8139: +++ C+ mode packet has bad IP version %d expected %d\n", IP_HEADER_VERSION(ip), IP_HEADER_VERSION_4));
- ip = NULL;
- } else {
- hlen = IP_HEADER_LENGTH(ip);
- ip_protocol = ip->ip_p;
- ip_data_len = be16_to_cpu(ip->ip_len) - hlen;
- }
- }
-
- if (ip)
- {
- if (txdw0 & CP_TX_IPCS)
- {
- DEBUG_PRINT(("RTL8139: +++ C+ mode need IP checksum\n"));
-
- if (hlen<sizeof(ip_header) || hlen>eth_payload_len) {/* min header length */
- /* bad packet header len */
- /* or packet too short */
- }
- else
- {
- ip->ip_sum = 0;
- ip->ip_sum = ip_checksum(ip, hlen);
- DEBUG_PRINT(("RTL8139: +++ C+ mode IP header len=%d checksum=%04x\n", hlen, ip->ip_sum));
- }
- }
-
- if ((txdw0 & CP_TX_LGSEN) && ip_protocol == IP_PROTO_TCP)
- {
-#if defined (DEBUG_RTL8139)
- int large_send_mss = (txdw0 >> 16) & CP_TC_LGSEN_MSS_MASK;
-#endif
- DEBUG_PRINT(("RTL8139: +++ C+ mode offloaded task TSO MTU=%d IP data %d frame data %d specified MSS=%d\n",
- ETH_MTU, ip_data_len, saved_size - ETH_HLEN, large_send_mss));
-
- int tcp_send_offset = 0;
- int send_count = 0;
-
- /* maximum IP header length is 60 bytes */
- uint8_t saved_ip_header[60];
-
- /* save IP header template; data area is used in tcp checksum calculation */
- memcpy(saved_ip_header, eth_payload_data, hlen);
-
- /* a placeholder for checksum calculation routine in tcp case */
- uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
- // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
-
- /* pointer to TCP header */
- tcp_header *p_tcp_hdr = (tcp_header*)(eth_payload_data + hlen);
-
- int tcp_hlen = TCP_HEADER_DATA_OFFSET(p_tcp_hdr);
-
- /* ETH_MTU = ip header len + tcp header len + payload */
- int tcp_data_len = ip_data_len - tcp_hlen;
- int tcp_chunk_size = ETH_MTU - hlen - tcp_hlen;
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP data len %d TCP hlen %d TCP data len %d TCP chunk size %d\n",
- ip_data_len, tcp_hlen, tcp_data_len, tcp_chunk_size));
-
- /* note the cycle below overwrites IP header data,
- but restores it from saved_ip_header before sending packet */
-
- int is_last_frame = 0;
-
- for (tcp_send_offset = 0; tcp_send_offset < tcp_data_len; tcp_send_offset += tcp_chunk_size)
- {
- uint16_t chunk_size = tcp_chunk_size;
-
- /* check if this is the last frame */
- if (tcp_send_offset + tcp_chunk_size >= tcp_data_len)
- {
- is_last_frame = 1;
- chunk_size = tcp_data_len - tcp_send_offset;
- }
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP seqno %08x\n", be32_to_cpu(p_tcp_hdr->th_seq)));
-
- /* add 4 TCP pseudoheader fields */
- /* copy IP source and destination fields */
- memcpy(data_to_checksum, saved_ip_header + 12, 8);
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO calculating TCP checksum for packet with %d bytes data\n", tcp_hlen + chunk_size));
-
- if (tcp_send_offset)
- {
- memcpy((uint8_t*)p_tcp_hdr + tcp_hlen, (uint8_t*)p_tcp_hdr + tcp_hlen + tcp_send_offset, chunk_size);
- }
-
- /* keep PUSH and FIN flags only for the last frame */
- if (!is_last_frame)
- {
- TCP_HEADER_CLEAR_FLAGS(p_tcp_hdr, TCP_FLAG_PUSH|TCP_FLAG_FIN);
- }
-
- /* recalculate TCP checksum */
- ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
- p_tcpip_hdr->zeros = 0;
- p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
- p_tcpip_hdr->ip_payload = cpu_to_be16(tcp_hlen + chunk_size);
-
- p_tcp_hdr->th_sum = 0;
-
- int tcp_checksum = ip_checksum(data_to_checksum, tcp_hlen + chunk_size + 12);
- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO TCP checksum %04x\n", tcp_checksum));
-
- p_tcp_hdr->th_sum = tcp_checksum;
-
- /* restore IP header */
- memcpy(eth_payload_data, saved_ip_header, hlen);
-
- /* set IP data length and recalculate IP checksum */
- ip->ip_len = cpu_to_be16(hlen + tcp_hlen + chunk_size);
-
- /* increment IP id for subsequent frames */
- ip->ip_id = cpu_to_be16(tcp_send_offset/tcp_chunk_size + be16_to_cpu(ip->ip_id));
-
- ip->ip_sum = 0;
- ip->ip_sum = ip_checksum(eth_payload_data, hlen);
- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO IP header len=%d checksum=%04x\n", hlen, ip->ip_sum));
-
- int tso_send_size = ETH_HLEN + hlen + tcp_hlen + chunk_size;
- DEBUG_PRINT(("RTL8139: +++ C+ mode TSO transferring packet size %d\n", tso_send_size));
- rtl8139_transfer_frame(s, saved_buffer, tso_send_size, 0);
-
- /* add transferred count to TCP sequence number */
- p_tcp_hdr->th_seq = cpu_to_be32(chunk_size + be32_to_cpu(p_tcp_hdr->th_seq));
- ++send_count;
- }
-
- /* Stop sending this frame */
- saved_size = 0;
- }
- else if (txdw0 & (CP_TX_TCPCS|CP_TX_UDPCS))
- {
- DEBUG_PRINT(("RTL8139: +++ C+ mode need TCP or UDP checksum\n"));
-
- /* maximum IP header length is 60 bytes */
- uint8_t saved_ip_header[60];
- memcpy(saved_ip_header, eth_payload_data, hlen);
-
- uint8_t *data_to_checksum = eth_payload_data + hlen - 12;
- // size_t data_to_checksum_len = eth_payload_len - hlen + 12;
-
- /* add 4 TCP pseudoheader fields */
- /* copy IP source and destination fields */
- memcpy(data_to_checksum, saved_ip_header + 12, 8);
-
- if ((txdw0 & CP_TX_TCPCS) && ip_protocol == IP_PROTO_TCP)
- {
- DEBUG_PRINT(("RTL8139: +++ C+ mode calculating TCP checksum for packet with %d bytes data\n", ip_data_len));
-
- ip_pseudo_header *p_tcpip_hdr = (ip_pseudo_header *)data_to_checksum;
- p_tcpip_hdr->zeros = 0;
- p_tcpip_hdr->ip_proto = IP_PROTO_TCP;
- p_tcpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
-
- tcp_header* p_tcp_hdr = (tcp_header *) (data_to_checksum+12);
-
- p_tcp_hdr->th_sum = 0;
-
- int tcp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
- DEBUG_PRINT(("RTL8139: +++ C+ mode TCP checksum %04x\n", tcp_checksum));
-
- p_tcp_hdr->th_sum = tcp_checksum;
- }
- else if ((txdw0 & CP_TX_UDPCS) && ip_protocol == IP_PROTO_UDP)
- {
- DEBUG_PRINT(("RTL8139: +++ C+ mode calculating UDP checksum for packet with %d bytes data\n", ip_data_len));
-
- ip_pseudo_header *p_udpip_hdr = (ip_pseudo_header *)data_to_checksum;
- p_udpip_hdr->zeros = 0;
- p_udpip_hdr->ip_proto = IP_PROTO_UDP;
- p_udpip_hdr->ip_payload = cpu_to_be16(ip_data_len);
-
- udp_header *p_udp_hdr = (udp_header *) (data_to_checksum+12);
-
- p_udp_hdr->uh_sum = 0;
-
- int udp_checksum = ip_checksum(data_to_checksum, ip_data_len + 12);
- DEBUG_PRINT(("RTL8139: +++ C+ mode UDP checksum %04x\n", udp_checksum));
-
- p_udp_hdr->uh_sum = udp_checksum;
- }
-
- /* restore IP header */
- memcpy(eth_payload_data, saved_ip_header, hlen);
- }
- }
- }
-
- /* update tally counter */
- ++s->tally_counters.TxOk;
-
- DEBUG_PRINT(("RTL8139: +++ C+ mode transmitting %d bytes packet\n", saved_size));
-
- rtl8139_transfer_frame(s, saved_buffer, saved_size, 1);
-
- /* restore card space if there was no recursion and reset offset */
- if (!s->cplus_txbuffer)
- {
- s->cplus_txbuffer = saved_buffer;
- s->cplus_txbuffer_len = saved_buffer_len;
- s->cplus_txbuffer_offset = 0;
- }
- else
- {
- free(saved_buffer);
- }
- }
- else
- {
- DEBUG_PRINT(("RTL8139: +++ C+ mode transmission continue to next descriptor\n"));
- }
-
- return 1;
-}
-
-static void rtl8139_cplus_transmit(RTL8139State *s)
-{
- int txcount = 0;
-
- while (rtl8139_cplus_transmit_one(s))
- {
- ++txcount;
- }
-
- /* Mark transfer completed */
- if (!txcount)
- {
- DEBUG_PRINT(("RTL8139: C+ mode : transmitter queue stalled, current TxDesc = %d\n",
- s->currCPlusTxDesc));
- }
- else
- {
- /* update interrupt status */
- s->IntrStatus |= TxOK;
- rtl8139_update_irq(s);
- }
-}
-
-static void rtl8139_transmit(RTL8139State *s)
-{
- int descriptor = s->currTxDesc, txcount = 0;
-
- /*while*/
- if (rtl8139_transmit_one(s, descriptor))
- {
- ++s->currTxDesc;
- s->currTxDesc %= 4;
- ++txcount;
- }
-
- /* Mark transfer completed */
- if (!txcount)
- {
- DEBUG_PRINT(("RTL8139: transmitter queue stalled, current TxDesc = %d\n", s->currTxDesc));
- }
-}
-
-static void rtl8139_TxStatus_write(RTL8139State *s, uint32_t txRegOffset, uint32_t val)
-{
-
- int descriptor = txRegOffset/4;
-
- /* handle C+ transmit mode register configuration */
-
- if (rtl8139_cp_transmitter_enabled(s))
- {
- DEBUG_PRINT(("RTL8139C+ DTCCR write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor));
-
- /* handle Dump Tally Counters command */
- s->TxStatus[descriptor] = val;
-
- if (descriptor == 0 && (val & 0x8))
- {
- target_phys_addr_t tc_addr = rtl8139_addr64(s->TxStatus[0] & ~0x3f, s->TxStatus[1]);
-
- /* dump tally counters to specified memory location */
- RTL8139TallyCounters_physical_memory_write( tc_addr, &s->tally_counters);
-
- /* mark dump completed */
- s->TxStatus[0] &= ~0x8;
- }
-
- return;
- }
-
- DEBUG_PRINT(("RTL8139: TxStatus write offset=0x%x val=0x%08x descriptor=%d\n", txRegOffset, val, descriptor));
-
- /* mask only reserved bits */
- val &= ~0xff00c000; /* these bits are reset on write */
- val = SET_MASKED(val, 0x00c00000, s->TxStatus[descriptor]);
-
- s->TxStatus[descriptor] = val;
-
- /* attempt to start transmission */
- rtl8139_transmit(s);
-}
-
-static uint32_t rtl8139_TxStatus_read(RTL8139State *s, uint32_t txRegOffset)
-{
- uint32_t ret = s->TxStatus[txRegOffset/4];
-
- DEBUG_PRINT(("RTL8139: TxStatus read offset=0x%x val=0x%08x\n", txRegOffset, ret));
-
- return ret;
-}
-
-static uint16_t rtl8139_TSAD_read(RTL8139State *s)
-{
- uint16_t ret = 0;
-
- /* Simulate TSAD, it is read only anyway */
-
- ret = ((s->TxStatus[3] & TxStatOK )?TSAD_TOK3:0)
- |((s->TxStatus[2] & TxStatOK )?TSAD_TOK2:0)
- |((s->TxStatus[1] & TxStatOK )?TSAD_TOK1:0)
- |((s->TxStatus[0] & TxStatOK )?TSAD_TOK0:0)
-
- |((s->TxStatus[3] & TxUnderrun)?TSAD_TUN3:0)
- |((s->TxStatus[2] & TxUnderrun)?TSAD_TUN2:0)
- |((s->TxStatus[1] & TxUnderrun)?TSAD_TUN1:0)
- |((s->TxStatus[0] & TxUnderrun)?TSAD_TUN0:0)
-
- |((s->TxStatus[3] & TxAborted )?TSAD_TABT3:0)
- |((s->TxStatus[2] & TxAborted )?TSAD_TABT2:0)
- |((s->TxStatus[1] & TxAborted )?TSAD_TABT1:0)
- |((s->TxStatus[0] & TxAborted )?TSAD_TABT0:0)
-
- |((s->TxStatus[3] & TxHostOwns )?TSAD_OWN3:0)
- |((s->TxStatus[2] & TxHostOwns )?TSAD_OWN2:0)
- |((s->TxStatus[1] & TxHostOwns )?TSAD_OWN1:0)
- |((s->TxStatus[0] & TxHostOwns )?TSAD_OWN0:0) ;
-
-
- DEBUG_PRINT(("RTL8139: TSAD read val=0x%04x\n", ret));
-
- return ret;
-}
-
-static uint16_t rtl8139_CSCR_read(RTL8139State *s)
-{
- uint16_t ret = s->CSCR;
-
- DEBUG_PRINT(("RTL8139: CSCR read val=0x%04x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_TxAddr_write(RTL8139State *s, uint32_t txAddrOffset, uint32_t val)
-{
- DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val));
-
- s->TxAddr[txAddrOffset/4] = le32_to_cpu(val);
-}
-
-static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)
-{
- uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]);
-
- DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret));
-
- return ret;
-}
-
-static void rtl8139_RxBufPtr_write(RTL8139State *s, uint32_t val)
-{
- DEBUG_PRINT(("RTL8139: RxBufPtr write val=0x%04x\n", val));
-
- /* this value is off by 16 */
- s->RxBufPtr = MOD2(val + 0x10, s->RxBufferSize);
-
- DEBUG_PRINT((" CAPR write: rx buffer length %d head 0x%04x read 0x%04x\n",
- s->RxBufferSize, s->RxBufAddr, s->RxBufPtr));
-}
-
-static uint32_t rtl8139_RxBufPtr_read(RTL8139State *s)
-{
- /* this value is off by 16 */
- uint32_t ret = s->RxBufPtr - 0x10;
-
- DEBUG_PRINT(("RTL8139: RxBufPtr read val=0x%04x\n", ret));
-
- return ret;
-}
-
-static uint32_t rtl8139_RxBufAddr_read(RTL8139State *s)
-{
- /* this value is NOT off by 16 */
- uint32_t ret = s->RxBufAddr;
-
- DEBUG_PRINT(("RTL8139: RxBufAddr read val=0x%04x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_RxBuf_write(RTL8139State *s, uint32_t val)
-{
- DEBUG_PRINT(("RTL8139: RxBuf write val=0x%08x\n", val));
-
- s->RxBuf = val;
-
- /* may need to reset rxring here */
-}
-
-static uint32_t rtl8139_RxBuf_read(RTL8139State *s)
-{
- uint32_t ret = s->RxBuf;
-
- DEBUG_PRINT(("RTL8139: RxBuf read val=0x%08x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_IntrMask_write(RTL8139State *s, uint32_t val)
-{
- DEBUG_PRINT(("RTL8139: IntrMask write(w) val=0x%04x\n", val));
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0x1e00, s->IntrMask);
-
- s->IntrMask = val;
-
- rtl8139_update_irq(s);
-}
-
-static uint32_t rtl8139_IntrMask_read(RTL8139State *s)
-{
- uint32_t ret = s->IntrMask;
-
- DEBUG_PRINT(("RTL8139: IntrMask read(w) val=0x%04x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_IntrStatus_write(RTL8139State *s, uint32_t val)
-{
- DEBUG_PRINT(("RTL8139: IntrStatus write(w) val=0x%04x\n", val));
-
-#if 0
-
- /* writing to ISR has no effect */
-
- return;
-
-#else
- uint16_t newStatus = s->IntrStatus & ~val;
-
- /* mask unwriteable bits */
- newStatus = SET_MASKED(newStatus, 0x1e00, s->IntrStatus);
-
- /* writing 1 to interrupt status register bit clears it */
- s->IntrStatus = 0;
- rtl8139_update_irq(s);
-
- s->IntrStatus = newStatus;
- rtl8139_update_irq(s);
-#endif
-}
-
-static uint32_t rtl8139_IntrStatus_read(RTL8139State *s)
-{
- uint32_t ret = s->IntrStatus;
-
- DEBUG_PRINT(("RTL8139: IntrStatus read(w) val=0x%04x\n", ret));
-
-#if 0
-
- /* reading ISR clears all interrupts */
- s->IntrStatus = 0;
-
- rtl8139_update_irq(s);
-
-#endif
-
- return ret;
-}
-
-static void rtl8139_MultiIntr_write(RTL8139State *s, uint32_t val)
-{
- DEBUG_PRINT(("RTL8139: MultiIntr write(w) val=0x%04x\n", val));
-
- /* mask unwriteable bits */
- val = SET_MASKED(val, 0xf000, s->MultiIntr);
-
- s->MultiIntr = val;
-}
-
-static uint32_t rtl8139_MultiIntr_read(RTL8139State *s)
-{
- uint32_t ret = s->MultiIntr;
-
- DEBUG_PRINT(("RTL8139: MultiIntr read(w) val=0x%04x\n", ret));
-
- return ret;
-}
-
-static void rtl8139_io_writeb(void *opaque, uint8_t addr, uint32_t val)
-{
- RTL8139State *s = opaque;
-
- addr &= 0xff;
-
- switch (addr)
- {
- case MAC0 ... MAC0+5:
- s->phys[addr - MAC0] = val;
- break;
- case MAC0+6 ... MAC0+7:
- /* reserved */
- break;
- case MAR0 ... MAR0+7:
- s->mult[addr - MAR0] = val;
- break;
- case ChipCmd:
- rtl8139_ChipCmd_write(s, val);
- break;
- case Cfg9346:
- rtl8139_Cfg9346_write(s, val);
- break;
- case TxConfig: /* windows driver sometimes writes using byte-lenth call */
- rtl8139_TxConfig_writeb(s, val);
- break;
- case Config0:
- rtl8139_Config0_write(s, val);
- break;
- case Config1:
- rtl8139_Config1_write(s, val);
- break;
- case Config3:
- rtl8139_Config3_write(s, val);
- break;
- case Config4:
- rtl8139_Config4_write(s, val);
- break;
- case Config5:
- rtl8139_Config5_write(s, val);
- break;
- case MediaStatus:
- /* ignore */
- DEBUG_PRINT(("RTL8139: not implemented write(b) to MediaStatus val=0x%02x\n", val));
- break;
-
- case HltClk:
- DEBUG_PRINT(("RTL8139: HltClk write val=0x%08x\n", val));
- if (val == 'R')
- {
- s->clock_enabled = 1;
- }
- else if (val == 'H')
- {
- s->clock_enabled = 0;
- }
- break;
-
- case TxThresh:
- DEBUG_PRINT(("RTL8139C+ TxThresh write(b) val=0x%02x\n", val));
- s->TxThresh = val;
- break;
-
- case TxPoll:
- DEBUG_PRINT(("RTL8139C+ TxPoll write(b) val=0x%02x\n", val));
- if (val & (1 << 7))
- {
- DEBUG_PRINT(("RTL8139C+ TxPoll high priority transmission (not implemented)\n"));
- //rtl8139_cplus_transmit(s);
- }
- if (val & (1 << 6))
- {
- DEBUG_PRINT(("RTL8139C+ TxPoll normal priority transmission\n"));
- rtl8139_cplus_transmit(s);
- }
-
- break;
-
- default:
- DEBUG_PRINT(("RTL8139: not implemented write(b) addr=0x%x val=0x%02x\n", addr, val));
- break;
- }
-}
-
-static void rtl8139_io_writew(void *opaque, uint8_t addr, uint32_t val)
-{
- RTL8139State *s = opaque;
-
- addr &= 0xfe;
-
- switch (addr)
- {
- case IntrMask:
- rtl8139_IntrMask_write(s, val);
- break;
-
- case IntrStatus:
- rtl8139_IntrStatus_write(s, val);
- break;
-
- case MultiIntr:
- rtl8139_MultiIntr_write(s, val);
- break;
-
- case RxBufPtr:
- rtl8139_RxBufPtr_write(s, val);
- break;
-
- case BasicModeCtrl:
- rtl8139_BasicModeCtrl_write(s, val);
- break;
- case BasicModeStatus:
- rtl8139_BasicModeStatus_write(s, val);
- break;
- case NWayAdvert:
- DEBUG_PRINT(("RTL8139: NWayAdvert write(w) val=0x%04x\n", val));
- s->NWayAdvert = val;
- break;
- case NWayLPAR:
- DEBUG_PRINT(("RTL8139: forbidden NWayLPAR write(w) val=0x%04x\n", val));
- break;
- case NWayExpansion:
- DEBUG_PRINT(("RTL8139: NWayExpansion write(w) val=0x%04x\n", val));
- s->NWayExpansion = val;
- break;
-
- case CpCmd:
- rtl8139_CpCmd_write(s, val);
- break;
-
- case IntrMitigate:
- rtl8139_IntrMitigate_write(s, val);
- break;
-
- default:
- DEBUG_PRINT(("RTL8139: ioport write(w) addr=0x%x val=0x%04x via write(b)\n", addr, val));
-
-#ifdef TARGET_WORDS_BIGENDIAN
- rtl8139_io_writeb(opaque, addr, (val >> 8) & 0xff);
- rtl8139_io_writeb(opaque, addr + 1, val & 0xff);
-#else
- rtl8139_io_writeb(opaque, addr, val & 0xff);
- rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
- break;
- }
-}
-
-static void rtl8139_io_writel(void *opaque, uint8_t addr, uint32_t val)
-{
- RTL8139State *s = opaque;
-
- addr &= 0xfc;
-
- switch (addr)
- {
- case RxMissed:
- DEBUG_PRINT(("RTL8139: RxMissed clearing on write\n"));
- s->RxMissed = 0;
- break;
-
- case TxConfig:
- rtl8139_TxConfig_write(s, val);
- break;
-
- case RxConfig:
- rtl8139_RxConfig_write(s, val);
- break;
-
- case TxStatus0 ... TxStatus0+4*4-1:
- rtl8139_TxStatus_write(s, addr-TxStatus0, val);
- break;
-
- case TxAddr0 ... TxAddr0+4*4-1:
- rtl8139_TxAddr_write(s, addr-TxAddr0, val);
- break;
-
- case RxBuf:
- rtl8139_RxBuf_write(s, val);
- break;
-
- case RxRingAddrLO:
- DEBUG_PRINT(("RTL8139: C+ RxRing low bits write val=0x%08x\n", val));
- s->RxRingAddrLO = val;
- break;
-
- case RxRingAddrHI:
- DEBUG_PRINT(("RTL8139: C+ RxRing high bits write val=0x%08x\n", val));
- s->RxRingAddrHI = val;
- break;
-
- case Timer:
- DEBUG_PRINT(("RTL8139: TCTR Timer reset on write\n"));
- s->TCTR = 0;
- s->TCTR_base = qemu_get_clock(vm_clock);
- break;
-
- case FlashReg:
- DEBUG_PRINT(("RTL8139: FlashReg TimerInt write val=0x%08x\n", val));
- s->TimerInt = val;
- break;
-
- default:
- DEBUG_PRINT(("RTL8139: ioport write(l) addr=0x%x val=0x%08x via write(b)\n", addr, val));
-#ifdef TARGET_WORDS_BIGENDIAN
- rtl8139_io_writeb(opaque, addr, (val >> 24) & 0xff);
- rtl8139_io_writeb(opaque, addr + 1, (val >> 16) & 0xff);
- rtl8139_io_writeb(opaque, addr + 2, (val >> 8) & 0xff);
- rtl8139_io_writeb(opaque, addr + 3, val & 0xff);
-#else
- rtl8139_io_writeb(opaque, addr, val & 0xff);
- rtl8139_io_writeb(opaque, addr + 1, (val >> 8) & 0xff);
- rtl8139_io_writeb(opaque, addr + 2, (val >> 16) & 0xff);
- rtl8139_io_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-#endif
- break;
- }
-}
-
-static uint32_t rtl8139_io_readb(void *opaque, uint8_t addr)
-{
- RTL8139State *s = opaque;
- int ret;
-
- addr &= 0xff;
-
- switch (addr)
- {
- case MAC0 ... MAC0+5:
- ret = s->phys[addr - MAC0];
- break;
- case MAC0+6 ... MAC0+7:
- ret = 0;
- break;
- case MAR0 ... MAR0+7:
- ret = s->mult[addr - MAR0];
- break;
- case ChipCmd:
- ret = rtl8139_ChipCmd_read(s);
- break;
- case Cfg9346:
- ret = rtl8139_Cfg9346_read(s);
- break;
- case Config0:
- ret = rtl8139_Config0_read(s);
- break;
- case Config1:
- ret = rtl8139_Config1_read(s);
- break;
- case Config3:
- ret = rtl8139_Config3_read(s);
- break;
- case Config4:
- ret = rtl8139_Config4_read(s);
- break;
- case Config5:
- ret = rtl8139_Config5_read(s);
- break;
-
- case MediaStatus:
- ret = 0xd0;
- DEBUG_PRINT(("RTL8139: MediaStatus read 0x%x\n", ret));
- break;
-
- case HltClk:
- ret = s->clock_enabled;
- DEBUG_PRINT(("RTL8139: HltClk read 0x%x\n", ret));
- break;
-
- case PCIRevisionID:
- ret = RTL8139_PCI_REVID;
- DEBUG_PRINT(("RTL8139: PCI Revision ID read 0x%x\n", ret));
- break;
-
- case TxThresh:
- ret = s->TxThresh;
- DEBUG_PRINT(("RTL8139C+ TxThresh read(b) val=0x%02x\n", ret));
- break;
-
- case 0x43: /* Part of TxConfig register. Windows driver tries to read it */
- ret = s->TxConfig >> 24;
- DEBUG_PRINT(("RTL8139C TxConfig at 0x43 read(b) val=0x%02x\n", ret));
- break;
-
- default:
- DEBUG_PRINT(("RTL8139: not implemented read(b) addr=0x%x\n", addr));
- ret = 0;
- break;
- }
-
- return ret;
-}
-
-static uint32_t rtl8139_io_readw(void *opaque, uint8_t addr)
-{
- RTL8139State *s = opaque;
- uint32_t ret;
-
- addr &= 0xfe; /* mask lower bit */
-
- switch (addr)
- {
- case IntrMask:
- ret = rtl8139_IntrMask_read(s);
- break;
-
- case IntrStatus:
- ret = rtl8139_IntrStatus_read(s);
- break;
-
- case MultiIntr:
- ret = rtl8139_MultiIntr_read(s);
- break;
-
- case RxBufPtr:
- ret = rtl8139_RxBufPtr_read(s);
- break;
-
- case RxBufAddr:
- ret = rtl8139_RxBufAddr_read(s);
- break;
-
- case BasicModeCtrl:
- ret = rtl8139_BasicModeCtrl_read(s);
- break;
- case BasicModeStatus:
- ret = rtl8139_BasicModeStatus_read(s);
- break;
- case NWayAdvert:
- ret = s->NWayAdvert;
- DEBUG_PRINT(("RTL8139: NWayAdvert read(w) val=0x%04x\n", ret));
- break;
- case NWayLPAR:
- ret = s->NWayLPAR;
- DEBUG_PRINT(("RTL8139: NWayLPAR read(w) val=0x%04x\n", ret));
- break;
- case NWayExpansion:
- ret = s->NWayExpansion;
- DEBUG_PRINT(("RTL8139: NWayExpansion read(w) val=0x%04x\n", ret));
- break;
-
- case CpCmd:
- ret = rtl8139_CpCmd_read(s);
- break;
-
- case IntrMitigate:
- ret = rtl8139_IntrMitigate_read(s);
- break;
-
- case TxSummary:
- ret = rtl8139_TSAD_read(s);
- break;
-
- case CSCR:
- ret = rtl8139_CSCR_read(s);
- break;
-
- default:
- DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x via read(b)\n", addr));
-
-#ifdef TARGET_WORDS_BIGENDIAN
- ret = rtl8139_io_readb(opaque, addr) << 8;
- ret |= rtl8139_io_readb(opaque, addr + 1);
-#else
- ret = rtl8139_io_readb(opaque, addr);
- ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
-#endif
-
- DEBUG_PRINT(("RTL8139: ioport read(w) addr=0x%x val=0x%04x\n", addr, ret));
- break;
- }
-
- return ret;
-}
-
-static uint32_t rtl8139_io_readl(void *opaque, uint8_t addr)
-{
- RTL8139State *s = opaque;
- uint32_t ret;
-
- addr &= 0xfc; /* also mask low 2 bits */
-
- switch (addr)
- {
- case RxMissed:
- ret = s->RxMissed;
-
- DEBUG_PRINT(("RTL8139: RxMissed read val=0x%08x\n", ret));
- break;
-
- case TxConfig:
- ret = rtl8139_TxConfig_read(s);
- break;
-
- case RxConfig:
- ret = rtl8139_RxConfig_read(s);
- break;
-
- case TxStatus0 ... TxStatus0+4*4-1:
- ret = rtl8139_TxStatus_read(s, addr-TxStatus0);
- break;
-
- case TxAddr0 ... TxAddr0+4*4-1:
- ret = rtl8139_TxAddr_read(s, addr-TxAddr0);
- break;
-
- case RxBuf:
- ret = rtl8139_RxBuf_read(s);
- break;
-
- case RxRingAddrLO:
- ret = s->RxRingAddrLO;
- DEBUG_PRINT(("RTL8139: C+ RxRing low bits read val=0x%08x\n", ret));
- break;
-
- case RxRingAddrHI:
- ret = s->RxRingAddrHI;
- DEBUG_PRINT(("RTL8139: C+ RxRing high bits read val=0x%08x\n", ret));
- break;
-
- case Timer:
- ret = s->TCTR;
- DEBUG_PRINT(("RTL8139: TCTR Timer read val=0x%08x\n", ret));
- break;
-
- case FlashReg:
- ret = s->TimerInt;
- DEBUG_PRINT(("RTL8139: FlashReg TimerInt read val=0x%08x\n", ret));
- break;
-
- default:
- DEBUG_PRINT(("RTL8139: ioport read(l) addr=0x%x via read(b)\n", addr));
-
-#ifdef TARGET_WORDS_BIGENDIAN
- ret = rtl8139_io_readb(opaque, addr) << 24;
- ret |= rtl8139_io_readb(opaque, addr + 1) << 16;
- ret |= rtl8139_io_readb(opaque, addr + 2) << 8;
- ret |= rtl8139_io_readb(opaque, addr + 3);
-#else
- ret = rtl8139_io_readb(opaque, addr);
- ret |= rtl8139_io_readb(opaque, addr + 1) << 8;
- ret |= rtl8139_io_readb(opaque, addr + 2) << 16;
- ret |= rtl8139_io_readb(opaque, addr + 3) << 24;
-#endif
-
- DEBUG_PRINT(("RTL8139: read(l) addr=0x%x val=%08x\n", addr, ret));
- break;
- }
-
- return ret;
-}
-
-/* */
-
-static void rtl8139_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- rtl8139_io_writeb(opaque, addr & 0xFF, val);
-}
-
-static void rtl8139_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- rtl8139_io_writew(opaque, addr & 0xFF, val);
-}
-
-static void rtl8139_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- rtl8139_io_writel(opaque, addr & 0xFF, val);
-}
-
-static uint32_t rtl8139_ioport_readb(void *opaque, uint32_t addr)
-{
- return rtl8139_io_readb(opaque, addr & 0xFF);
-}
-
-static uint32_t rtl8139_ioport_readw(void *opaque, uint32_t addr)
-{
- return rtl8139_io_readw(opaque, addr & 0xFF);
-}
-
-static uint32_t rtl8139_ioport_readl(void *opaque, uint32_t addr)
-{
- return rtl8139_io_readl(opaque, addr & 0xFF);
-}
-
-/* */
-
-static void rtl8139_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- rtl8139_io_writeb(opaque, addr & 0xFF, val);
-}
-
-static void rtl8139_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- rtl8139_io_writew(opaque, addr & 0xFF, val);
-}
-
-static void rtl8139_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- rtl8139_io_writel(opaque, addr & 0xFF, val);
-}
-
-static uint32_t rtl8139_mmio_readb(void *opaque, target_phys_addr_t addr)
-{
- return rtl8139_io_readb(opaque, addr & 0xFF);
-}
-
-static uint32_t rtl8139_mmio_readw(void *opaque, target_phys_addr_t addr)
-{
- return rtl8139_io_readw(opaque, addr & 0xFF);
-}
-
-static uint32_t rtl8139_mmio_readl(void *opaque, target_phys_addr_t addr)
-{
- return rtl8139_io_readl(opaque, addr & 0xFF);
-}
-
-/* */
-
-static void rtl8139_save(QEMUFile* f,void* opaque)
-{
- RTL8139State* s=(RTL8139State*)opaque;
- int i;
-
- qemu_put_buffer(f, s->phys, 6);
- qemu_put_buffer(f, s->mult, 8);
-
- for (i=0; i<4; ++i)
- {
- qemu_put_be32s(f, &s->TxStatus[i]); /* TxStatus0 */
- }
- for (i=0; i<4; ++i)
- {
- qemu_put_be32s(f, &s->TxAddr[i]); /* TxAddr0 */
- }
-
- qemu_put_be32s(f, &s->RxBuf); /* Receive buffer */
- qemu_put_be32s(f, &s->RxBufferSize);/* internal variable, receive ring buffer size in C mode */
- qemu_put_be32s(f, &s->RxBufPtr);
- qemu_put_be32s(f, &s->RxBufAddr);
-
- qemu_put_be16s(f, &s->IntrStatus);
- qemu_put_be16s(f, &s->IntrMask);
-
- qemu_put_be32s(f, &s->TxConfig);
- qemu_put_be32s(f, &s->RxConfig);
- qemu_put_be32s(f, &s->RxMissed);
- qemu_put_be16s(f, &s->CSCR);
-
- qemu_put_8s(f, &s->Cfg9346);
- qemu_put_8s(f, &s->Config0);
- qemu_put_8s(f, &s->Config1);
- qemu_put_8s(f, &s->Config3);
- qemu_put_8s(f, &s->Config4);
- qemu_put_8s(f, &s->Config5);
-
- qemu_put_8s(f, &s->clock_enabled);
- qemu_put_8s(f, &s->bChipCmdState);
-
- qemu_put_be16s(f, &s->MultiIntr);
-
- qemu_put_be16s(f, &s->BasicModeCtrl);
- qemu_put_be16s(f, &s->BasicModeStatus);
- qemu_put_be16s(f, &s->NWayAdvert);
- qemu_put_be16s(f, &s->NWayLPAR);
- qemu_put_be16s(f, &s->NWayExpansion);
-
- qemu_put_be16s(f, &s->CpCmd);
- qemu_put_8s(f, &s->TxThresh);
-
- qemu_put_be32s(f, &s->irq);
- qemu_put_buffer(f, s->macaddr, 6);
- qemu_put_be32s(f, &s->rtl8139_mmio_io_addr);
-
- qemu_put_be32s(f, &s->currTxDesc);
- qemu_put_be32s(f, &s->currCPlusRxDesc);
- qemu_put_be32s(f, &s->currCPlusTxDesc);
- qemu_put_be32s(f, &s->RxRingAddrLO);
- qemu_put_be32s(f, &s->RxRingAddrHI);
-
- for (i=0; i<EEPROM_9346_SIZE; ++i)
- {
- qemu_put_be16s(f, &s->eeprom.contents[i]);
- }
- qemu_put_be32s(f, &s->eeprom.mode);
- qemu_put_be32s(f, &s->eeprom.tick);
- qemu_put_8s(f, &s->eeprom.address);
- qemu_put_be16s(f, &s->eeprom.input);
- qemu_put_be16s(f, &s->eeprom.output);
-
- qemu_put_8s(f, &s->eeprom.eecs);
- qemu_put_8s(f, &s->eeprom.eesk);
- qemu_put_8s(f, &s->eeprom.eedi);
- qemu_put_8s(f, &s->eeprom.eedo);
-
- qemu_put_be32s(f, &s->TCTR);
- qemu_put_be32s(f, &s->TimerInt);
- qemu_put_be64s(f, &s->TCTR_base);
-
- RTL8139TallyCounters_save(f, &s->tally_counters);
-}
-
-static int rtl8139_load(QEMUFile* f,void* opaque,int version_id)
-{
- RTL8139State* s=(RTL8139State*)opaque;
- int i;
-
- /* just 2 versions for now */
- if (version_id > 2)
- return -EINVAL;
-
- /* saved since version 1 */
- qemu_get_buffer(f, s->phys, 6);
- qemu_get_buffer(f, s->mult, 8);
-
- for (i=0; i<4; ++i)
- {
- qemu_get_be32s(f, &s->TxStatus[i]); /* TxStatus0 */
- }
- for (i=0; i<4; ++i)
- {
- qemu_get_be32s(f, &s->TxAddr[i]); /* TxAddr0 */
- }
-
- qemu_get_be32s(f, &s->RxBuf); /* Receive buffer */
- qemu_get_be32s(f, &s->RxBufferSize);/* internal variable, receive ring buffer size in C mode */
- qemu_get_be32s(f, &s->RxBufPtr);
- qemu_get_be32s(f, &s->RxBufAddr);
-
- qemu_get_be16s(f, &s->IntrStatus);
- qemu_get_be16s(f, &s->IntrMask);
-
- qemu_get_be32s(f, &s->TxConfig);
- qemu_get_be32s(f, &s->RxConfig);
- qemu_get_be32s(f, &s->RxMissed);
- qemu_get_be16s(f, &s->CSCR);
-
- qemu_get_8s(f, &s->Cfg9346);
- qemu_get_8s(f, &s->Config0);
- qemu_get_8s(f, &s->Config1);
- qemu_get_8s(f, &s->Config3);
- qemu_get_8s(f, &s->Config4);
- qemu_get_8s(f, &s->Config5);
-
- qemu_get_8s(f, &s->clock_enabled);
- qemu_get_8s(f, &s->bChipCmdState);
-
- qemu_get_be16s(f, &s->MultiIntr);
-
- qemu_get_be16s(f, &s->BasicModeCtrl);
- qemu_get_be16s(f, &s->BasicModeStatus);
- qemu_get_be16s(f, &s->NWayAdvert);
- qemu_get_be16s(f, &s->NWayLPAR);
- qemu_get_be16s(f, &s->NWayExpansion);
-
- qemu_get_be16s(f, &s->CpCmd);
- qemu_get_8s(f, &s->TxThresh);
-
- qemu_get_be32s(f, &s->irq);
- qemu_get_buffer(f, s->macaddr, 6);
- qemu_get_be32s(f, &s->rtl8139_mmio_io_addr);
-
- qemu_get_be32s(f, &s->currTxDesc);
- qemu_get_be32s(f, &s->currCPlusRxDesc);
- qemu_get_be32s(f, &s->currCPlusTxDesc);
- qemu_get_be32s(f, &s->RxRingAddrLO);
- qemu_get_be32s(f, &s->RxRingAddrHI);
-
- for (i=0; i<EEPROM_9346_SIZE; ++i)
- {
- qemu_get_be16s(f, &s->eeprom.contents[i]);
- }
- qemu_get_be32s(f, &s->eeprom.mode);
- qemu_get_be32s(f, &s->eeprom.tick);
- qemu_get_8s(f, &s->eeprom.address);
- qemu_get_be16s(f, &s->eeprom.input);
- qemu_get_be16s(f, &s->eeprom.output);
-
- qemu_get_8s(f, &s->eeprom.eecs);
- qemu_get_8s(f, &s->eeprom.eesk);
- qemu_get_8s(f, &s->eeprom.eedi);
- qemu_get_8s(f, &s->eeprom.eedo);
-
- /* saved since version 2 */
- if (version_id >= 2)
- {
- qemu_get_be32s(f, &s->TCTR);
- qemu_get_be32s(f, &s->TimerInt);
- qemu_get_be64s(f, &s->TCTR_base);
-
- RTL8139TallyCounters_load(f, &s->tally_counters);
- }
- else
- {
- /* not saved, use default */
- s->TCTR = 0;
- s->TimerInt = 0;
- s->TCTR_base = 0;
-
- RTL8139TallyCounters_clear(&s->tally_counters);
- }
-
- return 0;
-}
-
-/***********************************************************/
-/* PCI RTL8139 definitions */
-
-typedef struct PCIRTL8139State {
- PCIDevice dev;
- RTL8139State rtl8139;
-} PCIRTL8139State;
-
-static void rtl8139_mmio_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- PCIRTL8139State *d = (PCIRTL8139State *)pci_dev;
- RTL8139State *s = &d->rtl8139;
-
- cpu_register_physical_memory(addr + 0, 0x100, s->rtl8139_mmio_io_addr);
-}
-
-static void rtl8139_ioport_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- PCIRTL8139State *d = (PCIRTL8139State *)pci_dev;
- RTL8139State *s = &d->rtl8139;
-
- register_ioport_write(addr, 0x100, 1, rtl8139_ioport_writeb, s);
- register_ioport_read( addr, 0x100, 1, rtl8139_ioport_readb, s);
-
- register_ioport_write(addr, 0x100, 2, rtl8139_ioport_writew, s);
- register_ioport_read( addr, 0x100, 2, rtl8139_ioport_readw, s);
-
- register_ioport_write(addr, 0x100, 4, rtl8139_ioport_writel, s);
- register_ioport_read( addr, 0x100, 4, rtl8139_ioport_readl, s);
-}
-
-static CPUReadMemoryFunc *rtl8139_mmio_read[3] = {
- rtl8139_mmio_readb,
- rtl8139_mmio_readw,
- rtl8139_mmio_readl,
-};
-
-static CPUWriteMemoryFunc *rtl8139_mmio_write[3] = {
- rtl8139_mmio_writeb,
- rtl8139_mmio_writew,
- rtl8139_mmio_writel,
-};
-
-static inline int64_t rtl8139_get_next_tctr_time(RTL8139State *s, int64_t current_time)
-{
- int64_t next_time = current_time +
- muldiv64(1, ticks_per_sec, PCI_FREQUENCY);
- if (next_time <= current_time)
- next_time = current_time + 1;
- return next_time;
-}
-
-#if RTL8139_ONBOARD_TIMER
-static void rtl8139_timer(void *opaque)
-{
- RTL8139State *s = opaque;
-
- int is_timeout = 0;
-
- int64_t curr_time;
- uint32_t curr_tick;
-
- if (!s->clock_enabled)
- {
- DEBUG_PRINT(("RTL8139: >>> timer: clock is not running\n"));
- return;
- }
-
- curr_time = qemu_get_clock(vm_clock);
-
- curr_tick = muldiv64(curr_time - s->TCTR_base, PCI_FREQUENCY, ticks_per_sec);
-
- if (s->TimerInt && curr_tick >= s->TimerInt)
- {
- if (s->TCTR < s->TimerInt || curr_tick < s->TCTR)
- {
- is_timeout = 1;
- }
- }
-
- s->TCTR = curr_tick;
-
-// DEBUG_PRINT(("RTL8139: >>> timer: tick=%08u\n", s->TCTR));
-
- if (is_timeout)
- {
- DEBUG_PRINT(("RTL8139: >>> timer: timeout tick=%08u\n", s->TCTR));
- s->IntrStatus |= PCSTimeout;
- rtl8139_update_irq(s);
- }
-
- qemu_mod_timer(s->timer,
- rtl8139_get_next_tctr_time(s,curr_time));
-}
-#endif /* RTL8139_ONBOARD_TIMER */
-
-void pci_rtl8139_init(PCIBus *bus, NICInfo *nd)
-{
- PCIRTL8139State *d;
- RTL8139State *s;
- uint8_t *pci_conf;
-
- d = (PCIRTL8139State *)pci_register_device(bus,
- "RTL8139", sizeof(PCIRTL8139State),
- -1,
- NULL, NULL);
- pci_conf = d->dev.config;
- pci_conf[0x00] = 0xec; /* Realtek 8139 */
- pci_conf[0x01] = 0x10;
- pci_conf[0x02] = 0x39;
- pci_conf[0x03] = 0x81;
- pci_conf[0x04] = 0x05; /* command = I/O space, Bus Master */
- pci_conf[0x08] = RTL8139_PCI_REVID; /* PCI revision ID; >=0x20 is for 8139C+ */
- pci_conf[0x0a] = 0x00; /* ethernet network controller */
- pci_conf[0x0b] = 0x02;
- pci_conf[0x0e] = 0x00; /* header_type */
- pci_conf[0x3d] = 1; /* interrupt pin 0 */
- pci_conf[0x34] = 0xdc;
-
- s = &d->rtl8139;
-
- /* I/O handler for memory-mapped I/O */
- s->rtl8139_mmio_io_addr =
- cpu_register_io_memory(0, rtl8139_mmio_read, rtl8139_mmio_write, s);
-
- pci_register_io_region(&d->dev, 0, 0x100,
- PCI_ADDRESS_SPACE_IO, rtl8139_ioport_map);
-
- 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);
- s->vc = qemu_new_vlan_client(nd->vlan, rtl8139_receive,
- rtl8139_can_receive, s);
-
- snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "rtl8139 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]);
-
- s->cplus_txbuffer = NULL;
- s->cplus_txbuffer_len = 0;
- s->cplus_txbuffer_offset = 0;
-
- /* XXX: instance number ? */
- register_savevm("rtl8139", 0, 2, rtl8139_save, rtl8139_load, s);
- register_savevm("rtl8139_pci", 0, 1, generic_pci_save, generic_pci_load,
- &d->dev);
-
-#if RTL8139_ONBOARD_TIMER
- s->timer = qemu_new_timer(vm_clock, rtl8139_timer, s);
-
- qemu_mod_timer(s->timer,
- rtl8139_get_next_tctr_time(s,qemu_get_clock(vm_clock)));
-#endif /* RTL8139_ONBOARD_TIMER */
-}
-
diff --git a/hw/sb16.c b/hw/sb16.c
deleted file mode 100644
index 04325ac..0000000
--- a/hw/sb16.c
+++ /dev/null
@@ -1,1451 +0,0 @@
-/*
- * QEMU Soundblaster 16 emulation
- *
- * Copyright (c) 2003-2005 Vassili Karpov (malc)
- *
- * 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 LENOFA(a) ((int) (sizeof(a)/sizeof(a[0])))
-
-#define dolog(...) AUD_log ("sb16", __VA_ARGS__)
-
-/* #define DEBUG */
-/* #define DEBUG_SB16_MOST */
-
-#ifdef DEBUG
-#define ldebug(...) dolog (__VA_ARGS__)
-#else
-#define ldebug(...)
-#endif
-
-#define IO_READ_PROTO(name) \
- uint32_t name (void *opaque, uint32_t nport)
-#define IO_WRITE_PROTO(name) \
- void name (void *opaque, uint32_t nport, uint32_t val)
-
-static const char e3[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
-
-static struct {
- int ver_lo;
- int ver_hi;
- int irq;
- int dma;
- int hdma;
- int port;
-} conf = {5, 4, 5, 1, 5, 0x220};
-
-typedef struct SB16State {
- QEMUSoundCard card;
- int irq;
- int dma;
- int hdma;
- int port;
- int ver;
-
- int in_index;
- int out_data_len;
- int fmt_stereo;
- int fmt_signed;
- int fmt_bits;
- audfmt_e fmt;
- int dma_auto;
- int block_size;
- int fifo;
- int freq;
- int time_const;
- int speaker;
- int needed_bytes;
- int cmd;
- int use_hdma;
- int highspeed;
- int can_write;
-
- int v2x6;
-
- uint8_t csp_param;
- uint8_t csp_value;
- uint8_t csp_mode;
- uint8_t csp_regs[256];
- uint8_t csp_index;
- uint8_t csp_reg83[4];
- int csp_reg83r;
- int csp_reg83w;
-
- uint8_t in2_data[10];
- uint8_t out_data[50];
- uint8_t test_reg;
- uint8_t last_read_byte;
- int nzero;
-
- int left_till_irq;
-
- int dma_running;
- int bytes_per_second;
- int align;
- int audio_free;
- SWVoiceOut *voice;
-
- QEMUTimer *aux_ts;
- /* mixer state */
- int mixer_nreg;
- uint8_t mixer_regs[256];
-} SB16State;
-
-static void SB_audio_callback (void *opaque, int free);
-
-static int magic_of_irq (int irq)
-{
- switch (irq) {
- case 5:
- return 2;
- case 7:
- return 4;
- case 9:
- return 1;
- case 10:
- return 8;
- default:
- dolog ("bad irq %d\n", irq);
- return 2;
- }
-}
-
-static int irq_of_magic (int magic)
-{
- switch (magic) {
- case 1:
- return 9;
- case 2:
- return 5;
- case 4:
- return 7;
- case 8:
- return 10;
- default:
- dolog ("bad irq magic %d\n", magic);
- return -1;
- }
-}
-
-#if 0
-static void log_dsp (SB16State *dsp)
-{
- ldebug ("%s:%s:%d:%s:dmasize=%d:freq=%d:const=%d:speaker=%d\n",
- dsp->fmt_stereo ? "Stereo" : "Mono",
- dsp->fmt_signed ? "Signed" : "Unsigned",
- dsp->fmt_bits,
- dsp->dma_auto ? "Auto" : "Single",
- dsp->block_size,
- dsp->freq,
- dsp->time_const,
- dsp->speaker);
-}
-#endif
-
-static void speaker (SB16State *s, int on)
-{
- s->speaker = on;
- /* AUD_enable (s->voice, on); */
-}
-
-static void control (SB16State *s, int hold)
-{
- int dma = s->use_hdma ? s->hdma : s->dma;
- s->dma_running = hold;
-
- ldebug ("hold %d high %d dma %d\n", hold, s->use_hdma, dma);
-
- if (hold) {
- DMA_hold_DREQ (dma);
- AUD_set_active_out (s->voice, 1);
- }
- else {
- DMA_release_DREQ (dma);
- AUD_set_active_out (s->voice, 0);
- }
-}
-
-static void aux_timer (void *opaque)
-{
- SB16State *s = opaque;
- s->can_write = 1;
- pic_set_irq (s->irq, 1);
-}
-
-#define DMA8_AUTO 1
-#define DMA8_HIGH 2
-
-static void continue_dma8 (SB16State *s)
-{
- if (s->freq > 0) {
- audsettings_t as;
-
- s->audio_free = 0;
-
- as.freq = s->freq;
- as.nchannels = 1 << s->fmt_stereo;
- as.fmt = s->fmt;
- as.endianness = 0;
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "sb16",
- s,
- SB_audio_callback,
- &as
- );
- }
-
- control (s, 1);
-}
-
-static void dma_cmd8 (SB16State *s, int mask, int dma_len)
-{
- s->fmt = AUD_FMT_U8;
- s->use_hdma = 0;
- s->fmt_bits = 8;
- s->fmt_signed = 0;
- s->fmt_stereo = (s->mixer_regs[0x0e] & 2) != 0;
- if (-1 == s->time_const) {
- if (s->freq <= 0)
- s->freq = 11025;
- }
- else {
- int tmp = (256 - s->time_const);
- s->freq = (1000000 + (tmp / 2)) / tmp;
- }
-
- if (dma_len != -1) {
- s->block_size = dma_len << s->fmt_stereo;
- }
- else {
- /* This is apparently the only way to make both Act1/PL
- and SecondReality/FC work
-
- Act1 sets block size via command 0x48 and it's an odd number
- SR does the same with even number
- Both use stereo, and Creatives own documentation states that
- 0x48 sets block size in bytes less one.. go figure */
- s->block_size &= ~s->fmt_stereo;
- }
-
- s->freq >>= s->fmt_stereo;
- s->left_till_irq = s->block_size;
- s->bytes_per_second = (s->freq << s->fmt_stereo);
- /* s->highspeed = (mask & DMA8_HIGH) != 0; */
- s->dma_auto = (mask & DMA8_AUTO) != 0;
- s->align = (1 << s->fmt_stereo) - 1;
-
- if (s->block_size & s->align) {
- dolog ("warning: misaligned block size %d, alignment %d\n",
- s->block_size, s->align + 1);
- }
-
- ldebug ("freq %d, stereo %d, sign %d, bits %d, "
- "dma %d, auto %d, fifo %d, high %d\n",
- s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
- s->block_size, s->dma_auto, s->fifo, s->highspeed);
-
- continue_dma8 (s);
- speaker (s, 1);
-}
-
-static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)
-{
- s->use_hdma = cmd < 0xc0;
- s->fifo = (cmd >> 1) & 1;
- s->dma_auto = (cmd >> 2) & 1;
- s->fmt_signed = (d0 >> 4) & 1;
- s->fmt_stereo = (d0 >> 5) & 1;
-
- switch (cmd >> 4) {
- case 11:
- s->fmt_bits = 16;
- break;
-
- case 12:
- s->fmt_bits = 8;
- break;
- }
-
- if (-1 != s->time_const) {
-#if 1
- int tmp = 256 - s->time_const;
- s->freq = (1000000 + (tmp / 2)) / tmp;
-#else
- /* s->freq = 1000000 / ((255 - s->time_const) << s->fmt_stereo); */
- s->freq = 1000000 / ((255 - s->time_const));
-#endif
- s->time_const = -1;
- }
-
- s->block_size = dma_len + 1;
- s->block_size <<= (s->fmt_bits == 16);
- if (!s->dma_auto) {
- /* It is clear that for DOOM and auto-init this value
- shouldn't take stereo into account, while Miles Sound Systems
- setsound.exe with single transfer mode wouldn't work without it
- wonders of SB16 yet again */
- s->block_size <<= s->fmt_stereo;
- }
-
- ldebug ("freq %d, stereo %d, sign %d, bits %d, "
- "dma %d, auto %d, fifo %d, high %d\n",
- s->freq, s->fmt_stereo, s->fmt_signed, s->fmt_bits,
- s->block_size, s->dma_auto, s->fifo, s->highspeed);
-
- if (16 == s->fmt_bits) {
- if (s->fmt_signed) {
- s->fmt = AUD_FMT_S16;
- }
- else {
- s->fmt = AUD_FMT_U16;
- }
- }
- else {
- if (s->fmt_signed) {
- s->fmt = AUD_FMT_S8;
- }
- else {
- s->fmt = AUD_FMT_U8;
- }
- }
-
- s->left_till_irq = s->block_size;
-
- s->bytes_per_second = (s->freq << s->fmt_stereo) << (s->fmt_bits == 16);
- s->highspeed = 0;
- s->align = (1 << (s->fmt_stereo + (s->fmt_bits == 16))) - 1;
- if (s->block_size & s->align) {
- dolog ("warning: misaligned block size %d, alignment %d\n",
- s->block_size, s->align + 1);
- }
-
- if (s->freq) {
- audsettings_t as;
-
- s->audio_free = 0;
-
- as.freq = s->freq;
- as.nchannels = 1 << s->fmt_stereo;
- as.fmt = s->fmt;
- as.endianness = 0;
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "sb16",
- s,
- SB_audio_callback,
- &as
- );
- }
-
- control (s, 1);
- speaker (s, 1);
-}
-
-static inline void dsp_out_data (SB16State *s, uint8_t val)
-{
- ldebug ("outdata %#x\n", val);
- if ((size_t) s->out_data_len < sizeof (s->out_data)) {
- s->out_data[s->out_data_len++] = val;
- }
-}
-
-static inline uint8_t dsp_get_data (SB16State *s)
-{
- if (s->in_index) {
- return s->in2_data[--s->in_index];
- }
- else {
- dolog ("buffer underflow\n");
- return 0;
- }
-}
-
-static void command (SB16State *s, uint8_t cmd)
-{
- ldebug ("command %#x\n", cmd);
-
- if (cmd > 0xaf && cmd < 0xd0) {
- if (cmd & 8) {
- dolog ("ADC not yet supported (command %#x)\n", cmd);
- }
-
- switch (cmd >> 4) {
- case 11:
- case 12:
- break;
- default:
- dolog ("%#x wrong bits\n", cmd);
- }
- s->needed_bytes = 3;
- }
- else {
- s->needed_bytes = 0;
-
- switch (cmd) {
- case 0x03:
- dsp_out_data (s, 0x10); /* s->csp_param); */
- goto warn;
-
- case 0x04:
- s->needed_bytes = 1;
- goto warn;
-
- case 0x05:
- s->needed_bytes = 2;
- goto warn;
-
- case 0x08:
- /* __asm__ ("int3"); */
- goto warn;
-
- case 0x0e:
- s->needed_bytes = 2;
- goto warn;
-
- case 0x09:
- dsp_out_data (s, 0xf8);
- goto warn;
-
- case 0x0f:
- s->needed_bytes = 1;
- goto warn;
-
- case 0x10:
- s->needed_bytes = 1;
- goto warn;
-
- case 0x14:
- s->needed_bytes = 2;
- s->block_size = 0;
- break;
-
- case 0x1c: /* Auto-Initialize DMA DAC, 8-bit */
- dma_cmd8 (s, DMA8_AUTO, -1);
- break;
-
- case 0x20: /* Direct ADC, Juice/PL */
- dsp_out_data (s, 0xff);
- goto warn;
-
- case 0x35:
- dolog ("0x35 - MIDI command not implemented\n");
- break;
-
- case 0x40:
- s->freq = -1;
- s->time_const = -1;
- s->needed_bytes = 1;
- break;
-
- case 0x41:
- s->freq = -1;
- s->time_const = -1;
- s->needed_bytes = 2;
- break;
-
- case 0x42:
- s->freq = -1;
- s->time_const = -1;
- s->needed_bytes = 2;
- goto warn;
-
- case 0x45:
- dsp_out_data (s, 0xaa);
- goto warn;
-
- case 0x47: /* Continue Auto-Initialize DMA 16bit */
- break;
-
- case 0x48:
- s->needed_bytes = 2;
- break;
-
- case 0x74:
- s->needed_bytes = 2; /* DMA DAC, 4-bit ADPCM */
- dolog ("0x75 - DMA DAC, 4-bit ADPCM not implemented\n");
- break;
-
- case 0x75: /* DMA DAC, 4-bit ADPCM Reference */
- s->needed_bytes = 2;
- dolog ("0x74 - DMA DAC, 4-bit ADPCM Reference not implemented\n");
- break;
-
- case 0x76: /* DMA DAC, 2.6-bit ADPCM */
- s->needed_bytes = 2;
- dolog ("0x74 - DMA DAC, 2.6-bit ADPCM not implemented\n");
- break;
-
- case 0x77: /* DMA DAC, 2.6-bit ADPCM Reference */
- s->needed_bytes = 2;
- dolog ("0x74 - DMA DAC, 2.6-bit ADPCM Reference not implemented\n");
- break;
-
- case 0x7d:
- dolog ("0x7d - Autio-Initialize DMA DAC, 4-bit ADPCM Reference\n");
- dolog ("not implemented\n");
- break;
-
- case 0x7f:
- dolog (
- "0x7d - Autio-Initialize DMA DAC, 2.6-bit ADPCM Reference\n"
- );
- dolog ("not implemented\n");
- break;
-
- case 0x80:
- s->needed_bytes = 2;
- break;
-
- case 0x90:
- case 0x91:
- dma_cmd8 (s, ((cmd & 1) == 0) | DMA8_HIGH, -1);
- break;
-
- case 0xd0: /* halt DMA operation. 8bit */
- control (s, 0);
- break;
-
- case 0xd1: /* speaker on */
- speaker (s, 1);
- break;
-
- case 0xd3: /* speaker off */
- speaker (s, 0);
- break;
-
- case 0xd4: /* continue DMA operation. 8bit */
- /* KQ6 (or maybe Sierras audblst.drv in general) resets
- the frequency between halt/continue */
- continue_dma8 (s);
- break;
-
- case 0xd5: /* halt DMA operation. 16bit */
- control (s, 0);
- break;
-
- case 0xd6: /* continue DMA operation. 16bit */
- control (s, 1);
- break;
-
- case 0xd9: /* exit auto-init DMA after this block. 16bit */
- s->dma_auto = 0;
- break;
-
- case 0xda: /* exit auto-init DMA after this block. 8bit */
- s->dma_auto = 0;
- break;
-
- case 0xe0: /* DSP identification */
- s->needed_bytes = 1;
- break;
-
- case 0xe1:
- dsp_out_data (s, s->ver & 0xff);
- dsp_out_data (s, s->ver >> 8);
- break;
-
- case 0xe2:
- s->needed_bytes = 1;
- goto warn;
-
- case 0xe3:
- {
- int i;
- for (i = sizeof (e3) - 1; i >= 0; --i)
- dsp_out_data (s, e3[i]);
- }
- break;
-
- case 0xe4: /* write test reg */
- s->needed_bytes = 1;
- break;
-
- case 0xe7:
- dolog ("Attempt to probe for ESS (0xe7)?\n");
- break;
-
- case 0xe8: /* read test reg */
- dsp_out_data (s, s->test_reg);
- break;
-
- case 0xf2:
- case 0xf3:
- dsp_out_data (s, 0xaa);
- s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
- pic_set_irq (s->irq, 1);
- break;
-
- case 0xf9:
- s->needed_bytes = 1;
- goto warn;
-
- case 0xfa:
- dsp_out_data (s, 0);
- goto warn;
-
- case 0xfc: /* FIXME */
- dsp_out_data (s, 0);
- goto warn;
-
- default:
- dolog ("Unrecognized command %#x\n", cmd);
- break;
- }
- }
-
- if (!s->needed_bytes) {
- ldebug ("\n");
- }
-
- exit:
- if (!s->needed_bytes) {
- s->cmd = -1;
- }
- else {
- s->cmd = cmd;
- }
- return;
-
- warn:
- dolog ("warning: command %#x,%d is not truly understood yet\n",
- cmd, s->needed_bytes);
- goto exit;
-
-}
-
-static uint16_t dsp_get_lohi (SB16State *s)
-{
- uint8_t hi = dsp_get_data (s);
- uint8_t lo = dsp_get_data (s);
- return (hi << 8) | lo;
-}
-
-static uint16_t dsp_get_hilo (SB16State *s)
-{
- uint8_t lo = dsp_get_data (s);
- uint8_t hi = dsp_get_data (s);
- return (hi << 8) | lo;
-}
-
-static void complete (SB16State *s)
-{
- int d0, d1, d2;
- ldebug ("complete command %#x, in_index %d, needed_bytes %d\n",
- s->cmd, s->in_index, s->needed_bytes);
-
- if (s->cmd > 0xaf && s->cmd < 0xd0) {
- d2 = dsp_get_data (s);
- d1 = dsp_get_data (s);
- d0 = dsp_get_data (s);
-
- if (s->cmd & 8) {
- dolog ("ADC params cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
- s->cmd, d0, d1, d2);
- }
- else {
- ldebug ("cmd = %#x d0 = %d, d1 = %d, d2 = %d\n",
- s->cmd, d0, d1, d2);
- dma_cmd (s, s->cmd, d0, d1 + (d2 << 8));
- }
- }
- else {
- switch (s->cmd) {
- case 0x04:
- s->csp_mode = dsp_get_data (s);
- s->csp_reg83r = 0;
- s->csp_reg83w = 0;
- ldebug ("CSP command 0x04: mode=%#x\n", s->csp_mode);
- break;
-
- case 0x05:
- s->csp_param = dsp_get_data (s);
- s->csp_value = dsp_get_data (s);
- ldebug ("CSP command 0x05: param=%#x value=%#x\n",
- s->csp_param,
- s->csp_value);
- break;
-
- case 0x0e:
- d0 = dsp_get_data (s);
- d1 = dsp_get_data (s);
- ldebug ("write CSP register %d <- %#x\n", d1, d0);
- if (d1 == 0x83) {
- ldebug ("0x83[%d] <- %#x\n", s->csp_reg83r, d0);
- s->csp_reg83[s->csp_reg83r % 4] = d0;
- s->csp_reg83r += 1;
- }
- else {
- s->csp_regs[d1] = d0;
- }
- break;
-
- case 0x0f:
- d0 = dsp_get_data (s);
- ldebug ("read CSP register %#x -> %#x, mode=%#x\n",
- d0, s->csp_regs[d0], s->csp_mode);
- if (d0 == 0x83) {
- ldebug ("0x83[%d] -> %#x\n",
- s->csp_reg83w,
- s->csp_reg83[s->csp_reg83w % 4]);
- dsp_out_data (s, s->csp_reg83[s->csp_reg83w % 4]);
- s->csp_reg83w += 1;
- }
- else {
- dsp_out_data (s, s->csp_regs[d0]);
- }
- break;
-
- case 0x10:
- d0 = dsp_get_data (s);
- dolog ("cmd 0x10 d0=%#x\n", d0);
- break;
-
- case 0x14:
- dma_cmd8 (s, 0, dsp_get_lohi (s) + 1);
- break;
-
- case 0x40:
- s->time_const = dsp_get_data (s);
- ldebug ("set time const %d\n", s->time_const);
- break;
-
- case 0x42: /* FT2 sets output freq with this, go figure */
-#if 0
- dolog ("cmd 0x42 might not do what it think it should\n");
-#endif
- case 0x41:
- s->freq = dsp_get_hilo (s);
- ldebug ("set freq %d\n", s->freq);
- break;
-
- case 0x48:
- s->block_size = dsp_get_lohi (s) + 1;
- ldebug ("set dma block len %d\n", s->block_size);
- break;
-
- case 0x74:
- case 0x75:
- case 0x76:
- case 0x77:
- /* ADPCM stuff, ignore */
- break;
-
- case 0x80:
- {
- int freq, samples, bytes;
- int64_t ticks;
-
- freq = s->freq > 0 ? s->freq : 11025;
- samples = dsp_get_lohi (s) + 1;
- 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);
- }
- else {
- if (s->aux_ts) {
- qemu_mod_timer (
- s->aux_ts,
- qemu_get_clock (vm_clock) + ticks
- );
- }
- }
- ldebug ("mix silence %d %d %" PRId64 "\n", samples, bytes, ticks);
- }
- break;
-
- case 0xe0:
- d0 = dsp_get_data (s);
- s->out_data_len = 0;
- ldebug ("E0 data = %#x\n", d0);
- dsp_out_data (s, ~d0);
- break;
-
- case 0xe2:
- d0 = dsp_get_data (s);
- ldebug ("E2 = %#x\n", d0);
- break;
-
- case 0xe4:
- s->test_reg = dsp_get_data (s);
- break;
-
- case 0xf9:
- d0 = dsp_get_data (s);
- ldebug ("command 0xf9 with %#x\n", d0);
- switch (d0) {
- case 0x0e:
- dsp_out_data (s, 0xff);
- break;
-
- case 0x0f:
- dsp_out_data (s, 0x07);
- break;
-
- case 0x37:
- dsp_out_data (s, 0x38);
- break;
-
- default:
- dsp_out_data (s, 0x00);
- break;
- }
- break;
-
- default:
- dolog ("complete: unrecognized command %#x\n", s->cmd);
- return;
- }
- }
-
- ldebug ("\n");
- s->cmd = -1;
- return;
-}
-
-static void legacy_reset (SB16State *s)
-{
- audsettings_t as;
-
- s->freq = 11025;
- s->fmt_signed = 0;
- s->fmt_bits = 8;
- s->fmt_stereo = 0;
-
- as.freq = s->freq;
- as.nchannels = 1;
- as.fmt = AUD_FMT_U8;
- as.endianness = 0;
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "sb16",
- s,
- SB_audio_callback,
- &as
- );
-
- /* Not sure about that... */
- /* AUD_set_active_out (s->voice, 1); */
-}
-
-static void reset (SB16State *s)
-{
- pic_set_irq (s->irq, 0);
- if (s->dma_auto) {
- pic_set_irq (s->irq, 1);
- pic_set_irq (s->irq, 0);
- }
-
- s->mixer_regs[0x82] = 0;
- s->dma_auto = 0;
- s->in_index = 0;
- s->out_data_len = 0;
- s->left_till_irq = 0;
- s->needed_bytes = 0;
- s->block_size = -1;
- s->nzero = 0;
- s->highspeed = 0;
- s->v2x6 = 0;
- s->cmd = -1;
-
- dsp_out_data(s, 0xaa);
- speaker (s, 0);
- control (s, 0);
- legacy_reset (s);
-}
-
-static IO_WRITE_PROTO (dsp_write)
-{
- SB16State *s = opaque;
- int iport;
-
- iport = nport - s->port;
-
- ldebug ("write %#x <- %#x\n", nport, val);
- switch (iport) {
- case 0x06:
- switch (val) {
- case 0x00:
- if (s->v2x6 == 1) {
- if (0 && s->highspeed) {
- s->highspeed = 0;
- pic_set_irq (s->irq, 0);
- control (s, 0);
- }
- else {
- reset (s);
- }
- }
- s->v2x6 = 0;
- break;
-
- case 0x01:
- case 0x03: /* FreeBSD kludge */
- s->v2x6 = 1;
- break;
-
- case 0xc6:
- s->v2x6 = 0; /* Prince of Persia, csp.sys, diagnose.exe */
- break;
-
- case 0xb8: /* Panic */
- reset (s);
- break;
-
- case 0x39:
- dsp_out_data (s, 0x38);
- reset (s);
- s->v2x6 = 0x39;
- break;
-
- default:
- s->v2x6 = val;
- break;
- }
- break;
-
- case 0x0c: /* write data or command | write status */
-/* if (s->highspeed) */
-/* break; */
-
- if (0 == s->needed_bytes) {
- command (s, val);
-#if 0
- if (0 == s->needed_bytes) {
- log_dsp (s);
- }
-#endif
- }
- else {
- if (s->in_index == sizeof (s->in2_data)) {
- dolog ("in data overrun\n");
- }
- else {
- s->in2_data[s->in_index++] = val;
- if (s->in_index == s->needed_bytes) {
- s->needed_bytes = 0;
- complete (s);
-#if 0
- log_dsp (s);
-#endif
- }
- }
- }
- break;
-
- default:
- ldebug ("(nport=%#x, val=%#x)\n", nport, val);
- break;
- }
-}
-
-static IO_READ_PROTO (dsp_read)
-{
- SB16State *s = opaque;
- int iport, retval, ack = 0;
-
- iport = nport - s->port;
-
- switch (iport) {
- case 0x06: /* reset */
- retval = 0xff;
- break;
-
- case 0x0a: /* read data */
- if (s->out_data_len) {
- retval = s->out_data[--s->out_data_len];
- s->last_read_byte = retval;
- }
- else {
- if (s->cmd != -1) {
- dolog ("empty output buffer for command %#x\n",
- s->cmd);
- }
- retval = s->last_read_byte;
- /* goto error; */
- }
- break;
-
- case 0x0c: /* 0 can write */
- retval = s->can_write ? 0 : 0x80;
- break;
-
- case 0x0d: /* timer interrupt clear */
- /* dolog ("timer interrupt clear\n"); */
- retval = 0;
- break;
-
- case 0x0e: /* data available status | irq 8 ack */
- retval = (!s->out_data_len || s->highspeed) ? 0 : 0x80;
- if (s->mixer_regs[0x82] & 1) {
- ack = 1;
- s->mixer_regs[0x82] &= 1;
- pic_set_irq (s->irq, 0);
- }
- break;
-
- case 0x0f: /* irq 16 ack */
- retval = 0xff;
- if (s->mixer_regs[0x82] & 2) {
- ack = 1;
- s->mixer_regs[0x82] &= 2;
- pic_set_irq (s->irq, 0);
- }
- break;
-
- default:
- goto error;
- }
-
- if (!ack) {
- ldebug ("read %#x -> %#x\n", nport, retval);
- }
-
- return retval;
-
- error:
- dolog ("warning: dsp_read %#x error\n", nport);
- return 0xff;
-}
-
-static void reset_mixer (SB16State *s)
-{
- int i;
-
- memset (s->mixer_regs, 0xff, 0x7f);
- memset (s->mixer_regs + 0x83, 0xff, sizeof (s->mixer_regs) - 0x83);
-
- s->mixer_regs[0x02] = 4; /* master volume 3bits */
- s->mixer_regs[0x06] = 4; /* MIDI volume 3bits */
- s->mixer_regs[0x08] = 0; /* CD volume 3bits */
- s->mixer_regs[0x0a] = 0; /* voice volume 2bits */
-
- /* d5=input filt, d3=lowpass filt, d1,d2=input source */
- s->mixer_regs[0x0c] = 0;
-
- /* d5=output filt, d1=stereo switch */
- s->mixer_regs[0x0e] = 0;
-
- /* voice volume L d5,d7, R d1,d3 */
- s->mixer_regs[0x04] = (4 << 5) | (4 << 1);
- /* master ... */
- s->mixer_regs[0x22] = (4 << 5) | (4 << 1);
- /* MIDI ... */
- s->mixer_regs[0x26] = (4 << 5) | (4 << 1);
-
- for (i = 0x30; i < 0x48; i++) {
- s->mixer_regs[i] = 0x20;
- }
-}
-
-static IO_WRITE_PROTO(mixer_write_indexb)
-{
- SB16State *s = opaque;
- (void) nport;
- s->mixer_nreg = val;
-}
-
-static IO_WRITE_PROTO(mixer_write_datab)
-{
- SB16State *s = opaque;
-
- (void) nport;
- ldebug ("mixer_write [%#x] <- %#x\n", s->mixer_nreg, val);
-
- switch (s->mixer_nreg) {
- case 0x00:
- reset_mixer (s);
- break;
-
- case 0x80:
- {
- int irq = irq_of_magic (val);
- ldebug ("setting irq to %d (val=%#x)\n", irq, val);
- if (irq > 0) {
- s->irq = irq;
- }
- }
- break;
-
- case 0x81:
- {
- int dma, hdma;
-
- dma = lsbindex (val & 0xf);
- hdma = lsbindex (val & 0xf0);
- if (dma != s->dma || hdma != s->hdma) {
- dolog (
- "attempt to change DMA "
- "8bit %d(%d), 16bit %d(%d) (val=%#x)\n",
- dma, s->dma, hdma, s->hdma, val);
- }
-#if 0
- s->dma = dma;
- s->hdma = hdma;
-#endif
- }
- break;
-
- case 0x82:
- dolog ("attempt to write into IRQ status register (val=%#x)\n",
- val);
- return;
-
- default:
- if (s->mixer_nreg >= 0x80) {
- ldebug ("attempt to write mixer[%#x] <- %#x\n", s->mixer_nreg, val);
- }
- break;
- }
-
- s->mixer_regs[s->mixer_nreg] = val;
-}
-
-static IO_WRITE_PROTO(mixer_write_indexw)
-{
- mixer_write_indexb (opaque, nport, val & 0xff);
- mixer_write_datab (opaque, nport, (val >> 8) & 0xff);
-}
-
-static IO_READ_PROTO(mixer_read)
-{
- SB16State *s = opaque;
-
- (void) nport;
-#ifndef DEBUG_SB16_MOST
- if (s->mixer_nreg != 0x82) {
- ldebug ("mixer_read[%#x] -> %#x\n",
- s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
- }
-#else
- ldebug ("mixer_read[%#x] -> %#x\n",
- s->mixer_nreg, s->mixer_regs[s->mixer_nreg]);
-#endif
- return s->mixer_regs[s->mixer_nreg];
-}
-
-static int write_audio (SB16State *s, int nchan, int dma_pos,
- int dma_len, int len)
-{
- int temp, net;
- uint8_t tmpbuf[4096];
-
- temp = len;
- net = 0;
-
- while (temp) {
- int left = dma_len - dma_pos;
- int copied;
- size_t to_copy;
-
- to_copy = audio_MIN (temp, left);
- if (to_copy > sizeof (tmpbuf)) {
- to_copy = sizeof (tmpbuf);
- }
-
- copied = DMA_read_memory (nchan, tmpbuf, dma_pos, to_copy);
- copied = AUD_write (s->voice, tmpbuf, copied);
-
- temp -= copied;
- dma_pos = (dma_pos + copied) % dma_len;
- net += copied;
-
- if (!copied) {
- break;
- }
- }
-
- return net;
-}
-
-static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
-{
- SB16State *s = opaque;
- int till, copy, written, free;
-
- if (s->left_till_irq < 0) {
- s->left_till_irq = s->block_size;
- }
-
- if (s->voice) {
- free = s->audio_free & ~s->align;
- if ((free <= 0) || !dma_len) {
- return dma_pos;
- }
- }
- else {
- free = dma_len;
- }
-
- copy = free;
- till = s->left_till_irq;
-
-#ifdef DEBUG_SB16_MOST
- dolog ("pos:%06d %d till:%d len:%d\n",
- dma_pos, free, till, dma_len);
-#endif
-
- if (till <= copy) {
- if (0 == s->dma_auto) {
- copy = till;
- }
- }
-
- written = write_audio (s, nchan, dma_pos, dma_len, copy);
- dma_pos = (dma_pos + written) % dma_len;
- s->left_till_irq -= written;
-
- if (s->left_till_irq <= 0) {
- s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
- pic_set_irq (s->irq, 1);
- if (0 == s->dma_auto) {
- control (s, 0);
- speaker (s, 0);
- }
- }
-
-#ifdef DEBUG_SB16_MOST
- ldebug ("pos %5d free %5d size %5d till % 5d copy %5d written %5d size %5d\n",
- dma_pos, free, dma_len, s->left_till_irq, copy, written,
- s->block_size);
-#endif
-
- while (s->left_till_irq <= 0) {
- s->left_till_irq = s->block_size + s->left_till_irq;
- }
-
- return dma_pos;
-}
-
-static void SB_audio_callback (void *opaque, int free)
-{
- SB16State *s = opaque;
- s->audio_free = free;
-}
-
-static void SB_save (QEMUFile *f, void *opaque)
-{
- SB16State *s = opaque;
-
- qemu_put_be32s (f, &s->irq);
- qemu_put_be32s (f, &s->dma);
- qemu_put_be32s (f, &s->hdma);
- qemu_put_be32s (f, &s->port);
- qemu_put_be32s (f, &s->ver);
- qemu_put_be32s (f, &s->in_index);
- qemu_put_be32s (f, &s->out_data_len);
- qemu_put_be32s (f, &s->fmt_stereo);
- qemu_put_be32s (f, &s->fmt_signed);
- qemu_put_be32s (f, &s->fmt_bits);
- qemu_put_be32s (f, &s->fmt);
- qemu_put_be32s (f, &s->dma_auto);
- qemu_put_be32s (f, &s->block_size);
- qemu_put_be32s (f, &s->fifo);
- qemu_put_be32s (f, &s->freq);
- qemu_put_be32s (f, &s->time_const);
- qemu_put_be32s (f, &s->speaker);
- qemu_put_be32s (f, &s->needed_bytes);
- qemu_put_be32s (f, &s->cmd);
- qemu_put_be32s (f, &s->use_hdma);
- qemu_put_be32s (f, &s->highspeed);
- qemu_put_be32s (f, &s->can_write);
- qemu_put_be32s (f, &s->v2x6);
-
- qemu_put_8s (f, &s->csp_param);
- qemu_put_8s (f, &s->csp_value);
- qemu_put_8s (f, &s->csp_mode);
- qemu_put_8s (f, &s->csp_param);
- qemu_put_buffer (f, s->csp_regs, 256);
- qemu_put_8s (f, &s->csp_index);
- qemu_put_buffer (f, s->csp_reg83, 4);
- qemu_put_be32s (f, &s->csp_reg83r);
- qemu_put_be32s (f, &s->csp_reg83w);
-
- qemu_put_buffer (f, s->in2_data, sizeof (s->in2_data));
- qemu_put_buffer (f, s->out_data, sizeof (s->out_data));
- qemu_put_8s (f, &s->test_reg);
- qemu_put_8s (f, &s->last_read_byte);
-
- qemu_put_be32s (f, &s->nzero);
- qemu_put_be32s (f, &s->left_till_irq);
- qemu_put_be32s (f, &s->dma_running);
- qemu_put_be32s (f, &s->bytes_per_second);
- qemu_put_be32s (f, &s->align);
-
- qemu_put_be32s (f, &s->mixer_nreg);
- qemu_put_buffer (f, s->mixer_regs, 256);
-}
-
-static int SB_load (QEMUFile *f, void *opaque, int version_id)
-{
- SB16State *s = opaque;
-
- if (version_id != 1) {
- return -EINVAL;
- }
-
- qemu_get_be32s (f, &s->irq);
- qemu_get_be32s (f, &s->dma);
- qemu_get_be32s (f, &s->hdma);
- qemu_get_be32s (f, &s->port);
- qemu_get_be32s (f, &s->ver);
- qemu_get_be32s (f, &s->in_index);
- qemu_get_be32s (f, &s->out_data_len);
- qemu_get_be32s (f, &s->fmt_stereo);
- qemu_get_be32s (f, &s->fmt_signed);
- qemu_get_be32s (f, &s->fmt_bits);
- qemu_get_be32s (f, &s->fmt);
- qemu_get_be32s (f, &s->dma_auto);
- qemu_get_be32s (f, &s->block_size);
- qemu_get_be32s (f, &s->fifo);
- qemu_get_be32s (f, &s->freq);
- qemu_get_be32s (f, &s->time_const);
- qemu_get_be32s (f, &s->speaker);
- qemu_get_be32s (f, &s->needed_bytes);
- qemu_get_be32s (f, &s->cmd);
- qemu_get_be32s (f, &s->use_hdma);
- qemu_get_be32s (f, &s->highspeed);
- qemu_get_be32s (f, &s->can_write);
- qemu_get_be32s (f, &s->v2x6);
-
- qemu_get_8s (f, &s->csp_param);
- qemu_get_8s (f, &s->csp_value);
- qemu_get_8s (f, &s->csp_mode);
- qemu_get_8s (f, &s->csp_param);
- qemu_get_buffer (f, s->csp_regs, 256);
- qemu_get_8s (f, &s->csp_index);
- qemu_get_buffer (f, s->csp_reg83, 4);
- qemu_get_be32s (f, &s->csp_reg83r);
- qemu_get_be32s (f, &s->csp_reg83w);
-
- qemu_get_buffer (f, s->in2_data, sizeof (s->in2_data));
- qemu_get_buffer (f, s->out_data, sizeof (s->out_data));
- qemu_get_8s (f, &s->test_reg);
- qemu_get_8s (f, &s->last_read_byte);
-
- qemu_get_be32s (f, &s->nzero);
- qemu_get_be32s (f, &s->left_till_irq);
- qemu_get_be32s (f, &s->dma_running);
- qemu_get_be32s (f, &s->bytes_per_second);
- qemu_get_be32s (f, &s->align);
-
- qemu_get_be32s (f, &s->mixer_nreg);
- qemu_get_buffer (f, s->mixer_regs, 256);
-
- if (s->voice) {
- AUD_close_out (&s->card, s->voice);
- s->voice = NULL;
- }
-
- if (s->dma_running) {
- if (s->freq) {
- audsettings_t as;
-
- s->audio_free = 0;
-
- as.freq = s->freq;
- as.nchannels = 1 << s->fmt_stereo;
- as.fmt = s->fmt;
- as.endianness = 0;
-
- s->voice = AUD_open_out (
- &s->card,
- s->voice,
- "sb16",
- s,
- SB_audio_callback,
- &as
- );
- }
-
- control (s, 1);
- speaker (s, s->speaker);
- }
- return 0;
-}
-
-int SB16_init (AudioState *audio)
-{
- SB16State *s;
- int i;
- static const uint8_t dsp_write_ports[] = {0x6, 0xc};
- static const uint8_t dsp_read_ports[] = {0x6, 0xa, 0xc, 0xd, 0xe, 0xf};
-
- if (!audio) {
- dolog ("No audio state\n");
- return -1;
- }
-
- s = qemu_mallocz (sizeof (*s));
- if (!s) {
- dolog ("Could not allocate memory for SB16 (%zu bytes)\n",
- sizeof (*s));
- return -1;
- }
-
- s->cmd = -1;
- s->irq = conf.irq;
- s->dma = conf.dma;
- s->hdma = conf.hdma;
- s->port = conf.port;
- s->ver = conf.ver_lo | (conf.ver_hi << 8);
-
- s->mixer_regs[0x80] = magic_of_irq (s->irq);
- s->mixer_regs[0x81] = (1 << s->dma) | (1 << s->hdma);
- s->mixer_regs[0x82] = 2 << 5;
-
- s->csp_regs[5] = 1;
- s->csp_regs[9] = 0xf8;
-
- reset_mixer (s);
- s->aux_ts = qemu_new_timer (vm_clock, aux_timer, s);
- if (!s->aux_ts) {
- dolog ("warning: Could not create auxiliary timer\n");
- }
-
- for (i = 0; i < LENOFA (dsp_write_ports); i++) {
- register_ioport_write (s->port + dsp_write_ports[i], 1, 1, dsp_write, s);
- }
-
- for (i = 0; i < LENOFA (dsp_read_ports); i++) {
- register_ioport_read (s->port + dsp_read_ports[i], 1, 1, dsp_read, s);
- }
-
- register_ioport_write (s->port + 0x4, 1, 1, mixer_write_indexb, s);
- register_ioport_write (s->port + 0x4, 1, 2, mixer_write_indexw, s);
- register_ioport_read (s->port + 0x5, 1, 1, mixer_read, s);
- register_ioport_write (s->port + 0x5, 1, 1, mixer_write_datab, s);
-
- DMA_register_channel (s->hdma, SB_read_DMA, s);
- DMA_register_channel (s->dma, SB_read_DMA, s);
- s->can_write = 1;
-
- register_savevm ("sb16", 0, 1, SB_save, SB_load, s);
- AUD_register_card (audio, "sb16", &s->card);
- return 0;
-}
diff --git a/hw/sd.h b/hw/sd.h
new file mode 100644
index 0000000..f310062
--- /dev/null
+++ b/hw/sd.h
@@ -0,0 +1,83 @@
+/*
+ * include/linux/mmc/sd.h
+ *
+ * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
+ *
+ * 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.
+ */
+
+#ifndef MMC_SD_H
+#define MMC_SD_H
+
+/* SD commands type argument response */
+ /* class 0 */
+/* This is basically the same command as for MMC with some quirks. */
+#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
+#define SD_SEND_IF_COND 8 /* bcr [11:0] See below R7 */
+
+ /* class 10 */
+#define SD_SWITCH 6 /* adtc [31:0] See below R1 */
+
+ /* Application commands */
+#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
+#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
+#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
+#define SD_APP_SEND_SCR 51 /* adtc R1 */
+
+/*
+ * SD_SWITCH argument format:
+ *
+ * [31] Check (0) or switch (1)
+ * [30:24] Reserved (0)
+ * [23:20] Function group 6
+ * [19:16] Function group 5
+ * [15:12] Function group 4
+ * [11:8] Function group 3
+ * [7:4] Function group 2
+ * [3:0] Function group 1
+ */
+
+/*
+ * SD_SEND_IF_COND argument format:
+ *
+ * [31:12] Reserved (0)
+ * [11:8] Host Voltage Supply Flags
+ * [7:0] Check Pattern (0xAA)
+ */
+
+/*
+ * SCR field definitions
+ */
+
+#define SCR_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.01 */
+#define SCR_SPEC_VER_1 1 /* Implements system specification 1.10 */
+#define SCR_SPEC_VER_2 2 /* Implements system specification 2.00 */
+
+/*
+ * SD bus widths
+ */
+#define SD_BUS_WIDTH_1 0
+#define SD_BUS_WIDTH_4 2
+
+/*
+ * SD_SWITCH mode
+ */
+#define SD_SWITCH_CHECK 0
+#define SD_SWITCH_SET 1
+
+/*
+ * SD_SWITCH function groups
+ */
+#define SD_SWITCH_GRP_ACCESS 0
+
+/*
+ * SD_SWITCH access modes
+ */
+#define SD_SWITCH_ACCESS_DEF 0
+#define SD_SWITCH_ACCESS_HS 1
+
+#endif
+
diff --git a/hw/serial.c b/hw/serial.c
deleted file mode 100644
index f36beb2..0000000
--- a/hw/serial.c
+++ /dev/null
@@ -1,456 +0,0 @@
-/*
- * QEMU 16450 UART emulation
- *
- * Copyright (c) 2003-2004 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"
-
-//#define DEBUG_SERIAL
-
-#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */
-
-#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */
-#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */
-#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */
-#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */
-
-#define UART_IIR_NO_INT 0x01 /* No interrupts pending */
-#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */
-
-#define UART_IIR_MSI 0x00 /* Modem status interrupt */
-#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */
-#define UART_IIR_RDI 0x04 /* Receiver data interrupt */
-#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */
-
-/*
- * These are the definitions for the Modem Control Register
- */
-#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */
-#define UART_MCR_OUT2 0x08 /* Out2 complement */
-#define UART_MCR_OUT1 0x04 /* Out1 complement */
-#define UART_MCR_RTS 0x02 /* RTS complement */
-#define UART_MCR_DTR 0x01 /* DTR complement */
-
-/*
- * These are the definitions for the Modem Status Register
- */
-#define UART_MSR_DCD 0x80 /* Data Carrier Detect */
-#define UART_MSR_RI 0x40 /* Ring Indicator */
-#define UART_MSR_DSR 0x20 /* Data Set Ready */
-#define UART_MSR_CTS 0x10 /* Clear to Send */
-#define UART_MSR_DDCD 0x08 /* Delta DCD */
-#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */
-#define UART_MSR_DDSR 0x02 /* Delta DSR */
-#define UART_MSR_DCTS 0x01 /* Delta CTS */
-#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
-
-#define UART_LSR_TEMT 0x40 /* Transmitter empty */
-#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */
-#define UART_LSR_BI 0x10 /* Break interrupt indicator */
-#define UART_LSR_FE 0x08 /* Frame error indicator */
-#define UART_LSR_PE 0x04 /* Parity error indicator */
-#define UART_LSR_OE 0x02 /* Overrun error indicator */
-#define UART_LSR_DR 0x01 /* Receiver data ready */
-
-struct SerialState {
- uint8_t divider;
- uint8_t rbr; /* receive register */
- uint8_t ier;
- uint8_t iir; /* read only */
- uint8_t lcr;
- uint8_t mcr;
- uint8_t lsr; /* read only */
- uint8_t msr; /* read only */
- uint8_t scr;
- /* 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;
- CharDriverState *chr;
- int last_break_enable;
- target_ulong base;
- int it_shift;
-};
-
-static void serial_update_irq(SerialState *s)
-{
- if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) {
- s->iir = UART_IIR_RDI;
- } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) {
- s->iir = UART_IIR_THRI;
- } else {
- s->iir = UART_IIR_NO_INT;
- }
- if (s->iir != UART_IIR_NO_INT) {
- s->set_irq(s->irq_opaque, s->irq, 1);
- } else {
- s->set_irq(s->irq_opaque, s->irq, 0);
- }
-}
-
-static void serial_update_parameters(SerialState *s)
-{
- int speed, parity, data_bits, stop_bits;
- QEMUSerialSetParams ssp;
-
- if (s->lcr & 0x08) {
- if (s->lcr & 0x10)
- parity = 'E';
- else
- parity = 'O';
- } else {
- parity = 'N';
- }
- if (s->lcr & 0x04)
- stop_bits = 2;
- else
- stop_bits = 1;
- data_bits = (s->lcr & 0x03) + 5;
- if (s->divider == 0)
- return;
- speed = 115200 / s->divider;
- ssp.speed = speed;
- ssp.parity = parity;
- ssp.data_bits = data_bits;
- ssp.stop_bits = stop_bits;
- qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-#if 0
- printf("speed=%d parity=%c data=%d stop=%d\n",
- speed, parity, data_bits, stop_bits);
-#endif
-}
-
-static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- SerialState *s = opaque;
- unsigned char ch;
-
- addr &= 7;
-#ifdef DEBUG_SERIAL
- printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
-#endif
- switch(addr) {
- default:
- case 0:
- if (s->lcr & UART_LCR_DLAB) {
- s->divider = (s->divider & 0xff00) | val;
- serial_update_parameters(s);
- } else {
- s->thr_ipending = 0;
- s->lsr &= ~UART_LSR_THRE;
- serial_update_irq(s);
- ch = val;
- qemu_chr_write(s->chr, &ch, 1);
- s->thr_ipending = 1;
- s->lsr |= UART_LSR_THRE;
- s->lsr |= UART_LSR_TEMT;
- serial_update_irq(s);
- }
- break;
- case 1:
- if (s->lcr & UART_LCR_DLAB) {
- s->divider = (s->divider & 0x00ff) | (val << 8);
- serial_update_parameters(s);
- } else {
- s->ier = val & 0x0f;
- if (s->lsr & UART_LSR_THRE) {
- s->thr_ipending = 1;
- }
- serial_update_irq(s);
- }
- break;
- case 2:
- break;
- case 3:
- {
- int break_enable;
- s->lcr = val;
- serial_update_parameters(s);
- break_enable = (val >> 6) & 1;
- if (break_enable != s->last_break_enable) {
- s->last_break_enable = break_enable;
- qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
- &break_enable);
- }
- }
- break;
- case 4:
- s->mcr = val & 0x1f;
- break;
- case 5:
- break;
- case 6:
- break;
- case 7:
- s->scr = val;
- break;
- }
-}
-
-static uint32_t serial_ioport_read(void *opaque, uint32_t addr)
-{
- SerialState *s = opaque;
- uint32_t ret;
-
- addr &= 7;
- switch(addr) {
- default:
- case 0:
- if (s->lcr & UART_LCR_DLAB) {
- ret = s->divider & 0xff;
- } else {
- ret = s->rbr;
- s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
- serial_update_irq(s);
- }
- break;
- case 1:
- if (s->lcr & UART_LCR_DLAB) {
- ret = (s->divider >> 8) & 0xff;
- } else {
- ret = s->ier;
- }
- break;
- case 2:
- ret = s->iir;
- /* reset THR pending bit */
- if ((ret & 0x7) == UART_IIR_THRI)
- s->thr_ipending = 0;
- serial_update_irq(s);
- break;
- case 3:
- ret = s->lcr;
- break;
- case 4:
- ret = s->mcr;
- break;
- case 5:
- ret = s->lsr;
- break;
- case 6:
- if (s->mcr & UART_MCR_LOOP) {
- /* in loopback, the modem output pins are connected to the
- inputs */
- ret = (s->mcr & 0x0c) << 4;
- ret |= (s->mcr & 0x02) << 3;
- ret |= (s->mcr & 0x01) << 5;
- } else {
- ret = s->msr;
- }
- break;
- case 7:
- ret = s->scr;
- break;
- }
-#ifdef DEBUG_SERIAL
- printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
-#endif
- return ret;
-}
-
-static int serial_can_receive(SerialState *s)
-{
- return !(s->lsr & UART_LSR_DR);
-}
-
-static void serial_receive_byte(SerialState *s, int ch)
-{
- s->rbr = ch;
- s->lsr |= UART_LSR_DR;
- serial_update_irq(s);
-}
-
-static void serial_receive_break(SerialState *s)
-{
- s->rbr = 0;
- s->lsr |= UART_LSR_BI | UART_LSR_DR;
- serial_update_irq(s);
-}
-
-static int serial_can_receive1(void *opaque)
-{
- SerialState *s = opaque;
- return serial_can_receive(s);
-}
-
-static void serial_receive1(void *opaque, const uint8_t *buf, int size)
-{
- SerialState *s = opaque;
- serial_receive_byte(s, buf[0]);
-}
-
-static void serial_event(void *opaque, int event)
-{
- SerialState *s = opaque;
- if (event == CHR_EVENT_BREAK)
- serial_receive_break(s);
-}
-
-static void serial_save(QEMUFile *f, void *opaque)
-{
- SerialState *s = opaque;
-
- qemu_put_8s(f,&s->divider);
- qemu_put_8s(f,&s->rbr);
- qemu_put_8s(f,&s->ier);
- qemu_put_8s(f,&s->iir);
- qemu_put_8s(f,&s->lcr);
- qemu_put_8s(f,&s->mcr);
- qemu_put_8s(f,&s->lsr);
- qemu_put_8s(f,&s->msr);
- qemu_put_8s(f,&s->scr);
-}
-
-static int serial_load(QEMUFile *f, void *opaque, int version_id)
-{
- SerialState *s = opaque;
-
- if(version_id != 1)
- return -EINVAL;
-
- qemu_get_8s(f,&s->divider);
- qemu_get_8s(f,&s->rbr);
- qemu_get_8s(f,&s->ier);
- qemu_get_8s(f,&s->iir);
- qemu_get_8s(f,&s->lcr);
- qemu_get_8s(f,&s->mcr);
- qemu_get_8s(f,&s->lsr);
- qemu_get_8s(f,&s->msr);
- qemu_get_8s(f,&s->scr);
-
- return 0;
-}
-
-/* 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 *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;
- s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
-
- register_savevm("serial", base, 1, serial_save, serial_load, s);
-
- 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);
- return s;
-}
-
-/* Memory mapped interface */
-static 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)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- SerialState *s = opaque;
-
- serial_ioport_write(s, (addr - s->base) >> s->it_shift, value);
-}
-
-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,
-};
-
-SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
- target_ulong base, int it_shift,
- int irq, CharDriverState *chr)
-{
- SerialState *s;
- int s_io_memory;
-
- 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;
- s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
- s->base = base;
- s->it_shift = it_shift;
-
- register_savevm("serial", base, 1, 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);
- s->chr = chr;
- qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
- qemu_chr_add_event_handler(chr, serial_event);
- return s;
-}
diff --git a/hw/sh7750.c b/hw/sh7750.c
deleted file mode 100644
index 21f9bc0..0000000
--- a/hw/sh7750.c
+++ /dev/null
@@ -1,836 +0,0 @@
-/*
- * SH7750 device
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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 <stdio.h>
-#include <assert.h>
-#include "vl.h"
-#include "sh7750_regs.h"
-#include "sh7750_regnames.h"
-
-typedef struct {
- uint8_t data[16];
- uint8_t length; /* Number of characters in the FIFO */
- uint8_t write_idx; /* Index of first character to write */
- uint8_t read_idx; /* Index of first character to read */
-} fifo;
-
-#define NB_DEVICES 4
-
-typedef struct SH7750State {
- /* CPU */
- CPUSH4State *cpu;
- /* Peripheral frequency in Hz */
- uint32_t periph_freq;
- /* SDRAM controller */
- uint16_t rfcr;
- /* First serial port */
- CharDriverState *serial1;
- uint8_t scscr1;
- uint8_t scsmr1;
- uint8_t scbrr1;
- uint8_t scssr1;
- uint8_t scssr1_read;
- uint8_t sctsr1;
- uint8_t sctsr1_loaded;
- uint8_t sctdr1;
- uint8_t scrdr1;
- /* Second serial port */
- CharDriverState *serial2;
- uint16_t sclsr2;
- uint16_t scscr2;
- uint16_t scfcr2;
- uint16_t scfsr2;
- uint16_t scsmr2;
- uint8_t scbrr2;
- fifo serial2_receive_fifo;
- fifo serial2_transmit_fifo;
- /* Timers */
- uint8_t tstr;
- /* Timer 0 */
- QEMUTimer *timer0;
- uint16_t tcr0;
- uint32_t tcor0;
- uint32_t tcnt0;
- /* IO ports */
- uint16_t gpioic;
- uint32_t pctra;
- uint32_t pctrb;
- uint16_t portdira; /* Cached */
- uint16_t portpullupa; /* Cached */
- uint16_t portdirb; /* Cached */
- uint16_t portpullupb; /* Cached */
- uint16_t pdtra;
- uint16_t pdtrb;
- uint16_t periph_pdtra; /* Imposed by the peripherals */
- uint16_t periph_portdira; /* Direction seen from the peripherals */
- uint16_t periph_pdtrb; /* Imposed by the peripherals */
- uint16_t periph_portdirb; /* Direction seen from the peripherals */
- sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */
- /* Cache */
- uint32_t ccr;
-} SH7750State;
-
-/**********************************************************************
- Timers
-**********************************************************************/
-
-/* XXXXX At this time, timer0 works in underflow only mode, that is
- the value of tcnt0 is read at alarm computation time and cannot
- be read back by the guest OS */
-
-static void start_timer0(SH7750State * s)
-{
- uint64_t now, next, prescaler;
-
- if ((s->tcr0 & 6) == 6) {
- fprintf(stderr, "rtc clock for timer 0 not supported\n");
- assert(0);
- }
-
- if ((s->tcr0 & 7) == 5) {
- fprintf(stderr, "timer 0 configuration not supported\n");
- assert(0);
- }
-
- if ((s->tcr0 & 4) == 4)
- prescaler = 1024;
- else
- prescaler = 4 << (s->tcr0 & 3);
-
- now = qemu_get_clock(vm_clock);
- /* XXXXX */
- next =
- now + muldiv64(prescaler * s->tcnt0, ticks_per_sec,
- s->periph_freq);
- if (next == now)
- next = now + 1;
- fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next);
- fprintf(stderr, "timer will underflow in %f seconds\n",
- (float) (next - now) / (float) ticks_per_sec);
-
- qemu_mod_timer(s->timer0, next);
-}
-
-static void timer_start_changed(SH7750State * s)
-{
- if (s->tstr & SH7750_TSTR_STR0) {
- start_timer0(s);
- } else {
- fprintf(stderr, "timer 0 is stopped\n");
- qemu_del_timer(s->timer0);
- }
-}
-
-static void timer0_cb(void *opaque)
-{
- SH7750State *s = opaque;
-
- s->tcnt0 = (uint32_t) 0; /* XXXXX */
- if (--s->tcnt0 == (uint32_t) - 1) {
- fprintf(stderr, "timer 0 underflow\n");
- s->tcnt0 = s->tcor0;
- s->tcr0 |= SH7750_TCR_UNF;
- if (s->tcr0 & SH7750_TCR_UNIE) {
- fprintf(stderr,
- "interrupt generation for timer 0 not supported\n");
- assert(0);
- }
- }
- start_timer0(s);
-}
-
-static void init_timers(SH7750State * s)
-{
- s->tcor0 = 0xffffffff;
- s->tcnt0 = 0xffffffff;
- s->timer0 = qemu_new_timer(vm_clock, &timer0_cb, s);
-}
-
-/**********************************************************************
- First serial port
-**********************************************************************/
-
-static int serial1_can_receive(void *opaque)
-{
- SH7750State *s = opaque;
-
- return s->scscr1 & SH7750_SCSCR_RE;
-}
-
-static void serial1_receive_char(SH7750State * s, uint8_t c)
-{
- if (s->scssr1 & SH7750_SCSSR1_RDRF) {
- s->scssr1 |= SH7750_SCSSR1_ORER;
- return;
- }
-
- s->scrdr1 = c;
- s->scssr1 |= SH7750_SCSSR1_RDRF;
-}
-
-static void serial1_receive(void *opaque, const uint8_t * buf, int size)
-{
- SH7750State *s = opaque;
- int i;
-
- for (i = 0; i < size; i++) {
- serial1_receive_char(s, buf[i]);
- }
-}
-
-static void serial1_event(void *opaque, int event)
-{
- assert(0);
-}
-
-static void serial1_maybe_send(SH7750State * s)
-{
- uint8_t c;
-
- if (s->scssr1 & SH7750_SCSSR1_TDRE)
- return;
- c = s->sctdr1;
- s->scssr1 |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND;
- if (s->scscr1 & SH7750_SCSCR_TIE) {
- fprintf(stderr, "interrupts for serial port 1 not implemented\n");
- assert(0);
- }
- /* XXXXX Check for errors in write */
- qemu_chr_write(s->serial1, &c, 1);
-}
-
-static void serial1_change_scssr1(SH7750State * s, uint8_t mem_value)
-{
- uint8_t new_flags;
-
- /* If transmit disable, TDRE and TEND stays up */
- if ((s->scscr1 & SH7750_SCSCR_TE) == 0) {
- mem_value |= SH7750_SCSSR1_TDRE | SH7750_SCSSR1_TEND;
- }
-
- /* Only clear bits which have been read before and do not set any bit
- in the flags */
- new_flags = s->scssr1 & ~s->scssr1_read; /* Preserve unread flags */
- new_flags &= mem_value | ~s->scssr1_read; /* Clear read flags */
-
- s->scssr1 = (new_flags & 0xf8) | (mem_value & 1);
- s->scssr1_read &= mem_value;
-
- /* If TDRE has been cleared, TEND will also be cleared */
- if ((s->scssr1 & SH7750_SCSSR1_TDRE) == 0) {
- s->scssr1 &= ~SH7750_SCSSR1_TEND;
- }
-
- /* Check for transmission to start */
- serial1_maybe_send(s);
-}
-
-static void serial1_update_parameters(SH7750State * s)
-{
- QEMUSerialSetParams ssp;
-
- if (s->scsmr1 & SH7750_SCSMR_CHR_7)
- ssp.data_bits = 7;
- else
- ssp.data_bits = 8;
- if (s->scsmr1 & SH7750_SCSMR_PE) {
- if (s->scsmr1 & SH7750_SCSMR_PM_ODD)
- ssp.parity = 'O';
- else
- ssp.parity = 'E';
- } else
- ssp.parity = 'N';
- if (s->scsmr1 & SH7750_SCSMR_STOP_2)
- ssp.stop_bits = 2;
- else
- ssp.stop_bits = 1;
- fprintf(stderr, "SCSMR1=%04x SCBRR1=%02x\n", s->scsmr1, s->scbrr1);
- ssp.speed = s->periph_freq /
- (32 * s->scbrr1 * (1 << (2 * (s->scsmr1 & 3)))) - 1;
- fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n",
- ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed);
- qemu_chr_ioctl(s->serial1, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-}
-
-static void scscr1_changed(SH7750State * s)
-{
- if (s->scscr1 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) {
- if (!s->serial1) {
- fprintf(stderr, "serial port 1 not bound to anything\n");
- assert(0);
- }
- serial1_update_parameters(s);
- }
- if ((s->scscr1 & SH7750_SCSCR_RE) == 0) {
- s->scssr1 |= SH7750_SCSSR1_TDRE;
- }
-}
-
-static void init_serial1(SH7750State * s, int serial_nb)
-{
- CharDriverState *chr;
-
- s->scssr1 = 0x84;
- chr = serial_hds[serial_nb];
- if (!chr) {
- fprintf(stderr,
- "no serial port associated to SH7750 first serial port\n");
- return;
- }
-
- s->serial1 = chr;
- qemu_chr_add_read_handler(chr, serial1_can_receive,
- serial1_receive, s);
- qemu_chr_add_event_handler(chr, serial1_event);
-}
-
-/**********************************************************************
- Second serial port
-**********************************************************************/
-
-static int serial2_can_receive(void *opaque)
-{
- SH7750State *s = opaque;
- static uint8_t max_fifo_size[] = { 15, 1, 4, 6, 8, 10, 12, 14 };
-
- return s->serial2_receive_fifo.length <
- max_fifo_size[(s->scfcr2 >> 9) & 7];
-}
-
-static void serial2_adjust_receive_flags(SH7750State * s)
-{
- static uint8_t max_fifo_size[] = { 1, 4, 8, 14 };
-
- /* XXXXX Add interrupt generation */
- if (s->serial2_receive_fifo.length >=
- max_fifo_size[(s->scfcr2 >> 7) & 3]) {
- s->scfsr2 |= SH7750_SCFSR2_RDF;
- s->scfsr2 &= ~SH7750_SCFSR2_DR;
- } else {
- s->scfsr2 &= ~SH7750_SCFSR2_RDF;
- if (s->serial2_receive_fifo.length > 0)
- s->scfsr2 |= SH7750_SCFSR2_DR;
- else
- s->scfsr2 &= ~SH7750_SCFSR2_DR;
- }
-}
-
-static void serial2_append_char(SH7750State * s, uint8_t c)
-{
- if (s->serial2_receive_fifo.length == 16) {
- /* Overflow */
- s->sclsr2 |= SH7750_SCLSR2_ORER;
- return;
- }
-
- s->serial2_receive_fifo.data[s->serial2_receive_fifo.write_idx++] = c;
- s->serial2_receive_fifo.length++;
- serial2_adjust_receive_flags(s);
-}
-
-static void serial2_receive(void *opaque, const uint8_t * buf, int size)
-{
- SH7750State *s = opaque;
- int i;
-
- for (i = 0; i < size; i++)
- serial2_append_char(s, buf[i]);
-}
-
-static void serial2_event(void *opaque, int event)
-{
- /* XXXXX */
- assert(0);
-}
-
-static void serial2_update_parameters(SH7750State * s)
-{
- QEMUSerialSetParams ssp;
-
- if (s->scsmr2 & SH7750_SCSMR_CHR_7)
- ssp.data_bits = 7;
- else
- ssp.data_bits = 8;
- if (s->scsmr2 & SH7750_SCSMR_PE) {
- if (s->scsmr2 & SH7750_SCSMR_PM_ODD)
- ssp.parity = 'O';
- else
- ssp.parity = 'E';
- } else
- ssp.parity = 'N';
- if (s->scsmr2 & SH7750_SCSMR_STOP_2)
- ssp.stop_bits = 2;
- else
- ssp.stop_bits = 1;
- fprintf(stderr, "SCSMR2=%04x SCBRR2=%02x\n", s->scsmr2, s->scbrr2);
- ssp.speed = s->periph_freq /
- (32 * s->scbrr2 * (1 << (2 * (s->scsmr2 & 3)))) - 1;
- fprintf(stderr, "data bits=%d, stop bits=%d, parity=%c, speed=%d\n",
- ssp.data_bits, ssp.stop_bits, ssp.parity, ssp.speed);
- qemu_chr_ioctl(s->serial2, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-}
-
-static void scscr2_changed(SH7750State * s)
-{
- if (s->scscr2 & (SH7750_SCSCR_TE | SH7750_SCSCR_RE)) {
- if (!s->serial2) {
- fprintf(stderr, "serial port 2 not bound to anything\n");
- assert(0);
- }
- serial2_update_parameters(s);
- }
-}
-
-static void init_serial2(SH7750State * s, int serial_nb)
-{
- CharDriverState *chr;
-
- s->scfsr2 = 0x0060;
-
- chr = serial_hds[serial_nb];
- if (!chr) {
- fprintf(stderr,
- "no serial port associated to SH7750 second serial port\n");
- return;
- }
-
- s->serial2 = chr;
- qemu_chr_add_read_handler(chr, serial2_can_receive,
- serial2_receive, s);
- qemu_chr_add_event_handler(chr, serial2_event);
-}
-
-static void init_serial_ports(SH7750State * s)
-{
- init_serial1(s, 0);
- init_serial2(s, 1);
-}
-
-/**********************************************************************
- I/O ports
-**********************************************************************/
-
-int sh7750_register_io_device(SH7750State * s, sh7750_io_device * device)
-{
- int i;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] == NULL) {
- s->devices[i] = device;
- return 0;
- }
- }
- return -1;
-}
-
-static uint16_t portdir(uint32_t v)
-{
-#define EVENPORTMASK(n) ((v & (1<<((n)<<1))) >> (n))
- return
- EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) |
- EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) |
- EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) |
- EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) |
- EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) |
- EVENPORTMASK(0);
-}
-
-static uint16_t portpullup(uint32_t v)
-{
-#define ODDPORTMASK(n) ((v & (1<<(((n)<<1)+1))) >> (n))
- return
- ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) |
- ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) |
- ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) |
- ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) |
- ODDPORTMASK(1) | ODDPORTMASK(0);
-}
-
-static uint16_t porta_lines(SH7750State * s)
-{
- return (s->portdira & s->pdtra) | /* CPU */
- (s->periph_portdira & s->periph_pdtra) | /* Peripherals */
- (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */
-}
-
-static uint16_t portb_lines(SH7750State * s)
-{
- return (s->portdirb & s->pdtrb) | /* CPU */
- (s->periph_portdirb & s->periph_pdtrb) | /* Peripherals */
- (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */
-}
-
-static void gen_port_interrupts(SH7750State * s)
-{
- /* XXXXX interrupts not generated */
-}
-
-static void porta_changed(SH7750State * s, uint16_t prev)
-{
- uint16_t currenta, changes;
- int i, r = 0;
-
-#if 0
- fprintf(stderr, "porta changed from 0x%04x to 0x%04x\n",
- prev, porta_lines(s));
- fprintf(stderr, "pdtra=0x%04x, pctra=0x%08x\n", s->pdtra, s->pctra);
-#endif
- currenta = porta_lines(s);
- if (currenta == prev)
- return;
- changes = currenta ^ prev;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) {
- r |= s->devices[i]->port_change_cb(currenta, portb_lines(s),
- &s->periph_pdtra,
- &s->periph_portdira,
- &s->periph_pdtrb,
- &s->periph_portdirb);
- }
- }
-
- if (r)
- gen_port_interrupts(s);
-}
-
-static void portb_changed(SH7750State * s, uint16_t prev)
-{
- uint16_t currentb, changes;
- int i, r = 0;
-
- currentb = portb_lines(s);
- if (currentb == prev)
- return;
- changes = currentb ^ prev;
-
- for (i = 0; i < NB_DEVICES; i++) {
- if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) {
- r |= s->devices[i]->port_change_cb(portb_lines(s), currentb,
- &s->periph_pdtra,
- &s->periph_portdira,
- &s->periph_pdtrb,
- &s->periph_portdirb);
- }
- }
-
- if (r)
- gen_port_interrupts(s);
-}
-
-/**********************************************************************
- Memory
-**********************************************************************/
-
-static void error_access(const char *kind, target_phys_addr_t addr)
-{
- fprintf(stderr, "%s to %s (0x%08x) not supported\n",
- kind, regname(addr), addr);
-}
-
-static void ignore_access(const char *kind, target_phys_addr_t addr)
-{
- fprintf(stderr, "%s to %s (0x%08x) ignored\n",
- kind, regname(addr), addr);
-}
-
-static uint32_t sh7750_mem_readb(void *opaque, target_phys_addr_t addr)
-{
- SH7750State *s = opaque;
- uint8_t r;
-
- switch (addr) {
- case SH7750_SCSSR1_A7:
- r = s->scssr1;
- s->scssr1_read |= r;
- return s->scssr1;
- case SH7750_SCRDR1_A7:
- s->scssr1 &= ~SH7750_SCSSR1_RDRF;
- return s->scrdr1;
- default:
- error_access("byte read", addr);
- assert(0);
- }
-}
-
-static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr)
-{
- SH7750State *s = opaque;
- uint16_t r;
-
- switch (addr) {
- case SH7750_RFCR_A7:
- fprintf(stderr,
- "Read access to refresh count register, incrementing\n");
- return s->rfcr++;
- case SH7750_TCR0_A7:
- return s->tcr0;
- case SH7750_SCLSR2_A7:
- /* Read and clear overflow bit */
- r = s->sclsr2;
- s->sclsr2 = 0;
- return r;
- case SH7750_SCSFR2_A7:
- return s->scfsr2;
- case SH7750_PDTRA_A7:
- return porta_lines(s);
- case SH7750_PDTRB_A7:
- return portb_lines(s);
- default:
- error_access("word read", addr);
- assert(0);
- }
-}
-
-static uint32_t sh7750_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- SH7750State *s = opaque;
-
- switch (addr) {
- case SH7750_MMUCR_A7:
- return s->cpu->mmucr;
- case SH7750_PTEH_A7:
- return s->cpu->pteh;
- case SH7750_PTEL_A7:
- return s->cpu->ptel;
- case SH7750_TTB_A7:
- return s->cpu->ttb;
- case SH7750_TEA_A7:
- return s->cpu->tea;
- case SH7750_TRA_A7:
- return s->cpu->tra;
- case SH7750_EXPEVT_A7:
- return s->cpu->expevt;
- case SH7750_INTEVT_A7:
- return s->cpu->intevt;
- case SH7750_CCR_A7:
- return s->ccr;
- case 0x1f000030: /* Processor version PVR */
- return 0x00050000; /* SH7750R */
- case 0x1f000040: /* Processor version CVR */
- return 0x00110000; /* Minimum caches */
- case 0x1f000044: /* Processor version PRR */
- return 0x00000100; /* SH7750R */
- default:
- error_access("long read", addr);
- assert(0);
- }
-}
-
-static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr,
- uint32_t mem_value)
-{
- SH7750State *s = opaque;
-
- switch (addr) {
- /* PRECHARGE ? XXXXX */
- case SH7750_PRECHARGE0_A7:
- case SH7750_PRECHARGE1_A7:
- ignore_access("byte write", addr);
- return;
- case SH7750_SCBRR2_A7:
- s->scbrr2 = mem_value;
- return;
- case SH7750_TSTR_A7:
- s->tstr = mem_value;
- timer_start_changed(s);
- return;
- case SH7750_SCSCR1_A7:
- s->scscr1 = mem_value;
- scscr1_changed(s);
- return;
- case SH7750_SCSMR1_A7:
- s->scsmr1 = mem_value;
- return;
- case SH7750_SCBRR1_A7:
- s->scbrr1 = mem_value;
- return;
- case SH7750_SCTDR1_A7:
- s->scssr1 &= ~SH7750_SCSSR1_TEND;
- s->sctdr1 = mem_value;
- return;
- case SH7750_SCSSR1_A7:
- serial1_change_scssr1(s, mem_value);
- return;
- default:
- error_access("byte write", addr);
- assert(0);
- }
-}
-
-static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr,
- uint32_t mem_value)
-{
- SH7750State *s = opaque;
- uint16_t temp;
-
- switch (addr) {
- /* SDRAM controller */
- case SH7750_SCBRR1_A7:
- case SH7750_SCBRR2_A7:
- case SH7750_BCR2_A7:
- case SH7750_BCR3_A7:
- case SH7750_RTCOR_A7:
- case SH7750_RTCNT_A7:
- case SH7750_RTCSR_A7:
- ignore_access("word write", addr);
- return;
- /* IO ports */
- case SH7750_PDTRA_A7:
- temp = porta_lines(s);
- s->pdtra = mem_value;
- porta_changed(s, temp);
- return;
- case SH7750_PDTRB_A7:
- temp = portb_lines(s);
- s->pdtrb = mem_value;
- portb_changed(s, temp);
- return;
- case SH7750_RFCR_A7:
- fprintf(stderr, "Write access to refresh count register\n");
- s->rfcr = mem_value;
- return;
- case SH7750_SCLSR2_A7:
- s->sclsr2 = mem_value;
- return;
- case SH7750_SCSCR2_A7:
- s->scscr2 = mem_value;
- scscr2_changed(s);
- return;
- case SH7750_SCFCR2_A7:
- s->scfcr2 = mem_value;
- return;
- case SH7750_SCSMR2_A7:
- s->scsmr2 = mem_value;
- return;
- case SH7750_TCR0_A7:
- s->tcr0 = mem_value;
- return;
- case SH7750_GPIOIC_A7:
- s->gpioic = mem_value;
- if (mem_value != 0) {
- fprintf(stderr, "I/O interrupts not implemented\n");
- assert(0);
- }
- return;
- default:
- error_access("word write", addr);
- assert(0);
- }
-}
-
-static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr,
- uint32_t mem_value)
-{
- SH7750State *s = opaque;
- uint16_t temp;
-
- switch (addr) {
- /* SDRAM controller */
- case SH7750_BCR1_A7:
- case SH7750_BCR4_A7:
- case SH7750_WCR1_A7:
- case SH7750_WCR2_A7:
- case SH7750_WCR3_A7:
- case SH7750_MCR_A7:
- ignore_access("long write", addr);
- return;
- /* IO ports */
- case SH7750_PCTRA_A7:
- temp = porta_lines(s);
- s->pctra = mem_value;
- s->portdira = portdir(mem_value);
- s->portpullupa = portpullup(mem_value);
- porta_changed(s, temp);
- return;
- case SH7750_PCTRB_A7:
- temp = portb_lines(s);
- s->pctrb = mem_value;
- s->portdirb = portdir(mem_value);
- s->portpullupb = portpullup(mem_value);
- portb_changed(s, temp);
- return;
- case SH7750_TCNT0_A7:
- s->tcnt0 = mem_value & 0xf;
- return;
- case SH7750_MMUCR_A7:
- s->cpu->mmucr = mem_value;
- return;
- case SH7750_PTEH_A7:
- s->cpu->pteh = mem_value;
- return;
- case SH7750_PTEL_A7:
- s->cpu->ptel = mem_value;
- return;
- case SH7750_TTB_A7:
- s->cpu->ttb = mem_value;
- return;
- case SH7750_TEA_A7:
- s->cpu->tea = mem_value;
- return;
- case SH7750_TRA_A7:
- s->cpu->tra = mem_value & 0x000007ff;
- return;
- case SH7750_EXPEVT_A7:
- s->cpu->expevt = mem_value & 0x000007ff;
- return;
- case SH7750_INTEVT_A7:
- s->cpu->intevt = mem_value & 0x000007ff;
- return;
- case SH7750_CCR_A7:
- s->ccr = mem_value;
- return;
- default:
- error_access("long write", addr);
- assert(0);
- }
-}
-
-static CPUReadMemoryFunc *sh7750_mem_read[] = {
- sh7750_mem_readb,
- sh7750_mem_readw,
- sh7750_mem_readl
-};
-
-static CPUWriteMemoryFunc *sh7750_mem_write[] = {
- sh7750_mem_writeb,
- sh7750_mem_writew,
- sh7750_mem_writel
-};
-
-SH7750State *sh7750_init(CPUSH4State * cpu)
-{
- SH7750State *s;
- int sh7750_io_memory;
-
- s = qemu_mallocz(sizeof(SH7750State));
- s->cpu = cpu;
- s->periph_freq = 60000000; /* 60MHz */
- sh7750_io_memory = cpu_register_io_memory(0,
- sh7750_mem_read,
- sh7750_mem_write, s);
- cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory);
- init_timers(s);
- init_serial_ports(s);
- return s;
-}
diff --git a/hw/sh7750_regnames.c b/hw/sh7750_regnames.c
deleted file mode 100644
index 5fcb0d6..0000000
--- a/hw/sh7750_regnames.c
+++ /dev/null
@@ -1,128 +0,0 @@
-#include "vl.h"
-#include "sh7750_regs.h"
-
-#define REGNAME(r) {r, #r},
-
-typedef struct {
- uint32_t regaddr;
- const char *regname;
-} regname_t;
-
-static regname_t regnames[] = {
- REGNAME(SH7750_PTEH_A7)
- REGNAME(SH7750_PTEL_A7)
- REGNAME(SH7750_PTEA_A7)
- REGNAME(SH7750_TTB_A7)
- REGNAME(SH7750_TEA_A7)
- REGNAME(SH7750_MMUCR_A7)
- REGNAME(SH7750_CCR_A7)
- REGNAME(SH7750_QACR0_A7)
- REGNAME(SH7750_QACR1_A7)
- REGNAME(SH7750_TRA_A7)
- REGNAME(SH7750_EXPEVT_A7)
- REGNAME(SH7750_INTEVT_A7)
- REGNAME(SH7750_STBCR_A7)
- REGNAME(SH7750_STBCR2_A7)
- REGNAME(SH7750_FRQCR_A7)
- REGNAME(SH7750_WTCNT_A7)
- REGNAME(SH7750_WTCSR_A7)
- REGNAME(SH7750_R64CNT_A7)
- REGNAME(SH7750_RSECCNT_A7)
- REGNAME(SH7750_RMINCNT_A7)
- REGNAME(SH7750_RHRCNT_A7)
- REGNAME(SH7750_RWKCNT_A7)
- REGNAME(SH7750_RDAYCNT_A7)
- REGNAME(SH7750_RMONCNT_A7)
- REGNAME(SH7750_RYRCNT_A7)
- REGNAME(SH7750_RSECAR_A7)
- REGNAME(SH7750_RMINAR_A7)
- REGNAME(SH7750_RHRAR_A7)
- REGNAME(SH7750_RWKAR_A7)
- REGNAME(SH7750_RDAYAR_A7)
- REGNAME(SH7750_RMONAR_A7)
- REGNAME(SH7750_RCR1_A7)
- REGNAME(SH7750_RCR2_A7)
- REGNAME(SH7750_TOCR_A7)
- REGNAME(SH7750_TSTR_A7)
- REGNAME(SH7750_TCOR0_A7)
- REGNAME(SH7750_TCOR1_A7)
- REGNAME(SH7750_TCOR2_A7)
- REGNAME(SH7750_TCNT0_A7)
- REGNAME(SH7750_TCNT1_A7)
- REGNAME(SH7750_TCNT2_A7)
- REGNAME(SH7750_TCR0_A7)
- REGNAME(SH7750_TCR1_A7)
- REGNAME(SH7750_TCR2_A7)
- REGNAME(SH7750_TCPR2_A7)
- REGNAME(SH7750_BCR1_A7)
- REGNAME(SH7750_BCR2_A7)
- REGNAME(SH7750_WCR1_A7)
- REGNAME(SH7750_WCR2_A7)
- REGNAME(SH7750_WCR3_A7)
- REGNAME(SH7750_MCR_A7)
- REGNAME(SH7750_PCR_A7)
- REGNAME(SH7750_RTCSR_A7)
- REGNAME(SH7750_RTCNT_A7)
- REGNAME(SH7750_RTCOR_A7)
- REGNAME(SH7750_RFCR_A7)
- REGNAME(SH7750_SAR0_A7)
- REGNAME(SH7750_SAR1_A7)
- REGNAME(SH7750_SAR2_A7)
- REGNAME(SH7750_SAR3_A7)
- REGNAME(SH7750_DAR0_A7)
- REGNAME(SH7750_DAR1_A7)
- REGNAME(SH7750_DAR2_A7)
- REGNAME(SH7750_DAR3_A7)
- REGNAME(SH7750_DMATCR0_A7)
- REGNAME(SH7750_DMATCR1_A7)
- REGNAME(SH7750_DMATCR2_A7)
- REGNAME(SH7750_DMATCR3_A7)
- REGNAME(SH7750_CHCR0_A7)
- REGNAME(SH7750_CHCR1_A7)
- REGNAME(SH7750_CHCR2_A7)
- REGNAME(SH7750_CHCR3_A7)
- REGNAME(SH7750_DMAOR_A7)
- REGNAME(SH7750_SCRDR1_A7)
- REGNAME(SH7750_SCRDR2_A7)
- REGNAME(SH7750_SCTDR1_A7)
- REGNAME(SH7750_SCTDR2_A7)
- REGNAME(SH7750_SCSMR1_A7)
- REGNAME(SH7750_SCSMR2_A7)
- REGNAME(SH7750_SCSCR1_A7)
- REGNAME(SH7750_SCSCR2_A7)
- REGNAME(SH7750_SCSSR1_A7)
- REGNAME(SH7750_SCSFR2_A7)
- REGNAME(SH7750_SCSPTR1_A7)
- REGNAME(SH7750_SCSPTR2_A7)
- REGNAME(SH7750_SCBRR1_A7)
- REGNAME(SH7750_SCBRR2_A7)
- REGNAME(SH7750_SCFCR2_A7)
- REGNAME(SH7750_SCFDR2_A7)
- REGNAME(SH7750_SCLSR2_A7)
- REGNAME(SH7750_SCSCMR1_A7)
- REGNAME(SH7750_PCTRA_A7)
- REGNAME(SH7750_PDTRA_A7)
- REGNAME(SH7750_PCTRB_A7)
- REGNAME(SH7750_PDTRB_A7)
- REGNAME(SH7750_GPIOIC_A7)
- REGNAME(SH7750_ICR_A7)
- REGNAME(SH7750_IPRA_A7)
- REGNAME(SH7750_IPRB_A7)
- REGNAME(SH7750_IPRC_A7)
- REGNAME(SH7750_BCR3_A7)
- REGNAME(SH7750_BCR4_A7)
- REGNAME(SH7750_PRECHARGE0_A7)
- REGNAME(SH7750_PRECHARGE1_A7) {(uint32_t) - 1, 0}
-};
-
-const char *regname(uint32_t addr)
-{
- unsigned int i;
-
- for (i = 0; regnames[i].regaddr != (uint32_t) - 1; i++) {
- if (regnames[i].regaddr == addr)
- return regnames[i].regname;
- }
-
- return "<unknown reg>";
-}
diff --git a/hw/sh7750_regnames.h b/hw/sh7750_regnames.h
deleted file mode 100644
index 7463709..0000000
--- a/hw/sh7750_regnames.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SH7750_REGNAMES_H
-#define _SH7750_REGNAMES_H
-
-const char *regname(uint32_t addr);
-
-#endif /* _SH7750_REGNAMES_H */
diff --git a/hw/sh7750_regs.h b/hw/sh7750_regs.h
deleted file mode 100644
index 44ae95b..0000000
--- a/hw/sh7750_regs.h
+++ /dev/null
@@ -1,1623 +0,0 @@
-/*
- * SH-7750 memory-mapped registers
- * This file based on information provided in the following document:
- * "Hitachi SuperH (tm) RISC engine. SH7750 Series (SH7750, SH7750S)
- * Hardware Manual"
- * Document Number ADE-602-124C, Rev. 4.0, 4/21/00, Hitachi Ltd.
- *
- * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
- * Author: Alexandra Kossovsky <sasha@oktet.ru>
- * Victor V. Vengerov <vvv@oktet.ru>
- *
- * The license and distribution terms for this file may be
- * found in the file LICENSE in this distribution or at
- * http://www.rtems.com/license/LICENSE.
- *
- * @(#) sh7750_regs.h,v 1.2.4.1 2003/09/04 18:46:00 joel Exp
- */
-
-#ifndef __SH7750_REGS_H__
-#define __SH7750_REGS_H__
-
-/*
- * All register has 2 addresses: in 0xff000000 - 0xffffffff (P4 address) and
- * in 0x1f000000 - 0x1fffffff (area 7 address)
- */
-#define SH7750_P4_BASE 0xff000000 /* Accessable only in
- priveleged mode */
-#define SH7750_A7_BASE 0x1f000000 /* Accessable only using TLB */
-
-#define SH7750_P4_REG32(ofs) (SH7750_P4_BASE + (ofs))
-#define SH7750_A7_REG32(ofs) (SH7750_A7_BASE + (ofs))
-
-/*
- * MMU Registers
- */
-
-/* Page Table Entry High register - PTEH */
-#define SH7750_PTEH_REGOFS 0x000000 /* offset */
-#define SH7750_PTEH SH7750_P4_REG32(SH7750_PTEH_REGOFS)
-#define SH7750_PTEH_A7 SH7750_A7_REG32(SH7750_PTEH_REGOFS)
-#define SH7750_PTEH_VPN 0xfffffd00 /* Virtual page number */
-#define SH7750_PTEH_VPN_S 10
-#define SH7750_PTEH_ASID 0x000000ff /* Address space identifier */
-#define SH7750_PTEH_ASID_S 0
-
-/* Page Table Entry Low register - PTEL */
-#define SH7750_PTEL_REGOFS 0x000004 /* offset */
-#define SH7750_PTEL SH7750_P4_REG32(SH7750_PTEL_REGOFS)
-#define SH7750_PTEL_A7 SH7750_A7_REG32(SH7750_PTEL_REGOFS)
-#define SH7750_PTEL_PPN 0x1ffffc00 /* Physical page number */
-#define SH7750_PTEL_PPN_S 10
-#define SH7750_PTEL_V 0x00000100 /* Validity (0-entry is invalid) */
-#define SH7750_PTEL_SZ1 0x00000080 /* Page size bit 1 */
-#define SH7750_PTEL_SZ0 0x00000010 /* Page size bit 0 */
-#define SH7750_PTEL_SZ_1KB 0x00000000 /* 1-kbyte page */
-#define SH7750_PTEL_SZ_4KB 0x00000010 /* 4-kbyte page */
-#define SH7750_PTEL_SZ_64KB 0x00000080 /* 64-kbyte page */
-#define SH7750_PTEL_SZ_1MB 0x00000090 /* 1-Mbyte page */
-#define SH7750_PTEL_PR 0x00000060 /* Protection Key Data */
-#define SH7750_PTEL_PR_ROPO 0x00000000 /* read-only in priv mode */
-#define SH7750_PTEL_PR_RWPO 0x00000020 /* read-write in priv mode */
-#define SH7750_PTEL_PR_ROPU 0x00000040 /* read-only in priv or user mode */
-#define SH7750_PTEL_PR_RWPU 0x00000060 /* read-write in priv or user mode */
-#define SH7750_PTEL_C 0x00000008 /* Cacheability
- (0 - page not cacheable) */
-#define SH7750_PTEL_D 0x00000004 /* Dirty bit (1 - write has been
- performed to a page) */
-#define SH7750_PTEL_SH 0x00000002 /* Share Status bit (1 - page are
- shared by processes) */
-#define SH7750_PTEL_WT 0x00000001 /* Write-through bit, specifies the
- cache write mode:
- 0 - Copy-back mode
- 1 - Write-through mode */
-
-/* Page Table Entry Assistance register - PTEA */
-#define SH7750_PTEA_REGOFS 0x000034 /* offset */
-#define SH7750_PTEA SH7750_P4_REG32(SH7750_PTEA_REGOFS)
-#define SH7750_PTEA_A7 SH7750_A7_REG32(SH7750_PTEA_REGOFS)
-#define SH7750_PTEA_TC 0x00000008 /* Timing Control bit
- 0 - use area 5 wait states
- 1 - use area 6 wait states */
-#define SH7750_PTEA_SA 0x00000007 /* Space Attribute bits: */
-#define SH7750_PTEA_SA_UNDEF 0x00000000 /* 0 - undefined */
-#define SH7750_PTEA_SA_IOVAR 0x00000001 /* 1 - variable-size I/O space */
-#define SH7750_PTEA_SA_IO8 0x00000002 /* 2 - 8-bit I/O space */
-#define SH7750_PTEA_SA_IO16 0x00000003 /* 3 - 16-bit I/O space */
-#define SH7750_PTEA_SA_CMEM8 0x00000004 /* 4 - 8-bit common memory space */
-#define SH7750_PTEA_SA_CMEM16 0x00000005 /* 5 - 16-bit common memory space */
-#define SH7750_PTEA_SA_AMEM8 0x00000006 /* 6 - 8-bit attr memory space */
-#define SH7750_PTEA_SA_AMEM16 0x00000007 /* 7 - 16-bit attr memory space */
-
-
-/* Translation table base register */
-#define SH7750_TTB_REGOFS 0x000008 /* offset */
-#define SH7750_TTB SH7750_P4_REG32(SH7750_TTB_REGOFS)
-#define SH7750_TTB_A7 SH7750_A7_REG32(SH7750_TTB_REGOFS)
-
-/* TLB exeption address register - TEA */
-#define SH7750_TEA_REGOFS 0x00000c /* offset */
-#define SH7750_TEA SH7750_P4_REG32(SH7750_TEA_REGOFS)
-#define SH7750_TEA_A7 SH7750_A7_REG32(SH7750_TEA_REGOFS)
-
-/* MMU control register - MMUCR */
-#define SH7750_MMUCR_REGOFS 0x000010 /* offset */
-#define SH7750_MMUCR SH7750_P4_REG32(SH7750_MMUCR_REGOFS)
-#define SH7750_MMUCR_A7 SH7750_A7_REG32(SH7750_MMUCR_REGOFS)
-#define SH7750_MMUCR_AT 0x00000001 /* Address translation bit */
-#define SH7750_MMUCR_TI 0x00000004 /* TLB invalidate */
-#define SH7750_MMUCR_SV 0x00000100 /* Single Virtual Mode bit */
-#define SH7750_MMUCR_SQMD 0x00000200 /* Store Queue Mode bit */
-#define SH7750_MMUCR_URC 0x0000FC00 /* UTLB Replace Counter */
-#define SH7750_MMUCR_URC_S 10
-#define SH7750_MMUCR_URB 0x00FC0000 /* UTLB Replace Boundary */
-#define SH7750_MMUCR_URB_S 18
-#define SH7750_MMUCR_LRUI 0xFC000000 /* Least Recently Used ITLB */
-#define SH7750_MMUCR_LRUI_S 26
-
-
-
-
-/*
- * Cache registers
- * IC -- instructions cache
- * OC -- operand cache
- */
-
-/* Cache Control Register - CCR */
-#define SH7750_CCR_REGOFS 0x00001c /* offset */
-#define SH7750_CCR SH7750_P4_REG32(SH7750_CCR_REGOFS)
-#define SH7750_CCR_A7 SH7750_A7_REG32(SH7750_CCR_REGOFS)
-
-#define SH7750_CCR_IIX 0x00008000 /* IC index enable bit */
-#define SH7750_CCR_ICI 0x00000800 /* IC invalidation bit:
- set it to clear IC */
-#define SH7750_CCR_ICE 0x00000100 /* IC enable bit */
-#define SH7750_CCR_OIX 0x00000080 /* OC index enable bit */
-#define SH7750_CCR_ORA 0x00000020 /* OC RAM enable bit
- if you set OCE = 0,
- you should set ORA = 0 */
-#define SH7750_CCR_OCI 0x00000008 /* OC invalidation bit */
-#define SH7750_CCR_CB 0x00000004 /* Copy-back bit for P1 area */
-#define SH7750_CCR_WT 0x00000002 /* Write-through bit for P0,U0,P3 area */
-#define SH7750_CCR_OCE 0x00000001 /* OC enable bit */
-
-/* Queue address control register 0 - QACR0 */
-#define SH7750_QACR0_REGOFS 0x000038 /* offset */
-#define SH7750_QACR0 SH7750_P4_REG32(SH7750_QACR0_REGOFS)
-#define SH7750_QACR0_A7 SH7750_A7_REG32(SH7750_QACR0_REGOFS)
-
-/* Queue address control register 1 - QACR1 */
-#define SH7750_QACR1_REGOFS 0x00003c /* offset */
-#define SH7750_QACR1 SH7750_P4_REG32(SH7750_QACR1_REGOFS)
-#define SH7750_QACR1_A7 SH7750_A7_REG32(SH7750_QACR1_REGOFS)
-
-
-/*
- * Exeption-related registers
- */
-
-/* Immediate data for TRAPA instuction - TRA */
-#define SH7750_TRA_REGOFS 0x000020 /* offset */
-#define SH7750_TRA SH7750_P4_REG32(SH7750_TRA_REGOFS)
-#define SH7750_TRA_A7 SH7750_A7_REG32(SH7750_TRA_REGOFS)
-
-#define SH7750_TRA_IMM 0x000003fd /* Immediate data operand */
-#define SH7750_TRA_IMM_S 2
-
-/* Exeption event register - EXPEVT */
-#define SH7750_EXPEVT_REGOFS 0x000024
-#define SH7750_EXPEVT SH7750_P4_REG32(SH7750_EXPEVT_REGOFS)
-#define SH7750_EXPEVT_A7 SH7750_A7_REG32(SH7750_EXPEVT_REGOFS)
-
-#define SH7750_EXPEVT_EX 0x00000fff /* Exeption code */
-#define SH7750_EXPEVT_EX_S 0
-
-/* Interrupt event register */
-#define SH7750_INTEVT_REGOFS 0x000028
-#define SH7750_INTEVT SH7750_P4_REG32(SH7750_INTEVT_REGOFS)
-#define SH7750_INTEVT_A7 SH7750_A7_REG32(SH7750_INTEVT_REGOFS)
-#define SH7750_INTEVT_EX 0x00000fff /* Exeption code */
-#define SH7750_INTEVT_EX_S 0
-
-/*
- * Exception/interrupt codes
- */
-#define SH7750_EVT_TO_NUM(evt) ((evt) >> 5)
-
-/* Reset exception category */
-#define SH7750_EVT_POWER_ON_RST 0x000 /* Power-on reset */
-#define SH7750_EVT_MANUAL_RST 0x020 /* Manual reset */
-#define SH7750_EVT_TLB_MULT_HIT 0x140 /* TLB multiple-hit exception */
-
-/* General exception category */
-#define SH7750_EVT_USER_BREAK 0x1E0 /* User break */
-#define SH7750_EVT_IADDR_ERR 0x0E0 /* Instruction address error */
-#define SH7750_EVT_TLB_READ_MISS 0x040 /* ITLB miss exception /
- DTLB miss exception (read) */
-#define SH7750_EVT_TLB_READ_PROTV 0x0A0 /* ITLB protection violation /
- DTLB protection violation (read) */
-#define SH7750_EVT_ILLEGAL_INSTR 0x180 /* General Illegal Instruction
- exception */
-#define SH7750_EVT_SLOT_ILLEGAL_INSTR 0x1A0 /* Slot Illegal Instruction
- exception */
-#define SH7750_EVT_FPU_DISABLE 0x800 /* General FPU disable exception */
-#define SH7750_EVT_SLOT_FPU_DISABLE 0x820 /* Slot FPU disable exception */
-#define SH7750_EVT_DATA_READ_ERR 0x0E0 /* Data address error (read) */
-#define SH7750_EVT_DATA_WRITE_ERR 0x100 /* Data address error (write) */
-#define SH7750_EVT_DTLB_WRITE_MISS 0x060 /* DTLB miss exception (write) */
-#define SH7750_EVT_DTLB_WRITE_PROTV 0x0C0 /* DTLB protection violation
- exception (write) */
-#define SH7750_EVT_FPU_EXCEPTION 0x120 /* FPU exception */
-#define SH7750_EVT_INITIAL_PGWRITE 0x080 /* Initial Page Write exception */
-#define SH7750_EVT_TRAPA 0x160 /* Unconditional trap (TRAPA) */
-
-/* Interrupt exception category */
-#define SH7750_EVT_NMI 0x1C0 /* Non-maskable interrupt */
-#define SH7750_EVT_IRQ0 0x200 /* External Interrupt 0 */
-#define SH7750_EVT_IRQ1 0x220 /* External Interrupt 1 */
-#define SH7750_EVT_IRQ2 0x240 /* External Interrupt 2 */
-#define SH7750_EVT_IRQ3 0x260 /* External Interrupt 3 */
-#define SH7750_EVT_IRQ4 0x280 /* External Interrupt 4 */
-#define SH7750_EVT_IRQ5 0x2A0 /* External Interrupt 5 */
-#define SH7750_EVT_IRQ6 0x2C0 /* External Interrupt 6 */
-#define SH7750_EVT_IRQ7 0x2E0 /* External Interrupt 7 */
-#define SH7750_EVT_IRQ8 0x300 /* External Interrupt 8 */
-#define SH7750_EVT_IRQ9 0x320 /* External Interrupt 9 */
-#define SH7750_EVT_IRQA 0x340 /* External Interrupt A */
-#define SH7750_EVT_IRQB 0x360 /* External Interrupt B */
-#define SH7750_EVT_IRQC 0x380 /* External Interrupt C */
-#define SH7750_EVT_IRQD 0x3A0 /* External Interrupt D */
-#define SH7750_EVT_IRQE 0x3C0 /* External Interrupt E */
-
-/* Peripheral Module Interrupts - Timer Unit (TMU) */
-#define SH7750_EVT_TUNI0 0x400 /* TMU Underflow Interrupt 0 */
-#define SH7750_EVT_TUNI1 0x420 /* TMU Underflow Interrupt 1 */
-#define SH7750_EVT_TUNI2 0x440 /* TMU Underflow Interrupt 2 */
-#define SH7750_EVT_TICPI2 0x460 /* TMU Input Capture Interrupt 2 */
-
-/* Peripheral Module Interrupts - Real-Time Clock (RTC) */
-#define SH7750_EVT_RTC_ATI 0x480 /* Alarm Interrupt Request */
-#define SH7750_EVT_RTC_PRI 0x4A0 /* Periodic Interrupt Request */
-#define SH7750_EVT_RTC_CUI 0x4C0 /* Carry Interrupt Request */
-
-/* Peripheral Module Interrupts - Serial Communication Interface (SCI) */
-#define SH7750_EVT_SCI_ERI 0x4E0 /* Receive Error */
-#define SH7750_EVT_SCI_RXI 0x500 /* Receive Data Register Full */
-#define SH7750_EVT_SCI_TXI 0x520 /* Transmit Data Register Empty */
-#define SH7750_EVT_SCI_TEI 0x540 /* Transmit End */
-
-/* Peripheral Module Interrupts - Watchdog Timer (WDT) */
-#define SH7750_EVT_WDT_ITI 0x560 /* Interval Timer Interrupt
- (used when WDT operates in
- interval timer mode) */
-
-/* Peripheral Module Interrupts - Memory Refresh Unit (REF) */
-#define SH7750_EVT_REF_RCMI 0x580 /* Compare-match Interrupt */
-#define SH7750_EVT_REF_ROVI 0x5A0 /* Refresh Counter Overflow
- interrupt */
-
-/* Peripheral Module Interrupts - Hitachi User Debug Interface (H-UDI) */
-#define SH7750_EVT_HUDI 0x600 /* UDI interrupt */
-
-/* Peripheral Module Interrupts - General-Purpose I/O (GPIO) */
-#define SH7750_EVT_GPIO 0x620 /* GPIO Interrupt */
-
-/* Peripheral Module Interrupts - DMA Controller (DMAC) */
-#define SH7750_EVT_DMAC_DMTE0 0x640 /* DMAC 0 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMTE1 0x660 /* DMAC 1 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMTE2 0x680 /* DMAC 2 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMTE3 0x6A0 /* DMAC 3 Transfer End Interrupt */
-#define SH7750_EVT_DMAC_DMAE 0x6C0 /* DMAC Address Error Interrupt */
-
-/* Peripheral Module Interrupts - Serial Communication Interface with FIFO */
-/* (SCIF) */
-#define SH7750_EVT_SCIF_ERI 0x700 /* Receive Error */
-#define SH7750_EVT_SCIF_RXI 0x720 /* Receive FIFO Data Full or
- Receive Data ready interrupt */
-#define SH7750_EVT_SCIF_BRI 0x740 /* Break or overrun error */
-#define SH7750_EVT_SCIF_TXI 0x760 /* Transmit FIFO Data Empty */
-
-/*
- * Power Management
- */
-#define SH7750_STBCR_REGOFS 0xC00004 /* offset */
-#define SH7750_STBCR SH7750_P4_REG32(SH7750_STBCR_REGOFS)
-#define SH7750_STBCR_A7 SH7750_A7_REG32(SH7750_STBCR_REGOFS)
-
-#define SH7750_STBCR_STBY 0x80 /* Specifies a transition to standby mode:
- 0 - Transition to SLEEP mode on SLEEP
- 1 - Transition to STANDBY mode on SLEEP */
-#define SH7750_STBCR_PHZ 0x40 /* State of peripheral module pins in
- standby mode:
- 0 - normal state
- 1 - high-impendance state */
-
-#define SH7750_STBCR_PPU 0x20 /* Peripheral module pins pull-up controls */
-#define SH7750_STBCR_MSTP4 0x10 /* Stopping the clock supply to DMAC */
-#define SH7750_STBCR_DMAC_STP SH7750_STBCR_MSTP4
-#define SH7750_STBCR_MSTP3 0x08 /* Stopping the clock supply to SCIF */
-#define SH7750_STBCR_SCIF_STP SH7750_STBCR_MSTP3
-#define SH7750_STBCR_MSTP2 0x04 /* Stopping the clock supply to TMU */
-#define SH7750_STBCR_TMU_STP SH7750_STBCR_MSTP2
-#define SH7750_STBCR_MSTP1 0x02 /* Stopping the clock supply to RTC */
-#define SH7750_STBCR_RTC_STP SH7750_STBCR_MSTP1
-#define SH7750_STBCR_MSPT0 0x01 /* Stopping the clock supply to SCI */
-#define SH7750_STBCR_SCI_STP SH7750_STBCR_MSTP0
-
-#define SH7750_STBCR_STBY 0x80
-
-
-#define SH7750_STBCR2_REGOFS 0xC00010 /* offset */
-#define SH7750_STBCR2 SH7750_P4_REG32(SH7750_STBCR2_REGOFS)
-#define SH7750_STBCR2_A7 SH7750_A7_REG32(SH7750_STBCR2_REGOFS)
-
-#define SH7750_STBCR2_DSLP 0x80 /* Specifies transition to deep sleep mode:
- 0 - transition to sleep or standby mode
- as it is specified in STBY bit
- 1 - transition to deep sleep mode on
- execution of SLEEP instruction */
-#define SH7750_STBCR2_MSTP6 0x02 /* Stopping the clock supply to Store Queue
- in the cache controller */
-#define SH7750_STBCR2_SQ_STP SH7750_STBCR2_MSTP6
-#define SH7750_STBCR2_MSTP5 0x01 /* Stopping the clock supply to the User
- Break Controller (UBC) */
-#define SH7750_STBCR2_UBC_STP SH7750_STBCR2_MSTP5
-
-/*
- * Clock Pulse Generator (CPG)
- */
-#define SH7750_FRQCR_REGOFS 0xC00000 /* offset */
-#define SH7750_FRQCR SH7750_P4_REG32(SH7750_FRQCR_REGOFS)
-#define SH7750_FRQCR_A7 SH7750_A7_REG32(SH7750_FRQCR_REGOFS)
-
-#define SH7750_FRQCR_CKOEN 0x0800 /* Clock Output Enable
- 0 - CKIO pin goes to HiZ/pullup
- 1 - Clock is output from CKIO */
-#define SH7750_FRQCR_PLL1EN 0x0400 /* PLL circuit 1 enable */
-#define SH7750_FRQCR_PLL2EN 0x0200 /* PLL circuit 2 enable */
-
-#define SH7750_FRQCR_IFC 0x01C0 /* CPU clock frequency division ratio: */
-#define SH7750_FRQCR_IFCDIV1 0x0000 /* 0 - * 1 */
-#define SH7750_FRQCR_IFCDIV2 0x0040 /* 1 - * 1/2 */
-#define SH7750_FRQCR_IFCDIV3 0x0080 /* 2 - * 1/3 */
-#define SH7750_FRQCR_IFCDIV4 0x00C0 /* 3 - * 1/4 */
-#define SH7750_FRQCR_IFCDIV6 0x0100 /* 4 - * 1/6 */
-#define SH7750_FRQCR_IFCDIV8 0x0140 /* 5 - * 1/8 */
-
-#define SH7750_FRQCR_BFC 0x0038 /* Bus clock frequency division ratio: */
-#define SH7750_FRQCR_BFCDIV1 0x0000 /* 0 - * 1 */
-#define SH7750_FRQCR_BFCDIV2 0x0008 /* 1 - * 1/2 */
-#define SH7750_FRQCR_BFCDIV3 0x0010 /* 2 - * 1/3 */
-#define SH7750_FRQCR_BFCDIV4 0x0018 /* 3 - * 1/4 */
-#define SH7750_FRQCR_BFCDIV6 0x0020 /* 4 - * 1/6 */
-#define SH7750_FRQCR_BFCDIV8 0x0028 /* 5 - * 1/8 */
-
-#define SH7750_FRQCR_PFC 0x0007 /* Peripheral module clock frequency
- division ratio: */
-#define SH7750_FRQCR_PFCDIV2 0x0000 /* 0 - * 1/2 */
-#define SH7750_FRQCR_PFCDIV3 0x0001 /* 1 - * 1/3 */
-#define SH7750_FRQCR_PFCDIV4 0x0002 /* 2 - * 1/4 */
-#define SH7750_FRQCR_PFCDIV6 0x0003 /* 3 - * 1/6 */
-#define SH7750_FRQCR_PFCDIV8 0x0004 /* 4 - * 1/8 */
-
-/*
- * Watchdog Timer (WDT)
- */
-
-/* Watchdog Timer Counter register - WTCNT */
-#define SH7750_WTCNT_REGOFS 0xC00008 /* offset */
-#define SH7750_WTCNT SH7750_P4_REG32(SH7750_WTCNT_REGOFS)
-#define SH7750_WTCNT_A7 SH7750_A7_REG32(SH7750_WTCNT_REGOFS)
-#define SH7750_WTCNT_KEY 0x5A00 /* When WTCNT byte register written,
- you have to set the upper byte to
- 0x5A */
-
-/* Watchdog Timer Control/Status register - WTCSR */
-#define SH7750_WTCSR_REGOFS 0xC0000C /* offset */
-#define SH7750_WTCSR SH7750_P4_REG32(SH7750_WTCSR_REGOFS)
-#define SH7750_WTCSR_A7 SH7750_A7_REG32(SH7750_WTCSR_REGOFS)
-#define SH7750_WTCSR_KEY 0xA500 /* When WTCSR byte register written,
- you have to set the upper byte to
- 0xA5 */
-#define SH7750_WTCSR_TME 0x80 /* Timer enable (1-upcount start) */
-#define SH7750_WTCSR_MODE 0x40 /* Timer Mode Select: */
-#define SH7750_WTCSR_MODE_WT 0x40 /* Watchdog Timer Mode */
-#define SH7750_WTCSR_MODE_IT 0x00 /* Interval Timer Mode */
-#define SH7750_WTCSR_RSTS 0x20 /* Reset Select: */
-#define SH7750_WTCSR_RST_MAN 0x20 /* Manual Reset */
-#define SH7750_WTCSR_RST_PWR 0x00 /* Power-on Reset */
-#define SH7750_WTCSR_WOVF 0x10 /* Watchdog Timer Overflow Flag */
-#define SH7750_WTCSR_IOVF 0x08 /* Interval Timer Overflow Flag */
-#define SH7750_WTCSR_CKS 0x07 /* Clock Select: */
-#define SH7750_WTCSR_CKS_DIV32 0x00 /* 1/32 of frequency divider 2 input */
-#define SH7750_WTCSR_CKS_DIV64 0x01 /* 1/64 */
-#define SH7750_WTCSR_CKS_DIV128 0x02 /* 1/128 */
-#define SH7750_WTCSR_CKS_DIV256 0x03 /* 1/256 */
-#define SH7750_WTCSR_CKS_DIV512 0x04 /* 1/512 */
-#define SH7750_WTCSR_CKS_DIV1024 0x05 /* 1/1024 */
-#define SH7750_WTCSR_CKS_DIV2048 0x06 /* 1/2048 */
-#define SH7750_WTCSR_CKS_DIV4096 0x07 /* 1/4096 */
-
-/*
- * Real-Time Clock (RTC)
- */
-/* 64-Hz Counter Register (byte, read-only) - R64CNT */
-#define SH7750_R64CNT_REGOFS 0xC80000 /* offset */
-#define SH7750_R64CNT SH7750_P4_REG32(SH7750_R64CNT_REGOFS)
-#define SH7750_R64CNT_A7 SH7750_A7_REG32(SH7750_R64CNT_REGOFS)
-
-/* Second Counter Register (byte, BCD-coded) - RSECCNT */
-#define SH7750_RSECCNT_REGOFS 0xC80004 /* offset */
-#define SH7750_RSECCNT SH7750_P4_REG32(SH7750_RSECCNT_REGOFS)
-#define SH7750_RSECCNT_A7 SH7750_A7_REG32(SH7750_RSECCNT_REGOFS)
-
-/* Minute Counter Register (byte, BCD-coded) - RMINCNT */
-#define SH7750_RMINCNT_REGOFS 0xC80008 /* offset */
-#define SH7750_RMINCNT SH7750_P4_REG32(SH7750_RMINCNT_REGOFS)
-#define SH7750_RMINCNT_A7 SH7750_A7_REG32(SH7750_RMINCNT_REGOFS)
-
-/* Hour Counter Register (byte, BCD-coded) - RHRCNT */
-#define SH7750_RHRCNT_REGOFS 0xC8000C /* offset */
-#define SH7750_RHRCNT SH7750_P4_REG32(SH7750_RHRCNT_REGOFS)
-#define SH7750_RHRCNT_A7 SH7750_A7_REG32(SH7750_RHRCNT_REGOFS)
-
-/* Day-of-Week Counter Register (byte) - RWKCNT */
-#define SH7750_RWKCNT_REGOFS 0xC80010 /* offset */
-#define SH7750_RWKCNT SH7750_P4_REG32(SH7750_RWKCNT_REGOFS)
-#define SH7750_RWKCNT_A7 SH7750_A7_REG32(SH7750_RWKCNT_REGOFS)
-
-#define SH7750_RWKCNT_SUN 0 /* Sunday */
-#define SH7750_RWKCNT_MON 1 /* Monday */
-#define SH7750_RWKCNT_TUE 2 /* Tuesday */
-#define SH7750_RWKCNT_WED 3 /* Wednesday */
-#define SH7750_RWKCNT_THU 4 /* Thursday */
-#define SH7750_RWKCNT_FRI 5 /* Friday */
-#define SH7750_RWKCNT_SAT 6 /* Saturday */
-
-/* Day Counter Register (byte, BCD-coded) - RDAYCNT */
-#define SH7750_RDAYCNT_REGOFS 0xC80014 /* offset */
-#define SH7750_RDAYCNT SH7750_P4_REG32(SH7750_RDAYCNT_REGOFS)
-#define SH7750_RDAYCNT_A7 SH7750_A7_REG32(SH7750_RDAYCNT_REGOFS)
-
-/* Month Counter Register (byte, BCD-coded) - RMONCNT */
-#define SH7750_RMONCNT_REGOFS 0xC80018 /* offset */
-#define SH7750_RMONCNT SH7750_P4_REG32(SH7750_RMONCNT_REGOFS)
-#define SH7750_RMONCNT_A7 SH7750_A7_REG32(SH7750_RMONCNT_REGOFS)
-
-/* Year Counter Register (half, BCD-coded) - RYRCNT */
-#define SH7750_RYRCNT_REGOFS 0xC8001C /* offset */
-#define SH7750_RYRCNT SH7750_P4_REG32(SH7750_RYRCNT_REGOFS)
-#define SH7750_RYRCNT_A7 SH7750_A7_REG32(SH7750_RYRCNT_REGOFS)
-
-/* Second Alarm Register (byte, BCD-coded) - RSECAR */
-#define SH7750_RSECAR_REGOFS 0xC80020 /* offset */
-#define SH7750_RSECAR SH7750_P4_REG32(SH7750_RSECAR_REGOFS)
-#define SH7750_RSECAR_A7 SH7750_A7_REG32(SH7750_RSECAR_REGOFS)
-#define SH7750_RSECAR_ENB 0x80 /* Second Alarm Enable */
-
-/* Minute Alarm Register (byte, BCD-coded) - RMINAR */
-#define SH7750_RMINAR_REGOFS 0xC80024 /* offset */
-#define SH7750_RMINAR SH7750_P4_REG32(SH7750_RMINAR_REGOFS)
-#define SH7750_RMINAR_A7 SH7750_A7_REG32(SH7750_RMINAR_REGOFS)
-#define SH7750_RMINAR_ENB 0x80 /* Minute Alarm Enable */
-
-/* Hour Alarm Register (byte, BCD-coded) - RHRAR */
-#define SH7750_RHRAR_REGOFS 0xC80028 /* offset */
-#define SH7750_RHRAR SH7750_P4_REG32(SH7750_RHRAR_REGOFS)
-#define SH7750_RHRAR_A7 SH7750_A7_REG32(SH7750_RHRAR_REGOFS)
-#define SH7750_RHRAR_ENB 0x80 /* Hour Alarm Enable */
-
-/* Day-of-Week Alarm Register (byte) - RWKAR */
-#define SH7750_RWKAR_REGOFS 0xC8002C /* offset */
-#define SH7750_RWKAR SH7750_P4_REG32(SH7750_RWKAR_REGOFS)
-#define SH7750_RWKAR_A7 SH7750_A7_REG32(SH7750_RWKAR_REGOFS)
-#define SH7750_RWKAR_ENB 0x80 /* Day-of-week Alarm Enable */
-
-#define SH7750_RWKAR_SUN 0 /* Sunday */
-#define SH7750_RWKAR_MON 1 /* Monday */
-#define SH7750_RWKAR_TUE 2 /* Tuesday */
-#define SH7750_RWKAR_WED 3 /* Wednesday */
-#define SH7750_RWKAR_THU 4 /* Thursday */
-#define SH7750_RWKAR_FRI 5 /* Friday */
-#define SH7750_RWKAR_SAT 6 /* Saturday */
-
-/* Day Alarm Register (byte, BCD-coded) - RDAYAR */
-#define SH7750_RDAYAR_REGOFS 0xC80030 /* offset */
-#define SH7750_RDAYAR SH7750_P4_REG32(SH7750_RDAYAR_REGOFS)
-#define SH7750_RDAYAR_A7 SH7750_A7_REG32(SH7750_RDAYAR_REGOFS)
-#define SH7750_RDAYAR_ENB 0x80 /* Day Alarm Enable */
-
-/* Month Counter Register (byte, BCD-coded) - RMONAR */
-#define SH7750_RMONAR_REGOFS 0xC80034 /* offset */
-#define SH7750_RMONAR SH7750_P4_REG32(SH7750_RMONAR_REGOFS)
-#define SH7750_RMONAR_A7 SH7750_A7_REG32(SH7750_RMONAR_REGOFS)
-#define SH7750_RMONAR_ENB 0x80 /* Month Alarm Enable */
-
-/* RTC Control Register 1 (byte) - RCR1 */
-#define SH7750_RCR1_REGOFS 0xC80038 /* offset */
-#define SH7750_RCR1 SH7750_P4_REG32(SH7750_RCR1_REGOFS)
-#define SH7750_RCR1_A7 SH7750_A7_REG32(SH7750_RCR1_REGOFS)
-#define SH7750_RCR1_CF 0x80 /* Carry Flag */
-#define SH7750_RCR1_CIE 0x10 /* Carry Interrupt Enable */
-#define SH7750_RCR1_AIE 0x08 /* Alarm Interrupt Enable */
-#define SH7750_RCR1_AF 0x01 /* Alarm Flag */
-
-/* RTC Control Register 2 (byte) - RCR2 */
-#define SH7750_RCR2_REGOFS 0xC8003C /* offset */
-#define SH7750_RCR2 SH7750_P4_REG32(SH7750_RCR2_REGOFS)
-#define SH7750_RCR2_A7 SH7750_A7_REG32(SH7750_RCR2_REGOFS)
-#define SH7750_RCR2_PEF 0x80 /* Periodic Interrupt Flag */
-#define SH7750_RCR2_PES 0x70 /* Periodic Interrupt Enable: */
-#define SH7750_RCR2_PES_DIS 0x00 /* Periodic Interrupt Disabled */
-#define SH7750_RCR2_PES_DIV256 0x10 /* Generated at 1/256 sec interval */
-#define SH7750_RCR2_PES_DIV64 0x20 /* Generated at 1/64 sec interval */
-#define SH7750_RCR2_PES_DIV16 0x30 /* Generated at 1/16 sec interval */
-#define SH7750_RCR2_PES_DIV4 0x40 /* Generated at 1/4 sec interval */
-#define SH7750_RCR2_PES_DIV2 0x50 /* Generated at 1/2 sec interval */
-#define SH7750_RCR2_PES_x1 0x60 /* Generated at 1 sec interval */
-#define SH7750_RCR2_PES_x2 0x70 /* Generated at 2 sec interval */
-#define SH7750_RCR2_RTCEN 0x08 /* RTC Crystal Oscillator is Operated */
-#define SH7750_RCR2_ADJ 0x04 /* 30-Second Adjastment */
-#define SH7750_RCR2_RESET 0x02 /* Frequency divider circuits are reset */
-#define SH7750_RCR2_START 0x01 /* 0 - sec, min, hr, day-of-week, month,
- year counters are stopped
- 1 - sec, min, hr, day-of-week, month,
- year counters operate normally */
-
-
-/*
- * Timer Unit (TMU)
- */
-/* Timer Output Control Register (byte) - TOCR */
-#define SH7750_TOCR_REGOFS 0xD80000 /* offset */
-#define SH7750_TOCR SH7750_P4_REG32(SH7750_TOCR_REGOFS)
-#define SH7750_TOCR_A7 SH7750_A7_REG32(SH7750_TOCR_REGOFS)
-#define SH7750_TOCR_TCOE 0x01 /* Timer Clock Pin Control:
- 0 - TCLK is used as external clock
- input or input capture control
- 1 - TCLK is used as on-chip RTC
- output clock pin */
-
-/* Timer Start Register (byte) - TSTR */
-#define SH7750_TSTR_REGOFS 0xD80004 /* offset */
-#define SH7750_TSTR SH7750_P4_REG32(SH7750_TSTR_REGOFS)
-#define SH7750_TSTR_A7 SH7750_A7_REG32(SH7750_TSTR_REGOFS)
-#define SH7750_TSTR_STR2 0x04 /* TCNT2 performs count operations */
-#define SH7750_TSTR_STR1 0x02 /* TCNT1 performs count operations */
-#define SH7750_TSTR_STR0 0x01 /* TCNT0 performs count operations */
-#define SH7750_TSTR_STR(n) (1 << (n))
-
-/* Timer Constant Register - TCOR0, TCOR1, TCOR2 */
-#define SH7750_TCOR_REGOFS(n) (0xD80008 + ((n)*12)) /* offset */
-#define SH7750_TCOR(n) SH7750_P4_REG32(SH7750_TCOR_REGOFS(n))
-#define SH7750_TCOR_A7(n) SH7750_A7_REG32(SH7750_TCOR_REGOFS(n))
-#define SH7750_TCOR0 SH7750_TCOR(0)
-#define SH7750_TCOR1 SH7750_TCOR(1)
-#define SH7750_TCOR2 SH7750_TCOR(2)
-#define SH7750_TCOR0_A7 SH7750_TCOR_A7(0)
-#define SH7750_TCOR1_A7 SH7750_TCOR_A7(1)
-#define SH7750_TCOR2_A7 SH7750_TCOR_A7(2)
-
-/* Timer Counter Register - TCNT0, TCNT1, TCNT2 */
-#define SH7750_TCNT_REGOFS(n) (0xD8000C + ((n)*12)) /* offset */
-#define SH7750_TCNT(n) SH7750_P4_REG32(SH7750_TCNT_REGOFS(n))
-#define SH7750_TCNT_A7(n) SH7750_A7_REG32(SH7750_TCNT_REGOFS(n))
-#define SH7750_TCNT0 SH7750_TCNT(0)
-#define SH7750_TCNT1 SH7750_TCNT(1)
-#define SH7750_TCNT2 SH7750_TCNT(2)
-#define SH7750_TCNT0_A7 SH7750_TCNT_A7(0)
-#define SH7750_TCNT1_A7 SH7750_TCNT_A7(1)
-#define SH7750_TCNT2_A7 SH7750_TCNT_A7(2)
-
-/* Timer Control Register (half) - TCR0, TCR1, TCR2 */
-#define SH7750_TCR_REGOFS(n) (0xD80010 + ((n)*12)) /* offset */
-#define SH7750_TCR(n) SH7750_P4_REG32(SH7750_TCR_REGOFS(n))
-#define SH7750_TCR_A7(n) SH7750_A7_REG32(SH7750_TCR_REGOFS(n))
-#define SH7750_TCR0 SH7750_TCR(0)
-#define SH7750_TCR1 SH7750_TCR(1)
-#define SH7750_TCR2 SH7750_TCR(2)
-#define SH7750_TCR0_A7 SH7750_TCR_A7(0)
-#define SH7750_TCR1_A7 SH7750_TCR_A7(1)
-#define SH7750_TCR2_A7 SH7750_TCR_A7(2)
-
-#define SH7750_TCR2_ICPF 0x200 /* Input Capture Interrupt Flag
- (1 - input capture has occured) */
-#define SH7750_TCR_UNF 0x100 /* Underflow flag */
-#define SH7750_TCR2_ICPE 0x0C0 /* Input Capture Control: */
-#define SH7750_TCR2_ICPE_DIS 0x000 /* Input Capture function is not used */
-#define SH7750_TCR2_ICPE_NOINT 0x080 /* Input Capture function is used, but
- input capture interrupt is not
- enabled */
-#define SH7750_TCR2_ICPE_INT 0x0C0 /* Input Capture function is used,
- input capture interrupt enabled */
-#define SH7750_TCR_UNIE 0x020 /* Underflow Interrupt Control
- (1 - underflow interrupt enabled) */
-#define SH7750_TCR_CKEG 0x018 /* Clock Edge selection: */
-#define SH7750_TCR_CKEG_RAISE 0x000 /* Count/capture on rising edge */
-#define SH7750_TCR_CKEG_FALL 0x008 /* Count/capture on falling edge */
-#define SH7750_TCR_CKEG_BOTH 0x018 /* Count/capture on both rising and
- falling edges */
-#define SH7750_TCR_TPSC 0x007 /* Timer prescaler */
-#define SH7750_TCR_TPSC_DIV4 0x000 /* Counts on peripheral clock/4 */
-#define SH7750_TCR_TPSC_DIV16 0x001 /* Counts on peripheral clock/16 */
-#define SH7750_TCR_TPSC_DIV64 0x002 /* Counts on peripheral clock/64 */
-#define SH7750_TCR_TPSC_DIV256 0x003 /* Counts on peripheral clock/256 */
-#define SH7750_TCR_TPSC_DIV1024 0x004 /* Counts on peripheral clock/1024 */
-#define SH7750_TCR_TPSC_RTC 0x006 /* Counts on on-chip RTC output clk */
-#define SH7750_TCR_TPSC_EXT 0x007 /* Counts on external clock */
-
-/* Input Capture Register (read-only) - TCPR2 */
-#define SH7750_TCPR2_REGOFS 0xD8002C /* offset */
-#define SH7750_TCPR2 SH7750_P4_REG32(SH7750_TCPR2_REGOFS)
-#define SH7750_TCPR2_A7 SH7750_A7_REG32(SH7750_TCPR2_REGOFS)
-
-/*
- * Bus State Controller - BSC
- */
-/* Bus Control Register 1 - BCR1 */
-#define SH7750_BCR1_REGOFS 0x800000 /* offset */
-#define SH7750_BCR1 SH7750_P4_REG32(SH7750_BCR1_REGOFS)
-#define SH7750_BCR1_A7 SH7750_A7_REG32(SH7750_BCR1_REGOFS)
-#define SH7750_BCR1_ENDIAN 0x80000000 /* Endianness (1 - little endian) */
-#define SH7750_BCR1_MASTER 0x40000000 /* Master/Slave mode (1-master) */
-#define SH7750_BCR1_A0MPX 0x20000000 /* Area 0 Memory Type (0-SRAM,1-MPX) */
-#define SH7750_BCR1_IPUP 0x02000000 /* Input Pin Pull-up Control:
- 0 - pull-up resistor is on for
- control input pins
- 1 - pull-up resistor is off */
-#define SH7750_BCR1_OPUP 0x01000000 /* Output Pin Pull-up Control:
- 0 - pull-up resistor is on for
- control output pins
- 1 - pull-up resistor is off */
-#define SH7750_BCR1_A1MBC 0x00200000 /* Area 1 SRAM Byte Control Mode:
- 0 - Area 1 SRAM is set to
- normal mode
- 1 - Area 1 SRAM is set to byte
- control mode */
-#define SH7750_BCR1_A4MBC 0x00100000 /* Area 4 SRAM Byte Control Mode:
- 0 - Area 4 SRAM is set to
- normal mode
- 1 - Area 4 SRAM is set to byte
- control mode */
-#define SH7750_BCR1_BREQEN 0x00080000 /* BREQ Enable:
- 0 - External requests are not
- accepted
- 1 - External requests are
- accepted */
-#define SH7750_BCR1_PSHR 0x00040000 /* Partial Sharing Bit:
- 0 - Master Mode
- 1 - Partial-sharing Mode */
-#define SH7750_BCR1_MEMMPX 0x00020000 /* Area 1 to 6 MPX Interface:
- 0 - SRAM/burst ROM interface
- 1 - MPX interface */
-#define SH7750_BCR1_HIZMEM 0x00008000 /* High Impendance Control. Specifies
- the state of A[25:0], BS\, CSn\,
- RD/WR\, CE2A\, CE2B\ in standby
- mode and when bus is released:
- 0 - signals go to High-Z mode
- 1 - signals driven */
-#define SH7750_BCR1_HIZCNT 0x00004000 /* High Impendance Control. Specifies
- the state of the RAS\, RAS2\, WEn\,
- CASn\, DQMn, RD\, CASS\, FRAME\,
- RD2\ signals in standby mode and
- when bus is released:
- 0 - signals go to High-Z mode
- 1 - signals driven */
-#define SH7750_BCR1_A0BST 0x00003800 /* Area 0 Burst ROM Control */
-#define SH7750_BCR1_A0BST_SRAM 0x0000 /* Area 0 accessed as SRAM i/f */
-#define SH7750_BCR1_A0BST_ROM4 0x0800 /* Area 0 accessed as burst ROM
- interface, 4 cosequtive access */
-#define SH7750_BCR1_A0BST_ROM8 0x1000 /* Area 0 accessed as burst ROM
- interface, 8 cosequtive access */
-#define SH7750_BCR1_A0BST_ROM16 0x1800 /* Area 0 accessed as burst ROM
- interface, 16 cosequtive access */
-#define SH7750_BCR1_A0BST_ROM32 0x2000 /* Area 0 accessed as burst ROM
- interface, 32 cosequtive access */
-
-#define SH7750_BCR1_A5BST 0x00000700 /* Area 5 Burst ROM Control */
-#define SH7750_BCR1_A5BST_SRAM 0x0000 /* Area 5 accessed as SRAM i/f */
-#define SH7750_BCR1_A5BST_ROM4 0x0100 /* Area 5 accessed as burst ROM
- interface, 4 cosequtive access */
-#define SH7750_BCR1_A5BST_ROM8 0x0200 /* Area 5 accessed as burst ROM
- interface, 8 cosequtive access */
-#define SH7750_BCR1_A5BST_ROM16 0x0300 /* Area 5 accessed as burst ROM
- interface, 16 cosequtive access */
-#define SH7750_BCR1_A5BST_ROM32 0x0400 /* Area 5 accessed as burst ROM
- interface, 32 cosequtive access */
-
-#define SH7750_BCR1_A6BST 0x000000E0 /* Area 6 Burst ROM Control */
-#define SH7750_BCR1_A6BST_SRAM 0x0000 /* Area 6 accessed as SRAM i/f */
-#define SH7750_BCR1_A6BST_ROM4 0x0020 /* Area 6 accessed as burst ROM
- interface, 4 cosequtive access */
-#define SH7750_BCR1_A6BST_ROM8 0x0040 /* Area 6 accessed as burst ROM
- interface, 8 cosequtive access */
-#define SH7750_BCR1_A6BST_ROM16 0x0060 /* Area 6 accessed as burst ROM
- interface, 16 cosequtive access */
-#define SH7750_BCR1_A6BST_ROM32 0x0080 /* Area 6 accessed as burst ROM
- interface, 32 cosequtive access */
-
-#define SH7750_BCR1_DRAMTP 0x001C /* Area 2 and 3 Memory Type */
-#define SH7750_BCR1_DRAMTP_2SRAM_3SRAM 0x0000 /* Area 2 and 3 are SRAM or MPX
- interface. */
-#define SH7750_BCR1_DRAMTP_2SRAM_3SDRAM 0x0008 /* Area 2 - SRAM/MPX, Area 3 -
- synchronous DRAM */
-#define SH7750_BCR1_DRAMTP_2SDRAM_3SDRAM 0x000C /* Area 2 and 3 are synchronous
- DRAM interface */
-#define SH7750_BCR1_DRAMTP_2SRAM_3DRAM 0x0010 /* Area 2 - SRAM/MPX, Area 3 -
- DRAM interface */
-#define SH7750_BCR1_DRAMTP_2DRAM_3DRAM 0x0014 /* Area 2 and 3 are DRAM
- interface */
-
-#define SH7750_BCR1_A56PCM 0x00000001 /* Area 5 and 6 Bus Type:
- 0 - SRAM interface
- 1 - PCMCIA interface */
-
-/* Bus Control Register 2 (half) - BCR2 */
-#define SH7750_BCR2_REGOFS 0x800004 /* offset */
-#define SH7750_BCR2 SH7750_P4_REG32(SH7750_BCR2_REGOFS)
-#define SH7750_BCR2_A7 SH7750_A7_REG32(SH7750_BCR2_REGOFS)
-
-#define SH7750_BCR2_A0SZ 0xC000 /* Area 0 Bus Width */
-#define SH7750_BCR2_A0SZ_S 14
-#define SH7750_BCR2_A6SZ 0x3000 /* Area 6 Bus Width */
-#define SH7750_BCR2_A6SZ_S 12
-#define SH7750_BCR2_A5SZ 0x0C00 /* Area 5 Bus Width */
-#define SH7750_BCR2_A5SZ_S 10
-#define SH7750_BCR2_A4SZ 0x0300 /* Area 4 Bus Width */
-#define SH7750_BCR2_A4SZ_S 8
-#define SH7750_BCR2_A3SZ 0x00C0 /* Area 3 Bus Width */
-#define SH7750_BCR2_A3SZ_S 6
-#define SH7750_BCR2_A2SZ 0x0030 /* Area 2 Bus Width */
-#define SH7750_BCR2_A2SZ_S 4
-#define SH7750_BCR2_A1SZ 0x000C /* Area 1 Bus Width */
-#define SH7750_BCR2_A1SZ_S 2
-#define SH7750_BCR2_SZ_64 0 /* 64 bits */
-#define SH7750_BCR2_SZ_8 1 /* 8 bits */
-#define SH7750_BCR2_SZ_16 2 /* 16 bits */
-#define SH7750_BCR2_SZ_32 3 /* 32 bits */
-#define SH7750_BCR2_PORTEN 0x0001 /* Port Function Enable :
- 0 - D51-D32 are not used as a port
- 1 - D51-D32 are used as a port */
-
-/* Wait Control Register 1 - WCR1 */
-#define SH7750_WCR1_REGOFS 0x800008 /* offset */
-#define SH7750_WCR1 SH7750_P4_REG32(SH7750_WCR1_REGOFS)
-#define SH7750_WCR1_A7 SH7750_A7_REG32(SH7750_WCR1_REGOFS)
-#define SH7750_WCR1_DMAIW 0x70000000 /* DACK Device Inter-Cycle Idle
- specification */
-#define SH7750_WCR1_DMAIW_S 28
-#define SH7750_WCR1_A6IW 0x07000000 /* Area 6 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A6IW_S 24
-#define SH7750_WCR1_A5IW 0x00700000 /* Area 5 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A5IW_S 20
-#define SH7750_WCR1_A4IW 0x00070000 /* Area 4 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A4IW_S 16
-#define SH7750_WCR1_A3IW 0x00007000 /* Area 3 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A3IW_S 12
-#define SH7750_WCR1_A2IW 0x00000700 /* Area 2 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A2IW_S 8
-#define SH7750_WCR1_A1IW 0x00000070 /* Area 1 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A1IW_S 4
-#define SH7750_WCR1_A0IW 0x00000007 /* Area 0 Inter-Cycle Idle spec. */
-#define SH7750_WCR1_A0IW_S 0
-
-/* Wait Control Register 2 - WCR2 */
-#define SH7750_WCR2_REGOFS 0x80000C /* offset */
-#define SH7750_WCR2 SH7750_P4_REG32(SH7750_WCR2_REGOFS)
-#define SH7750_WCR2_A7 SH7750_A7_REG32(SH7750_WCR2_REGOFS)
-
-#define SH7750_WCR2_A6W 0xE0000000 /* Area 6 Wait Control */
-#define SH7750_WCR2_A6W_S 29
-#define SH7750_WCR2_A6B 0x1C000000 /* Area 6 Burst Pitch */
-#define SH7750_WCR2_A6B_S 26
-#define SH7750_WCR2_A5W 0x03800000 /* Area 5 Wait Control */
-#define SH7750_WCR2_A5W_S 23
-#define SH7750_WCR2_A5B 0x00700000 /* Area 5 Burst Pitch */
-#define SH7750_WCR2_A5B_S 20
-#define SH7750_WCR2_A4W 0x000E0000 /* Area 4 Wait Control */
-#define SH7750_WCR2_A4W_S 17
-#define SH7750_WCR2_A3W 0x0000E000 /* Area 3 Wait Control */
-#define SH7750_WCR2_A3W_S 13
-#define SH7750_WCR2_A2W 0x00000E00 /* Area 2 Wait Control */
-#define SH7750_WCR2_A2W_S 9
-#define SH7750_WCR2_A1W 0x000001C0 /* Area 1 Wait Control */
-#define SH7750_WCR2_A1W_S 6
-#define SH7750_WCR2_A0W 0x00000038 /* Area 0 Wait Control */
-#define SH7750_WCR2_A0W_S 3
-#define SH7750_WCR2_A0B 0x00000007 /* Area 0 Burst Pitch */
-#define SH7750_WCR2_A0B_S 0
-
-#define SH7750_WCR2_WS0 0 /* 0 wait states inserted */
-#define SH7750_WCR2_WS1 1 /* 1 wait states inserted */
-#define SH7750_WCR2_WS2 2 /* 2 wait states inserted */
-#define SH7750_WCR2_WS3 3 /* 3 wait states inserted */
-#define SH7750_WCR2_WS6 4 /* 6 wait states inserted */
-#define SH7750_WCR2_WS9 5 /* 9 wait states inserted */
-#define SH7750_WCR2_WS12 6 /* 12 wait states inserted */
-#define SH7750_WCR2_WS15 7 /* 15 wait states inserted */
-
-#define SH7750_WCR2_BPWS0 0 /* 0 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS1 1 /* 1 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS2 2 /* 2 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS3 3 /* 3 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS4 4 /* 4 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS5 5 /* 5 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS6 6 /* 6 wait states inserted from 2nd access */
-#define SH7750_WCR2_BPWS7 7 /* 7 wait states inserted from 2nd access */
-
-/* DRAM CAS\ Assertion Delay (area 3,2) */
-#define SH7750_WCR2_DRAM_CAS_ASW1 0 /* 1 cycle */
-#define SH7750_WCR2_DRAM_CAS_ASW2 1 /* 2 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW3 2 /* 3 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW4 3 /* 4 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW7 4 /* 7 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW10 5 /* 10 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW13 6 /* 13 cycles */
-#define SH7750_WCR2_DRAM_CAS_ASW16 7 /* 16 cycles */
-
-/* SDRAM CAS\ Latency Cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT1 1 /* 1 cycle */
-#define SH7750_WCR2_SDRAM_CAS_LAT2 2 /* 2 cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT3 3 /* 3 cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT4 4 /* 4 cycles */
-#define SH7750_WCR2_SDRAM_CAS_LAT5 5 /* 5 cycles */
-
-/* Wait Control Register 3 - WCR3 */
-#define SH7750_WCR3_REGOFS 0x800010 /* offset */
-#define SH7750_WCR3 SH7750_P4_REG32(SH7750_WCR3_REGOFS)
-#define SH7750_WCR3_A7 SH7750_A7_REG32(SH7750_WCR3_REGOFS)
-
-#define SH7750_WCR3_A6S 0x04000000 /* Area 6 Write Strobe Setup time */
-#define SH7750_WCR3_A6H 0x03000000 /* Area 6 Data Hold Time */
-#define SH7750_WCR3_A6H_S 24
-#define SH7750_WCR3_A5S 0x00400000 /* Area 5 Write Strobe Setup time */
-#define SH7750_WCR3_A5H 0x00300000 /* Area 5 Data Hold Time */
-#define SH7750_WCR3_A5H_S 20
-#define SH7750_WCR3_A4S 0x00040000 /* Area 4 Write Strobe Setup time */
-#define SH7750_WCR3_A4H 0x00030000 /* Area 4 Data Hold Time */
-#define SH7750_WCR3_A4H_S 16
-#define SH7750_WCR3_A3S 0x00004000 /* Area 3 Write Strobe Setup time */
-#define SH7750_WCR3_A3H 0x00003000 /* Area 3 Data Hold Time */
-#define SH7750_WCR3_A3H_S 12
-#define SH7750_WCR3_A2S 0x00000400 /* Area 2 Write Strobe Setup time */
-#define SH7750_WCR3_A2H 0x00000300 /* Area 2 Data Hold Time */
-#define SH7750_WCR3_A2H_S 8
-#define SH7750_WCR3_A1S 0x00000040 /* Area 1 Write Strobe Setup time */
-#define SH7750_WCR3_A1H 0x00000030 /* Area 1 Data Hold Time */
-#define SH7750_WCR3_A1H_S 4
-#define SH7750_WCR3_A0S 0x00000004 /* Area 0 Write Strobe Setup time */
-#define SH7750_WCR3_A0H 0x00000003 /* Area 0 Data Hold Time */
-#define SH7750_WCR3_A0H_S 0
-
-#define SH7750_WCR3_DHWS_0 0 /* 0 wait states data hold time */
-#define SH7750_WCR3_DHWS_1 1 /* 1 wait states data hold time */
-#define SH7750_WCR3_DHWS_2 2 /* 2 wait states data hold time */
-#define SH7750_WCR3_DHWS_3 3 /* 3 wait states data hold time */
-
-#define SH7750_MCR_REGOFS 0x800014 /* offset */
-#define SH7750_MCR SH7750_P4_REG32(SH7750_MCR_REGOFS)
-#define SH7750_MCR_A7 SH7750_A7_REG32(SH7750_MCR_REGOFS)
-
-#define SH7750_MCR_RASD 0x80000000 /* RAS Down mode */
-#define SH7750_MCR_MRSET 0x40000000 /* SDRAM Mode Register Set */
-#define SH7750_MCR_PALL 0x00000000 /* SDRAM Precharge All cmd. Mode */
-#define SH7750_MCR_TRC 0x38000000 /* RAS Precharge Time at End of
- Refresh: */
-#define SH7750_MCR_TRC_0 0x00000000 /* 0 */
-#define SH7750_MCR_TRC_3 0x08000000 /* 3 */
-#define SH7750_MCR_TRC_6 0x10000000 /* 6 */
-#define SH7750_MCR_TRC_9 0x18000000 /* 9 */
-#define SH7750_MCR_TRC_12 0x20000000 /* 12 */
-#define SH7750_MCR_TRC_15 0x28000000 /* 15 */
-#define SH7750_MCR_TRC_18 0x30000000 /* 18 */
-#define SH7750_MCR_TRC_21 0x38000000 /* 21 */
-
-#define SH7750_MCR_TCAS 0x00800000 /* CAS Negation Period */
-#define SH7750_MCR_TCAS_1 0x00000000 /* 1 */
-#define SH7750_MCR_TCAS_2 0x00800000 /* 2 */
-
-#define SH7750_MCR_TPC 0x00380000 /* DRAM: RAS Precharge Period
- SDRAM: minimum number of cycles
- until the next bank active cmd
- is output after precharging */
-#define SH7750_MCR_TPC_S 19
-#define SH7750_MCR_TPC_SDRAM_1 0x00000000 /* 1 cycle */
-#define SH7750_MCR_TPC_SDRAM_2 0x00080000 /* 2 cycles */
-#define SH7750_MCR_TPC_SDRAM_3 0x00100000 /* 3 cycles */
-#define SH7750_MCR_TPC_SDRAM_4 0x00180000 /* 4 cycles */
-#define SH7750_MCR_TPC_SDRAM_5 0x00200000 /* 5 cycles */
-#define SH7750_MCR_TPC_SDRAM_6 0x00280000 /* 6 cycles */
-#define SH7750_MCR_TPC_SDRAM_7 0x00300000 /* 7 cycles */
-#define SH7750_MCR_TPC_SDRAM_8 0x00380000 /* 8 cycles */
-
-#define SH7750_MCR_RCD 0x00030000 /* DRAM: RAS-CAS Assertion Delay time
- SDRAM: bank active-read/write cmd
- delay time */
-#define SH7750_MCR_RCD_DRAM_2 0x00000000 /* DRAM delay 2 clocks */
-#define SH7750_MCR_RCD_DRAM_3 0x00010000 /* DRAM delay 3 clocks */
-#define SH7750_MCR_RCD_DRAM_4 0x00020000 /* DRAM delay 4 clocks */
-#define SH7750_MCR_RCD_DRAM_5 0x00030000 /* DRAM delay 5 clocks */
-#define SH7750_MCR_RCD_SDRAM_2 0x00010000 /* DRAM delay 2 clocks */
-#define SH7750_MCR_RCD_SDRAM_3 0x00020000 /* DRAM delay 3 clocks */
-#define SH7750_MCR_RCD_SDRAM_4 0x00030000 /* DRAM delay 4 clocks */
-
-#define SH7750_MCR_TRWL 0x0000E000 /* SDRAM Write Precharge Delay */
-#define SH7750_MCR_TRWL_1 0x00000000 /* 1 */
-#define SH7750_MCR_TRWL_2 0x00002000 /* 2 */
-#define SH7750_MCR_TRWL_3 0x00004000 /* 3 */
-#define SH7750_MCR_TRWL_4 0x00006000 /* 4 */
-#define SH7750_MCR_TRWL_5 0x00008000 /* 5 */
-
-#define SH7750_MCR_TRAS 0x00001C00 /* DRAM: CAS-Before-RAS Refresh RAS
- asserting period
- SDRAM: Command interval after
- synchronous DRAM refresh */
-#define SH7750_MCR_TRAS_DRAM_2 0x00000000 /* 2 */
-#define SH7750_MCR_TRAS_DRAM_3 0x00000400 /* 3 */
-#define SH7750_MCR_TRAS_DRAM_4 0x00000800 /* 4 */
-#define SH7750_MCR_TRAS_DRAM_5 0x00000C00 /* 5 */
-#define SH7750_MCR_TRAS_DRAM_6 0x00001000 /* 6 */
-#define SH7750_MCR_TRAS_DRAM_7 0x00001400 /* 7 */
-#define SH7750_MCR_TRAS_DRAM_8 0x00001800 /* 8 */
-#define SH7750_MCR_TRAS_DRAM_9 0x00001C00 /* 9 */
-
-#define SH7750_MCR_TRAS_SDRAM_TRC_4 0x00000000 /* 4 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_5 0x00000400 /* 5 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_6 0x00000800 /* 6 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_7 0x00000C00 /* 7 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_8 0x00001000 /* 8 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_9 0x00001400 /* 9 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_10 0x00001800 /* 10 + TRC */
-#define SH7750_MCR_TRAS_SDRAM_TRC_11 0x00001C00 /* 11 + TRC */
-
-#define SH7750_MCR_BE 0x00000200 /* Burst Enable */
-#define SH7750_MCR_SZ 0x00000180 /* Memory Data Size */
-#define SH7750_MCR_SZ_64 0x00000000 /* 64 bits */
-#define SH7750_MCR_SZ_16 0x00000100 /* 16 bits */
-#define SH7750_MCR_SZ_32 0x00000180 /* 32 bits */
-
-#define SH7750_MCR_AMX 0x00000078 /* Address Multiplexing */
-#define SH7750_MCR_AMX_S 3
-#define SH7750_MCR_AMX_DRAM_8BIT_COL 0x00000000 /* 8-bit column addr */
-#define SH7750_MCR_AMX_DRAM_9BIT_COL 0x00000008 /* 9-bit column addr */
-#define SH7750_MCR_AMX_DRAM_10BIT_COL 0x00000010 /* 10-bit column addr */
-#define SH7750_MCR_AMX_DRAM_11BIT_COL 0x00000018 /* 11-bit column addr */
-#define SH7750_MCR_AMX_DRAM_12BIT_COL 0x00000020 /* 12-bit column addr */
-/* See SH7750 Hardware Manual for SDRAM address multiplexor selection */
-
-#define SH7750_MCR_RFSH 0x00000004 /* Refresh Control */
-#define SH7750_MCR_RMODE 0x00000002 /* Refresh Mode: */
-#define SH7750_MCR_RMODE_NORMAL 0x00000000 /* Normal Refresh Mode */
-#define SH7750_MCR_RMODE_SELF 0x00000002 /* Self-Refresh Mode */
-#define SH7750_MCR_RMODE_EDO 0x00000001 /* EDO Mode */
-
-/* SDRAM Mode Set address */
-#define SH7750_SDRAM_MODE_A2_BASE 0xFF900000
-#define SH7750_SDRAM_MODE_A3_BASE 0xFF940000
-#define SH7750_SDRAM_MODE_A2_32BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 2))
-#define SH7750_SDRAM_MODE_A3_32BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 2))
-#define SH7750_SDRAM_MODE_A2_64BIT(x) (SH7750_SDRAM_MODE_A2_BASE + ((x) << 3))
-#define SH7750_SDRAM_MODE_A3_64BIT(x) (SH7750_SDRAM_MODE_A3_BASE + ((x) << 3))
-
-
-/* PCMCIA Control Register (half) - PCR */
-#define SH7750_PCR_REGOFS 0x800018 /* offset */
-#define SH7750_PCR SH7750_P4_REG32(SH7750_PCR_REGOFS)
-#define SH7750_PCR_A7 SH7750_A7_REG32(SH7750_PCR_REGOFS)
-
-#define SH7750_PCR_A5PCW 0xC000 /* Area 5 PCMCIA Wait - Number of wait
- states to be added to the number of
- waits specified by WCR2 in a low-speed
- PCMCIA wait cycle */
-#define SH7750_PCR_A5PCW_0 0x0000 /* 0 waits inserted */
-#define SH7750_PCR_A5PCW_15 0x4000 /* 15 waits inserted */
-#define SH7750_PCR_A5PCW_30 0x8000 /* 30 waits inserted */
-#define SH7750_PCR_A5PCW_50 0xC000 /* 50 waits inserted */
-
-#define SH7750_PCR_A6PCW 0x3000 /* Area 6 PCMCIA Wait - Number of wait
- states to be added to the number of
- waits specified by WCR2 in a low-speed
- PCMCIA wait cycle */
-#define SH7750_PCR_A6PCW_0 0x0000 /* 0 waits inserted */
-#define SH7750_PCR_A6PCW_15 0x1000 /* 15 waits inserted */
-#define SH7750_PCR_A6PCW_30 0x2000 /* 30 waits inserted */
-#define SH7750_PCR_A6PCW_50 0x3000 /* 50 waits inserted */
-
-#define SH7750_PCR_A5TED 0x0E00 /* Area 5 Address-OE\/WE\ Assertion Delay,
- delay time from address output to
- OE\/WE\ assertion on the connected
- PCMCIA interface */
-#define SH7750_PCR_A5TED_S 9
-#define SH7750_PCR_A6TED 0x01C0 /* Area 6 Address-OE\/WE\ Assertion Delay */
-#define SH7750_PCR_A6TED_S 6
-
-#define SH7750_PCR_TED_0WS 0 /* 0 Waits inserted */
-#define SH7750_PCR_TED_1WS 1 /* 1 Waits inserted */
-#define SH7750_PCR_TED_2WS 2 /* 2 Waits inserted */
-#define SH7750_PCR_TED_3WS 3 /* 3 Waits inserted */
-#define SH7750_PCR_TED_6WS 4 /* 6 Waits inserted */
-#define SH7750_PCR_TED_9WS 5 /* 9 Waits inserted */
-#define SH7750_PCR_TED_12WS 6 /* 12 Waits inserted */
-#define SH7750_PCR_TED_15WS 7 /* 15 Waits inserted */
-
-#define SH7750_PCR_A5TEH 0x0038 /* Area 5 OE\/WE\ Negation Address delay,
- address hold delay time from OE\/WE\
- negation in a write on the connected
- PCMCIA interface */
-#define SH7750_PCR_A5TEH_S 3
-
-#define SH7750_PCR_A6TEH 0x0007 /* Area 6 OE\/WE\ Negation Address delay */
-#define SH7750_PCR_A6TEH_S 0
-
-#define SH7750_PCR_TEH_0WS 0 /* 0 Waits inserted */
-#define SH7750_PCR_TEH_1WS 1 /* 1 Waits inserted */
-#define SH7750_PCR_TEH_2WS 2 /* 2 Waits inserted */
-#define SH7750_PCR_TEH_3WS 3 /* 3 Waits inserted */
-#define SH7750_PCR_TEH_6WS 4 /* 6 Waits inserted */
-#define SH7750_PCR_TEH_9WS 5 /* 9 Waits inserted */
-#define SH7750_PCR_TEH_12WS 6 /* 12 Waits inserted */
-#define SH7750_PCR_TEH_15WS 7 /* 15 Waits inserted */
-
-/* Refresh Timer Control/Status Register (half) - RTSCR */
-#define SH7750_RTCSR_REGOFS 0x80001C /* offset */
-#define SH7750_RTCSR SH7750_P4_REG32(SH7750_RTCSR_REGOFS)
-#define SH7750_RTCSR_A7 SH7750_A7_REG32(SH7750_RTCSR_REGOFS)
-
-#define SH7750_RTCSR_KEY 0xA500 /* RTCSR write key */
-#define SH7750_RTCSR_CMF 0x0080 /* Compare-Match Flag (indicates a
- match between the refresh timer
- counter and refresh time constant) */
-#define SH7750_RTCSR_CMIE 0x0040 /* Compare-Match Interrupt Enable */
-#define SH7750_RTCSR_CKS 0x0038 /* Refresh Counter Clock Selects */
-#define SH7750_RTCSR_CKS_DIS 0x0000 /* Clock Input Disabled */
-#define SH7750_RTCSR_CKS_CKIO_DIV4 0x0008 /* Bus Clock / 4 */
-#define SH7750_RTCSR_CKS_CKIO_DIV16 0x0010 /* Bus Clock / 16 */
-#define SH7750_RTCSR_CKS_CKIO_DIV64 0x0018 /* Bus Clock / 64 */
-#define SH7750_RTCSR_CKS_CKIO_DIV256 0x0020 /* Bus Clock / 256 */
-#define SH7750_RTCSR_CKS_CKIO_DIV1024 0x0028 /* Bus Clock / 1024 */
-#define SH7750_RTCSR_CKS_CKIO_DIV2048 0x0030 /* Bus Clock / 2048 */
-#define SH7750_RTCSR_CKS_CKIO_DIV4096 0x0038 /* Bus Clock / 4096 */
-
-#define SH7750_RTCSR_OVF 0x0004 /* Refresh Count Overflow Flag */
-#define SH7750_RTCSR_OVIE 0x0002 /* Refresh Count Overflow Interrupt
- Enable */
-#define SH7750_RTCSR_LMTS 0x0001 /* Refresh Count Overflow Limit Select */
-#define SH7750_RTCSR_LMTS_1024 0x0000 /* Count Limit is 1024 */
-#define SH7750_RTCSR_LMTS_512 0x0001 /* Count Limit is 512 */
-
-/* Refresh Timer Counter (half) - RTCNT */
-#define SH7750_RTCNT_REGOFS 0x800020 /* offset */
-#define SH7750_RTCNT SH7750_P4_REG32(SH7750_RTCNT_REGOFS)
-#define SH7750_RTCNT_A7 SH7750_A7_REG32(SH7750_RTCNT_REGOFS)
-
-#define SH7750_RTCNT_KEY 0xA500 /* RTCNT write key */
-
-/* Refresh Time Constant Register (half) - RTCOR */
-#define SH7750_RTCOR_REGOFS 0x800024 /* offset */
-#define SH7750_RTCOR SH7750_P4_REG32(SH7750_RTCOR_REGOFS)
-#define SH7750_RTCOR_A7 SH7750_A7_REG32(SH7750_RTCOR_REGOFS)
-
-#define SH7750_RTCOR_KEY 0xA500 /* RTCOR write key */
-
-/* Refresh Count Register (half) - RFCR */
-#define SH7750_RFCR_REGOFS 0x800028 /* offset */
-#define SH7750_RFCR SH7750_P4_REG32(SH7750_RFCR_REGOFS)
-#define SH7750_RFCR_A7 SH7750_A7_REG32(SH7750_RFCR_REGOFS)
-
-#define SH7750_RFCR_KEY 0xA400 /* RFCR write key */
-
-/*
- * Direct Memory Access Controller (DMAC)
- */
-
-/* DMA Source Address Register - SAR0, SAR1, SAR2, SAR3 */
-#define SH7750_SAR_REGOFS(n) (0xA00000 + ((n)*16)) /* offset */
-#define SH7750_SAR(n) SH7750_P4_REG32(SH7750_SAR_REGOFS(n))
-#define SH7750_SAR_A7(n) SH7750_A7_REG32(SH7750_SAR_REGOFS(n))
-#define SH7750_SAR0 SH7750_SAR(0)
-#define SH7750_SAR1 SH7750_SAR(1)
-#define SH7750_SAR2 SH7750_SAR(2)
-#define SH7750_SAR3 SH7750_SAR(3)
-#define SH7750_SAR0_A7 SH7750_SAR_A7(0)
-#define SH7750_SAR1_A7 SH7750_SAR_A7(1)
-#define SH7750_SAR2_A7 SH7750_SAR_A7(2)
-#define SH7750_SAR3_A7 SH7750_SAR_A7(3)
-
-/* DMA Destination Address Register - DAR0, DAR1, DAR2, DAR3 */
-#define SH7750_DAR_REGOFS(n) (0xA00004 + ((n)*16)) /* offset */
-#define SH7750_DAR(n) SH7750_P4_REG32(SH7750_DAR_REGOFS(n))
-#define SH7750_DAR_A7(n) SH7750_A7_REG32(SH7750_DAR_REGOFS(n))
-#define SH7750_DAR0 SH7750_DAR(0)
-#define SH7750_DAR1 SH7750_DAR(1)
-#define SH7750_DAR2 SH7750_DAR(2)
-#define SH7750_DAR3 SH7750_DAR(3)
-#define SH7750_DAR0_A7 SH7750_DAR_A7(0)
-#define SH7750_DAR1_A7 SH7750_DAR_A7(1)
-#define SH7750_DAR2_A7 SH7750_DAR_A7(2)
-#define SH7750_DAR3_A7 SH7750_DAR_A7(3)
-
-/* DMA Transfer Count Register - DMATCR0, DMATCR1, DMATCR2, DMATCR3 */
-#define SH7750_DMATCR_REGOFS(n) (0xA00008 + ((n)*16)) /* offset */
-#define SH7750_DMATCR(n) SH7750_P4_REG32(SH7750_DMATCR_REGOFS(n))
-#define SH7750_DMATCR_A7(n) SH7750_A7_REG32(SH7750_DMATCR_REGOFS(n))
-#define SH7750_DMATCR0_P4 SH7750_DMATCR(0)
-#define SH7750_DMATCR1_P4 SH7750_DMATCR(1)
-#define SH7750_DMATCR2_P4 SH7750_DMATCR(2)
-#define SH7750_DMATCR3_P4 SH7750_DMATCR(3)
-#define SH7750_DMATCR0_A7 SH7750_DMATCR_A7(0)
-#define SH7750_DMATCR1_A7 SH7750_DMATCR_A7(1)
-#define SH7750_DMATCR2_A7 SH7750_DMATCR_A7(2)
-#define SH7750_DMATCR3_A7 SH7750_DMATCR_A7(3)
-
-/* DMA Channel Control Register - CHCR0, CHCR1, CHCR2, CHCR3 */
-#define SH7750_CHCR_REGOFS(n) (0xA0000C + ((n)*16)) /* offset */
-#define SH7750_CHCR(n) SH7750_P4_REG32(SH7750_CHCR_REGOFS(n))
-#define SH7750_CHCR_A7(n) SH7750_A7_REG32(SH7750_CHCR_REGOFS(n))
-#define SH7750_CHCR0 SH7750_CHCR(0)
-#define SH7750_CHCR1 SH7750_CHCR(1)
-#define SH7750_CHCR2 SH7750_CHCR(2)
-#define SH7750_CHCR3 SH7750_CHCR(3)
-#define SH7750_CHCR0_A7 SH7750_CHCR_A7(0)
-#define SH7750_CHCR1_A7 SH7750_CHCR_A7(1)
-#define SH7750_CHCR2_A7 SH7750_CHCR_A7(2)
-#define SH7750_CHCR3_A7 SH7750_CHCR_A7(3)
-
-#define SH7750_CHCR_SSA 0xE0000000 /* Source Address Space Attribute */
-#define SH7750_CHCR_SSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */
-#define SH7750_CHCR_SSA_DYNBSZ 0x20000000 /* Dynamic Bus Sizing I/O space */
-#define SH7750_CHCR_SSA_IO8 0x40000000 /* 8-bit I/O space */
-#define SH7750_CHCR_SSA_IO16 0x60000000 /* 16-bit I/O space */
-#define SH7750_CHCR_SSA_CMEM8 0x80000000 /* 8-bit common memory space */
-#define SH7750_CHCR_SSA_CMEM16 0xA0000000 /* 16-bit common memory space */
-#define SH7750_CHCR_SSA_AMEM8 0xC0000000 /* 8-bit attribute memory space */
-#define SH7750_CHCR_SSA_AMEM16 0xE0000000 /* 16-bit attribute memory space */
-
-#define SH7750_CHCR_STC 0x10000000 /* Source Address Wait Control Select,
- specifies CS5 or CS6 space wait
- control for PCMCIA access */
-
-#define SH7750_CHCR_DSA 0x0E000000 /* Source Address Space Attribute */
-#define SH7750_CHCR_DSA_PCMCIA 0x00000000 /* Reserved in PCMCIA access */
-#define SH7750_CHCR_DSA_DYNBSZ 0x02000000 /* Dynamic Bus Sizing I/O space */
-#define SH7750_CHCR_DSA_IO8 0x04000000 /* 8-bit I/O space */
-#define SH7750_CHCR_DSA_IO16 0x06000000 /* 16-bit I/O space */
-#define SH7750_CHCR_DSA_CMEM8 0x08000000 /* 8-bit common memory space */
-#define SH7750_CHCR_DSA_CMEM16 0x0A000000 /* 16-bit common memory space */
-#define SH7750_CHCR_DSA_AMEM8 0x0C000000 /* 8-bit attribute memory space */
-#define SH7750_CHCR_DSA_AMEM16 0x0E000000 /* 16-bit attribute memory space */
-
-#define SH7750_CHCR_DTC 0x01000000 /* Destination Address Wait Control
- Select, specifies CS5 or CS6
- space wait control for PCMCIA
- access */
-
-#define SH7750_CHCR_DS 0x00080000 /* DREQ\ Select : */
-#define SH7750_CHCR_DS_LOWLVL 0x00000000 /* Low Level Detection */
-#define SH7750_CHCR_DS_FALL 0x00080000 /* Falling Edge Detection */
-
-#define SH7750_CHCR_RL 0x00040000 /* Request Check Level: */
-#define SH7750_CHCR_RL_ACTH 0x00000000 /* DRAK is an active high out */
-#define SH7750_CHCR_RL_ACTL 0x00040000 /* DRAK is an active low out */
-
-#define SH7750_CHCR_AM 0x00020000 /* Acknowledge Mode: */
-#define SH7750_CHCR_AM_RD 0x00000000 /* DACK is output in read cycle */
-#define SH7750_CHCR_AM_WR 0x00020000 /* DACK is output in write cycle */
-
-#define SH7750_CHCR_AL 0x00010000 /* Acknowledge Level: */
-#define SH7750_CHCR_AL_ACTH 0x00000000 /* DACK is an active high out */
-#define SH7750_CHCR_AL_ACTL 0x00010000 /* DACK is an active low out */
-
-#define SH7750_CHCR_DM 0x0000C000 /* Destination Address Mode: */
-#define SH7750_CHCR_DM_FIX 0x00000000 /* Destination Addr Fixed */
-#define SH7750_CHCR_DM_INC 0x00004000 /* Destination Addr Incremented */
-#define SH7750_CHCR_DM_DEC 0x00008000 /* Destination Addr Decremented */
-
-#define SH7750_CHCR_SM 0x00003000 /* Source Address Mode: */
-#define SH7750_CHCR_SM_FIX 0x00000000 /* Source Addr Fixed */
-#define SH7750_CHCR_SM_INC 0x00001000 /* Source Addr Incremented */
-#define SH7750_CHCR_SM_DEC 0x00002000 /* Source Addr Decremented */
-
-#define SH7750_CHCR_RS 0x00000F00 /* Request Source Select: */
-#define SH7750_CHCR_RS_ER_DA_EA_TO_EA 0x000 /* External Request, Dual Address
- Mode (External Addr Space->
- External Addr Space) */
-#define SH7750_CHCR_RS_ER_SA_EA_TO_ED 0x200 /* External Request, Single
- Address Mode (External Addr
- Space -> External Device) */
-#define SH7750_CHCR_RS_ER_SA_ED_TO_EA 0x300 /* External Request, Single
- Address Mode, (External
- Device -> External Addr
- Space) */
-#define SH7750_CHCR_RS_AR_EA_TO_EA 0x400 /* Auto-Request (External Addr
- Space -> External Addr Space) */
-
-#define SH7750_CHCR_RS_AR_EA_TO_OCP 0x500 /* Auto-Request (External Addr
- Space -> On-chip Peripheral
- Module) */
-#define SH7750_CHCR_RS_AR_OCP_TO_EA 0x600 /* Auto-Request (On-chip
- Peripheral Module ->
- External Addr Space */
-#define SH7750_CHCR_RS_SCITX_EA_TO_SC 0x800 /* SCI Transmit-Data-Empty intr
- transfer request (external
- address space -> SCTDR1) */
-#define SH7750_CHCR_RS_SCIRX_SC_TO_EA 0x900 /* SCI Receive-Data-Full intr
- transfer request (SCRDR1 ->
- External Addr Space) */
-#define SH7750_CHCR_RS_SCIFTX_EA_TO_SC 0xA00 /* SCIF Transmit-Data-Empty intr
- transfer request (external
- address space -> SCFTDR1) */
-#define SH7750_CHCR_RS_SCIFRX_SC_TO_EA 0xB00 /* SCIF Receive-Data-Full intr
- transfer request (SCFRDR2 ->
- External Addr Space) */
-#define SH7750_CHCR_RS_TMU2_EA_TO_EA 0xC00 /* TMU Channel 2 (input capture
- interrupt), (external address
- space -> external address
- space) */
-#define SH7750_CHCR_RS_TMU2_EA_TO_OCP 0xD00 /* TMU Channel 2 (input capture
- interrupt), (external address
- space -> on-chip peripheral
- module) */
-#define SH7750_CHCR_RS_TMU2_OCP_TO_EA 0xE00 /* TMU Channel 2 (input capture
- interrupt), (on-chip
- peripheral module -> external
- address space) */
-
-#define SH7750_CHCR_TM 0x00000080 /* Transmit mode: */
-#define SH7750_CHCR_TM_CSTEAL 0x00000000 /* Cycle Steal Mode */
-#define SH7750_CHCR_TM_BURST 0x00000080 /* Burst Mode */
-
-#define SH7750_CHCR_TS 0x00000070 /* Transmit Size: */
-#define SH7750_CHCR_TS_QUAD 0x00000000 /* Quadword Size (64 bits) */
-#define SH7750_CHCR_TS_BYTE 0x00000010 /* Byte Size (8 bit) */
-#define SH7750_CHCR_TS_WORD 0x00000020 /* Word Size (16 bit) */
-#define SH7750_CHCR_TS_LONG 0x00000030 /* Longword Size (32 bit) */
-#define SH7750_CHCR_TS_BLOCK 0x00000040 /* 32-byte block transfer */
-
-#define SH7750_CHCR_IE 0x00000004 /* Interrupt Enable */
-#define SH7750_CHCR_TE 0x00000002 /* Transfer End */
-#define SH7750_CHCR_DE 0x00000001 /* DMAC Enable */
-
-/* DMA Operation Register - DMAOR */
-#define SH7750_DMAOR_REGOFS 0xA00040 /* offset */
-#define SH7750_DMAOR SH7750_P4_REG32(SH7750_DMAOR_REGOFS)
-#define SH7750_DMAOR_A7 SH7750_A7_REG32(SH7750_DMAOR_REGOFS)
-
-#define SH7750_DMAOR_DDT 0x00008000 /* On-Demand Data Transfer Mode */
-
-#define SH7750_DMAOR_PR 0x00000300 /* Priority Mode: */
-#define SH7750_DMAOR_PR_0123 0x00000000 /* CH0 > CH1 > CH2 > CH3 */
-#define SH7750_DMAOR_PR_0231 0x00000100 /* CH0 > CH2 > CH3 > CH1 */
-#define SH7750_DMAOR_PR_2013 0x00000200 /* CH2 > CH0 > CH1 > CH3 */
-#define SH7750_DMAOR_PR_RR 0x00000300 /* Round-robin mode */
-
-#define SH7750_DMAOR_COD 0x00000010 /* Check Overrun for DREQ\ */
-#define SH7750_DMAOR_AE 0x00000004 /* Address Error flag */
-#define SH7750_DMAOR_NMIF 0x00000002 /* NMI Flag */
-#define SH7750_DMAOR_DME 0x00000001 /* DMAC Master Enable */
-
-/*
- * Serial Communication Interface - SCI
- * Serial Communication Interface with FIFO - SCIF
- */
-/* SCI Receive Data Register (byte, read-only) - SCRDR1, SCFRDR2 */
-#define SH7750_SCRDR_REGOFS(n) ((n) == 1 ? 0xE00014 : 0xE80014) /* offset */
-#define SH7750_SCRDR(n) SH7750_P4_REG32(SH7750_SCRDR_REGOFS(n))
-#define SH7750_SCRDR1 SH7750_SCRDR(1)
-#define SH7750_SCRDR2 SH7750_SCRDR(2)
-#define SH7750_SCRDR_A7(n) SH7750_A7_REG32(SH7750_SCRDR_REGOFS(n))
-#define SH7750_SCRDR1_A7 SH7750_SCRDR_A7(1)
-#define SH7750_SCRDR2_A7 SH7750_SCRDR_A7(2)
-
-/* SCI Transmit Data Register (byte) - SCTDR1, SCFTDR2 */
-#define SH7750_SCTDR_REGOFS(n) ((n) == 1 ? 0xE0000C : 0xE8000C) /* offset */
-#define SH7750_SCTDR(n) SH7750_P4_REG32(SH7750_SCTDR_REGOFS(n))
-#define SH7750_SCTDR1 SH7750_SCTDR(1)
-#define SH7750_SCTDR2 SH7750_SCTDR(2)
-#define SH7750_SCTDR_A7(n) SH7750_A7_REG32(SH7750_SCTDR_REGOFS(n))
-#define SH7750_SCTDR1_A7 SH7750_SCTDR_A7(1)
-#define SH7750_SCTDR2_A7 SH7750_SCTDR_A7(2)
-
-/* SCI Serial Mode Register - SCSMR1(byte), SCSMR2(half) */
-#define SH7750_SCSMR_REGOFS(n) ((n) == 1 ? 0xE00000 : 0xE80000) /* offset */
-#define SH7750_SCSMR(n) SH7750_P4_REG32(SH7750_SCSMR_REGOFS(n))
-#define SH7750_SCSMR1 SH7750_SCSMR(1)
-#define SH7750_SCSMR2 SH7750_SCSMR(2)
-#define SH7750_SCSMR_A7(n) SH7750_A7_REG32(SH7750_SCSMR_REGOFS(n))
-#define SH7750_SCSMR1_A7 SH7750_SCSMR_A7(1)
-#define SH7750_SCSMR2_A7 SH7750_SCSMR_A7(2)
-
-#define SH7750_SCSMR1_CA 0x80 /* Communication Mode (C/A\): */
-#define SH7750_SCSMR1_CA_ASYNC 0x00 /* Asynchronous Mode */
-#define SH7750_SCSMR1_CA_SYNC 0x80 /* Synchronous Mode */
-#define SH7750_SCSMR_CHR 0x40 /* Character Length: */
-#define SH7750_SCSMR_CHR_8 0x00 /* 8-bit data */
-#define SH7750_SCSMR_CHR_7 0x40 /* 7-bit data */
-#define SH7750_SCSMR_PE 0x20 /* Parity Enable */
-#define SH7750_SCSMR_PM 0x10 /* Parity Mode: */
-#define SH7750_SCSMR_PM_EVEN 0x00 /* Even Parity */
-#define SH7750_SCSMR_PM_ODD 0x10 /* Odd Parity */
-#define SH7750_SCSMR_STOP 0x08 /* Stop Bit Length: */
-#define SH7750_SCSMR_STOP_1 0x00 /* 1 stop bit */
-#define SH7750_SCSMR_STOP_2 0x08 /* 2 stop bit */
-#define SH7750_SCSMR1_MP 0x04 /* Multiprocessor Mode */
-#define SH7750_SCSMR_CKS 0x03 /* Clock Select */
-#define SH7750_SCSMR_CKS_S 0
-#define SH7750_SCSMR_CKS_DIV1 0x00 /* Periph clock */
-#define SH7750_SCSMR_CKS_DIV4 0x01 /* Periph clock / 4 */
-#define SH7750_SCSMR_CKS_DIV16 0x02 /* Periph clock / 16 */
-#define SH7750_SCSMR_CKS_DIV64 0x03 /* Periph clock / 64 */
-
-/* SCI Serial Control Register - SCSCR1(byte), SCSCR2(half) */
-#define SH7750_SCSCR_REGOFS(n) ((n) == 1 ? 0xE00008 : 0xE80008) /* offset */
-#define SH7750_SCSCR(n) SH7750_P4_REG32(SH7750_SCSCR_REGOFS(n))
-#define SH7750_SCSCR1 SH7750_SCSCR(1)
-#define SH7750_SCSCR2 SH7750_SCSCR(2)
-#define SH7750_SCSCR_A7(n) SH7750_A7_REG32(SH7750_SCSCR_REGOFS(n))
-#define SH7750_SCSCR1_A7 SH7750_SCSCR_A7(1)
-#define SH7750_SCSCR2_A7 SH7750_SCSCR_A7(2)
-
-#define SH7750_SCSCR_TIE 0x80 /* Transmit Interrupt Enable */
-#define SH7750_SCSCR_RIE 0x40 /* Receive Interrupt Enable */
-#define SH7750_SCSCR_TE 0x20 /* Transmit Enable */
-#define SH7750_SCSCR_RE 0x10 /* Receive Enable */
-#define SH7750_SCSCR1_MPIE 0x08 /* Multiprocessor Interrupt Enable */
-#define SH7750_SCSCR2_REIE 0x08 /* Receive Error Interrupt Enable */
-#define SH7750_SCSCR1_TEIE 0x04 /* Transmit End Interrupt Enable */
-#define SH7750_SCSCR1_CKE 0x03 /* Clock Enable: */
-#define SH7750_SCSCR_CKE_INTCLK 0x00 /* Use Internal Clock */
-#define SH7750_SCSCR_CKE_EXTCLK 0x02 /* Use External Clock from SCK */
-#define SH7750_SCSCR1_CKE_ASYNC_SCK_CLKOUT 0x01 /* Use SCK as a clock output
- in asynchronous mode */
-
-/* SCI Serial Status Register - SCSSR1(byte), SCSFR2(half) */
-#define SH7750_SCSSR_REGOFS(n) ((n) == 1 ? 0xE00010 : 0xE80010) /* offset */
-#define SH7750_SCSSR(n) SH7750_P4_REG32(SH7750_SCSSR_REGOFS(n))
-#define SH7750_SCSSR1 SH7750_SCSSR(1)
-#define SH7750_SCSFR2 SH7750_SCSSR(2)
-#define SH7750_SCSSR_A7(n) SH7750_A7_REG32(SH7750_SCSSR_REGOFS(n))
-#define SH7750_SCSSR1_A7 SH7750_SCSSR_A7(1)
-#define SH7750_SCSFR2_A7 SH7750_SCSSR_A7(2)
-
-#define SH7750_SCSSR1_TDRE 0x80 /* Transmit Data Register Empty */
-#define SH7750_SCSSR1_RDRF 0x40 /* Receive Data Register Full */
-#define SH7750_SCSSR1_ORER 0x20 /* Overrun Error */
-#define SH7750_SCSSR1_FER 0x10 /* Framing Error */
-#define SH7750_SCSSR1_PER 0x08 /* Parity Error */
-#define SH7750_SCSSR1_TEND 0x04 /* Transmit End */
-#define SH7750_SCSSR1_MPB 0x02 /* Multiprocessor Bit */
-#define SH7750_SCSSR1_MPBT 0x01 /* Multiprocessor Bit Transfer */
-
-#define SH7750_SCFSR2_PERN 0xF000 /* Number of Parity Errors */
-#define SH7750_SCFSR2_PERN_S 12
-#define SH7750_SCFSR2_FERN 0x0F00 /* Number of Framing Errors */
-#define SH7750_SCFSR2_FERN_S 8
-#define SH7750_SCFSR2_ER 0x0080 /* Receive Error */
-#define SH7750_SCFSR2_TEND 0x0040 /* Transmit End */
-#define SH7750_SCFSR2_TDFE 0x0020 /* Transmit FIFO Data Empty */
-#define SH7750_SCFSR2_BRK 0x0010 /* Break Detect */
-#define SH7750_SCFSR2_FER 0x0008 /* Framing Error */
-#define SH7750_SCFSR2_PER 0x0004 /* Parity Error */
-#define SH7750_SCFSR2_RDF 0x0002 /* Receive FIFO Data Full */
-#define SH7750_SCFSR2_DR 0x0001 /* Receive Data Ready */
-
-/* SCI Serial Port Register - SCSPTR1(byte) */
-#define SH7750_SCSPTR1_REGOFS 0xE0001C /* offset */
-#define SH7750_SCSPTR1 SH7750_P4_REG32(SH7750_SCSPTR1_REGOFS)
-#define SH7750_SCSPTR1_A7 SH7750_A7_REG32(SH7750_SCSPTR1_REGOFS)
-
-#define SH7750_SCSPTR1_EIO 0x80 /* Error Interrupt Only */
-#define SH7750_SCSPTR1_SPB1IO 0x08 /* 1: Output SPB1DT bit to SCK pin */
-#define SH7750_SCSPTR1_SPB1DT 0x04 /* Serial Port Clock Port Data */
-#define SH7750_SCSPTR1_SPB0IO 0x02 /* 1: Output SPB0DT bit to TxD pin */
-#define SH7750_SCSPTR1_SPB0DT 0x01 /* Serial Port Break Data */
-
-/* SCIF Serial Port Register - SCSPTR2(half) */
-#define SH7750_SCSPTR2_REGOFS 0xE80020 /* offset */
-#define SH7750_SCSPTR2 SH7750_P4_REG32(SH7750_SCSPTR2_REGOFS)
-#define SH7750_SCSPTR2_A7 SH7750_A7_REG32(SH7750_SCSPTR2_REGOFS)
-
-#define SH7750_SCSPTR2_RTSIO 0x80 /* 1: Output RTSDT bit to RTS2\ pin */
-#define SH7750_SCSPTR2_RTSDT 0x40 /* RTS Port Data */
-#define SH7750_SCSPTR2_CTSIO 0x20 /* 1: Output CTSDT bit to CTS2\ pin */
-#define SH7750_SCSPTR2_CTSDT 0x10 /* CTS Port Data */
-#define SH7750_SCSPTR2_SPB2IO 0x02 /* 1: Output SPBDT bit to TxD2 pin */
-#define SH7750_SCSPTR2_SPB2DT 0x01 /* Serial Port Break Data */
-
-/* SCI Bit Rate Register - SCBRR1(byte), SCBRR2(byte) */
-#define SH7750_SCBRR_REGOFS(n) ((n) == 1 ? 0xE00004 : 0xE80004) /* offset */
-#define SH7750_SCBRR(n) SH7750_P4_REG32(SH7750_SCBRR_REGOFS(n))
-#define SH7750_SCBRR1 SH7750_SCBRR_P4(1)
-#define SH7750_SCBRR2 SH7750_SCBRR_P4(2)
-#define SH7750_SCBRR_A7(n) SH7750_A7_REG32(SH7750_SCBRR_REGOFS(n))
-#define SH7750_SCBRR1_A7 SH7750_SCBRR_A7(1)
-#define SH7750_SCBRR2_A7 SH7750_SCBRR_A7(2)
-
-/* SCIF FIFO Control Register - SCFCR2(half) */
-#define SH7750_SCFCR2_REGOFS 0xE80018 /* offset */
-#define SH7750_SCFCR2 SH7750_P4_REG32(SH7750_SCFCR2_REGOFS)
-#define SH7750_SCFCR2_A7 SH7750_A7_REG32(SH7750_SCFCR2_REGOFS)
-
-#define SH7750_SCFCR2_RSTRG 0x700 /* RTS2\ Output Active Trigger; RTS2\
- signal goes to high level when the
- number of received data stored in
- FIFO exceeds the trigger number */
-#define SH7750_SCFCR2_RSTRG_15 0x000 /* 15 bytes */
-#define SH7750_SCFCR2_RSTRG_1 0x000 /* 1 byte */
-#define SH7750_SCFCR2_RSTRG_4 0x000 /* 4 bytes */
-#define SH7750_SCFCR2_RSTRG_6 0x000 /* 6 bytes */
-#define SH7750_SCFCR2_RSTRG_8 0x000 /* 8 bytes */
-#define SH7750_SCFCR2_RSTRG_10 0x000 /* 10 bytes */
-#define SH7750_SCFCR2_RSTRG_14 0x000 /* 14 bytes */
-
-#define SH7750_SCFCR2_RTRG 0x0C0 /* Receive FIFO Data Number Trigger,
- Receive Data Full (RDF) Flag sets
- when number of receive data bytes is
- equal or greater than the trigger
- number */
-#define SH7750_SCFCR2_RTRG_1 0x000 /* 1 byte */
-#define SH7750_SCFCR2_RTRG_4 0x040 /* 4 bytes */
-#define SH7750_SCFCR2_RTRG_8 0x080 /* 8 bytes */
-#define SH7750_SCFCR2_RTRG_14 0x0C0 /* 14 bytes */
-
-#define SH7750_SCFCR2_TTRG 0x030 /* Transmit FIFO Data Number Trigger,
- Transmit FIFO Data Register Empty (TDFE)
- flag sets when the number of remaining
- transmit data bytes is equal or less
- than the trigger number */
-#define SH7750_SCFCR2_TTRG_8 0x000 /* 8 bytes */
-#define SH7750_SCFCR2_TTRG_4 0x010 /* 4 bytes */
-#define SH7750_SCFCR2_TTRG_2 0x020 /* 2 bytes */
-#define SH7750_SCFCR2_TTRG_1 0x030 /* 1 byte */
-
-#define SH7750_SCFCR2_MCE 0x008 /* Modem Control Enable */
-#define SH7750_SCFCR2_TFRST 0x004 /* Transmit FIFO Data Register Reset,
- invalidates the transmit data in the
- transmit FIFO */
-#define SH7750_SCFCR2_RFRST 0x002 /* Receive FIFO Data Register Reset,
- invalidates the receive data in the
- receive FIFO data register and resets
- it to the empty state */
-#define SH7750_SCFCR2_LOOP 0x001 /* Loopback Test */
-
-/* SCIF FIFO Data Count Register - SCFDR2(half, read-only) */
-#define SH7750_SCFDR2_REGOFS 0xE8001C /* offset */
-#define SH7750_SCFDR2 SH7750_P4_REG32(SH7750_SCFDR2_REGOFS)
-#define SH7750_SCFDR2_A7 SH7750_A7_REG32(SH7750_SCFDR2_REGOFS)
-
-#define SH7750_SCFDR2_T 0x1F00 /* Number of untransmitted data bytes
- in transmit FIFO */
-#define SH7750_SCFDR2_T_S 8
-#define SH7750_SCFDR2_R 0x001F /* Number of received data bytes in
- receive FIFO */
-#define SH7750_SCFDR2_R_S 0
-
-/* SCIF Line Status Register - SCLSR2(half, read-only) */
-#define SH7750_SCLSR2_REGOFS 0xE80024 /* offset */
-#define SH7750_SCLSR2 SH7750_P4_REG32(SH7750_SCLSR2_REGOFS)
-#define SH7750_SCLSR2_A7 SH7750_A7_REG32(SH7750_SCLSR2_REGOFS)
-
-#define SH7750_SCLSR2_ORER 0x0001 /* Overrun Error */
-
-/*
- * SCI-based Smart Card Interface
- */
-/* Smart Card Mode Register - SCSCMR1(byte) */
-#define SH7750_SCSCMR1_REGOFS 0xE00018 /* offset */
-#define SH7750_SCSCMR1 SH7750_P4_REG32(SH7750_SCSCMR1_REGOFS)
-#define SH7750_SCSCMR1_A7 SH7750_A7_REG32(SH7750_SCSCMR1_REGOFS)
-
-#define SH7750_SCSCMR1_SDIR 0x08 /* Smart Card Data Transfer Direction: */
-#define SH7750_SCSCMR1_SDIR_LSBF 0x00 /* LSB-first */
-#define SH7750_SCSCMR1_SDIR_MSBF 0x08 /* MSB-first */
-
-#define SH7750_SCSCMR1_SINV 0x04 /* Smart Card Data Inversion */
-#define SH7750_SCSCMR1_SMIF 0x01 /* Smart Card Interface Mode Select */
-
-/* Smart-card specific bits in other registers */
-/* SCSMR1: */
-#define SH7750_SCSMR1_GSM 0x80 /* GSM mode select */
-
-/* SCSSR1: */
-#define SH7750_SCSSR1_ERS 0x10 /* Error Signal Status */
-
-/*
- * I/O Ports
- */
-/* Port Control Register A - PCTRA */
-#define SH7750_PCTRA_REGOFS 0x80002C /* offset */
-#define SH7750_PCTRA SH7750_P4_REG32(SH7750_PCTRA_REGOFS)
-#define SH7750_PCTRA_A7 SH7750_A7_REG32(SH7750_PCTRA_REGOFS)
-
-#define SH7750_PCTRA_PBPUP(n) 0 /* Bit n is pulled up */
-#define SH7750_PCTRA_PBNPUP(n) (1 << ((n)*2+1)) /* Bit n is not pulled up */
-#define SH7750_PCTRA_PBINP(n) 0 /* Bit n is an input */
-#define SH7750_PCTRA_PBOUT(n) (1 << ((n)*2)) /* Bit n is an output */
-
-/* Port Data Register A - PDTRA(half) */
-#define SH7750_PDTRA_REGOFS 0x800030 /* offset */
-#define SH7750_PDTRA SH7750_P4_REG32(SH7750_PDTRA_REGOFS)
-#define SH7750_PDTRA_A7 SH7750_A7_REG32(SH7750_PDTRA_REGOFS)
-
-#define SH7750_PDTRA_BIT(n) (1 << (n))
-
-/* Port Control Register B - PCTRB */
-#define SH7750_PCTRB_REGOFS 0x800040 /* offset */
-#define SH7750_PCTRB SH7750_P4_REG32(SH7750_PCTRB_REGOFS)
-#define SH7750_PCTRB_A7 SH7750_A7_REG32(SH7750_PCTRB_REGOFS)
-
-#define SH7750_PCTRB_PBPUP(n) 0 /* Bit n is pulled up */
-#define SH7750_PCTRB_PBNPUP(n) (1 << ((n-16)*2+1)) /* Bit n is not pulled up */
-#define SH7750_PCTRB_PBINP(n) 0 /* Bit n is an input */
-#define SH7750_PCTRB_PBOUT(n) (1 << ((n-16)*2)) /* Bit n is an output */
-
-/* Port Data Register B - PDTRB(half) */
-#define SH7750_PDTRB_REGOFS 0x800044 /* offset */
-#define SH7750_PDTRB SH7750_P4_REG32(SH7750_PDTRB_REGOFS)
-#define SH7750_PDTRB_A7 SH7750_A7_REG32(SH7750_PDTRB_REGOFS)
-
-#define SH7750_PDTRB_BIT(n) (1 << ((n)-16))
-
-/* GPIO Interrupt Control Register - GPIOIC(half) */
-#define SH7750_GPIOIC_REGOFS 0x800048 /* offset */
-#define SH7750_GPIOIC SH7750_P4_REG32(SH7750_GPIOIC_REGOFS)
-#define SH7750_GPIOIC_A7 SH7750_A7_REG32(SH7750_GPIOIC_REGOFS)
-
-#define SH7750_GPIOIC_PTIREN(n) (1 << (n)) /* Port n is used as a GPIO int */
-
-/*
- * Interrupt Controller - INTC
- */
-/* Interrupt Control Register - ICR (half) */
-#define SH7750_ICR_REGOFS 0xD00000 /* offset */
-#define SH7750_ICR SH7750_P4_REG32(SH7750_ICR_REGOFS)
-#define SH7750_ICR_A7 SH7750_A7_REG32(SH7750_ICR_REGOFS)
-
-#define SH7750_ICR_NMIL 0x8000 /* NMI Input Level */
-#define SH7750_ICR_MAI 0x4000 /* NMI Interrupt Mask */
-
-#define SH7750_ICR_NMIB 0x0200 /* NMI Block Mode: */
-#define SH7750_ICR_NMIB_BLK 0x0000 /* NMI requests held pending while
- SR.BL bit is set to 1 */
-#define SH7750_ICR_NMIB_NBLK 0x0200 /* NMI requests detected when SR.BL bit
- set to 1 */
-
-#define SH7750_ICR_NMIE 0x0100 /* NMI Edge Select: */
-#define SH7750_ICR_NMIE_FALL 0x0000 /* Interrupt request detected on falling
- edge of NMI input */
-#define SH7750_ICR_NMIE_RISE 0x0100 /* Interrupt request detected on rising
- edge of NMI input */
-
-#define SH7750_ICR_IRLM 0x0080 /* IRL Pin Mode: */
-#define SH7750_ICR_IRLM_ENC 0x0000 /* IRL\ pins used as a level-encoded
- interrupt requests */
-#define SH7750_ICR_IRLM_RAW 0x0080 /* IRL\ pins used as a four independent
- interrupt requests */
-
-/* Interrupt Priority Register A - IPRA (half) */
-#define SH7750_IPRA_REGOFS 0xD00004 /* offset */
-#define SH7750_IPRA SH7750_P4_REG32(SH7750_IPRA_REGOFS)
-#define SH7750_IPRA_A7 SH7750_A7_REG32(SH7750_IPRA_REGOFS)
-
-#define SH7750_IPRA_TMU0 0xF000 /* TMU0 interrupt priority */
-#define SH7750_IPRA_TMU0_S 12
-#define SH7750_IPRA_TMU1 0x0F00 /* TMU1 interrupt priority */
-#define SH7750_IPRA_TMU1_S 8
-#define SH7750_IPRA_TMU2 0x00F0 /* TMU2 interrupt priority */
-#define SH7750_IPRA_TMU2_S 4
-#define SH7750_IPRA_RTC 0x000F /* RTC interrupt priority */
-#define SH7750_IPRA_RTC_S 0
-
-/* Interrupt Priority Register B - IPRB (half) */
-#define SH7750_IPRB_REGOFS 0xD00008 /* offset */
-#define SH7750_IPRB SH7750_P4_REG32(SH7750_IPRB_REGOFS)
-#define SH7750_IPRB_A7 SH7750_A7_REG32(SH7750_IPRB_REGOFS)
-
-#define SH7750_IPRB_WDT 0xF000 /* WDT interrupt priority */
-#define SH7750_IPRB_WDT_S 12
-#define SH7750_IPRB_REF 0x0F00 /* Memory Refresh unit interrupt
- priority */
-#define SH7750_IPRB_REF_S 8
-#define SH7750_IPRB_SCI1 0x00F0 /* SCI1 interrupt priority */
-#define SH7750_IPRB_SCI1_S 4
-
-/* Interrupt Priority Register ó - IPRó (half) */
-#define SH7750_IPRC_REGOFS 0xD00004 /* offset */
-#define SH7750_IPRC SH7750_P4_REG32(SH7750_IPRC_REGOFS)
-#define SH7750_IPRC_A7 SH7750_A7_REG32(SH7750_IPRC_REGOFS)
-
-#define SH7750_IPRC_GPIO 0xF000 /* GPIO interrupt priority */
-#define SH7750_IPRC_GPIO_S 12
-#define SH7750_IPRC_DMAC 0x0F00 /* DMAC interrupt priority */
-#define SH7750_IPRC_DMAC_S 8
-#define SH7750_IPRC_SCIF 0x00F0 /* SCIF interrupt priority */
-#define SH7750_IPRC_SCIF_S 4
-#define SH7750_IPRC_HUDI 0x000F /* H-UDI interrupt priority */
-#define SH7750_IPRC_HUDI_S 0
-
-
-/*
- * User Break Controller registers
- */
-#define SH7750_BARA 0x200000 /* Break address regiser A */
-#define SH7750_BAMRA 0x200004 /* Break address mask regiser A */
-#define SH7750_BBRA 0x200008 /* Break bus cycle regiser A */
-#define SH7750_BARB 0x20000c /* Break address regiser B */
-#define SH7750_BAMRB 0x200010 /* Break address mask regiser B */
-#define SH7750_BBRB 0x200014 /* Break bus cycle regiser B */
-#define SH7750_BASRB 0x000018 /* Break ASID regiser B */
-#define SH7750_BDRB 0x200018 /* Break data regiser B */
-#define SH7750_BDMRB 0x20001c /* Break data mask regiser B */
-#define SH7750_BRCR 0x200020 /* Break control register */
-
-#define SH7750_BRCR_UDBE 0x0001 /* User break debug enable bit */
-
-/*
- * Missing in RTEMS, added for QEMU
- */
-#define SH7750_BCR3_A7 0x1f800050
-#define SH7750_BCR4_A7 0x1e0a00f0
-#define SH7750_PRECHARGE0_A7 0x1f900088
-#define SH7750_PRECHARGE1_A7 0x1f940088
-
-#endif
diff --git a/hw/shix.c b/hw/shix.c
deleted file mode 100644
index 9577c09..0000000
--- a/hw/shix.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * SHIX 2.0 board description
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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.
- */
-/*
- Shix 2.0 board by Alexis Polti, described at
- http://perso.enst.fr/~polti/realisations/shix20/
-
- More information in target-sh4/README.sh4
-*/
-#include "vl.h"
-
-#define BIOS_FILENAME "shix_bios.bin"
-#define BIOS_ADDRESS 0xA0000000
-
-void DMA_run(void)
-{
- /* XXXXX */
-}
-
-void irq_info(void)
-{
- /* XXXXX */
-}
-
-void pic_set_irq(int irq, int level)
-{
- /* XXXXX */
-}
-
-void pic_info()
-{
- /* XXXXX */
-}
-
-void vga_update_display()
-{
- /* XXXXX */
-}
-
-void vga_invalidate_display()
-{
- /* XXXXX */
-}
-
-void vga_screen_dump(const char *filename)
-{
- /* XXXXX */
-}
-
-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)
-{
- int ret;
- CPUState *env;
- struct SH7750State *s;
-
- printf("Initializing CPU\n");
- env = cpu_init();
-
- /* Allocate memory space */
- printf("Allocating ROM\n");
- cpu_register_physical_memory(0x00000000, 0x00004000, IO_MEM_ROM);
- printf("Allocating SDRAM 1\n");
- cpu_register_physical_memory(0x08000000, 0x01000000, 0x00004000);
- printf("Allocating SDRAM 2\n");
- cpu_register_physical_memory(0x0c000000, 0x01000000, 0x01004000);
-
- /* Load BIOS in 0 (and access it through P2, 0xA0000000) */
- printf("%s: load BIOS '%s'\n", __func__, BIOS_FILENAME);
- ret = load_image(BIOS_FILENAME, phys_ram_base);
- if (ret < 0) { /* Check bios size */
- fprintf(stderr, "ret=%d\n", ret);
- fprintf(stderr, "qemu: could not load SHIX bios '%s'\n",
- BIOS_FILENAME);
- exit(1);
- }
-
- /* Register peripherals */
- s = sh7750_init(env);
- /* XXXXX Check success */
- tc58128_init(s, "shix_linux_nand.bin", NULL);
- fprintf(stderr, "initialization terminated\n");
-}
-
-QEMUMachine shix_machine = {
- "shix",
- "shix card",
- shix_init
-};
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
deleted file mode 100644
index 288fb50..0000000
--- a/hw/slavio_intctl.c
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * QEMU Sparc SLAVIO interrupt controller emulation
- *
- * Copyright (c) 2003-2005 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"
-//#define DEBUG_IRQ_COUNT
-//#define DEBUG_IRQ
-
-#ifdef DEBUG_IRQ
-#define DPRINTF(fmt, args...) \
-do { printf("IRQ: " fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...)
-#endif
-
-/*
- * Registers of interrupt controller in sun4m.
- *
- * This is the interrupt controller part of chip STP2001 (Slave I/O), also
- * produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * There is a system master controller and one for each cpu.
- *
- */
-
-#define MAX_CPUS 16
-
-typedef struct SLAVIO_INTCTLState {
- uint32_t intreg_pending[MAX_CPUS];
- uint32_t intregm_pending;
- uint32_t intregm_disabled;
- uint32_t target_cpu;
-#ifdef DEBUG_IRQ_COUNT
- uint64_t irq_count[32];
-#endif
- CPUState *cpu_envs[MAX_CPUS];
-} SLAVIO_INTCTLState;
-
-#define INTCTL_MAXADDR 0xf
-#define INTCTLM_MAXADDR 0xf
-static void slavio_check_interrupts(void *opaque);
-
-// per-cpu interrupt controller
-static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- SLAVIO_INTCTLState *s = opaque;
- uint32_t saddr;
- int cpu;
-
- cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
- saddr = (addr & INTCTL_MAXADDR) >> 2;
- switch (saddr) {
- case 0:
- return s->intreg_pending[cpu];
- default:
- break;
- }
- return 0;
-}
-
-static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- SLAVIO_INTCTLState *s = opaque;
- uint32_t saddr;
- int cpu;
-
- cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
- saddr = (addr & INTCTL_MAXADDR) >> 2;
- switch (saddr) {
- case 1: // clear pending softints
- if (val & 0x4000)
- val |= 80000000;
- val &= 0xfffe0000;
- s->intreg_pending[cpu] &= ~val;
- DPRINTF("Cleared cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
- break;
- case 2: // set softint
- val &= 0xfffe0000;
- s->intreg_pending[cpu] |= val;
- slavio_check_interrupts(s);
- DPRINTF("Set cpu %d irq mask %x, curmask %x\n", cpu, val, s->intreg_pending[cpu]);
- break;
- default:
- break;
- }
-}
-
-static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
- slavio_intctl_mem_readl,
- slavio_intctl_mem_readl,
- slavio_intctl_mem_readl,
-};
-
-static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
- slavio_intctl_mem_writel,
- slavio_intctl_mem_writel,
- slavio_intctl_mem_writel,
-};
-
-// master system interrupt controller
-static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- SLAVIO_INTCTLState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & INTCTLM_MAXADDR) >> 2;
- switch (saddr) {
- case 0:
- return s->intregm_pending & 0x7fffffff;
- case 1:
- return s->intregm_disabled;
- case 4:
- return s->target_cpu;
- default:
- break;
- }
- return 0;
-}
-
-static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- SLAVIO_INTCTLState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & INTCTLM_MAXADDR) >> 2;
- switch (saddr) {
- case 2: // clear (enable)
- // Force clear unused bits
- val &= ~0x4fb2007f;
- s->intregm_disabled &= ~val;
- DPRINTF("Enabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
- slavio_check_interrupts(s);
- break;
- case 3: // set (disable, clear pending)
- // Force clear unused bits
- val &= ~0x4fb2007f;
- s->intregm_disabled |= val;
- s->intregm_pending &= ~val;
- DPRINTF("Disabled master irq mask %x, curmask %x\n", val, s->intregm_disabled);
- break;
- case 4:
- s->target_cpu = val & (MAX_CPUS - 1);
- DPRINTF("Set master irq cpu %d\n", s->target_cpu);
- break;
- default:
- break;
- }
-}
-
-static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
- slavio_intctlm_mem_readl,
- slavio_intctlm_mem_readl,
- slavio_intctlm_mem_readl,
-};
-
-static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
- slavio_intctlm_mem_writel,
- slavio_intctlm_mem_writel,
- slavio_intctlm_mem_writel,
-};
-
-void slavio_pic_info(void *opaque)
-{
- SLAVIO_INTCTLState *s = opaque;
- int i;
-
- for (i = 0; i < MAX_CPUS; i++) {
- term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
- }
- term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
-}
-
-void slavio_irq_info(void *opaque)
-{
-#ifndef DEBUG_IRQ_COUNT
- term_printf("irq statistic code not compiled.\n");
-#else
- SLAVIO_INTCTLState *s = opaque;
- int i;
- int64_t count;
-
- term_printf("IRQ statistics:\n");
- for (i = 0; i < 32; i++) {
- count = s->irq_count[i];
- if (count > 0)
- term_printf("%2d: %" PRId64 "\n", i, count);
- }
-#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;
- SLAVIO_INTCTLState *s = opaque;
- uint32_t pending = s->intregm_pending;
- unsigned int i, j, max = 0;
-
- pending &= ~s->intregm_disabled;
-
- 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];
- }
- }
- env = s->cpu_envs[s->target_cpu];
- if (!env) {
- DPRINTF("No CPU %d, not triggered (pending %x)\n", s->target_cpu, pending);
- }
- else {
- if (env->halted)
- env->halted = 0;
- if (env->interrupt_index == 0) {
- DPRINTF("Triggered CPU %d pil %d\n", s->target_cpu, max);
-#ifdef DEBUG_IRQ_COUNT
- s->irq_count[max]++;
-#endif
- env->interrupt_index = TT_EXTINT | max;
- cpu_interrupt(env, CPU_INTERRUPT_HARD);
- }
- else
- DPRINTF("Not triggered (pending %x), pending exception %x\n", pending, env->interrupt_index);
- }
- }
- else
- DPRINTF("Not triggered (pending %x), disabled %x\n", pending, s->intregm_disabled);
-
- for (i = 0; i < MAX_CPUS; i++) {
- max = 0;
- env = s->cpu_envs[i];
- if (!env)
- continue;
- for (j = 17; j < 32; j++) {
- if (s->intreg_pending[i] & (1 << j)) {
- if (max < j - 16)
- max = j - 16;
- }
- }
- if (max > 0) {
- if (env->halted)
- env->halted = 0;
- if (env->interrupt_index == 0) {
- DPRINTF("Triggered softint %d for cpu %d (pending %x)\n", max, i, pending);
-#ifdef DEBUG_IRQ_COUNT
- s->irq_count[max]++;
-#endif
- env->interrupt_index = TT_EXTINT | max;
- cpu_interrupt(env, CPU_INTERRUPT_HARD);
- }
- }
- }
-}
-
-/*
- * "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)
-{
- 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];
- if (pil > 0) {
- if (level) {
- s->intregm_pending |= mask;
- s->intreg_pending[s->target_cpu] |= 1 << pil;
- }
- else {
- s->intregm_pending &= ~mask;
- s->intreg_pending[s->target_cpu] &= ~(1 << pil);
- }
- }
- }
- slavio_check_interrupts(s);
-}
-
-void slavio_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);
- return;
- }
- if (irq < 32) {
- uint32_t pil = intbit_to_level[irq];
- if (pil > 0) {
- if (level) {
- s->intreg_pending[cpu] |= 1 << pil;
- }
- else {
- s->intreg_pending[cpu] &= ~(1 << pil);
- }
- }
- }
- slavio_check_interrupts(s);
-}
-
-static void slavio_intctl_save(QEMUFile *f, void *opaque)
-{
- SLAVIO_INTCTLState *s = opaque;
- int i;
-
- for (i = 0; i < MAX_CPUS; i++) {
- qemu_put_be32s(f, &s->intreg_pending[i]);
- }
- qemu_put_be32s(f, &s->intregm_pending);
- qemu_put_be32s(f, &s->intregm_disabled);
- qemu_put_be32s(f, &s->target_cpu);
-}
-
-static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
-{
- SLAVIO_INTCTLState *s = opaque;
- int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- for (i = 0; i < MAX_CPUS; i++) {
- qemu_get_be32s(f, &s->intreg_pending[i]);
- }
- qemu_get_be32s(f, &s->intregm_pending);
- qemu_get_be32s(f, &s->intregm_disabled);
- qemu_get_be32s(f, &s->target_cpu);
- return 0;
-}
-
-static void slavio_intctl_reset(void *opaque)
-{
- SLAVIO_INTCTLState *s = opaque;
- int i;
-
- for (i = 0; i < MAX_CPUS; i++) {
- s->intreg_pending[i] = 0;
- }
- s->intregm_disabled = ~0xffb2007f;
- s->intregm_pending = 0;
- s->target_cpu = 0;
-}
-
-void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env)
-{
- SLAVIO_INTCTLState *s = opaque;
- s->cpu_envs[cpu] = env;
-}
-
-void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
-{
- int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
- SLAVIO_INTCTLState *s;
-
- s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
- if (!s)
- return NULL;
-
- 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);
- }
-
- slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
- cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
-
- register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
- qemu_register_reset(slavio_intctl_reset, s);
- slavio_intctl_reset(s);
- return s;
-}
-
diff --git a/hw/slavio_misc.c b/hw/slavio_misc.c
deleted file mode 100644
index 904f44e..0000000
--- a/hw/slavio_misc.c
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * QEMU Sparc SLAVIO aux io port emulation
- *
- * Copyright (c) 2005 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"
-/* debug misc */
-//#define DEBUG_MISC
-
-/*
- * This is the auxio port, chip control and system control part of
- * chip STP2001 (Slave I/O), also produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * This also includes the PMC CPU idle controller.
- */
-
-#ifdef DEBUG_MISC
-#define MISC_DPRINTF(fmt, args...) \
-do { printf("MISC: " fmt , ##args); } while (0)
-#else
-#define MISC_DPRINTF(fmt, args...)
-#endif
-
-typedef struct MiscState {
- int irq;
- uint8_t config;
- uint8_t aux1, aux2;
- uint8_t diag, mctrl, sysctrl;
-} MiscState;
-
-#define MISC_MAXADDR 1
-
-static void slavio_misc_update_irq(void *opaque)
-{
- MiscState *s = opaque;
-
- if ((s->aux2 & 0x4) && (s->config & 0x8)) {
- pic_set_irq(s->irq, 1);
- } else {
- pic_set_irq(s->irq, 0);
- }
-}
-
-static void slavio_misc_reset(void *opaque)
-{
- MiscState *s = opaque;
-
- // Diagnostic and system control registers not cleared in reset
- s->config = s->aux1 = s->aux2 = s->mctrl = 0;
-}
-
-void slavio_set_power_fail(void *opaque, int power_failing)
-{
- MiscState *s = opaque;
-
- MISC_DPRINTF("Power fail: %d, config: %d\n", power_failing, s->config);
- if (power_failing && (s->config & 0x8)) {
- s->aux2 |= 0x4;
- } else {
- s->aux2 &= ~0x4;
- }
- slavio_misc_update_irq(s);
-}
-
-static void slavio_misc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- MiscState *s = opaque;
-
- switch (addr & 0xfff0000) {
- case 0x1800000:
- MISC_DPRINTF("Write config %2.2x\n", val & 0xff);
- s->config = val & 0xff;
- slavio_misc_update_irq(s);
- break;
- case 0x1900000:
- MISC_DPRINTF("Write aux1 %2.2x\n", val & 0xff);
- s->aux1 = val & 0xff;
- break;
- case 0x1910000:
- val &= 0x3;
- MISC_DPRINTF("Write aux2 %2.2x\n", val);
- val |= s->aux2 & 0x4;
- if (val & 0x2) // Clear Power Fail int
- val &= 0x1;
- s->aux2 = val;
- if (val & 1)
- qemu_system_shutdown_request();
- slavio_misc_update_irq(s);
- break;
- case 0x1a00000:
- MISC_DPRINTF("Write diag %2.2x\n", val & 0xff);
- s->diag = val & 0xff;
- break;
- case 0x1b00000:
- MISC_DPRINTF("Write modem control %2.2x\n", val & 0xff);
- s->mctrl = val & 0xff;
- break;
- case 0x1f00000:
- MISC_DPRINTF("Write system control %2.2x\n", val & 0xff);
- if (val & 1) {
- s->sysctrl = 0x2;
- qemu_system_reset_request();
- }
- break;
- case 0xa000000:
- MISC_DPRINTF("Write power management %2.2x\n", val & 0xff);
-#if 0
- // XXX almost works
- cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
-#endif
- break;
- }
-}
-
-static uint32_t slavio_misc_mem_readb(void *opaque, target_phys_addr_t addr)
-{
- MiscState *s = opaque;
- uint32_t ret = 0;
-
- switch (addr & 0xfff0000) {
- case 0x1800000:
- ret = s->config;
- MISC_DPRINTF("Read config %2.2x\n", ret);
- break;
- case 0x1900000:
- ret = s->aux1;
- MISC_DPRINTF("Read aux1 %2.2x\n", ret);
- break;
- case 0x1910000:
- ret = s->aux2;
- MISC_DPRINTF("Read aux2 %2.2x\n", ret);
- break;
- case 0x1a00000:
- ret = s->diag;
- MISC_DPRINTF("Read diag %2.2x\n", ret);
- break;
- case 0x1b00000:
- ret = s->mctrl;
- MISC_DPRINTF("Read modem control %2.2x\n", ret);
- break;
- case 0x1f00000:
- MISC_DPRINTF("Read system control %2.2x\n", ret);
- ret = s->sysctrl;
- break;
- case 0xa000000:
- MISC_DPRINTF("Read power management %2.2x\n", ret);
- break;
- }
- return ret;
-}
-
-static CPUReadMemoryFunc *slavio_misc_mem_read[3] = {
- slavio_misc_mem_readb,
- slavio_misc_mem_readb,
- slavio_misc_mem_readb,
-};
-
-static CPUWriteMemoryFunc *slavio_misc_mem_write[3] = {
- slavio_misc_mem_writeb,
- slavio_misc_mem_writeb,
- slavio_misc_mem_writeb,
-};
-
-static void slavio_misc_save(QEMUFile *f, void *opaque)
-{
- MiscState *s = opaque;
-
- qemu_put_be32s(f, &s->irq);
- qemu_put_8s(f, &s->config);
- qemu_put_8s(f, &s->aux1);
- qemu_put_8s(f, &s->aux2);
- qemu_put_8s(f, &s->diag);
- qemu_put_8s(f, &s->mctrl);
- qemu_put_8s(f, &s->sysctrl);
-}
-
-static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
-{
- MiscState *s = opaque;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_be32s(f, &s->irq);
- qemu_get_8s(f, &s->config);
- qemu_get_8s(f, &s->aux1);
- qemu_get_8s(f, &s->aux2);
- qemu_get_8s(f, &s->diag);
- qemu_get_8s(f, &s->mctrl);
- qemu_get_8s(f, &s->sysctrl);
- return 0;
-}
-
-void *slavio_misc_init(uint32_t base, int irq)
-{
- int slavio_misc_io_memory;
- MiscState *s;
-
- s = qemu_mallocz(sizeof(MiscState));
- if (!s)
- return NULL;
-
- slavio_misc_io_memory = cpu_register_io_memory(0, slavio_misc_mem_read, slavio_misc_mem_write, s);
- // Slavio control
- cpu_register_physical_memory(base + 0x1800000, MISC_MAXADDR, slavio_misc_io_memory);
- // AUX 1
- cpu_register_physical_memory(base + 0x1900000, MISC_MAXADDR, slavio_misc_io_memory);
- // AUX 2
- cpu_register_physical_memory(base + 0x1910000, MISC_MAXADDR, slavio_misc_io_memory);
- // Diagnostics
- cpu_register_physical_memory(base + 0x1a00000, MISC_MAXADDR, slavio_misc_io_memory);
- // Modem control
- cpu_register_physical_memory(base + 0x1b00000, MISC_MAXADDR, slavio_misc_io_memory);
- // System control
- cpu_register_physical_memory(base + 0x1f00000, MISC_MAXADDR, slavio_misc_io_memory);
- // Power management
- cpu_register_physical_memory(base + 0xa000000, MISC_MAXADDR, slavio_misc_io_memory);
-
- s->irq = irq;
-
- register_savevm("slavio_misc", base, 1, slavio_misc_save, slavio_misc_load, s);
- qemu_register_reset(slavio_misc_reset, s);
- slavio_misc_reset(s);
- return s;
-}
diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c
deleted file mode 100644
index b13e7c4..0000000
--- a/hw/slavio_serial.c
+++ /dev/null
@@ -1,545 +0,0 @@
-/*
- * QEMU Sparc SLAVIO serial port emulation
- *
- * Copyright (c) 2003-2005 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"
-/* debug serial */
-//#define DEBUG_SERIAL
-
-/* debug keyboard */
-//#define DEBUG_KBD
-
-/* debug mouse */
-//#define DEBUG_MOUSE
-
-/*
- * This is the serial port, mouse and keyboard part of chip STP2001
- * (Slave I/O), also produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
- * mouse and keyboard ports don't implement all functions and they are
- * only asynchronous. There is no DMA.
- *
- */
-
-#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
-#ifdef DEBUG_KBD
-#define KBD_DPRINTF(fmt, args...) \
-do { printf("KBD: " fmt , ##args); } while (0)
-#else
-#define KBD_DPRINTF(fmt, args...)
-#endif
-#ifdef DEBUG_MOUSE
-#define MS_DPRINTF(fmt, args...) \
-do { printf("SER: " fmt , ##args); } while (0)
-#else
-#define MS_DPRINTF(fmt, args...)
-#endif
-
-typedef enum {
- chn_a, chn_b,
-} chn_id_t;
-
-typedef enum {
- ser, kbd, mouse,
-} chn_type_t;
-
-#define KBD_QUEUE_SIZE 256
-
-typedef struct {
- uint8_t data[KBD_QUEUE_SIZE];
- int rptr, wptr, count;
-} KBDQueue;
-
-typedef struct ChannelState {
- int irq;
- int reg;
- int rxint, txint;
- chn_id_t chn; // this channel, A (base+4) or B (base+0)
- chn_type_t type;
- struct ChannelState *otherchn;
- uint8_t rx, tx, wregs[16], rregs[16];
- KBDQueue queue;
- CharDriverState *chr;
-} ChannelState;
-
-struct SerialState {
- struct ChannelState chn[2];
-};
-
-#define SERIAL_MAXADDR 7
-
-static void handle_kbd_command(ChannelState *s, int val);
-static int serial_can_receive(void *opaque);
-static void serial_receive_byte(ChannelState *s, int ch);
-
-static void put_queue(void *opaque, int b)
-{
- ChannelState *s = opaque;
- KBDQueue *q = &s->queue;
-
- KBD_DPRINTF("put: 0x%02x\n", b);
- if (q->count >= KBD_QUEUE_SIZE)
- return;
- q->data[q->wptr] = b;
- if (++q->wptr == KBD_QUEUE_SIZE)
- q->wptr = 0;
- q->count++;
- serial_receive_byte(s, 0);
-}
-
-static uint32_t get_queue(void *opaque)
-{
- ChannelState *s = opaque;
- KBDQueue *q = &s->queue;
- int val;
-
- if (q->count == 0) {
- return 0;
- } else {
- val = q->data[q->rptr];
- if (++q->rptr == KBD_QUEUE_SIZE)
- q->rptr = 0;
- q->count--;
- }
- KBD_DPRINTF("get 0x%02x\n", val);
- if (q->count > 0)
- serial_receive_byte(s, 0);
- return val;
-}
-
-static void slavio_serial_update_irq(ChannelState *s)
-{
- if ((s->wregs[1] & 1) && // interrupts enabled
- (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending
- ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) &&
- s->rxint == 1) || // rx ints enabled, pending
- ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p
- pic_set_irq(s->irq, 1);
- } else {
- pic_set_irq(s->irq, 0);
- }
-}
-
-static void slavio_serial_reset_chn(ChannelState *s)
-{
- int i;
-
- s->reg = 0;
- for (i = 0; i < SERIAL_MAXADDR; i++) {
- s->rregs[i] = 0;
- s->wregs[i] = 0;
- }
- s->wregs[4] = 4;
- s->wregs[9] = 0xc0;
- s->wregs[11] = 8;
- s->wregs[14] = 0x30;
- s->wregs[15] = 0xf8;
- s->rregs[0] = 0x44;
- s->rregs[1] = 6;
-
- s->rx = s->tx = 0;
- s->rxint = s->txint = 0;
-}
-
-static void slavio_serial_reset(void *opaque)
-{
- SerialState *s = opaque;
- slavio_serial_reset_chn(&s->chn[0]);
- slavio_serial_reset_chn(&s->chn[1]);
-}
-
-static inline void clr_rxint(ChannelState *s)
-{
- s->rxint = 0;
- if (s->chn == 0)
- s->rregs[3] &= ~0x20;
- else {
- s->otherchn->rregs[3] &= ~4;
- }
- slavio_serial_update_irq(s);
-}
-
-static inline void set_rxint(ChannelState *s)
-{
- s->rxint = 1;
- if (s->chn == 0)
- 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;
- if (s->chn == 0)
- s->rregs[3] &= ~0x10;
- else {
- s->otherchn->rregs[3] &= ~2;
- }
- slavio_serial_update_irq(s);
-}
-
-static inline void set_txint(ChannelState *s)
-{
- s->txint = 1;
- if (s->chn == 0)
- s->rregs[3] |= 0x10;
- else {
- s->otherchn->rregs[3] |= 2;
- }
- slavio_serial_update_irq(s);
-}
-
-static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- SerialState *ser = opaque;
- ChannelState *s;
- uint32_t saddr;
- int newreg, channel;
-
- val &= 0xff;
- saddr = (addr & 3) >> 1;
- channel = (addr & SERIAL_MAXADDR) >> 2;
- s = &ser->chn[channel];
- switch (saddr) {
- case 0:
- SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff);
- newreg = 0;
- switch (s->reg) {
- case 0:
- newreg = val & 7;
- val &= 0x38;
- switch (val) {
- case 8:
- newreg |= 0x8;
- break;
- case 0x20:
- clr_rxint(s);
- break;
- case 0x28:
- clr_txint(s);
- break;
- case 0x38:
- clr_rxint(s);
- clr_txint(s);
- break;
- default:
- break;
- }
- break;
- case 1 ... 8:
- case 10 ... 15:
- s->wregs[s->reg] = val;
- break;
- case 9:
- switch (val & 0xc0) {
- case 0:
- default:
- break;
- case 0x40:
- slavio_serial_reset_chn(&ser->chn[1]);
- return;
- case 0x80:
- slavio_serial_reset_chn(&ser->chn[0]);
- return;
- case 0xc0:
- slavio_serial_reset(ser);
- return;
- }
- break;
- default:
- break;
- }
- if (s->reg == 0)
- s->reg = newreg;
- else
- s->reg = 0;
- break;
- case 1:
- SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val);
- if (s->wregs[5] & 8) { // tx enabled
- s->tx = val;
- if (s->chr)
- qemu_chr_write(s->chr, &s->tx, 1);
- else if (s->type == kbd) {
- handle_kbd_command(s, val);
- }
- s->txint = 1;
- s->rregs[0] |= 4; // Tx buffer empty
- s->rregs[1] |= 1; // All sent
- set_txint(s);
- slavio_serial_update_irq(s);
- }
- break;
- default:
- break;
- }
-}
-
-static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
-{
- SerialState *ser = opaque;
- ChannelState *s;
- uint32_t saddr;
- uint32_t ret;
- int channel;
-
- saddr = (addr & 3) >> 1;
- channel = (addr & SERIAL_MAXADDR) >> 2;
- s = &ser->chn[channel];
- switch (saddr) {
- case 0:
- SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]);
- ret = s->rregs[s->reg];
- s->reg = 0;
- return ret;
- case 1:
- s->rregs[0] &= ~1;
- clr_rxint(s);
- if (s->type == kbd)
- ret = get_queue(s);
- else
- ret = s->rx;
- SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', ret);
- return ret;
- default:
- break;
- }
- return 0;
-}
-
-static int serial_can_receive(void *opaque)
-{
- ChannelState *s = opaque;
- if (((s->wregs[3] & 1) == 0) // Rx not enabled
- || ((s->rregs[0] & 1) == 1)) // char already available
- return 0;
- else
- return 1;
-}
-
-static void serial_receive_byte(ChannelState *s, int ch)
-{
- SER_DPRINTF("put ch %d\n", ch);
- s->rregs[0] |= 1;
- s->rx = ch;
- set_rxint(s);
-}
-
-static void serial_receive_break(ChannelState *s)
-{
- s->rregs[0] |= 0x80;
- slavio_serial_update_irq(s);
-}
-
-static void serial_receive1(void *opaque, const uint8_t *buf, int size)
-{
- ChannelState *s = opaque;
- serial_receive_byte(s, buf[0]);
-}
-
-static void serial_event(void *opaque, int event)
-{
- ChannelState *s = opaque;
- if (event == CHR_EVENT_BREAK)
- serial_receive_break(s);
-}
-
-static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
- slavio_serial_mem_readb,
- slavio_serial_mem_readb,
- slavio_serial_mem_readb,
-};
-
-static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
- slavio_serial_mem_writeb,
- slavio_serial_mem_writeb,
- slavio_serial_mem_writeb,
-};
-
-static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
-{
- qemu_put_be32s(f, &s->irq);
- qemu_put_be32s(f, &s->reg);
- qemu_put_be32s(f, &s->rxint);
- qemu_put_be32s(f, &s->txint);
- qemu_put_8s(f, &s->rx);
- qemu_put_8s(f, &s->tx);
- qemu_put_buffer(f, s->wregs, 16);
- qemu_put_buffer(f, s->rregs, 16);
-}
-
-static void slavio_serial_save(QEMUFile *f, void *opaque)
-{
- SerialState *s = opaque;
-
- slavio_serial_save_chn(f, &s->chn[0]);
- slavio_serial_save_chn(f, &s->chn[1]);
-}
-
-static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
-{
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_be32s(f, &s->irq);
- qemu_get_be32s(f, &s->reg);
- qemu_get_be32s(f, &s->rxint);
- qemu_get_be32s(f, &s->txint);
- qemu_get_8s(f, &s->rx);
- qemu_get_8s(f, &s->tx);
- qemu_get_buffer(f, s->wregs, 16);
- qemu_get_buffer(f, s->rregs, 16);
- return 0;
-}
-
-static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id)
-{
- SerialState *s = opaque;
- int ret;
-
- ret = slavio_serial_load_chn(f, &s->chn[0], version_id);
- if (ret != 0)
- return ret;
- ret = slavio_serial_load_chn(f, &s->chn[1], version_id);
- return ret;
-
-}
-
-SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2)
-{
- int slavio_serial_io_memory, i;
- SerialState *s;
-
- s = qemu_mallocz(sizeof(SerialState));
- if (!s)
- return NULL;
-
- slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
- cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
-
- s->chn[0].chr = chr1;
- s->chn[1].chr = chr2;
-
- for (i = 0; i < 2; i++) {
- s->chn[i].irq = irq;
- 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);
- }
- }
- s->chn[0].otherchn = &s->chn[1];
- s->chn[1].otherchn = &s->chn[0];
- register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s);
- qemu_register_reset(slavio_serial_reset, s);
- slavio_serial_reset(s);
- return s;
-}
-
-static const uint8_t keycodes[128] = {
- 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
- 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
- 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
- 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
- 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
- 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
- 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
- 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
-};
-
-static void sunkbd_event(void *opaque, int ch)
-{
- ChannelState *s = opaque;
- int release = ch & 0x80;
-
- ch = keycodes[ch & 0x7f];
- KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press");
- put_queue(s, ch | release);
-}
-
-static void handle_kbd_command(ChannelState *s, int val)
-{
- KBD_DPRINTF("Command %d\n", val);
- switch (val) {
- case 1: // Reset, return type code
- put_queue(s, 0xff);
- put_queue(s, 5); // Type 5
- break;
- case 7: // Query layout
- put_queue(s, 0xfe);
- put_queue(s, 0x20); // XXX, layout?
- break;
- default:
- break;
- }
-}
-
-static void sunmouse_event(void *opaque,
- int dx, int dy, int dz, int buttons_state)
-{
- ChannelState *s = opaque;
- int ch;
-
- // XXX
- ch = 0x42;
- serial_receive_byte(s, ch);
-}
-
-void slavio_serial_ms_kbd_init(int base, int irq)
-{
- int slavio_serial_io_memory, i;
- SerialState *s;
-
- s = qemu_mallocz(sizeof(SerialState));
- if (!s)
- return;
- for (i = 0; i < 2; i++) {
- s->chn[i].irq = irq;
- s->chn[i].chn = 1 - i;
- s->chn[i].chr = NULL;
- }
- s->chn[0].otherchn = &s->chn[1];
- s->chn[1].otherchn = &s->chn[0];
- s->chn[0].type = mouse;
- s->chn[1].type = kbd;
-
- slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
- cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
-
- qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0);
- qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
- qemu_register_reset(slavio_serial_reset, s);
- slavio_serial_reset(s);
-}
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
deleted file mode 100644
index 976f0d4..0000000
--- a/hw/slavio_timer.c
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * QEMU Sparc SLAVIO timer controller emulation
- *
- * Copyright (c) 2003-2005 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"
-
-//#define DEBUG_TIMER
-
-#ifdef DEBUG_TIMER
-#define DPRINTF(fmt, args...) \
-do { printf("TIMER: " fmt , ##args); } while (0)
-#else
-#define DPRINTF(fmt, args...)
-#endif
-
-/*
- * Registers of hardware timer in sun4m.
- *
- * This is the timer/counter part of chip STP2001 (Slave I/O), also
- * produced as NCR89C105. See
- * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
- *
- * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
- * are zero. Bit 31 is 1 when count has been reached.
- *
- * Per-CPU timers interrupt local CPU, system timer uses normal
- * interrupt routing.
- *
- */
-
-typedef struct SLAVIO_TIMERState {
- uint32_t limit, count, counthigh;
- int64_t count_load_time;
- int64_t expire_time;
- int64_t stop_time, tick_offset;
- QEMUTimer *irq_timer;
- int irq;
- int reached, stopped;
- int mode; // 0 = processor, 1 = user, 2 = system
- unsigned int cpu;
-} SLAVIO_TIMERState;
-
-#define TIMER_MAXADDR 0x1f
-#define CNT_FREQ 2000000
-
-// Update count, set irq, update expire_time
-static void slavio_timer_get_out(SLAVIO_TIMERState *s)
-{
- int out;
- int64_t diff, ticks, count;
- uint32_t limit;
-
- // There are three clock tick units: CPU ticks, register units
- // (nanoseconds), and counter ticks (500 ns).
- if (s->mode == 1 && s->stopped)
- ticks = s->stop_time;
- else
- ticks = qemu_get_clock(vm_clock) - s->tick_offset;
-
- out = (ticks > s->expire_time);
- if (out)
- s->reached = 0x80000000;
- if (!s->limit)
- limit = 0x7fffffff;
- else
- limit = s->limit;
-
- // Convert register units to counter ticks
- limit = limit >> 9;
-
- // Convert cpu ticks to counter ticks
- diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec);
-
- // Calculate what the counter should be, convert to register
- // units
- count = diff % limit;
- s->count = count << 9;
- s->counthigh = count >> 22;
-
- // Expire time: CPU ticks left to next interrupt
- // Convert remaining counter ticks to CPU ticks
- s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ);
-
- 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);
-}
-
-// timer callback
-static void slavio_timer_irq(void *opaque)
-{
- SLAVIO_TIMERState *s = opaque;
-
- if (!s->irq_timer)
- return;
- slavio_timer_get_out(s);
- if (s->mode != 1)
- qemu_mod_timer(s->irq_timer, s->expire_time);
-}
-
-static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- SLAVIO_TIMERState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & TIMER_MAXADDR) >> 2;
- switch (saddr) {
- case 0:
- // read limit (system counter mode) or read most signifying
- // 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);
- s->reached = 0;
- return s->limit;
- }
- else {
- slavio_timer_get_out(s);
- return s->counthigh & 0x7fffffff;
- }
- case 1:
- // read counter and reached bit (system mode) or read lsbits
- // of counter (user mode)
- slavio_timer_get_out(s);
- if (s->mode != 1)
- return (s->count & 0x7fffffff) | s->reached;
- else
- return s->count;
- case 3:
- // read start/stop status
- return s->stopped;
- case 4:
- // read user/system mode
- return s->mode & 1;
- default:
- return 0;
- }
-}
-
-static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- SLAVIO_TIMERState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & TIMER_MAXADDR) >> 2;
- switch (saddr) {
- case 0:
- // set limit, reset counter
- s->count_load_time = qemu_get_clock(vm_clock);
- // fall through
- case 2:
- // set limit without resetting counter
- if (!val)
- s->limit = 0x7fffffff;
- else
- s->limit = val & 0x7fffffff;
- slavio_timer_irq(s);
- break;
- case 3:
- // start/stop user counter
- if (s->mode == 1) {
- if (val & 1) {
- s->stop_time = qemu_get_clock(vm_clock);
- s->stopped = 1;
- }
- else {
- if (s->stopped)
- s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time;
- s->stopped = 0;
- }
- }
- break;
- case 4:
- // bit 0: user (1) or system (0) counter mode
- if (s->mode == 0 || s->mode == 1)
- s->mode = val & 1;
- break;
- default:
- break;
- }
-}
-
-static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
- slavio_timer_mem_readl,
- slavio_timer_mem_readl,
- slavio_timer_mem_readl,
-};
-
-static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
- slavio_timer_mem_writel,
- slavio_timer_mem_writel,
- slavio_timer_mem_writel,
-};
-
-static void slavio_timer_save(QEMUFile *f, void *opaque)
-{
- SLAVIO_TIMERState *s = opaque;
-
- qemu_put_be32s(f, &s->limit);
- qemu_put_be32s(f, &s->count);
- qemu_put_be32s(f, &s->counthigh);
- qemu_put_be64s(f, &s->count_load_time);
- qemu_put_be64s(f, &s->expire_time);
- qemu_put_be64s(f, &s->stop_time);
- qemu_put_be64s(f, &s->tick_offset);
- qemu_put_be32s(f, &s->irq);
- qemu_put_be32s(f, &s->reached);
- qemu_put_be32s(f, &s->stopped);
- qemu_put_be32s(f, &s->mode);
-}
-
-static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
-{
- SLAVIO_TIMERState *s = opaque;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_be32s(f, &s->limit);
- qemu_get_be32s(f, &s->count);
- qemu_get_be32s(f, &s->counthigh);
- qemu_get_be64s(f, &s->count_load_time);
- qemu_get_be64s(f, &s->expire_time);
- qemu_get_be64s(f, &s->stop_time);
- qemu_get_be64s(f, &s->tick_offset);
- qemu_get_be32s(f, &s->irq);
- qemu_get_be32s(f, &s->reached);
- qemu_get_be32s(f, &s->stopped);
- qemu_get_be32s(f, &s->mode);
- return 0;
-}
-
-static void slavio_timer_reset(void *opaque)
-{
- SLAVIO_TIMERState *s = opaque;
-
- s->limit = 0;
- s->count = 0;
- s->count_load_time = qemu_get_clock(vm_clock);;
- s->stop_time = s->count_load_time;
- s->tick_offset = 0;
- s->reached = 0;
- s->mode &= 2;
- s->stopped = 1;
- slavio_timer_get_out(s);
-}
-
-void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu)
-{
- int slavio_timer_io_memory;
- SLAVIO_TIMERState *s;
-
- s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
- if (!s)
- return;
- s->irq = irq;
- s->mode = mode;
- s->cpu = cpu;
- s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
-
- slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
- slavio_timer_mem_write, s);
- cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory);
- register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s);
- qemu_register_reset(slavio_timer_reset, s);
- slavio_timer_reset(s);
-}
diff --git a/hw/smc91c111.c b/hw/smc91c111.c
index 214e92e..28b5c5d 100644
--- a/hw/smc91c111.c
+++ b/hw/smc91c111.c
@@ -8,6 +8,7 @@
*/
#include "vl.h"
+#include "irq.h"
/* For crc32 */
#include <zlib.h>
@@ -24,8 +25,7 @@ typedef struct {
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 +86,7 @@ static void smc91c111_update(smc91c111_state *s)
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. */
@@ -159,7 +159,6 @@ static void smc91c111_do_tx(smc91c111_state *s)
int len;
int control;
int add_crc;
- uint32_t crc;
int packetnum;
uint8_t *p;
@@ -192,7 +191,7 @@ static void smc91c111_do_tx(smc91c111_state *s)
about. */
add_crc = (control & 0x10) || (s->tcr & TCR_NOCRC) == 0;
if (add_crc) {
- crc = crc32(~0, p, len);
+ uint32_t crc = crc32(~0, p, len);
memcpy(p + len, &crc, 4);
len += 4;
}
@@ -692,7 +691,7 @@ static CPUWriteMemoryFunc *smc91c111_writefn[] = {
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;
@@ -702,7 +701,6 @@ void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq)
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);
diff --git a/hw/sun4m.c b/hw/sun4m.c
deleted file mode 100644
index 203732f..0000000
--- a/hw/sun4m.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * QEMU Sun4m System Emulator
- *
- * Copyright (c) 2003-2005 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"
-
-#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_ESPDMA 0x78400000 /* ESP DMA controller */
-#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */
-#define PHYS_JJ_ESP_IRQ 18
-#define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */
-#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 MAX_CPUS 16
-
-/* TSC handling */
-
-uint64_t cpu_get_tsc()
-{
- return qemu_get_clock(vm_clock);
-}
-
-int DMA_get_channel_mode (int nchan)
-{
- return 0;
-}
-int DMA_read_memory (int nchan, void *buf, int pos, int size)
-{
- return 0;
-}
-int DMA_write_memory (int nchan, void *buf, int pos, int size)
-{
- return 0;
-}
-void DMA_hold_DREQ (int nchan) {}
-void DMA_release_DREQ (int nchan) {}
-void DMA_schedule(int nchan) {}
-void DMA_run (void) {}
-void DMA_init (int high_page_enable) {}
-void DMA_register_channel (int nchan,
- DMA_transfer_handler transfer_handler,
- void *opaque)
-{
-}
-
-static void nvram_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
-{
- m48t59_write(nvram, addr++, (value >> 8) & 0xff);
- m48t59_write(nvram, addr++, value & 0xff);
-}
-
-static void nvram_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
-{
- m48t59_write(nvram, addr++, value >> 24);
- m48t59_write(nvram, addr++, (value >> 16) & 0xff);
- m48t59_write(nvram, addr++, (value >> 8) & 0xff);
- m48t59_write(nvram, addr++, value & 0xff);
-}
-
-static void nvram_set_string (m48t59_t *nvram, uint32_t addr,
- const unsigned char *str, uint32_t max)
-{
- unsigned int i;
-
- for (i = 0; i < max && str[i] != '\0'; i++) {
- m48t59_write(nvram, addr + i, str[i]);
- }
- m48t59_write(nvram, addr + max - 1, '\0');
-}
-
-static m48t59_t *nvram;
-
-extern int nographic;
-
-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)
-{
- unsigned char tmp = 0;
- int i, j;
-
- // Try to match PPC NVRAM
- nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
- nvram_set_lword(nvram, 0x10, 0x00000001); /* structure v1 */
- // NVRAM_size, arch not applicable
- m48t59_write(nvram, 0x2D, smp_cpus & 0xff);
- m48t59_write(nvram, 0x2E, 0);
- m48t59_write(nvram, 0x2F, nographic & 0xff);
- nvram_set_lword(nvram, 0x30, RAM_size);
- m48t59_write(nvram, 0x34, boot_device & 0xff);
- nvram_set_lword(nvram, 0x38, KERNEL_LOAD_ADDR);
- nvram_set_lword(nvram, 0x3C, kernel_size);
- if (cmdline) {
- strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
- nvram_set_lword(nvram, 0x40, CMDLINE_ADDR);
- nvram_set_lword(nvram, 0x44, strlen(cmdline));
- }
- // initrd_image, initrd_size passed differently
- nvram_set_word(nvram, 0x54, width);
- nvram_set_word(nvram, 0x56, height);
- nvram_set_word(nvram, 0x58, depth);
-
- // Sun4m specific use
- i = 0x1fd8;
- m48t59_write(nvram, i++, 0x01);
- m48t59_write(nvram, i++, 0x80); /* Sun4m OBP */
- j = 0;
- m48t59_write(nvram, i++, macaddr[j++]);
- m48t59_write(nvram, i++, macaddr[j++]);
- m48t59_write(nvram, i++, macaddr[j++]);
- m48t59_write(nvram, i++, macaddr[j++]);
- m48t59_write(nvram, i++, macaddr[j++]);
- m48t59_write(nvram, i, macaddr[j]);
-
- /* Calculate checksum */
- for (i = 0x1fd8; i < 0x1fe7; i++) {
- tmp ^= m48t59_read(nvram, i);
- }
- m48t59_write(nvram, 0x1fe7, tmp);
-}
-
-static void *slavio_intctl;
-
-void pic_info()
-{
- slavio_pic_info(slavio_intctl);
-}
-
-void irq_info()
-{
- 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 *iommu;
-
-uint32_t iommu_translate(uint32_t addr)
-{
- return iommu_translate_local(iommu, addr);
-}
-
-static void *slavio_misc;
-
-void qemu_system_powerdown(void)
-{
- slavio_set_power_fail(slavio_misc, 1);
-}
-
-static void main_cpu_reset(void *opaque)
-{
- CPUState *env = opaque;
- 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)
-{
- 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;
-
- linux_boot = (kernel_filename != NULL);
-
- /* init CPUs */
- for(i = 0; i < smp_cpus; i++) {
- env = cpu_init();
- envs[i] = env;
- if (i != 0)
- env->halted = 1;
- register_savevm("cpu", i, 3, cpu_save, cpu_load, env);
- qemu_register_reset(main_cpu_reset, env);
- }
- /* 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);
- for(i = 0; i < smp_cpus; i++) {
- slavio_intctl_set_cpu(slavio_intctl, i, envs[i]);
- }
-
- tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height);
- if (nd_table[0].vlan) {
- if (nd_table[0].model == NULL
- || strcmp(nd_table[0].model, "lance") == 0) {
- lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA);
- } 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);
- 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(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 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);
- esp_init(bs_table, PHYS_JJ_ESP_IRQ, PHYS_JJ_ESP, PHYS_JJ_ESPDMA);
- slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ);
-
- 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);
- if (ret < 0) {
- fprintf(stderr, "qemu: could not load prom '%s'\n",
- buf);
- exit(1);
- }
-
- kernel_size = 0;
- if (linux_boot) {
- kernel_size = load_elf(kernel_filename, -0xf0000000, NULL);
- if (kernel_size < 0)
- kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
- if (kernel_size < 0)
- kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
-
- /* load initrd */
- initrd_size = 0;
- 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 initial ram disk '%s'\n",
- initrd_filename);
- exit(1);
- }
- }
- if (initrd_size > 0) {
- for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
- if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
- == 0x48647253) { // HdrS
- stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
- stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
- break;
- }
- }
- }
- }
- nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth);
-}
-
-QEMUMachine sun4m_machine = {
- "sun4m",
- "Sun4m platform",
- sun4m_init,
-};
diff --git a/hw/sun4u.c b/hw/sun4u.c
deleted file mode 100644
index 6d41369..0000000
--- a/hw/sun4u.c
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * QEMU Sun4u System Emulator
- *
- * Copyright (c) 2005 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"
-#include "m48t59.h"
-
-#define KERNEL_LOAD_ADDR 0x00404000
-#define CMDLINE_ADDR 0x003ff000
-#define INITRD_LOAD_ADDR 0x00300000
-#define PROM_SIZE_MAX (512 * 1024)
-#define PROM_ADDR 0x1fff0000000ULL
-#define APB_SPECIAL_BASE 0x1fe00000000ULL
-#define APB_MEM_BASE 0x1ff00000000ULL
-#define VGA_BASE (APB_MEM_BASE + 0x400000ULL)
-#define PROM_FILENAME "openbios-sparc64"
-#define NVRAM_SIZE 0x2000
-
-/* TSC handling */
-
-uint64_t cpu_get_tsc()
-{
- return qemu_get_clock(vm_clock);
-}
-
-int DMA_get_channel_mode (int nchan)
-{
- return 0;
-}
-int DMA_read_memory (int nchan, void *buf, int pos, int size)
-{
- return 0;
-}
-int DMA_write_memory (int nchan, void *buf, int pos, int size)
-{
- return 0;
-}
-void DMA_hold_DREQ (int nchan) {}
-void DMA_release_DREQ (int nchan) {}
-void DMA_schedule(int nchan) {}
-void DMA_run (void) {}
-void DMA_init (int high_page_enable) {}
-void DMA_register_channel (int nchan,
- DMA_transfer_handler transfer_handler,
- void *opaque)
-{
-}
-
-/* NVRAM helpers */
-void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value)
-{
- m48t59_write(nvram, addr, value);
-}
-
-uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr)
-{
- return m48t59_read(nvram, addr);
-}
-
-void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value)
-{
- m48t59_write(nvram, addr, value >> 8);
- m48t59_write(nvram, addr + 1, value & 0xFF);
-}
-
-uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr)
-{
- uint16_t tmp;
-
- tmp = m48t59_read(nvram, addr) << 8;
- tmp |= m48t59_read(nvram, addr + 1);
-
- return tmp;
-}
-
-void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value)
-{
- m48t59_write(nvram, addr, value >> 24);
- m48t59_write(nvram, addr + 1, (value >> 16) & 0xFF);
- m48t59_write(nvram, addr + 2, (value >> 8) & 0xFF);
- m48t59_write(nvram, addr + 3, value & 0xFF);
-}
-
-uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr)
-{
- uint32_t tmp;
-
- tmp = m48t59_read(nvram, addr) << 24;
- tmp |= m48t59_read(nvram, addr + 1) << 16;
- tmp |= m48t59_read(nvram, addr + 2) << 8;
- tmp |= m48t59_read(nvram, addr + 3);
-
- return tmp;
-}
-
-void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
- const unsigned char *str, uint32_t max)
-{
- int i;
-
- for (i = 0; i < max && str[i] != '\0'; i++) {
- m48t59_write(nvram, addr + i, str[i]);
- }
- m48t59_write(nvram, addr + max - 1, '\0');
-}
-
-int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max)
-{
- int i;
-
- memset(dst, 0, max);
- for (i = 0; i < max; i++) {
- dst[i] = NVRAM_get_byte(nvram, addr + i);
- if (dst[i] == '\0')
- break;
- }
-
- return i;
-}
-
-static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
-{
- uint16_t tmp;
- uint16_t pd, pd1, pd2;
-
- tmp = prev >> 8;
- pd = prev ^ value;
- pd1 = pd & 0x000F;
- pd2 = ((pd >> 4) & 0x000F) ^ pd1;
- tmp ^= (pd1 << 3) | (pd1 << 8);
- tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
-
- return tmp;
-}
-
-uint16_t NVRAM_compute_crc (m48t59_t *nvram, uint32_t start, uint32_t count)
-{
- uint32_t i;
- uint16_t crc = 0xFFFF;
- int odd;
-
- odd = count & 1;
- count &= ~1;
- for (i = 0; i != count; 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);
- }
-
- return crc;
-}
-
-extern int nographic;
-
-int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
- const unsigned char *arch,
- uint32_t RAM_size, int boot_device,
- uint32_t kernel_image, uint32_t kernel_size,
- const char *cmdline,
- uint32_t initrd_image, uint32_t initrd_size,
- uint32_t NVRAM_image,
- int width, int height, int depth)
-{
- uint16_t crc;
-
- /* Set parameters for Open Hack'Ware BIOS */
- NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
- NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
- NVRAM_set_word(nvram, 0x14, NVRAM_size);
- NVRAM_set_string(nvram, 0x20, arch, 16);
- NVRAM_set_byte(nvram, 0x2f, nographic & 0xff);
- NVRAM_set_lword(nvram, 0x30, RAM_size);
- NVRAM_set_byte(nvram, 0x34, boot_device);
- NVRAM_set_lword(nvram, 0x38, kernel_image);
- NVRAM_set_lword(nvram, 0x3C, kernel_size);
- if (cmdline) {
- /* XXX: put the cmdline in NVRAM too ? */
- strcpy(phys_ram_base + CMDLINE_ADDR, cmdline);
- NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
- NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
- } else {
- NVRAM_set_lword(nvram, 0x40, 0);
- NVRAM_set_lword(nvram, 0x44, 0);
- }
- NVRAM_set_lword(nvram, 0x48, initrd_image);
- NVRAM_set_lword(nvram, 0x4C, initrd_size);
- NVRAM_set_lword(nvram, 0x50, NVRAM_image);
-
- NVRAM_set_word(nvram, 0x54, width);
- NVRAM_set_word(nvram, 0x56, height);
- NVRAM_set_word(nvram, 0x58, depth);
- crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
- NVRAM_set_word(nvram, 0xFC, crc);
-
- return 0;
-}
-
-void pic_info()
-{
-}
-
-void irq_info()
-{
-}
-
-void pic_set_irq(int irq, int level)
-{
-}
-
-void pic_set_irq_new(void *opaque, int irq, int level)
-{
-}
-
-void qemu_system_powerdown(void)
-{
-}
-
-static void main_cpu_reset(void *opaque)
-{
- CPUState *env = opaque;
- cpu_reset(env);
-}
-
-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 const int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
-static const int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 };
-
-static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc };
-static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
-
-static fdctrl_t *floppy_controller;
-
-/* Sun4u hardware initialisation */
-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)
-{
- CPUState *env;
- char buf[1024];
- m48t59_t *nvram;
- int ret, linux_boot;
- unsigned int i;
- long prom_offset, initrd_size, kernel_size;
- PCIBus *pci_bus;
-
- linux_boot = (kernel_filename != NULL);
-
- env = cpu_init();
- 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, 0);
-
- prom_offset = ram_size + vga_ram_size;
- cpu_register_physical_memory(PROM_ADDR,
- (PROM_SIZE_MAX + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
- prom_offset | IO_MEM_ROM);
-
- snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
- ret = load_elf(buf, 0, NULL);
- if (ret < 0) {
- fprintf(stderr, "qemu: could not load prom '%s'\n",
- buf);
- exit(1);
- }
-
- kernel_size = 0;
- initrd_size = 0;
- if (linux_boot) {
- /* XXX: put correct offset */
- kernel_size = load_elf(kernel_filename, 0, NULL);
- if (kernel_size < 0)
- kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
- if (kernel_size < 0)
- kernel_size = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
- if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
- exit(1);
- }
-
- /* load initrd */
- 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 initial ram disk '%s'\n",
- initrd_filename);
- exit(1);
- }
- }
- if (initrd_size > 0) {
- for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
- if (ldl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i)
- == 0x48647253) { // HdrS
- stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 16, INITRD_LOAD_ADDR);
- stl_raw(phys_ram_base + KERNEL_LOAD_ADDR + i + 20, initrd_size);
- break;
- }
- }
- }
- }
- pci_bus = pci_apb_init(APB_SPECIAL_BASE, APB_MEM_BASE, NULL);
- isa_mem_base = VGA_BASE;
- pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size, vga_ram_size);
-
- 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]);
- }
- }
-
- for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
- if (parallel_hds[i]) {
- parallel_init(parallel_io[i], 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_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);
- sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device,
- KERNEL_LOAD_ADDR, kernel_size,
- kernel_cmdline,
- INITRD_LOAD_ADDR, initrd_size,
- /* XXX: need an option to load a NVRAM image */
- 0,
- graphic_width, graphic_height, graphic_depth);
-
-}
-
-QEMUMachine sun4u_machine = {
- "sun4u",
- "Sun4u platform",
- sun4u_init,
-};
diff --git a/hw/tc58128.c b/hw/tc58128.c
deleted file mode 100644
index a8b26f7..0000000
--- a/hw/tc58128.c
+++ /dev/null
@@ -1,181 +0,0 @@
-#include <assert.h>
-#include "vl.h"
-
-#define CE1 0x0100
-#define CE2 0x0200
-#define RE 0x0400
-#define WE 0x0800
-#define ALE 0x1000
-#define CLE 0x2000
-#define RDY1 0x4000
-#define RDY2 0x8000
-#define RDY(n) ((n) == 0 ? RDY1 : RDY2)
-
-typedef enum { WAIT, READ1, READ2, READ3 } state_t;
-
-typedef struct {
- uint8_t *flash_contents;
- state_t state;
- uint32_t address;
- uint8_t address_cycle;
-} tc58128_dev;
-
-static tc58128_dev tc58128_devs[2];
-
-#define FLASH_SIZE (16*1024*1024)
-
-void init_dev(tc58128_dev * dev, char *filename)
-{
- int ret, blocks;
-
- dev->state = WAIT;
- dev->flash_contents = qemu_mallocz(FLASH_SIZE);
- memset(dev->flash_contents, 0xff, FLASH_SIZE);
- if (!dev->flash_contents) {
- fprintf(stderr, "could not alloc memory for flash\n");
- exit(1);
- }
- if (filename) {
- /* Load flash image skipping the first block */
- ret = load_image(filename, dev->flash_contents + 528 * 32);
- if (ret < 0) {
- fprintf(stderr, "ret=%d\n", ret);
- fprintf(stderr, "qemu: could not load flash image %s\n",
- filename);
- exit(1);
- } else {
- /* Build first block with number of blocks */
- blocks = (ret + 528 * 32 - 1) / (528 * 32);
- dev->flash_contents[0] = blocks & 0xff;
- dev->flash_contents[1] = (blocks >> 8) & 0xff;
- dev->flash_contents[2] = (blocks >> 16) & 0xff;
- dev->flash_contents[3] = (blocks >> 24) & 0xff;
- fprintf(stderr, "loaded %d bytes for %s into flash\n", ret,
- filename);
- }
- }
-}
-
-void handle_command(tc58128_dev * dev, uint8_t command)
-{
- switch (command) {
- case 0xff:
- fprintf(stderr, "reset flash device\n");
- dev->state = WAIT;
- break;
- case 0x00:
- fprintf(stderr, "read mode 1\n");
- dev->state = READ1;
- dev->address_cycle = 0;
- break;
- case 0x01:
- fprintf(stderr, "read mode 2\n");
- dev->state = READ2;
- dev->address_cycle = 0;
- break;
- case 0x50:
- fprintf(stderr, "read mode 3\n");
- dev->state = READ3;
- dev->address_cycle = 0;
- break;
- default:
- fprintf(stderr, "unknown flash command 0x%02x\n", command);
- assert(0);
- }
-}
-
-void handle_address(tc58128_dev * dev, uint8_t data)
-{
- switch (dev->state) {
- case READ1:
- case READ2:
- case READ3:
- switch (dev->address_cycle) {
- case 0:
- dev->address = data;
- if (dev->state == READ2)
- dev->address |= 0x100;
- else if (dev->state == READ3)
- dev->address |= 0x200;
- break;
- case 1:
- dev->address += data * 528 * 0x100;
- break;
- case 2:
- dev->address += data * 528;
- fprintf(stderr, "address pointer in flash: 0x%08x\n",
- dev->address);
- break;
- default:
- /* Invalid data */
- assert(0);
- }
- dev->address_cycle++;
- break;
- default:
- assert(0);
- }
-}
-
-uint8_t handle_read(tc58128_dev * dev)
-{
-#if 0
- if (dev->address % 0x100000 == 0)
- fprintf(stderr, "reading flash at address 0x%08x\n", dev->address);
-#endif
- return dev->flash_contents[dev->address++];
-}
-
-/* We never mark the device as busy, so interrupts cannot be triggered
- XXXXX */
-
-int tc58128_cb(uint16_t porta, uint16_t portb,
- uint16_t * periph_pdtra, uint16_t * periph_portadir,
- uint16_t * periph_pdtrb, uint16_t * periph_portbdir)
-{
- int dev;
-
- if ((porta & CE1) == 0)
- dev = 0;
- else if ((porta & CE2) == 0)
- dev = 1;
- else
- return 0; /* No device selected */
-
- if ((porta & RE) && (porta & WE)) {
- /* Nothing to do, assert ready and return to input state */
- *periph_portadir &= 0xff00;
- *periph_portadir |= RDY(dev);
- *periph_pdtra |= RDY(dev);
- return 1;
- }
-
- if (porta & CLE) {
- /* Command */
- assert((porta & WE) == 0);
- handle_command(&tc58128_devs[dev], porta & 0x00ff);
- } else if (porta & ALE) {
- assert((porta & WE) == 0);
- handle_address(&tc58128_devs[dev], porta & 0x00ff);
- } else if ((porta & RE) == 0) {
- *periph_portadir |= 0x00ff;
- *periph_pdtra &= 0xff00;
- *periph_pdtra |= handle_read(&tc58128_devs[dev]);
- } else {
- assert(0);
- }
- return 1;
-}
-
-static sh7750_io_device tc58128 = {
- RE | WE, /* Port A triggers */
- 0, /* Port B triggers */
- tc58128_cb /* Callback */
-};
-
-int tc58128_init(struct SH7750State *s, char *zone1, char *zone2)
-{
- init_dev(&tc58128_devs[0], zone1);
- init_dev(&tc58128_devs[1], zone2);
- return sh7750_register_io_device(s, &tc58128);
-}
diff --git a/hw/tcx.c b/hw/tcx.c
deleted file mode 100644
index a3a2114..0000000
--- a/hw/tcx.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * QEMU TCX Frame buffer
- *
- * Copyright (c) 2003-2005 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"
-
-#define MAXX 1024
-#define MAXY 768
-#define TCX_DAC_NREGS 16
-
-typedef struct TCXState {
- uint32_t addr;
- DisplayState *ds;
- uint8_t *vram;
- unsigned long vram_offset;
- uint16_t width, height;
- uint8_t r[256], g[256], b[256];
- uint8_t dac_index, dac_state;
-} TCXState;
-
-static void tcx_screen_dump(void *opaque, const char *filename);
-
-static void tcx_draw_line32(TCXState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int x;
- uint8_t val;
-
- for(x = 0; x < width; x++) {
- val = *s++;
- *d++ = s1->b[val];
- *d++ = s1->g[val];
- *d++ = s1->r[val];
- d++;
- }
-}
-
-static void tcx_draw_line24(TCXState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int x;
- uint8_t val;
-
- for(x = 0; x < width; x++) {
- val = *s++;
- *d++ = s1->b[val];
- *d++ = s1->g[val];
- *d++ = s1->r[val];
- }
-}
-
-static void tcx_draw_line8(TCXState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int x;
- uint8_t val;
-
- for(x = 0; x < width; x++) {
- val = *s++;
- /* XXX translate between palettes? */
- *d++ = val;
- }
-}
-
-/* Fixed line length 1024 allows us to do nice tricks not possible on
- VGA... */
-static void tcx_update_display(void *opaque)
-{
- TCXState *ts = opaque;
- uint32_t page;
- int y, page_min, page_max, y_start, dd, ds;
- uint8_t *d, *s;
- void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
-
- if (ts->ds->depth == 0)
- return;
- page = ts->vram_offset;
- y_start = -1;
- page_min = 0x7fffffff;
- page_max = -1;
- d = ts->ds->data;
- s = ts->vram;
- dd = ts->ds->linesize;
- ds = 1024;
-
- switch (ts->ds->depth) {
- case 32:
- f = tcx_draw_line32;
- break;
- case 24:
- f = tcx_draw_line24;
- break;
- default:
- case 8:
- f = tcx_draw_line8;
- break;
- case 0:
- return;
- }
-
- for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE) {
- if (cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG)) {
- if (y_start < 0)
- y_start = y;
- if (page < page_min)
- page_min = page;
- if (page > page_max)
- page_max = page;
- f(ts, d, s, ts->width);
- d += dd;
- s += ds;
- f(ts, d, s, ts->width);
- d += dd;
- s += ds;
- f(ts, d, s, ts->width);
- d += dd;
- s += ds;
- f(ts, d, s, ts->width);
- d += dd;
- s += 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;
- }
- }
- if (y_start >= 0) {
- /* flush to display */
- dpy_update(ts->ds, 0, y_start,
- ts->width, y - y_start);
- }
- /* reset modified pages */
- if (page_max != -1) {
- cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
- VGA_DIRTY_FLAG);
- }
-}
-
-static void tcx_invalidate_display(void *opaque)
-{
- TCXState *s = opaque;
- int i;
-
- for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
- cpu_physical_memory_set_dirty(s->vram_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_be16s(f, (uint16_t *)&s->height);
- qemu_put_be16s(f, (uint16_t *)&s->width);
- qemu_put_buffer(f, s->r, 256);
- qemu_put_buffer(f, s->g, 256);
- qemu_put_buffer(f, s->b, 256);
- qemu_put_8s(f, &s->dac_index);
- qemu_put_8s(f, &s->dac_state);
-}
-
-static int tcx_load(QEMUFile *f, void *opaque, int version_id)
-{
- TCXState *s = opaque;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_be32s(f, (uint32_t *)&s->addr);
- qemu_get_be32s(f, (uint32_t *)&s->vram);
- qemu_get_be16s(f, (uint16_t *)&s->height);
- qemu_get_be16s(f, (uint16_t *)&s->width);
- 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);
- return 0;
-}
-
-static void tcx_reset(void *opaque)
-{
- TCXState *s = opaque;
-
- /* Initialize palette */
- memset(s->r, 0, 256);
- memset(s->g, 0, 256);
- memset(s->b, 0, 256);
- s->r[255] = s->g[255] = s->b[255] = 255;
- memset(s->vram, 0, MAXX*MAXY);
- cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY,
- VGA_DIRTY_FLAG);
- s->dac_index = 0;
- s->dac_state = 0;
-}
-
-static uint32_t tcx_dac_readl(void *opaque, target_phys_addr_t addr)
-{
- return 0;
-}
-
-static void tcx_dac_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- TCXState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr & (TCX_DAC_NREGS - 1)) >> 2;
- switch (saddr) {
- case 0:
- s->dac_index = val >> 24;
- s->dac_state = 0;
- break;
- case 1:
- switch (s->dac_state) {
- case 0:
- s->r[s->dac_index] = val >> 24;
- s->dac_state++;
- break;
- case 1:
- s->g[s->dac_index] = val >> 24;
- s->dac_state++;
- break;
- case 2:
- s->b[s->dac_index] = val >> 24;
- default:
- s->dac_state = 0;
- break;
- }
- break;
- default:
- break;
- }
- return;
-}
-
-static CPUReadMemoryFunc *tcx_dac_read[3] = {
- tcx_dac_readl,
- tcx_dac_readl,
- tcx_dac_readl,
-};
-
-static CPUWriteMemoryFunc *tcx_dac_write[3] = {
- tcx_dac_writel,
- tcx_dac_writel,
- tcx_dac_writel,
-};
-
-void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
- unsigned long vram_offset, int vram_size, int width, int height)
-{
- TCXState *s;
- int io_memory;
-
- 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;
-
- cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset);
- 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);
-
- 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);
- dpy_resize(s->ds, width, height);
-}
-
-static void tcx_screen_dump(void *opaque, const char *filename)
-{
- TCXState *s = opaque;
- FILE *f;
- uint8_t *d, *d1, v;
- 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;
- for(y = 0; y < s->height; y++) {
- d = d1;
- for(x = 0; x < s->width; x++) {
- v = *d;
- fputc(s->r[v], f);
- fputc(s->g[v], f);
- fputc(s->b[v], f);
- d++;
- }
- d1 += MAXX;
- }
- fclose(f);
- return;
-}
-
-
-
diff --git a/hw/unin_pci.c b/hw/unin_pci.c
deleted file mode 100644
index a7e3600..0000000
--- a/hw/unin_pci.c
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * QEMU Uninorth PCI host (for all Mac99 and newer machines)
- *
- * Copyright (c) 2006 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "vl.h"
-typedef target_phys_addr_t pci_addr_t;
-#include "pci_host.h"
-
-typedef PCIHostState UNINState;
-
-static void pci_unin_main_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- UNINState *s = opaque;
- int i;
-
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- for (i = 11; i < 32; i++) {
- if ((val & (1 << i)) != 0)
- break;
- }
-#if 0
- s->config_reg = 0x80000000 | (1 << 16) | (val & 0x7FC) | (i << 11);
-#else
- s->config_reg = 0x80000000 | (0 << 16) | (val & 0x7FC) | (i << 11);
-#endif
-}
-
-static uint32_t pci_unin_main_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- UNINState *s = opaque;
- uint32_t val;
- int devfn;
-
- devfn = (s->config_reg >> 8) & 0xFF;
- val = (1 << (devfn >> 3)) | ((devfn & 0x07) << 8) | (s->config_reg & 0xFC);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_main_config_write[] = {
- &pci_unin_main_config_writel,
- &pci_unin_main_config_writel,
- &pci_unin_main_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_main_config_read[] = {
- &pci_unin_main_config_readl,
- &pci_unin_main_config_readl,
- &pci_unin_main_config_readl,
-};
-
-static CPUWriteMemoryFunc *pci_unin_main_write[] = {
- &pci_host_data_writeb,
- &pci_host_data_writew,
- &pci_host_data_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_main_read[] = {
- &pci_host_data_readb,
- &pci_host_data_readw,
- &pci_host_data_readl,
-};
-
-#if 0
-
-static void pci_unin_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- UNINState *s = opaque;
-
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- s->config_reg = 0x80000000 | (val & ~0x00000001);
-}
-
-static uint32_t pci_unin_config_readl (void *opaque,
- target_phys_addr_t addr)
-{
- UNINState *s = opaque;
- uint32_t val;
-
- val = (s->config_reg | 0x00000001) & ~0x80000000;
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
-
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_unin_config_write[] = {
- &pci_unin_config_writel,
- &pci_unin_config_writel,
- &pci_unin_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_config_read[] = {
- &pci_unin_config_readl,
- &pci_unin_config_readl,
- &pci_unin_config_readl,
-};
-
-static CPUWriteMemoryFunc *pci_unin_write[] = {
- &pci_host_pci_writeb,
- &pci_host_pci_writew,
- &pci_host_pci_writel,
-};
-
-static CPUReadMemoryFunc *pci_unin_read[] = {
- &pci_host_pci_readb,
- &pci_host_pci_readw,
- &pci_host_pci_readl,
-};
-#endif
-
-static void pci_unin_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
-{
- openpic_set_irq(pic, d->config[PCI_INTERRUPT_LINE], level);
-}
-
-PCIBus *pci_pmac_init(void *pic)
-{
- UNINState *s;
- PCIDevice *d;
- int pci_mem_config, pci_mem_data;
-
- /* Use values found on a real PowerMac */
- /* Uninorth main bus */
- s = qemu_mallocz(sizeof(UNINState));
- s->bus = pci_register_bus(pci_unin_set_irq, NULL, 11 << 3);
-
- pci_mem_config = cpu_register_io_memory(0, pci_unin_main_config_read,
- pci_unin_main_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_unin_main_read,
- pci_unin_main_write, s);
- cpu_register_physical_memory(0xf2800000, 0x1000, pci_mem_config);
- cpu_register_physical_memory(0xf2c00000, 0x1000, pci_mem_data);
- d = pci_register_device(s->bus, "Uni-north main", sizeof(PCIDevice),
- 11 << 3, NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x1F; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- d->config[0x34] = 0x00; // capabilities_pointer
-
-#if 0 // XXX: not activated as PPC BIOS doesn't handle mutiple buses properly
- /* pci-to-pci bridge */
- d = pci_register_device("Uni-north bridge", sizeof(PCIDevice), 0, 13 << 3,
- NULL, NULL);
- d->config[0x00] = 0x11; // vendor_id : TI
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x26; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x05; // revision
- d->config[0x0A] = 0x04; // class_sub = pci2pci
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x20; // latency_timer
- d->config[0x0E] = 0x01; // header_type
-
- d->config[0x18] = 0x01; // primary_bus
- d->config[0x19] = 0x02; // secondary_bus
- d->config[0x1A] = 0x02; // subordinate_bus
- d->config[0x1B] = 0x20; // secondary_latency_timer
- d->config[0x1C] = 0x11; // io_base
- d->config[0x1D] = 0x01; // io_limit
- d->config[0x20] = 0x00; // memory_base
- d->config[0x21] = 0x80;
- d->config[0x22] = 0x00; // memory_limit
- d->config[0x23] = 0x80;
- d->config[0x24] = 0x01; // prefetchable_memory_base
- d->config[0x25] = 0x80;
- d->config[0x26] = 0xF1; // prefectchable_memory_limit
- d->config[0x27] = 0x7F;
- // d->config[0x34] = 0xdc // capabilities_pointer
-#endif
-#if 0 // XXX: not needed for now
- /* Uninorth AGP bus */
- s = &pci_bridge[1];
- pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
- pci_unin_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
- pci_unin_write, s);
- cpu_register_physical_memory(0xf0800000, 0x1000, pci_mem_config);
- cpu_register_physical_memory(0xf0c00000, 0x1000, pci_mem_data);
-
- d = pci_register_device("Uni-north AGP", sizeof(PCIDevice), 0, 11 << 3,
- NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x20; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- // d->config[0x34] = 0x80; // capabilities_pointer
-#endif
-
-#if 0 // XXX: not needed for now
- /* Uninorth internal bus */
- s = &pci_bridge[2];
- pci_mem_config = cpu_register_io_memory(0, pci_unin_config_read,
- pci_unin_config_write, s);
- pci_mem_data = cpu_register_io_memory(0, pci_unin_read,
- pci_unin_write, s);
- cpu_register_physical_memory(0xf4800000, 0x1000, pci_mem_config);
- cpu_register_physical_memory(0xf4c00000, 0x1000, pci_mem_data);
-
- d = pci_register_device("Uni-north internal", sizeof(PCIDevice),
- 3, 11 << 3, NULL, NULL);
- d->config[0x00] = 0x6b; // vendor_id : Apple
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x1E; // device_id
- d->config[0x03] = 0x00;
- d->config[0x08] = 0x00; // revision
- d->config[0x0A] = 0x00; // class_sub = pci host
- d->config[0x0B] = 0x06; // class_base = PCI_bridge
- d->config[0x0C] = 0x08; // cache_line_size
- d->config[0x0D] = 0x10; // latency_timer
- d->config[0x0E] = 0x00; // header_type
- d->config[0x34] = 0x00; // capabilities_pointer
-#endif
- return s->bus;
-}
-
diff --git a/hw/usb-hid.c b/hw/usb-hid.c
index 8fc0b74..93f46db 100644
--- a/hw/usb-hid.c
+++ b/hw/usb-hid.c
@@ -323,10 +323,16 @@ static int usb_tablet_poll(USBMouseState *s, uint8_t *buf, int len)
return l;
}
-static void usb_mouse_handle_reset(USBDevice *dev)
+static void usb_mouse_handle_reset(USBDevice *dev, int destroy)
{
USBMouseState *s = (USBMouseState *)dev;
+ if (destroy) {
+ qemu_add_mouse_event_handler(NULL, NULL, 0);
+ qemu_free(s);
+ return;
+ }
+
s->dx = 0;
s->dy = 0;
s->dz = 0;
@@ -500,14 +506,6 @@ static int usb_mouse_handle_data(USBDevice *dev, int pid,
return ret;
}
-static void usb_mouse_handle_destroy(USBDevice *dev)
-{
- USBMouseState *s = (USBMouseState *)dev;
-
- qemu_add_mouse_event_handler(NULL, NULL, 0);
- qemu_free(s);
-}
-
USBDevice *usb_tablet_init(void)
{
USBMouseState *s;
@@ -521,7 +519,6 @@ USBDevice *usb_tablet_init(void)
s->dev.handle_reset = usb_mouse_handle_reset;
s->dev.handle_control = usb_mouse_handle_control;
s->dev.handle_data = usb_mouse_handle_data;
- s->dev.handle_destroy = usb_mouse_handle_destroy;
s->kind = USB_TABLET;
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Tablet");
@@ -542,7 +539,6 @@ USBDevice *usb_mouse_init(void)
s->dev.handle_reset = usb_mouse_handle_reset;
s->dev.handle_control = usb_mouse_handle_control;
s->dev.handle_data = usb_mouse_handle_data;
- s->dev.handle_destroy = usb_mouse_handle_destroy;
s->kind = USB_MOUSE;
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Mouse");
diff --git a/hw/usb-hub.c b/hw/usb-hub.c
index 8350931..2eba905 100644
--- a/hw/usb-hub.c
+++ b/hw/usb-hub.c
@@ -199,9 +199,11 @@ static void usb_hub_attach(USBPort *port1, USBDevice *dev)
}
}
-static void usb_hub_handle_reset(USBDevice *dev)
+static void usb_hub_handle_reset(USBDevice *dev, int destroy)
{
/* XXX: do it */
+ if (destroy)
+ qemu_free(dev);
}
static int usb_hub_handle_control(USBDevice *dev, int request, int value,
@@ -523,13 +525,6 @@ static int usb_hub_handle_packet(USBDevice *dev, int pid,
return usb_generic_handle_packet(dev, pid, devaddr, devep, data, len);
}
-static void usb_hub_handle_destroy(USBDevice *dev)
-{
- USBHubState *s = (USBHubState *)dev;
-
- qemu_free(s);
-}
-
USBDevice *usb_hub_init(int nb_ports)
{
USBHubState *s;
@@ -548,7 +543,6 @@ USBDevice *usb_hub_init(int nb_ports)
s->dev.handle_reset = usb_hub_handle_reset;
s->dev.handle_control = usb_hub_handle_control;
s->dev.handle_data = usb_hub_handle_data;
- s->dev.handle_destroy = usb_hub_handle_destroy;
pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Hub");
diff --git a/hw/usb-msd.c b/hw/usb-msd.c
index ff2047d..3dccfb9 100644
--- a/hw/usb-msd.c
+++ b/hw/usb-msd.c
@@ -112,12 +112,16 @@ static void usb_msd_command_complete(void *opaque, uint32_t tag, int fail)
s->mode = USB_MSDM_CSW;
}
-static void usb_msd_handle_reset(USBDevice *dev)
+static void usb_msd_handle_reset(USBDevice *dev, int destroy)
{
MSDState *s = (MSDState *)dev;
DPRINTF("Reset\n");
s->mode = USB_MSDM_CBW;
+ if (destroy) {
+ scsi_disk_destroy(s->scsi_dev);
+ qemu_free(s);
+ }
}
static int usb_msd_handle_control(USBDevice *dev, int request, int value,
@@ -365,13 +369,6 @@ static int usb_msd_handle_data(USBDevice *dev, int pid, uint8_t devep,
return ret;
}
-static void usb_msd_handle_destroy(USBDevice *dev)
-{
- MSDState *s = (MSDState *)dev;
-
- scsi_disk_destroy(s->scsi_dev);
- qemu_free(s);
-}
USBDevice *usb_msd_init(const char *filename)
{
@@ -391,12 +388,11 @@ USBDevice *usb_msd_init(const char *filename)
s->dev.handle_reset = usb_msd_handle_reset;
s->dev.handle_control = usb_msd_handle_control;
s->dev.handle_data = usb_msd_handle_data;
- s->dev.handle_destroy = usb_msd_handle_destroy;
snprintf(s->dev.devname, sizeof(s->dev.devname), "QEMU USB MSD(%.16s)",
filename);
s->scsi_dev = scsi_disk_init(bdrv, usb_msd_command_complete, s);
- usb_msd_handle_reset((USBDevice *)s);
+ usb_msd_handle_reset((USBDevice *)s, 0);
return (USBDevice *)s;
}
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
deleted file mode 100644
index 1a6e013..0000000
--- a/hw/usb-uhci.c
+++ /dev/null
@@ -1,674 +0,0 @@
-/*
- * USB UHCI controller emulation
- *
- * Copyright (c) 2005 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"
-
-//#define DEBUG
-//#define DEBUG_PACKET
-
-#define UHCI_CMD_GRESET (1 << 2)
-#define UHCI_CMD_HCRESET (1 << 1)
-#define UHCI_CMD_RS (1 << 0)
-
-#define UHCI_STS_HCHALTED (1 << 5)
-#define UHCI_STS_HCPERR (1 << 4)
-#define UHCI_STS_HSERR (1 << 3)
-#define UHCI_STS_RD (1 << 2)
-#define UHCI_STS_USBERR (1 << 1)
-#define UHCI_STS_USBINT (1 << 0)
-
-#define TD_CTRL_SPD (1 << 29)
-#define TD_CTRL_ERROR_SHIFT 27
-#define TD_CTRL_IOS (1 << 25)
-#define TD_CTRL_IOC (1 << 24)
-#define TD_CTRL_ACTIVE (1 << 23)
-#define TD_CTRL_STALL (1 << 22)
-#define TD_CTRL_BABBLE (1 << 20)
-#define TD_CTRL_NAK (1 << 19)
-#define TD_CTRL_TIMEOUT (1 << 18)
-
-#define UHCI_PORT_RESET (1 << 9)
-#define UHCI_PORT_LSDA (1 << 8)
-#define UHCI_PORT_ENC (1 << 3)
-#define UHCI_PORT_EN (1 << 2)
-#define UHCI_PORT_CSC (1 << 1)
-#define UHCI_PORT_CCS (1 << 0)
-
-#define FRAME_TIMER_FREQ 1000
-
-#define FRAME_MAX_LOOPS 100
-
-#define NB_PORTS 2
-
-typedef struct UHCIPort {
- USBPort port;
- uint16_t ctrl;
-} UHCIPort;
-
-typedef struct UHCIState {
- PCIDevice dev;
- uint16_t cmd; /* cmd register */
- uint16_t status;
- uint16_t intr; /* interrupt enable register */
- uint16_t frnum; /* frame number */
- uint32_t fl_base_addr; /* frame list base address */
- uint8_t sof_timing;
- uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
- QEMUTimer *frame_timer;
- UHCIPort ports[NB_PORTS];
-} UHCIState;
-
-typedef struct UHCI_TD {
- uint32_t link;
- uint32_t ctrl; /* see TD_CTRL_xxx */
- uint32_t token;
- uint32_t buffer;
-} UHCI_TD;
-
-typedef struct UHCI_QH {
- uint32_t link;
- uint32_t el_link;
-} UHCI_QH;
-
-static void uhci_attach(USBPort *port1, USBDevice *dev);
-
-static void uhci_update_irq(UHCIState *s)
-{
- int level;
- if (((s->status2 & 1) && (s->intr & (1 << 2))) ||
- ((s->status2 & 2) && (s->intr & (1 << 3))) ||
- ((s->status & UHCI_STS_USBERR) && (s->intr & (1 << 0))) ||
- ((s->status & UHCI_STS_RD) && (s->intr & (1 << 1))) ||
- (s->status & UHCI_STS_HSERR) ||
- (s->status & UHCI_STS_HCPERR)) {
- level = 1;
- } else {
- level = 0;
- }
- pci_set_irq(&s->dev, 3, level);
-}
-
-static void uhci_reset(UHCIState *s)
-{
- uint8_t *pci_conf;
- int i;
- UHCIPort *port;
-
- pci_conf = s->dev.config;
-
- pci_conf[0x6a] = 0x01; /* usb clock */
- pci_conf[0x6b] = 0x00;
- s->cmd = 0;
- s->status = 0;
- s->status2 = 0;
- s->intr = 0;
- s->fl_base_addr = 0;
- s->sof_timing = 64;
- for(i = 0; i < NB_PORTS; i++) {
- port = &s->ports[i];
- port->ctrl = 0x0080;
- if (port->port.dev)
- uhci_attach(&port->port, port->port.dev);
- }
-}
-
-static void uhci_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
-{
- UHCIState *s = opaque;
-
- addr &= 0x1f;
- switch(addr) {
- case 0x0c:
- s->sof_timing = val;
- break;
- }
-}
-
-static uint32_t uhci_ioport_readb(void *opaque, uint32_t addr)
-{
- UHCIState *s = opaque;
- uint32_t val;
-
- addr &= 0x1f;
- switch(addr) {
- case 0x0c:
- val = s->sof_timing;
- break;
- default:
- val = 0xff;
- break;
- }
- return val;
-}
-
-static void uhci_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
-{
- UHCIState *s = opaque;
-
- addr &= 0x1f;
-#ifdef DEBUG
- printf("uhci writew port=0x%04x val=0x%04x\n", addr, val);
-#endif
- switch(addr) {
- case 0x00:
- if ((val & UHCI_CMD_RS) && !(s->cmd & UHCI_CMD_RS)) {
- /* start frame processing */
- qemu_mod_timer(s->frame_timer, qemu_get_clock(vm_clock));
- s->status &= ~UHCI_STS_HCHALTED;
- } else if (!(val & UHCI_CMD_RS)) {
- s->status |= UHCI_STS_HCHALTED;
- }
- if (val & UHCI_CMD_GRESET) {
- UHCIPort *port;
- USBDevice *dev;
- int i;
-
- /* send reset on the USB bus */
- for(i = 0; i < NB_PORTS; i++) {
- port = &s->ports[i];
- dev = port->port.dev;
- if (dev) {
- dev->handle_packet(dev,
- USB_MSG_RESET, 0, 0, NULL, 0);
- }
- }
- uhci_reset(s);
- return;
- }
- if (val & UHCI_CMD_HCRESET) {
- uhci_reset(s);
- return;
- }
- s->cmd = val;
- break;
- case 0x02:
- s->status &= ~val;
- /* XXX: the chip spec is not coherent, so we add a hidden
- register to distinguish between IOC and SPD */
- if (val & UHCI_STS_USBINT)
- s->status2 = 0;
- uhci_update_irq(s);
- break;
- case 0x04:
- s->intr = val;
- uhci_update_irq(s);
- break;
- case 0x06:
- if (s->status & UHCI_STS_HCHALTED)
- s->frnum = val & 0x7ff;
- break;
- case 0x10 ... 0x1f:
- {
- UHCIPort *port;
- USBDevice *dev;
- int n;
-
- n = (addr >> 1) & 7;
- if (n >= NB_PORTS)
- return;
- port = &s->ports[n];
- dev = port->port.dev;
- if (dev) {
- /* port reset */
- if ( (val & UHCI_PORT_RESET) &&
- !(port->ctrl & UHCI_PORT_RESET) ) {
- dev->handle_packet(dev,
- USB_MSG_RESET, 0, 0, NULL, 0);
- }
- }
- port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb);
- /* some bits are reset when a '1' is written to them */
- port->ctrl &= ~(val & 0x000a);
- }
- break;
- }
-}
-
-static uint32_t uhci_ioport_readw(void *opaque, uint32_t addr)
-{
- UHCIState *s = opaque;
- uint32_t val;
-
- addr &= 0x1f;
- switch(addr) {
- case 0x00:
- val = s->cmd;
- break;
- case 0x02:
- val = s->status;
- break;
- case 0x04:
- val = s->intr;
- break;
- case 0x06:
- val = s->frnum;
- break;
- case 0x10 ... 0x1f:
- {
- UHCIPort *port;
- int n;
- n = (addr >> 1) & 7;
- if (n >= NB_PORTS)
- goto read_default;
- port = &s->ports[n];
- val = port->ctrl;
- }
- break;
- default:
- read_default:
- val = 0xff7f; /* disabled port */
- break;
- }
-#ifdef DEBUG
- printf("uhci readw port=0x%04x val=0x%04x\n", addr, val);
-#endif
- return val;
-}
-
-static void uhci_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
-{
- UHCIState *s = opaque;
-
- addr &= 0x1f;
-#ifdef DEBUG
- printf("uhci writel port=0x%04x val=0x%08x\n", addr, val);
-#endif
- switch(addr) {
- case 0x08:
- s->fl_base_addr = val & ~0xfff;
- break;
- }
-}
-
-static uint32_t uhci_ioport_readl(void *opaque, uint32_t addr)
-{
- UHCIState *s = opaque;
- uint32_t val;
-
- addr &= 0x1f;
- switch(addr) {
- case 0x08:
- val = s->fl_base_addr;
- break;
- default:
- val = 0xffffffff;
- break;
- }
- return val;
-}
-
-static void uhci_attach(USBPort *port1, USBDevice *dev)
-{
- UHCIState *s = port1->opaque;
- UHCIPort *port = &s->ports[port1->index];
-
- if (dev) {
- if (port->port.dev) {
- usb_attach(port1, NULL);
- }
- /* set connect status */
- port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC;
-
- /* update speed */
- if (dev->speed == USB_SPEED_LOW)
- port->ctrl |= UHCI_PORT_LSDA;
- else
- port->ctrl &= ~UHCI_PORT_LSDA;
- port->port.dev = dev;
- /* send the attach message */
- dev->handle_packet(dev,
- USB_MSG_ATTACH, 0, 0, NULL, 0);
- } else {
- /* set connect status */
- if (port->ctrl & UHCI_PORT_CCS) {
- port->ctrl &= ~UHCI_PORT_CCS;
- port->ctrl |= UHCI_PORT_CSC;
- }
- /* disable port */
- if (port->ctrl & UHCI_PORT_EN) {
- port->ctrl &= ~UHCI_PORT_EN;
- port->ctrl |= UHCI_PORT_ENC;
- }
- dev = port->port.dev;
- if (dev) {
- /* send the detach message */
- dev->handle_packet(dev,
- USB_MSG_DETACH, 0, 0, NULL, 0);
- }
- port->port.dev = NULL;
- }
-}
-
-static int uhci_broadcast_packet(UHCIState *s, uint8_t pid,
- uint8_t devaddr, uint8_t devep,
- uint8_t *data, int len)
-{
- UHCIPort *port;
- USBDevice *dev;
- int i, ret;
-
-#ifdef DEBUG_PACKET
- {
- const char *pidstr;
- switch(pid) {
- case USB_TOKEN_SETUP: pidstr = "SETUP"; break;
- case USB_TOKEN_IN: pidstr = "IN"; break;
- case USB_TOKEN_OUT: pidstr = "OUT"; break;
- default: pidstr = "?"; break;
- }
- printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n",
- s->frnum, pidstr, devaddr, devep, len);
- if (pid != USB_TOKEN_IN) {
- printf(" data_out=");
- for(i = 0; i < len; i++) {
- printf(" %02x", data[i]);
- }
- printf("\n");
- }
- }
-#endif
- for(i = 0; i < NB_PORTS; i++) {
- port = &s->ports[i];
- dev = port->port.dev;
- if (dev && (port->ctrl & UHCI_PORT_EN)) {
- ret = dev->handle_packet(dev, pid,
- devaddr, devep,
- data, len);
- if (ret != USB_RET_NODEV) {
-#ifdef DEBUG_PACKET
- {
- printf(" ret=%d ", ret);
- if (pid == USB_TOKEN_IN && ret > 0) {
- printf("data_in=");
- for(i = 0; i < ret; i++) {
- printf(" %02x", data[i]);
- }
- }
- printf("\n");
- }
-#endif
- return ret;
- }
- }
- }
- return USB_RET_NODEV;
-}
-
-/* return -1 if fatal error (frame must be stopped)
- 0 if TD successful
- 1 if TD unsuccessful or inactive
-*/
-static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask)
-{
- uint8_t pid;
- uint8_t buf[1280];
- int len, max_len, err, ret;
-
- if (td->ctrl & TD_CTRL_IOC) {
- *int_mask |= 0x01;
- }
-
- if (!(td->ctrl & TD_CTRL_ACTIVE))
- return 1;
-
- /* TD is active */
- max_len = ((td->token >> 21) + 1) & 0x7ff;
- pid = td->token & 0xff;
- switch(pid) {
- case USB_TOKEN_OUT:
- case USB_TOKEN_SETUP:
- cpu_physical_memory_read(td->buffer, buf, max_len);
- ret = uhci_broadcast_packet(s, pid,
- (td->token >> 8) & 0x7f,
- (td->token >> 15) & 0xf,
- buf, max_len);
- len = max_len;
- break;
- case USB_TOKEN_IN:
- ret = uhci_broadcast_packet(s, pid,
- (td->token >> 8) & 0x7f,
- (td->token >> 15) & 0xf,
- buf, max_len);
- if (ret >= 0) {
- len = ret;
- if (len > max_len) {
- len = max_len;
- ret = USB_RET_BABBLE;
- }
- if (len > 0) {
- /* write the data back */
- cpu_physical_memory_write(td->buffer, buf, len);
- }
- } else {
- len = 0;
- }
- break;
- default:
- /* invalid pid : frame interrupted */
- s->status |= UHCI_STS_HCPERR;
- uhci_update_irq(s);
- return -1;
- }
- if (td->ctrl & TD_CTRL_IOS)
- td->ctrl &= ~TD_CTRL_ACTIVE;
- if (ret >= 0) {
- td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);
- td->ctrl &= ~TD_CTRL_ACTIVE;
- if (pid == USB_TOKEN_IN &&
- (td->ctrl & TD_CTRL_SPD) &&
- len < max_len) {
- *int_mask |= 0x02;
- /* short packet: do not update QH */
- return 1;
- } else {
- /* success */
- return 0;
- }
- } else {
- switch(ret) {
- default:
- case USB_RET_NODEV:
- do_timeout:
- td->ctrl |= TD_CTRL_TIMEOUT;
- err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;
- if (err != 0) {
- err--;
- if (err == 0) {
- td->ctrl &= ~TD_CTRL_ACTIVE;
- s->status |= UHCI_STS_USBERR;
- uhci_update_irq(s);
- }
- }
- td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
- (err << TD_CTRL_ERROR_SHIFT);
- return 1;
- case USB_RET_NAK:
- td->ctrl |= TD_CTRL_NAK;
- if (pid == USB_TOKEN_SETUP)
- goto do_timeout;
- return 1;
- case USB_RET_STALL:
- td->ctrl |= TD_CTRL_STALL;
- td->ctrl &= ~TD_CTRL_ACTIVE;
- return 1;
- case USB_RET_BABBLE:
- td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;
- td->ctrl &= ~TD_CTRL_ACTIVE;
- /* frame interrupted */
- return -1;
- }
- }
-}
-
-static void uhci_frame_timer(void *opaque)
-{
- UHCIState *s = opaque;
- int64_t expire_time;
- uint32_t frame_addr, link, old_td_ctrl, val;
- int int_mask, cnt, ret;
- UHCI_TD td;
- UHCI_QH qh;
-
- if (!(s->cmd & UHCI_CMD_RS)) {
- qemu_del_timer(s->frame_timer);
- /* set hchalted bit in status - UHCI11D 2.1.2 */
- s->status |= UHCI_STS_HCHALTED;
- return;
- }
- frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
- cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
- le32_to_cpus(&link);
- int_mask = 0;
- cnt = FRAME_MAX_LOOPS;
- while ((link & 1) == 0) {
- if (--cnt == 0)
- break;
- /* valid frame */
- if (link & 2) {
- /* QH */
- cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh));
- le32_to_cpus(&qh.link);
- le32_to_cpus(&qh.el_link);
- depth_first:
- if (qh.el_link & 1) {
- /* no element : go to next entry */
- link = qh.link;
- } else if (qh.el_link & 2) {
- /* QH */
- link = qh.el_link;
- } else {
- /* TD */
- if (--cnt == 0)
- break;
- cpu_physical_memory_read(qh.el_link & ~0xf,
- (uint8_t *)&td, sizeof(td));
- le32_to_cpus(&td.link);
- le32_to_cpus(&td.ctrl);
- le32_to_cpus(&td.token);
- le32_to_cpus(&td.buffer);
- old_td_ctrl = td.ctrl;
- ret = uhci_handle_td(s, &td, &int_mask);
- /* update the status bits of the TD */
- if (old_td_ctrl != td.ctrl) {
- val = cpu_to_le32(td.ctrl);
- cpu_physical_memory_write((qh.el_link & ~0xf) + 4,
- (const uint8_t *)&val,
- sizeof(val));
- }
- if (ret < 0)
- break; /* interrupted frame */
- if (ret == 0) {
- /* update qh element link */
- qh.el_link = td.link;
- val = cpu_to_le32(qh.el_link);
- cpu_physical_memory_write((link & ~0xf) + 4,
- (const uint8_t *)&val,
- sizeof(val));
- if (qh.el_link & 4) {
- /* depth first */
- goto depth_first;
- }
- }
- /* go to next entry */
- link = qh.link;
- }
- } else {
- /* TD */
- cpu_physical_memory_read(link & ~0xf, (uint8_t *)&td, sizeof(td));
- le32_to_cpus(&td.link);
- le32_to_cpus(&td.ctrl);
- le32_to_cpus(&td.token);
- le32_to_cpus(&td.buffer);
- old_td_ctrl = td.ctrl;
- ret = uhci_handle_td(s, &td, &int_mask);
- /* update the status bits of the TD */
- if (old_td_ctrl != td.ctrl) {
- val = cpu_to_le32(td.ctrl);
- cpu_physical_memory_write((link & ~0xf) + 4,
- (const uint8_t *)&val,
- sizeof(val));
- }
- if (ret < 0)
- break; /* interrupted frame */
- link = td.link;
- }
- }
- s->frnum = (s->frnum + 1) & 0x7ff;
- if (int_mask) {
- s->status2 |= int_mask;
- s->status |= UHCI_STS_USBINT;
- uhci_update_irq(s);
- }
- /* prepare the timer for the next frame */
- expire_time = qemu_get_clock(vm_clock) +
- (ticks_per_sec / FRAME_TIMER_FREQ);
- qemu_mod_timer(s->frame_timer, expire_time);
-}
-
-static void uhci_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- UHCIState *s = (UHCIState *)pci_dev;
-
- register_ioport_write(addr, 32, 2, uhci_ioport_writew, s);
- register_ioport_read(addr, 32, 2, uhci_ioport_readw, s);
- register_ioport_write(addr, 32, 4, uhci_ioport_writel, s);
- register_ioport_read(addr, 32, 4, uhci_ioport_readl, s);
- register_ioport_write(addr, 32, 1, uhci_ioport_writeb, s);
- register_ioport_read(addr, 32, 1, uhci_ioport_readb, s);
-}
-
-void usb_uhci_init(PCIBus *bus, int devfn)
-{
- UHCIState *s;
- uint8_t *pci_conf;
- int i;
-
- s = (UHCIState *)pci_register_device(bus,
- "USB-UHCI", sizeof(UHCIState),
- devfn, NULL, NULL);
- pci_conf = s->dev.config;
- pci_conf[0x00] = 0x86;
- pci_conf[0x01] = 0x80;
- pci_conf[0x02] = 0x20;
- pci_conf[0x03] = 0x70;
- pci_conf[0x08] = 0x01; // revision number
- pci_conf[0x09] = 0x00;
- pci_conf[0x0a] = 0x03;
- pci_conf[0x0b] = 0x0c;
- pci_conf[0x0e] = 0x00; // header_type
- pci_conf[0x3d] = 4; // interrupt pin 3
- pci_conf[0x60] = 0x10; // release number
-
- for(i = 0; i < NB_PORTS; i++) {
- qemu_register_usb_port(&s->ports[i].port, s, i, uhci_attach);
- }
- s->frame_timer = qemu_new_timer(vm_clock, uhci_frame_timer, s);
-
- uhci_reset(s);
-
- /* Use region 4 for consistency with real hardware. BSD guests seem
- to rely on this. */
- pci_register_io_region(&s->dev, 4, 0x20,
- PCI_ADDRESS_SPACE_IO, uhci_map);
-}
diff --git a/hw/usb.c b/hw/usb.c
index 34aac5f..a00d945 100644
--- a/hw/usb.c
+++ b/hw/usb.c
@@ -55,7 +55,10 @@ int usb_generic_handle_packet(USBDevice *s, int pid,
s->remote_wakeup = 0;
s->addr = 0;
s->state = USB_STATE_DEFAULT;
- s->handle_reset(s);
+ s->handle_reset(s, 0);
+ break;
+ case USB_MSG_DESTROY:
+ s->handle_reset(s, 1);
break;
case USB_TOKEN_SETUP:
if (s->state < USB_STATE_DEFAULT || devaddr != s->addr)
diff --git a/hw/usb.h b/hw/usb.h
index 98fde06..b0887d6 100644
--- a/hw/usb.h
+++ b/hw/usb.h
@@ -29,6 +29,7 @@
#define USB_MSG_ATTACH 0x100
#define USB_MSG_DETACH 0x101
#define USB_MSG_RESET 0x102
+#define USB_MSG_DESTROY 0x103
#define USB_RET_NODEV (-1)
#define USB_RET_NAK (-2)
@@ -116,14 +117,12 @@ struct USBDevice {
int (*handle_packet)(USBDevice *dev, int pid,
uint8_t devaddr, uint8_t devep,
uint8_t *data, int len);
- void (*handle_destroy)(USBDevice *dev);
-
int speed;
/* The following fields are used by the generic USB device
layer. They are here just to avoid creating a new structure for
them. */
- void (*handle_reset)(USBDevice *dev);
+ void (*handle_reset)(USBDevice *dev, int destroy);
int (*handle_control)(USBDevice *dev, int request, int value,
int index, int length, uint8_t *data);
int (*handle_data)(USBDevice *dev, int pid, uint8_t devep,
diff --git a/hw/versatile_pci.c b/hw/versatile_pci.c
deleted file mode 100644
index 34a4bc6..0000000
--- a/hw/versatile_pci.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * ARM Versatile/PB PCI host controller
- *
- * Copyright (c) 2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the LGPL.
- */
-
-#include "vl.h"
-
-static inline uint32_t vpb_pci_config_addr(target_phys_addr_t addr)
-{
- return addr & 0xf8ff;
-}
-
-static void pci_vpb_config_writeb (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
- pci_data_write(opaque, vpb_pci_config_addr (addr), val, 1);
-}
-
-static void pci_vpb_config_writew (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- pci_data_write(opaque, vpb_pci_config_addr (addr), val, 2);
-}
-
-static void pci_vpb_config_writel (void *opaque, target_phys_addr_t addr,
- uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- pci_data_write(opaque, vpb_pci_config_addr (addr), val, 4);
-}
-
-static uint32_t pci_vpb_config_readb (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
- val = pci_data_read(opaque, vpb_pci_config_addr (addr), 1);
- return val;
-}
-
-static uint32_t pci_vpb_config_readw (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
- val = pci_data_read(opaque, vpb_pci_config_addr (addr), 2);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap16(val);
-#endif
- return val;
-}
-
-static uint32_t pci_vpb_config_readl (void *opaque, target_phys_addr_t addr)
-{
- uint32_t val;
- val = pci_data_read(opaque, vpb_pci_config_addr (addr), 4);
-#ifdef TARGET_WORDS_BIGENDIAN
- val = bswap32(val);
-#endif
- return val;
-}
-
-static CPUWriteMemoryFunc *pci_vpb_config_write[] = {
- &pci_vpb_config_writeb,
- &pci_vpb_config_writew,
- &pci_vpb_config_writel,
-};
-
-static CPUReadMemoryFunc *pci_vpb_config_read[] = {
- &pci_vpb_config_readb,
- &pci_vpb_config_readw,
- &pci_vpb_config_readl,
-};
-
-static void pci_vpb_set_irq(PCIDevice *d, void *pic, int irq_num, int level)
-{
- pic_set_irq_new(pic, 27 + irq_num, level);
-}
-
-PCIBus *pci_vpb_init(void *pic)
-{
- PCIBus *s;
- PCIDevice *d;
- int mem_config;
-
- s = pci_register_bus(pci_vpb_set_irq, pic, 11 << 3);
- /* ??? Register memory space. */
-
- mem_config = cpu_register_io_memory(0, pci_vpb_config_read,
- pci_vpb_config_write, s);
- /* Selfconfig area. */
- cpu_register_physical_memory(0x41000000, 0x10000, mem_config);
- /* Normal config area. */
- cpu_register_physical_memory(0x42000000, 0x10000, mem_config);
-
- d = pci_register_device(s, "Versatile/PB PCI Controller",
- sizeof(PCIDevice), -1, NULL, NULL);
- d->config[0x00] = 0xee; // vendor_id
- d->config[0x01] = 0x10;
- d->config[0x02] = 0x00; // device_id
- d->config[0x03] = 0x03;
- d->config[0x04] = 0x00;
- d->config[0x05] = 0x00;
- d->config[0x06] = 0x20;
- d->config[0x07] = 0x02;
- d->config[0x08] = 0x00; // revision
- d->config[0x09] = 0x00; // programming i/f
- d->config[0x0A] = 0x40; // class_sub = pci host
- d->config[0x0B] = 0x0b; // class_base = PCI_bridge
- d->config[0x0D] = 0x10; // latency_timer
-
- return s;
-}
-
diff --git a/hw/versatilepb.c b/hw/versatilepb.c
deleted file mode 100644
index 28ec137..0000000
--- a/hw/versatilepb.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * ARM Versatile Platform/Application Baseboard System emulation.
- *
- * Copyright (c) 2005-2006 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licenced under the GPL.
- */
-
-#include "vl.h"
-#include "arm_pic.h"
-
-#define LOCK_VALUE 0xa05f
-
-/* Primary interrupt controller. */
-
-typedef struct vpb_sic_state
-{
- arm_pic_handler handler;
- uint32_t base;
- uint32_t level;
- uint32_t mask;
- uint32_t pic_enable;
- void *parent;
- int irq;
-} vpb_sic_state;
-
-static void vpb_sic_update(vpb_sic_state *s)
-{
- uint32_t flags;
-
- flags = s->level & s->mask;
- pic_set_irq_new(s->parent, s->irq, flags != 0);
-}
-
-static void vpb_sic_update_pic(vpb_sic_state *s)
-{
- int i;
- uint32_t mask;
-
- for (i = 21; i <= 30; i++) {
- mask = 1u << i;
- if (!(s->pic_enable & mask))
- continue;
- pic_set_irq_new(s->parent, i, (s->level & mask) != 0);
- }
-}
-
-static void vpb_sic_set_irq(void *opaque, int irq, int level)
-{
- vpb_sic_state *s = (vpb_sic_state *)opaque;
- if (level)
- s->level |= 1u << irq;
- else
- s->level &= ~(1u << irq);
- if (s->pic_enable & (1u << irq))
- pic_set_irq_new(s->parent, irq, level);
- vpb_sic_update(s);
-}
-
-static uint32_t vpb_sic_read(void *opaque, target_phys_addr_t offset)
-{
- vpb_sic_state *s = (vpb_sic_state *)opaque;
-
- offset -= s->base;
- switch (offset >> 2) {
- case 0: /* STATUS */
- return s->level & s->mask;
- case 1: /* RAWSTAT */
- return s->level;
- case 2: /* ENABLE */
- return s->mask;
- case 4: /* SOFTINT */
- return s->level & 1;
- case 8: /* PICENABLE */
- return s->pic_enable;
- default:
- printf ("vpb_sic_read: Bad register offset 0x%x\n", offset);
- return 0;
- }
-}
-
-static void vpb_sic_write(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- vpb_sic_state *s = (vpb_sic_state *)opaque;
- offset -= s->base;
-
- switch (offset >> 2) {
- case 2: /* ENSET */
- s->mask |= value;
- break;
- case 3: /* ENCLR */
- s->mask &= ~value;
- break;
- case 4: /* SOFTINTSET */
- if (value)
- s->mask |= 1;
- break;
- case 5: /* SOFTINTCLR */
- if (value)
- s->mask &= ~1u;
- break;
- case 8: /* PICENSET */
- s->pic_enable |= (value & 0x7fe00000);
- vpb_sic_update_pic(s);
- break;
- case 9: /* PICENCLR */
- s->pic_enable &= ~value;
- vpb_sic_update_pic(s);
- break;
- default:
- printf ("vpb_sic_write: Bad register offset 0x%x\n", offset);
- return;
- }
- vpb_sic_update(s);
-}
-
-static CPUReadMemoryFunc *vpb_sic_readfn[] = {
- vpb_sic_read,
- vpb_sic_read,
- vpb_sic_read
-};
-
-static CPUWriteMemoryFunc *vpb_sic_writefn[] = {
- vpb_sic_write,
- vpb_sic_write,
- vpb_sic_write
-};
-
-static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
-{
- vpb_sic_state *s;
- int iomemtype;
-
- s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state));
- if (!s)
- return NULL;
- s->handler = vpb_sic_set_irq;
- s->base = base;
- s->parent = parent;
- s->irq = irq;
- iomemtype = cpu_register_io_memory(0, vpb_sic_readfn,
- vpb_sic_writefn, s);
- cpu_register_physical_memory(base, 0x00000fff, iomemtype);
- /* ??? Save/restore. */
- return s;
-}
-
-/* System controller. */
-
-typedef struct {
- uint32_t base;
- uint32_t leds;
- uint16_t lockval;
- uint32_t cfgdata1;
- uint32_t cfgdata2;
- uint32_t flags;
- uint32_t nvflags;
- uint32_t resetlevel;
-} vpb_sys_state;
-
-static uint32_t vpb_sys_read(void *opaque, target_phys_addr_t offset)
-{
- vpb_sys_state *s = (vpb_sys_state *)opaque;
-
- offset -= s->base;
- switch (offset) {
- case 0x00: /* ID */
- return 0x41007004;
- case 0x04: /* SW */
- /* General purpose hardware switches.
- We don't have a useful way of exposing these to the user. */
- return 0;
- case 0x08: /* LED */
- return s->leds;
- case 0x20: /* LOCK */
- return s->lockval;
- case 0x0c: /* OSC0 */
- case 0x10: /* OSC1 */
- case 0x14: /* OSC2 */
- case 0x18: /* OSC3 */
- case 0x1c: /* OSC4 */
- case 0x24: /* 100HZ */
- /* ??? Implement these. */
- return 0;
- case 0x28: /* CFGDATA1 */
- return s->cfgdata1;
- case 0x2c: /* CFGDATA2 */
- return s->cfgdata2;
- case 0x30: /* FLAGS */
- return s->flags;
- case 0x38: /* NVFLAGS */
- return s->nvflags;
- case 0x40: /* RESETCTL */
- return s->resetlevel;
- case 0x44: /* PCICTL */
- return 1;
- case 0x48: /* MCI */
- return 0;
- case 0x4c: /* FLASH */
- return 0;
- case 0x50: /* CLCD */
- return 0x1000;
- case 0x54: /* CLCDSER */
- return 0;
- case 0x58: /* BOOTCS */
- return 0;
- case 0x5c: /* 24MHz */
- /* ??? not implemented. */
- return 0;
- case 0x60: /* MISC */
- return 0;
- case 0x64: /* DMAPSR0 */
- case 0x68: /* DMAPSR1 */
- case 0x6c: /* DMAPSR2 */
- case 0x8c: /* OSCRESET0 */
- case 0x90: /* OSCRESET1 */
- case 0x94: /* OSCRESET2 */
- case 0x98: /* OSCRESET3 */
- case 0x9c: /* OSCRESET4 */
- case 0xc0: /* SYS_TEST_OSC0 */
- case 0xc4: /* SYS_TEST_OSC1 */
- case 0xc8: /* SYS_TEST_OSC2 */
- case 0xcc: /* SYS_TEST_OSC3 */
- case 0xd0: /* SYS_TEST_OSC4 */
- return 0;
- default:
- printf ("vpb_sys_read: Bad register offset 0x%x\n", offset);
- return 0;
- }
-}
-
-static void vpb_sys_write(void *opaque, target_phys_addr_t offset,
- uint32_t val)
-{
- vpb_sys_state *s = (vpb_sys_state *)opaque;
- offset -= s->base;
-
- switch (offset) {
- case 0x08: /* LED */
- s->leds = val;
- case 0x0c: /* OSC0 */
- case 0x10: /* OSC1 */
- case 0x14: /* OSC2 */
- case 0x18: /* OSC3 */
- case 0x1c: /* OSC4 */
- /* ??? */
- break;
- case 0x20: /* LOCK */
- if (val == LOCK_VALUE)
- s->lockval = val;
- else
- s->lockval = val & 0x7fff;
- break;
- case 0x28: /* CFGDATA1 */
- /* ??? Need to implement this. */
- s->cfgdata1 = val;
- break;
- case 0x2c: /* CFGDATA2 */
- /* ??? Need to implement this. */
- s->cfgdata2 = val;
- break;
- case 0x30: /* FLAGSSET */
- s->flags |= val;
- break;
- case 0x34: /* FLAGSCLR */
- s->flags &= ~val;
- break;
- case 0x38: /* NVFLAGSSET */
- s->nvflags |= val;
- break;
- case 0x3c: /* NVFLAGSCLR */
- s->nvflags &= ~val;
- break;
- case 0x40: /* RESETCTL */
- if (s->lockval == LOCK_VALUE) {
- s->resetlevel = val;
- if (val & 0x100)
- cpu_abort(cpu_single_env, "Board reset\n");
- }
- break;
- case 0x44: /* PCICTL */
- /* nothing to do. */
- break;
- case 0x4c: /* FLASH */
- case 0x50: /* CLCD */
- case 0x54: /* CLCDSER */
- case 0x64: /* DMAPSR0 */
- case 0x68: /* DMAPSR1 */
- case 0x6c: /* DMAPSR2 */
- case 0x8c: /* OSCRESET0 */
- case 0x90: /* OSCRESET1 */
- case 0x94: /* OSCRESET2 */
- case 0x98: /* OSCRESET3 */
- case 0x9c: /* OSCRESET4 */
- break;
- default:
- printf ("vpb_sys_write: Bad register offset 0x%x\n", offset);
- return;
- }
-}
-
-static CPUReadMemoryFunc *vpb_sys_readfn[] = {
- vpb_sys_read,
- vpb_sys_read,
- vpb_sys_read
-};
-
-static CPUWriteMemoryFunc *vpb_sys_writefn[] = {
- vpb_sys_write,
- vpb_sys_write,
- vpb_sys_write
-};
-
-static vpb_sys_state *vpb_sys_init(uint32_t base)
-{
- vpb_sys_state *s;
- int iomemtype;
-
- s = (vpb_sys_state *)qemu_mallocz(sizeof(vpb_sys_state));
- if (!s)
- return NULL;
- s->base = base;
- iomemtype = cpu_register_io_memory(0, vpb_sys_readfn,
- vpb_sys_writefn, s);
- cpu_register_physical_memory(base, 0x00000fff, iomemtype);
- /* ??? Save/restore. */
- return s;
-}
-
-/* Board init. */
-
-/* The AB and PB boards both use the same core, just with different
- peripherans and expansion busses. For now we emulate a subset of the
- PB peripherals and just change the board ID. */
-
-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)
-{
- CPUState *env;
- void *pic;
- void *sic;
- void *scsi_hba;
- PCIBus *pci_bus;
- NICInfo *nd;
- int n;
- int done_smc = 0;
-
- env = cpu_init();
- cpu_arm_set_model(env, ARM_CPUID_ARM926);
- /* ??? RAM shoud repeat to fill physical memory space. */
- /* SDRAM at address zero. */
- cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
-
- vpb_sys_init(0x10000000);
- pic = arm_pic_init_cpu(env);
- pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
- sic = vpb_sic_init(0x10003000, pic, 31);
- pl050_init(0x10006000, sic, 3, 0);
- pl050_init(0x10007000, sic, 4, 1);
-
- pci_bus = pci_vpb_init(sic);
- /* The Versatile PCI bridge does not provide access to PCI IO space,
- so many of the qemu PCI devices are not useable. */
- for(n = 0; n < nb_nics; n++) {
- nd = &nd_table[n];
- if (!nd->model)
- nd->model = done_smc ? "rtl8139" : "smc91c111";
- if (strcmp(nd->model, "smc91c111") == 0) {
- smc91c111_init(nd, 0x10010000, sic, 25);
- } else {
- pci_nic_init(pci_bus, nd);
- }
- }
- if (usb_enabled) {
- usb_ohci_init(pci_bus, 3, -1);
- }
- scsi_hba = lsi_scsi_init(pci_bus, -1);
- for (n = 0; n < MAX_DISKS; n++) {
- if (bs_table[n]) {
- lsi_scsi_attach(scsi_hba, bs_table[n], n);
- }
- }
-
- 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);
- 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);
-
- /* 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. */
- /* 0x10006000 KMI0 (keyboard). */
- /* 0x10007000 KMI1 (mouse). */
- /* 0x10008000 Character LCD Interface. */
- /* 0x10009000 UART3. */
- /* 0x1000a000 Smart card 1. */
- /* 0x1000b000 MMCI1. */
- /* 0x10010000 Ethernet. */
- /* 0x10020000 USB. */
- /* 0x10100000 SSMC. */
- /* 0x10110000 MPMC. */
- /* 0x10120000 CLCD Controller. */
- /* 0x10130000 DMA Controller. */
- /* 0x10140000 Vectored interrupt controller. */
- /* 0x101d0000 AHB Monitor Interface. */
- /* 0x101e0000 System Controller. */
- /* 0x101e1000 Watchdog Interface. */
- /* 0x101e2000 Timer 0/1. */
- /* 0x101e3000 Timer 2/3. */
- /* 0x101e4000 GPIO port 0. */
- /* 0x101e5000 GPIO port 1. */
- /* 0x101e6000 GPIO port 2. */
- /* 0x101e7000 GPIO port 3. */
- /* 0x101e8000 RTC. */
- /* 0x101f0000 Smart card 0. */
- /* 0x101f1000 UART0. */
- /* 0x101f2000 UART1. */
- /* 0x101f3000 UART2. */
- /* 0x101f4000 SSPI. */
-
- arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
- initrd_filename, board_id);
-}
-
-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)
-{
- versatile_init(ram_size, vga_ram_size, boot_device,
- ds, fd_filename, snapshot,
- kernel_filename, kernel_cmdline,
- initrd_filename, 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)
-{
- versatile_init(ram_size, vga_ram_size, boot_device,
- ds, fd_filename, snapshot,
- kernel_filename, kernel_cmdline,
- initrd_filename, 0x25e);
-}
-
-QEMUMachine versatilepb_machine = {
- "versatilepb",
- "ARM Versatile/PB (ARM926EJ-S)",
- vpb_init,
-};
-
-QEMUMachine versatileab_machine = {
- "versatileab",
- "ARM Versatile/AB (ARM926EJ-S)",
- vab_init,
-};
diff --git a/hw/vga.c b/hw/vga.c
deleted file mode 100644
index 8f748b3..0000000
--- a/hw/vga.c
+++ /dev/null
@@ -1,1945 +0,0 @@
-/*
- * QEMU VGA Emulator.
- *
- * 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"
-#include "vga_int.h"
-
-//#define DEBUG_VGA
-//#define DEBUG_VGA_MEM
-//#define DEBUG_VGA_REG
-
-//#define DEBUG_BOCHS_VBE
-
-/* force some bits to zero */
-const uint8_t sr_mask[8] = {
- (uint8_t)~0xfc,
- (uint8_t)~0xc2,
- (uint8_t)~0xf0,
- (uint8_t)~0xc0,
- (uint8_t)~0xf1,
- (uint8_t)~0xff,
- (uint8_t)~0xff,
- (uint8_t)~0x00,
-};
-
-const uint8_t gr_mask[16] = {
- (uint8_t)~0xf0, /* 0x00 */
- (uint8_t)~0xf0, /* 0x01 */
- (uint8_t)~0xf0, /* 0x02 */
- (uint8_t)~0xe0, /* 0x03 */
- (uint8_t)~0xfc, /* 0x04 */
- (uint8_t)~0x84, /* 0x05 */
- (uint8_t)~0xf0, /* 0x06 */
- (uint8_t)~0xf0, /* 0x07 */
- (uint8_t)~0x00, /* 0x08 */
- (uint8_t)~0xff, /* 0x09 */
- (uint8_t)~0xff, /* 0x0a */
- (uint8_t)~0xff, /* 0x0b */
- (uint8_t)~0xff, /* 0x0c */
- (uint8_t)~0xff, /* 0x0d */
- (uint8_t)~0xff, /* 0x0e */
- (uint8_t)~0xff, /* 0x0f */
-};
-
-#define cbswap_32(__x) \
-((uint32_t)( \
- (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
- (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
- (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
- (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
-
-#ifdef WORDS_BIGENDIAN
-#define PAT(x) cbswap_32(x)
-#else
-#define PAT(x) (x)
-#endif
-
-#ifdef WORDS_BIGENDIAN
-#define BIG 1
-#else
-#define BIG 0
-#endif
-
-#ifdef WORDS_BIGENDIAN
-#define GET_PLANE(data, p) (((data) >> (24 - (p) * 8)) & 0xff)
-#else
-#define GET_PLANE(data, p) (((data) >> ((p) * 8)) & 0xff)
-#endif
-
-static const uint32_t mask16[16] = {
- PAT(0x00000000),
- PAT(0x000000ff),
- PAT(0x0000ff00),
- PAT(0x0000ffff),
- PAT(0x00ff0000),
- PAT(0x00ff00ff),
- PAT(0x00ffff00),
- PAT(0x00ffffff),
- PAT(0xff000000),
- PAT(0xff0000ff),
- PAT(0xff00ff00),
- PAT(0xff00ffff),
- PAT(0xffff0000),
- PAT(0xffff00ff),
- PAT(0xffffff00),
- PAT(0xffffffff),
-};
-
-#undef PAT
-
-#ifdef WORDS_BIGENDIAN
-#define PAT(x) (x)
-#else
-#define PAT(x) cbswap_32(x)
-#endif
-
-static const uint32_t dmask16[16] = {
- PAT(0x00000000),
- PAT(0x000000ff),
- PAT(0x0000ff00),
- PAT(0x0000ffff),
- PAT(0x00ff0000),
- PAT(0x00ff00ff),
- PAT(0x00ffff00),
- PAT(0x00ffffff),
- PAT(0xff000000),
- PAT(0xff0000ff),
- PAT(0xff00ff00),
- PAT(0xff00ffff),
- PAT(0xffff0000),
- PAT(0xffff00ff),
- PAT(0xffffff00),
- PAT(0xffffffff),
-};
-
-static const uint32_t dmask4[4] = {
- PAT(0x00000000),
- PAT(0x0000ffff),
- PAT(0xffff0000),
- PAT(0xffffffff),
-};
-
-static uint32_t expand4[256];
-static uint16_t expand2[256];
-static uint8_t expand4to8[16];
-
-VGAState *vga_state;
-int vga_io_memory;
-
-static void vga_screen_dump(void *opaque, const char *filename);
-
-static uint32_t vga_ioport_read(void *opaque, uint32_t addr)
-{
- VGAState *s = opaque;
- int val, index;
-
- /* check port range access depending on color/monochrome mode */
- if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
- (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION))) {
- val = 0xff;
- } else {
- switch(addr) {
- case 0x3c0:
- if (s->ar_flip_flop == 0) {
- val = s->ar_index;
- } else {
- val = 0;
- }
- break;
- case 0x3c1:
- index = s->ar_index & 0x1f;
- if (index < 21)
- val = s->ar[index];
- else
- val = 0;
- break;
- case 0x3c2:
- val = s->st00;
- break;
- case 0x3c4:
- val = s->sr_index;
- break;
- case 0x3c5:
- val = s->sr[s->sr_index];
-#ifdef DEBUG_VGA_REG
- printf("vga: read SR%x = 0x%02x\n", s->sr_index, val);
-#endif
- break;
- case 0x3c7:
- val = s->dac_state;
- break;
- case 0x3c8:
- val = s->dac_write_index;
- break;
- case 0x3c9:
- val = s->palette[s->dac_read_index * 3 + s->dac_sub_index];
- if (++s->dac_sub_index == 3) {
- s->dac_sub_index = 0;
- s->dac_read_index++;
- }
- break;
- case 0x3ca:
- val = s->fcr;
- break;
- case 0x3cc:
- val = s->msr;
- break;
- case 0x3ce:
- val = s->gr_index;
- break;
- case 0x3cf:
- val = s->gr[s->gr_index];
-#ifdef DEBUG_VGA_REG
- printf("vga: read GR%x = 0x%02x\n", s->gr_index, val);
-#endif
- break;
- case 0x3b4:
- case 0x3d4:
- val = s->cr_index;
- break;
- case 0x3b5:
- case 0x3d5:
- val = s->cr[s->cr_index];
-#ifdef DEBUG_VGA_REG
- printf("vga: read CR%x = 0x%02x\n", s->cr_index, val);
-#endif
- break;
- case 0x3ba:
- case 0x3da:
- /* just toggle to fool polling */
- s->st01 ^= ST01_V_RETRACE | ST01_DISP_ENABLE;
- val = s->st01;
- s->ar_flip_flop = 0;
- break;
- default:
- val = 0x00;
- break;
- }
- }
-#if defined(DEBUG_VGA)
- printf("VGA: read addr=0x%04x data=0x%02x\n", addr, val);
-#endif
- return val;
-}
-
-static void vga_ioport_write(void *opaque, uint32_t addr, uint32_t val)
-{
- VGAState *s = opaque;
- int index;
-
- /* check port range access depending on color/monochrome mode */
- if ((addr >= 0x3b0 && addr <= 0x3bf && (s->msr & MSR_COLOR_EMULATION)) ||
- (addr >= 0x3d0 && addr <= 0x3df && !(s->msr & MSR_COLOR_EMULATION)))
- return;
-
-#ifdef DEBUG_VGA
- printf("VGA: write addr=0x%04x data=0x%02x\n", addr, val);
-#endif
-
- switch(addr) {
- case 0x3c0:
- if (s->ar_flip_flop == 0) {
- val &= 0x3f;
- s->ar_index = val;
- } else {
- index = s->ar_index & 0x1f;
- switch(index) {
- case 0x00 ... 0x0f:
- s->ar[index] = val & 0x3f;
- break;
- case 0x10:
- s->ar[index] = val & ~0x10;
- break;
- case 0x11:
- s->ar[index] = val;
- break;
- case 0x12:
- s->ar[index] = val & ~0xc0;
- break;
- case 0x13:
- s->ar[index] = val & ~0xf0;
- break;
- case 0x14:
- s->ar[index] = val & ~0xf0;
- break;
- default:
- break;
- }
- }
- s->ar_flip_flop ^= 1;
- break;
- case 0x3c2:
- s->msr = val & ~0x10;
- break;
- case 0x3c4:
- s->sr_index = val & 7;
- break;
- case 0x3c5:
-#ifdef DEBUG_VGA_REG
- printf("vga: write SR%x = 0x%02x\n", s->sr_index, val);
-#endif
- s->sr[s->sr_index] = val & sr_mask[s->sr_index];
- break;
- case 0x3c7:
- s->dac_read_index = val;
- s->dac_sub_index = 0;
- s->dac_state = 3;
- break;
- case 0x3c8:
- s->dac_write_index = val;
- s->dac_sub_index = 0;
- s->dac_state = 0;
- break;
- case 0x3c9:
- s->dac_cache[s->dac_sub_index] = val;
- if (++s->dac_sub_index == 3) {
- memcpy(&s->palette[s->dac_write_index * 3], s->dac_cache, 3);
- s->dac_sub_index = 0;
- s->dac_write_index++;
- }
- break;
- case 0x3ce:
- s->gr_index = val & 0x0f;
- break;
- case 0x3cf:
-#ifdef DEBUG_VGA_REG
- printf("vga: write GR%x = 0x%02x\n", s->gr_index, val);
-#endif
- s->gr[s->gr_index] = val & gr_mask[s->gr_index];
- break;
- case 0x3b4:
- case 0x3d4:
- s->cr_index = val;
- break;
- case 0x3b5:
- case 0x3d5:
-#ifdef DEBUG_VGA_REG
- printf("vga: write CR%x = 0x%02x\n", s->cr_index, val);
-#endif
- /* handle CR0-7 protection */
- if ((s->cr[0x11] & 0x80) && s->cr_index <= 7) {
- /* can always write bit 4 of CR7 */
- if (s->cr_index == 7)
- s->cr[7] = (s->cr[7] & ~0x10) | (val & 0x10);
- return;
- }
- switch(s->cr_index) {
- case 0x01: /* horizontal display end */
- case 0x07:
- case 0x09:
- case 0x0c:
- case 0x0d:
- case 0x12: /* veritcal display end */
- s->cr[s->cr_index] = val;
- break;
- default:
- s->cr[s->cr_index] = val;
- break;
- }
- break;
- case 0x3ba:
- case 0x3da:
- s->fcr = val & 0x10;
- break;
- }
-}
-
-#ifdef CONFIG_BOCHS_VBE
-static uint32_t vbe_ioport_read_index(void *opaque, uint32_t addr)
-{
- VGAState *s = opaque;
- uint32_t val;
- val = s->vbe_index;
- return val;
-}
-
-static uint32_t vbe_ioport_read_data(void *opaque, uint32_t addr)
-{
- VGAState *s = opaque;
- uint32_t val;
-
- if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_GETCAPS) {
- switch(s->vbe_index) {
- /* XXX: do not hardcode ? */
- case VBE_DISPI_INDEX_XRES:
- val = VBE_DISPI_MAX_XRES;
- break;
- case VBE_DISPI_INDEX_YRES:
- val = VBE_DISPI_MAX_YRES;
- break;
- case VBE_DISPI_INDEX_BPP:
- val = VBE_DISPI_MAX_BPP;
- break;
- default:
- val = s->vbe_regs[s->vbe_index];
- break;
- }
- } else {
- val = s->vbe_regs[s->vbe_index];
- }
- } else {
- val = 0;
- }
-#ifdef DEBUG_BOCHS_VBE
- printf("VBE: read index=0x%x val=0x%x\n", s->vbe_index, val);
-#endif
- return val;
-}
-
-static void vbe_ioport_write_index(void *opaque, uint32_t addr, uint32_t val)
-{
- VGAState *s = opaque;
- s->vbe_index = val;
-}
-
-static void vbe_ioport_write_data(void *opaque, uint32_t addr, uint32_t val)
-{
- VGAState *s = opaque;
-
- if (s->vbe_index <= VBE_DISPI_INDEX_NB) {
-#ifdef DEBUG_BOCHS_VBE
- printf("VBE: write index=0x%x val=0x%x\n", s->vbe_index, val);
-#endif
- switch(s->vbe_index) {
- case VBE_DISPI_INDEX_ID:
- if (val == VBE_DISPI_ID0 ||
- val == VBE_DISPI_ID1 ||
- val == VBE_DISPI_ID2) {
- s->vbe_regs[s->vbe_index] = val;
- }
- break;
- case VBE_DISPI_INDEX_XRES:
- if ((val <= VBE_DISPI_MAX_XRES) && ((val & 7) == 0)) {
- s->vbe_regs[s->vbe_index] = val;
- }
- break;
- case VBE_DISPI_INDEX_YRES:
- if (val <= VBE_DISPI_MAX_YRES) {
- s->vbe_regs[s->vbe_index] = val;
- }
- break;
- case VBE_DISPI_INDEX_BPP:
- if (val == 0)
- val = 8;
- if (val == 4 || val == 8 || val == 15 ||
- val == 16 || val == 24 || val == 32) {
- s->vbe_regs[s->vbe_index] = val;
- }
- break;
- case VBE_DISPI_INDEX_BANK:
- val &= s->vbe_bank_mask;
- s->vbe_regs[s->vbe_index] = val;
- s->bank_offset = (val << 16);
- break;
- case VBE_DISPI_INDEX_ENABLE:
- if ((val & VBE_DISPI_ENABLED) &&
- !(s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED)) {
- int h, shift_control;
-
- s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] =
- s->vbe_regs[VBE_DISPI_INDEX_XRES];
- s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] =
- s->vbe_regs[VBE_DISPI_INDEX_YRES];
- s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET] = 0;
- s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET] = 0;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
- s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 1;
- else
- s->vbe_line_offset = s->vbe_regs[VBE_DISPI_INDEX_XRES] *
- ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
- s->vbe_start_addr = 0;
-
- /* clear the screen (should be done in BIOS) */
- if (!(val & VBE_DISPI_NOCLEARMEM)) {
- memset(s->vram_ptr, 0,
- s->vbe_regs[VBE_DISPI_INDEX_YRES] * s->vbe_line_offset);
- }
-
- /* we initialize the VGA graphic mode (should be done
- in BIOS) */
- s->gr[0x06] = (s->gr[0x06] & ~0x0c) | 0x05; /* graphic mode + memory map 1 */
- s->cr[0x17] |= 3; /* no CGA modes */
- s->cr[0x13] = s->vbe_line_offset >> 3;
- /* width */
- s->cr[0x01] = (s->vbe_regs[VBE_DISPI_INDEX_XRES] >> 3) - 1;
- /* height (only meaningful if < 1024) */
- h = s->vbe_regs[VBE_DISPI_INDEX_YRES] - 1;
- s->cr[0x12] = h;
- s->cr[0x07] = (s->cr[0x07] & ~0x42) |
- ((h >> 7) & 0x02) | ((h >> 3) & 0x40);
- /* line compare to 1023 */
- s->cr[0x18] = 0xff;
- s->cr[0x07] |= 0x10;
- s->cr[0x09] |= 0x40;
-
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4) {
- shift_control = 0;
- s->sr[0x01] &= ~8; /* no double line */
- } else {
- shift_control = 2;
- s->sr[4] |= 0x08; /* set chain 4 mode */
- s->sr[2] |= 0x0f; /* activate all planes */
- }
- s->gr[0x05] = (s->gr[0x05] & ~0x60) | (shift_control << 5);
- s->cr[0x09] &= ~0x9f; /* no double scan */
- } else {
- /* XXX: the bios should do that */
- s->bank_offset = 0;
- }
- s->vbe_regs[s->vbe_index] = val;
- break;
- case VBE_DISPI_INDEX_VIRT_WIDTH:
- {
- int w, h, line_offset;
-
- if (val < s->vbe_regs[VBE_DISPI_INDEX_XRES])
- return;
- w = val;
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
- line_offset = w >> 1;
- else
- line_offset = w * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
- h = s->vram_size / line_offset;
- /* XXX: support weird bochs semantics ? */
- if (h < s->vbe_regs[VBE_DISPI_INDEX_YRES])
- return;
- s->vbe_regs[VBE_DISPI_INDEX_VIRT_WIDTH] = w;
- s->vbe_regs[VBE_DISPI_INDEX_VIRT_HEIGHT] = h;
- s->vbe_line_offset = line_offset;
- }
- break;
- case VBE_DISPI_INDEX_X_OFFSET:
- case VBE_DISPI_INDEX_Y_OFFSET:
- {
- int x;
- s->vbe_regs[s->vbe_index] = val;
- s->vbe_start_addr = s->vbe_line_offset * s->vbe_regs[VBE_DISPI_INDEX_Y_OFFSET];
- x = s->vbe_regs[VBE_DISPI_INDEX_X_OFFSET];
- if (s->vbe_regs[VBE_DISPI_INDEX_BPP] == 4)
- s->vbe_start_addr += x >> 1;
- else
- s->vbe_start_addr += x * ((s->vbe_regs[VBE_DISPI_INDEX_BPP] + 7) >> 3);
- s->vbe_start_addr >>= 2;
- }
- break;
- default:
- break;
- }
- }
-}
-#endif
-
-/* called for accesses between 0xa0000 and 0xc0000 */
-uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr)
-{
- VGAState *s = opaque;
- int memory_map_mode, plane;
- uint32_t ret;
-
- /* convert to VGA memory offset */
- memory_map_mode = (s->gr[6] >> 2) & 3;
- addr &= 0x1ffff;
- switch(memory_map_mode) {
- case 0:
- break;
- case 1:
- if (addr >= 0x10000)
- return 0xff;
- addr += s->bank_offset;
- break;
- case 2:
- addr -= 0x10000;
- if (addr >= 0x8000)
- return 0xff;
- break;
- default:
- case 3:
- addr -= 0x18000;
- if (addr >= 0x8000)
- return 0xff;
- break;
- }
-
- if (s->sr[4] & 0x08) {
- /* chain 4 mode : simplest access */
- ret = s->vram_ptr[addr];
- } else if (s->gr[5] & 0x10) {
- /* odd/even mode (aka text mode mapping) */
- plane = (s->gr[4] & 2) | (addr & 1);
- ret = s->vram_ptr[((addr & ~1) << 1) | plane];
- } else {
- /* standard VGA latched access */
- s->latch = ((uint32_t *)s->vram_ptr)[addr];
-
- if (!(s->gr[5] & 0x08)) {
- /* read mode 0 */
- plane = s->gr[4];
- ret = GET_PLANE(s->latch, plane);
- } else {
- /* read mode 1 */
- ret = (s->latch ^ mask16[s->gr[2]]) & mask16[s->gr[7]];
- ret |= ret >> 16;
- ret |= ret >> 8;
- ret = (~ret) & 0xff;
- }
- }
- return ret;
-}
-
-static uint32_t vga_mem_readw(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = vga_mem_readb(opaque, addr) << 8;
- v |= vga_mem_readb(opaque, addr + 1);
-#else
- v = vga_mem_readb(opaque, addr);
- v |= vga_mem_readb(opaque, addr + 1) << 8;
-#endif
- return v;
-}
-
-static uint32_t vga_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = vga_mem_readb(opaque, addr) << 24;
- v |= vga_mem_readb(opaque, addr + 1) << 16;
- v |= vga_mem_readb(opaque, addr + 2) << 8;
- v |= vga_mem_readb(opaque, addr + 3);
-#else
- v = vga_mem_readb(opaque, addr);
- v |= vga_mem_readb(opaque, addr + 1) << 8;
- v |= vga_mem_readb(opaque, addr + 2) << 16;
- v |= vga_mem_readb(opaque, addr + 3) << 24;
-#endif
- return v;
-}
-
-/* called for accesses between 0xa0000 and 0xc0000 */
-void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- VGAState *s = opaque;
- int memory_map_mode, plane, write_mode, b, func_select, mask;
- uint32_t write_mask, bit_mask, set_mask;
-
-#ifdef DEBUG_VGA_MEM
- printf("vga: [0x%x] = 0x%02x\n", addr, val);
-#endif
- /* convert to VGA memory offset */
- memory_map_mode = (s->gr[6] >> 2) & 3;
- addr &= 0x1ffff;
- switch(memory_map_mode) {
- case 0:
- break;
- case 1:
- if (addr >= 0x10000)
- return;
- addr += s->bank_offset;
- break;
- case 2:
- addr -= 0x10000;
- if (addr >= 0x8000)
- return;
- break;
- default:
- case 3:
- addr -= 0x18000;
- if (addr >= 0x8000)
- return;
- break;
- }
-
- if (s->sr[4] & 0x08) {
- /* chain 4 mode : simplest access */
- plane = addr & 3;
- mask = (1 << plane);
- if (s->sr[2] & mask) {
- s->vram_ptr[addr] = val;
-#ifdef DEBUG_VGA_MEM
- printf("vga: chain4: [0x%x]\n", addr);
-#endif
- s->plane_updated |= mask; /* only used to detect font change */
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
- }
- } else if (s->gr[5] & 0x10) {
- /* odd/even mode (aka text mode mapping) */
- plane = (s->gr[4] & 2) | (addr & 1);
- mask = (1 << plane);
- if (s->sr[2] & mask) {
- addr = ((addr & ~1) << 1) | plane;
- s->vram_ptr[addr] = val;
-#ifdef DEBUG_VGA_MEM
- printf("vga: odd/even: [0x%x]\n", addr);
-#endif
- s->plane_updated |= mask; /* only used to detect font change */
- cpu_physical_memory_set_dirty(s->vram_offset + addr);
- }
- } else {
- /* standard VGA latched access */
- write_mode = s->gr[5] & 3;
- switch(write_mode) {
- default:
- case 0:
- /* rotate */
- b = s->gr[3] & 7;
- val = ((val >> b) | (val << (8 - b))) & 0xff;
- val |= val << 8;
- val |= val << 16;
-
- /* apply set/reset mask */
- set_mask = mask16[s->gr[1]];
- val = (val & ~set_mask) | (mask16[s->gr[0]] & set_mask);
- bit_mask = s->gr[8];
- break;
- case 1:
- val = s->latch;
- goto do_write;
- case 2:
- val = mask16[val & 0x0f];
- bit_mask = s->gr[8];
- break;
- case 3:
- /* rotate */
- b = s->gr[3] & 7;
- val = (val >> b) | (val << (8 - b));
-
- bit_mask = s->gr[8] & val;
- val = mask16[s->gr[0]];
- break;
- }
-
- /* apply logical operation */
- func_select = s->gr[3] >> 3;
- switch(func_select) {
- case 0:
- default:
- /* nothing to do */
- break;
- case 1:
- /* and */
- val &= s->latch;
- break;
- case 2:
- /* or */
- val |= s->latch;
- break;
- case 3:
- /* xor */
- val ^= s->latch;
- break;
- }
-
- /* apply bit mask */
- bit_mask |= bit_mask << 8;
- bit_mask |= bit_mask << 16;
- val = (val & bit_mask) | (s->latch & ~bit_mask);
-
- do_write:
- /* mask data according to sr[2] */
- mask = s->sr[2];
- s->plane_updated |= mask; /* only used to detect font change */
- write_mask = mask16[mask];
- ((uint32_t *)s->vram_ptr)[addr] =
- (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |
- (val & write_mask);
-#ifdef DEBUG_VGA_MEM
- printf("vga: latch: [0x%x] mask=0x%08x val=0x%08x\n",
- addr * 4, write_mask, val);
-#endif
- cpu_physical_memory_set_dirty(s->vram_offset + (addr << 2));
- }
-}
-
-static void vga_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- vga_mem_writeb(opaque, addr, (val >> 8) & 0xff);
- vga_mem_writeb(opaque, addr + 1, val & 0xff);
-#else
- vga_mem_writeb(opaque, addr, val & 0xff);
- vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
-}
-
-static void vga_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-#ifdef TARGET_WORDS_BIGENDIAN
- vga_mem_writeb(opaque, addr, (val >> 24) & 0xff);
- vga_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
- vga_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
- vga_mem_writeb(opaque, addr + 3, val & 0xff);
-#else
- vga_mem_writeb(opaque, addr, val & 0xff);
- vga_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
- vga_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
- vga_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
-#endif
-}
-
-typedef void vga_draw_glyph8_func(uint8_t *d, int linesize,
- const uint8_t *font_ptr, int h,
- uint32_t fgcol, uint32_t bgcol);
-typedef void vga_draw_glyph9_func(uint8_t *d, int linesize,
- const uint8_t *font_ptr, int h,
- uint32_t fgcol, uint32_t bgcol, int dup9);
-typedef void vga_draw_line_func(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width);
-
-static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
-{
- return ((r >> 5) << 5) | ((g >> 5) << 2) | (b >> 6);
-}
-
-static inline unsigned int rgb_to_pixel15(unsigned int r, unsigned int g, unsigned b)
-{
- return ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
-}
-
-static inline unsigned int rgb_to_pixel16(unsigned int r, unsigned int g, unsigned b)
-{
- return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
-}
-
-static inline unsigned int rgb_to_pixel32(unsigned int r, unsigned int g, unsigned b)
-{
- return (r << 16) | (g << 8) | b;
-}
-
-static inline unsigned int rgb_to_pixel32bgr(unsigned int r, unsigned int g, unsigned b)
-{
- return (b << 16) | (g << 8) | r;
-}
-
-#define DEPTH 8
-#include "vga_template.h"
-
-#define DEPTH 15
-#include "vga_template.h"
-
-#define DEPTH 16
-#include "vga_template.h"
-
-#define DEPTH 32
-#include "vga_template.h"
-
-#define BGR_FORMAT
-#define DEPTH 32
-#include "vga_template.h"
-
-static unsigned int rgb_to_pixel8_dup(unsigned int r, unsigned int g, unsigned b)
-{
- unsigned int col;
- col = rgb_to_pixel8(r, g, b);
- col |= col << 8;
- col |= col << 16;
- return col;
-}
-
-static unsigned int rgb_to_pixel15_dup(unsigned int r, unsigned int g, unsigned b)
-{
- unsigned int col;
- col = rgb_to_pixel15(r, g, b);
- col |= col << 16;
- return col;
-}
-
-static unsigned int rgb_to_pixel16_dup(unsigned int r, unsigned int g, unsigned b)
-{
- unsigned int col;
- col = rgb_to_pixel16(r, g, b);
- col |= col << 16;
- return col;
-}
-
-static unsigned int rgb_to_pixel32_dup(unsigned int r, unsigned int g, unsigned b)
-{
- unsigned int col;
- col = rgb_to_pixel32(r, g, b);
- return col;
-}
-
-static unsigned int rgb_to_pixel32bgr_dup(unsigned int r, unsigned int g, unsigned b)
-{
- unsigned int col;
- col = rgb_to_pixel32bgr(r, g, b);
- return col;
-}
-
-/* return true if the palette was modified */
-static int update_palette16(VGAState *s)
-{
- int full_update, i;
- uint32_t v, col, *palette;
-
- full_update = 0;
- palette = s->last_palette;
- for(i = 0; i < 16; i++) {
- v = s->ar[i];
- if (s->ar[0x10] & 0x80)
- v = ((s->ar[0x14] & 0xf) << 4) | (v & 0xf);
- else
- v = ((s->ar[0x14] & 0xc) << 4) | (v & 0x3f);
- v = v * 3;
- col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
- c6_to_8(s->palette[v + 1]),
- c6_to_8(s->palette[v + 2]));
- if (col != palette[i]) {
- full_update = 1;
- palette[i] = col;
- }
- }
- return full_update;
-}
-
-/* return true if the palette was modified */
-static int update_palette256(VGAState *s)
-{
- int full_update, i;
- uint32_t v, col, *palette;
-
- full_update = 0;
- palette = s->last_palette;
- v = 0;
- for(i = 0; i < 256; i++) {
- col = s->rgb_to_pixel(c6_to_8(s->palette[v]),
- c6_to_8(s->palette[v + 1]),
- c6_to_8(s->palette[v + 2]));
- if (col != palette[i]) {
- full_update = 1;
- palette[i] = col;
- }
- v += 3;
- }
- return full_update;
-}
-
-static void vga_get_offsets(VGAState *s,
- uint32_t *pline_offset,
- uint32_t *pstart_addr)
-{
- uint32_t start_addr, line_offset;
-#ifdef CONFIG_BOCHS_VBE
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
- line_offset = s->vbe_line_offset;
- start_addr = s->vbe_start_addr;
- } else
-#endif
- {
- /* compute line_offset in bytes */
- line_offset = s->cr[0x13];
- line_offset <<= 3;
-
- /* starting address */
- start_addr = s->cr[0x0d] | (s->cr[0x0c] << 8);
- }
- *pline_offset = line_offset;
- *pstart_addr = start_addr;
-}
-
-/* update start_addr and line_offset. Return TRUE if modified */
-static int update_basic_params(VGAState *s)
-{
- int full_update;
- uint32_t start_addr, line_offset, line_compare;
-
- full_update = 0;
-
- s->get_offsets(s, &line_offset, &start_addr);
- /* line compare */
- line_compare = s->cr[0x18] |
- ((s->cr[0x07] & 0x10) << 4) |
- ((s->cr[0x09] & 0x40) << 3);
-
- if (line_offset != s->line_offset ||
- start_addr != s->start_addr ||
- line_compare != s->line_compare) {
- s->line_offset = line_offset;
- s->start_addr = start_addr;
- s->line_compare = line_compare;
- full_update = 1;
- }
- return full_update;
-}
-
-#define NB_DEPTHS 5
-
-static inline int get_depth_index(DisplayState *s)
-{
- switch(s->depth) {
- default:
- case 8:
- return 0;
- case 15:
- return 1;
- case 16:
- return 2;
- case 32:
- if (s->bgr)
- return 4;
- else
- return 3;
- }
-}
-
-static vga_draw_glyph8_func *vga_draw_glyph8_table[NB_DEPTHS] = {
- vga_draw_glyph8_8,
- vga_draw_glyph8_16,
- vga_draw_glyph8_16,
- vga_draw_glyph8_32,
- vga_draw_glyph8_32,
-};
-
-static vga_draw_glyph8_func *vga_draw_glyph16_table[NB_DEPTHS] = {
- vga_draw_glyph16_8,
- vga_draw_glyph16_16,
- vga_draw_glyph16_16,
- vga_draw_glyph16_32,
- vga_draw_glyph16_32,
-};
-
-static vga_draw_glyph9_func *vga_draw_glyph9_table[NB_DEPTHS] = {
- vga_draw_glyph9_8,
- vga_draw_glyph9_16,
- vga_draw_glyph9_16,
- vga_draw_glyph9_32,
- vga_draw_glyph9_32,
-};
-
-static const uint8_t cursor_glyph[32 * 4] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-};
-
-/*
- * Text mode update
- * Missing:
- * - double scan
- * - double width
- * - underline
- * - flashing
- */
-static void vga_draw_text(VGAState *s, int full_update)
-{
- int cx, cy, cheight, cw, ch, cattr, height, width, ch_attr;
- int cx_min, cx_max, linesize, x_incr;
- uint32_t offset, fgcol, bgcol, v, cursor_offset;
- uint8_t *d1, *d, *src, *s1, *dest, *cursor_ptr;
- const uint8_t *font_ptr, *font_base[2];
- int dup9, line_offset, depth_index;
- uint32_t *palette;
- uint32_t *ch_attr_ptr;
- vga_draw_glyph8_func *vga_draw_glyph8;
- vga_draw_glyph9_func *vga_draw_glyph9;
-
- full_update |= update_palette16(s);
- palette = s->last_palette;
-
- /* compute font data address (in plane 2) */
- v = s->sr[3];
- offset = (((v >> 4) & 1) | ((v << 1) & 6)) * 8192 * 4 + 2;
- if (offset != s->font_offsets[0]) {
- s->font_offsets[0] = offset;
- full_update = 1;
- }
- font_base[0] = s->vram_ptr + offset;
-
- offset = (((v >> 5) & 1) | ((v >> 1) & 6)) * 8192 * 4 + 2;
- font_base[1] = s->vram_ptr + offset;
- if (offset != s->font_offsets[1]) {
- s->font_offsets[1] = offset;
- full_update = 1;
- }
- if (s->plane_updated & (1 << 2)) {
- /* if the plane 2 was modified since the last display, it
- indicates the font may have been modified */
- s->plane_updated = 0;
- full_update = 1;
- }
- full_update |= update_basic_params(s);
-
- line_offset = s->line_offset;
- s1 = s->vram_ptr + (s->start_addr * 4);
-
- /* total width & height */
- cheight = (s->cr[9] & 0x1f) + 1;
- cw = 8;
- if (!(s->sr[1] & 0x01))
- cw = 9;
- if (s->sr[1] & 0x08)
- cw = 16; /* NOTE: no 18 pixel wide */
- x_incr = cw * ((s->ds->depth + 7) >> 3);
- width = (s->cr[0x01] + 1);
- if (s->cr[0x06] == 100) {
- /* ugly hack for CGA 160x100x16 - explain me the logic */
- height = 100;
- } else {
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
- height = (height + 1) / cheight;
- }
- if ((height * width) > CH_ATTR_SIZE) {
- /* better than nothing: exit if transient size is too big */
- return;
- }
-
- if (width != s->last_width || height != s->last_height ||
- cw != s->last_cw || cheight != s->last_ch) {
- s->last_scr_width = width * cw;
- s->last_scr_height = height * cheight;
- dpy_resize(s->ds, s->last_scr_width, s->last_scr_height);
- s->last_width = width;
- s->last_height = height;
- s->last_ch = cheight;
- s->last_cw = cw;
- full_update = 1;
- }
- cursor_offset = ((s->cr[0x0e] << 8) | s->cr[0x0f]) - s->start_addr;
- if (cursor_offset != s->cursor_offset ||
- s->cr[0xa] != s->cursor_start ||
- s->cr[0xb] != s->cursor_end) {
- /* if the cursor position changed, we update the old and new
- chars */
- if (s->cursor_offset < CH_ATTR_SIZE)
- s->last_ch_attr[s->cursor_offset] = -1;
- if (cursor_offset < CH_ATTR_SIZE)
- s->last_ch_attr[cursor_offset] = -1;
- s->cursor_offset = cursor_offset;
- s->cursor_start = s->cr[0xa];
- s->cursor_end = s->cr[0xb];
- }
- cursor_ptr = s->vram_ptr + (s->start_addr + cursor_offset) * 4;
-
- depth_index = get_depth_index(s->ds);
- if (cw == 16)
- vga_draw_glyph8 = vga_draw_glyph16_table[depth_index];
- else
- vga_draw_glyph8 = vga_draw_glyph8_table[depth_index];
- vga_draw_glyph9 = vga_draw_glyph9_table[depth_index];
-
- dest = s->ds->data;
- linesize = s->ds->linesize;
- ch_attr_ptr = s->last_ch_attr;
- for(cy = 0; cy < height; cy++) {
- d1 = dest;
- src = s1;
- cx_min = width;
- cx_max = -1;
- for(cx = 0; cx < width; cx++) {
- ch_attr = *(uint16_t *)src;
- if (full_update || ch_attr != *ch_attr_ptr) {
- if (cx < cx_min)
- cx_min = cx;
- if (cx > cx_max)
- cx_max = cx;
- *ch_attr_ptr = ch_attr;
-#ifdef WORDS_BIGENDIAN
- ch = ch_attr >> 8;
- cattr = ch_attr & 0xff;
-#else
- ch = ch_attr & 0xff;
- cattr = ch_attr >> 8;
-#endif
- font_ptr = font_base[(cattr >> 3) & 1];
- font_ptr += 32 * 4 * ch;
- bgcol = palette[cattr >> 4];
- fgcol = palette[cattr & 0x0f];
- if (cw != 9) {
- vga_draw_glyph8(d1, linesize,
- font_ptr, cheight, fgcol, bgcol);
- } else {
- dup9 = 0;
- if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
- dup9 = 1;
- vga_draw_glyph9(d1, linesize,
- font_ptr, cheight, fgcol, bgcol, dup9);
- }
- if (src == cursor_ptr &&
- !(s->cr[0x0a] & 0x20)) {
- int line_start, line_last, h;
- /* draw the cursor */
- line_start = s->cr[0x0a] & 0x1f;
- line_last = s->cr[0x0b] & 0x1f;
- /* XXX: check that */
- if (line_last > cheight - 1)
- line_last = cheight - 1;
- if (line_last >= line_start && line_start < cheight) {
- h = line_last - line_start + 1;
- d = d1 + linesize * line_start;
- if (cw != 9) {
- vga_draw_glyph8(d, linesize,
- cursor_glyph, h, fgcol, bgcol);
- } else {
- vga_draw_glyph9(d, linesize,
- cursor_glyph, h, fgcol, bgcol, 1);
- }
- }
- }
- }
- d1 += x_incr;
- src += 4;
- ch_attr_ptr++;
- }
- if (cx_max != -1) {
- dpy_update(s->ds, cx_min * cw, cy * cheight,
- (cx_max - cx_min + 1) * cw, cheight);
- }
- dest += linesize * cheight;
- s1 += line_offset;
- }
-}
-
-enum {
- VGA_DRAW_LINE2,
- VGA_DRAW_LINE2D2,
- VGA_DRAW_LINE4,
- VGA_DRAW_LINE4D2,
- VGA_DRAW_LINE8D2,
- VGA_DRAW_LINE8,
- VGA_DRAW_LINE15,
- VGA_DRAW_LINE16,
- VGA_DRAW_LINE24,
- VGA_DRAW_LINE32,
- VGA_DRAW_LINE_NB,
-};
-
-static vga_draw_line_func *vga_draw_line_table[NB_DEPTHS * VGA_DRAW_LINE_NB] = {
- vga_draw_line2_8,
- vga_draw_line2_16,
- vga_draw_line2_16,
- vga_draw_line2_32,
- vga_draw_line2_32,
-
- vga_draw_line2d2_8,
- vga_draw_line2d2_16,
- vga_draw_line2d2_16,
- vga_draw_line2d2_32,
- vga_draw_line2d2_32,
-
- vga_draw_line4_8,
- vga_draw_line4_16,
- vga_draw_line4_16,
- vga_draw_line4_32,
- vga_draw_line4_32,
-
- vga_draw_line4d2_8,
- vga_draw_line4d2_16,
- vga_draw_line4d2_16,
- vga_draw_line4d2_32,
- vga_draw_line4d2_32,
-
- vga_draw_line8d2_8,
- vga_draw_line8d2_16,
- vga_draw_line8d2_16,
- vga_draw_line8d2_32,
- vga_draw_line8d2_32,
-
- vga_draw_line8_8,
- vga_draw_line8_16,
- vga_draw_line8_16,
- vga_draw_line8_32,
- vga_draw_line8_32,
-
- vga_draw_line15_8,
- vga_draw_line15_15,
- vga_draw_line15_16,
- vga_draw_line15_32,
- vga_draw_line15_32bgr,
-
- vga_draw_line16_8,
- vga_draw_line16_15,
- vga_draw_line16_16,
- vga_draw_line16_32,
- vga_draw_line16_32bgr,
-
- vga_draw_line24_8,
- vga_draw_line24_15,
- vga_draw_line24_16,
- vga_draw_line24_32,
- vga_draw_line24_32bgr,
-
- vga_draw_line32_8,
- vga_draw_line32_15,
- vga_draw_line32_16,
- vga_draw_line32_32,
- vga_draw_line32_32bgr,
-};
-
-typedef unsigned int rgb_to_pixel_dup_func(unsigned int r, unsigned int g, unsigned b);
-
-static rgb_to_pixel_dup_func *rgb_to_pixel_dup_table[NB_DEPTHS] = {
- rgb_to_pixel8_dup,
- rgb_to_pixel15_dup,
- rgb_to_pixel16_dup,
- rgb_to_pixel32_dup,
- rgb_to_pixel32bgr_dup,
-};
-
-static int vga_get_bpp(VGAState *s)
-{
- int ret;
-#ifdef CONFIG_BOCHS_VBE
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
- ret = s->vbe_regs[VBE_DISPI_INDEX_BPP];
- } else
-#endif
- {
- ret = 0;
- }
- return ret;
-}
-
-static void vga_get_resolution(VGAState *s, int *pwidth, int *pheight)
-{
- int width, height;
-
-#ifdef CONFIG_BOCHS_VBE
- if (s->vbe_regs[VBE_DISPI_INDEX_ENABLE] & VBE_DISPI_ENABLED) {
- width = s->vbe_regs[VBE_DISPI_INDEX_XRES];
- height = s->vbe_regs[VBE_DISPI_INDEX_YRES];
- } else
-#endif
- {
- width = (s->cr[0x01] + 1) * 8;
- height = s->cr[0x12] |
- ((s->cr[0x07] & 0x02) << 7) |
- ((s->cr[0x07] & 0x40) << 3);
- height = (height + 1);
- }
- *pwidth = width;
- *pheight = height;
-}
-
-void vga_invalidate_scanlines(VGAState *s, int y1, int y2)
-{
- int y;
- if (y1 >= VGA_MAX_HEIGHT)
- return;
- if (y2 >= VGA_MAX_HEIGHT)
- y2 = VGA_MAX_HEIGHT;
- for(y = y1; y < y2; y++) {
- s->invalidated_y_table[y >> 5] |= 1 << (y & 0x1f);
- }
-}
-
-/*
- * graphic modes
- */
-static void vga_draw_graphic(VGAState *s, int full_update)
-{
- int y1, y, update, page_min, page_max, linesize, y_start, double_scan, mask;
- int width, height, shift_control, line_offset, page0, page1, bwidth;
- int disp_width, multi_scan, multi_run;
- uint8_t *d;
- uint32_t v, addr1, addr;
- vga_draw_line_func *vga_draw_line;
-
- full_update |= update_basic_params(s);
-
- s->get_resolution(s, &width, &height);
- disp_width = width;
-
- shift_control = (s->gr[0x05] >> 5) & 3;
- double_scan = (s->cr[0x09] >> 7);
- if (shift_control != 1) {
- multi_scan = (((s->cr[0x09] & 0x1f) + 1) << double_scan) - 1;
- } else {
- /* in CGA modes, multi_scan is ignored */
- /* XXX: is it correct ? */
- multi_scan = double_scan;
- }
- multi_run = multi_scan;
- if (shift_control != s->shift_control ||
- double_scan != s->double_scan) {
- full_update = 1;
- s->shift_control = shift_control;
- s->double_scan = double_scan;
- }
-
- if (shift_control == 0) {
- full_update |= update_palette16(s);
- if (s->sr[0x01] & 8) {
- v = VGA_DRAW_LINE4D2;
- disp_width <<= 1;
- } else {
- v = VGA_DRAW_LINE4;
- }
- } else if (shift_control == 1) {
- full_update |= update_palette16(s);
- if (s->sr[0x01] & 8) {
- v = VGA_DRAW_LINE2D2;
- disp_width <<= 1;
- } else {
- v = VGA_DRAW_LINE2;
- }
- } else {
- switch(s->get_bpp(s)) {
- default:
- case 0:
- full_update |= update_palette256(s);
- v = VGA_DRAW_LINE8D2;
- break;
- case 8:
- full_update |= update_palette256(s);
- v = VGA_DRAW_LINE8;
- break;
- case 15:
- v = VGA_DRAW_LINE15;
- break;
- case 16:
- v = VGA_DRAW_LINE16;
- break;
- case 24:
- v = VGA_DRAW_LINE24;
- break;
- case 32:
- v = VGA_DRAW_LINE32;
- break;
- }
- }
- vga_draw_line = vga_draw_line_table[v * NB_DEPTHS + get_depth_index(s->ds)];
-
- if (disp_width != s->last_width ||
- height != s->last_height) {
- dpy_resize(s->ds, disp_width, height);
- s->last_scr_width = disp_width;
- s->last_scr_height = height;
- s->last_width = disp_width;
- s->last_height = height;
- full_update = 1;
- }
- if (s->cursor_invalidate)
- s->cursor_invalidate(s);
-
- line_offset = s->line_offset;
-#if 0
- printf("w=%d h=%d v=%d line_offset=%d cr[0x09]=0x%02x cr[0x17]=0x%02x linecmp=%d sr[0x01]=0x%02x\n",
- width, height, v, line_offset, s->cr[9], s->cr[0x17], s->line_compare, s->sr[0x01]);
-#endif
- addr1 = (s->start_addr * 4);
- bwidth = width * 4;
- y_start = -1;
- page_min = 0x7fffffff;
- page_max = -1;
- d = s->ds->data;
- linesize = s->ds->linesize;
- y1 = 0;
- for(y = 0; y < height; y++) {
- addr = addr1;
- if (!(s->cr[0x17] & 1)) {
- int shift;
- /* CGA compatibility handling */
- shift = 14 + ((s->cr[0x17] >> 6) & 1);
- addr = (addr & ~(1 << shift)) | ((y1 & 1) << shift);
- }
- if (!(s->cr[0x17] & 2)) {
- addr = (addr & ~0x8000) | ((y1 & 2) << 14);
- }
- page0 = s->vram_offset + (addr & TARGET_PAGE_MASK);
- page1 = s->vram_offset + ((addr + bwidth - 1) & TARGET_PAGE_MASK);
- update = full_update |
- cpu_physical_memory_get_dirty(page0, VGA_DIRTY_FLAG) |
- cpu_physical_memory_get_dirty(page1, VGA_DIRTY_FLAG);
- if ((page1 - page0) > TARGET_PAGE_SIZE) {
- /* if wide line, can use another page */
- update |= cpu_physical_memory_get_dirty(page0 + TARGET_PAGE_SIZE,
- VGA_DIRTY_FLAG);
- }
- /* explicit invalidation for the hardware cursor */
- update |= (s->invalidated_y_table[y >> 5] >> (y & 0x1f)) & 1;
- if (update) {
- if (y_start < 0)
- y_start = y;
- if (page0 < page_min)
- page_min = page0;
- if (page1 > page_max)
- page_max = page1;
- vga_draw_line(s, d, s->vram_ptr + addr, width);
- if (s->cursor_draw_line)
- s->cursor_draw_line(s, d, y);
- } else {
- if (y_start >= 0) {
- /* flush to display */
- dpy_update(s->ds, 0, y_start,
- disp_width, y - y_start);
- y_start = -1;
- }
- }
- if (!multi_run) {
- mask = (s->cr[0x17] & 3) ^ 3;
- if ((y1 & mask) == mask)
- addr1 += line_offset;
- y1++;
- multi_run = multi_scan;
- } else {
- multi_run--;
- }
- /* line compare acts on the displayed lines */
- if (y == s->line_compare)
- addr1 = 0;
- d += linesize;
- }
- if (y_start >= 0) {
- /* flush to display */
- dpy_update(s->ds, 0, y_start,
- disp_width, y - y_start);
- }
- /* reset modified pages */
- if (page_max != -1) {
- cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
- VGA_DIRTY_FLAG);
- }
- memset(s->invalidated_y_table, 0, ((height + 31) >> 5) * 4);
-}
-
-static void vga_draw_blank(VGAState *s, int full_update)
-{
- int i, w, val;
- uint8_t *d;
-
- if (!full_update)
- return;
- if (s->last_scr_width <= 0 || s->last_scr_height <= 0)
- return;
- if (s->ds->depth == 8)
- val = s->rgb_to_pixel(0, 0, 0);
- else
- val = 0;
- w = s->last_scr_width * ((s->ds->depth + 7) >> 3);
- d = s->ds->data;
- for(i = 0; i < s->last_scr_height; i++) {
- memset(d, val, w);
- d += s->ds->linesize;
- }
- dpy_update(s->ds, 0, 0,
- s->last_scr_width, s->last_scr_height);
-}
-
-#define GMODE_TEXT 0
-#define GMODE_GRAPH 1
-#define GMODE_BLANK 2
-
-static void vga_update_display(void *opaque)
-{
- VGAState *s = (VGAState *)opaque;
- int full_update, graphic_mode;
-
- if (s->ds->depth == 0) {
- /* nothing to do */
- } else {
- s->rgb_to_pixel =
- rgb_to_pixel_dup_table[get_depth_index(s->ds)];
-
- full_update = 0;
- if (!(s->ar_index & 0x20)) {
- graphic_mode = GMODE_BLANK;
- } else {
- graphic_mode = s->gr[6] & 1;
- }
- if (graphic_mode != s->graphic_mode) {
- s->graphic_mode = graphic_mode;
- full_update = 1;
- }
- switch(graphic_mode) {
- case GMODE_TEXT:
- vga_draw_text(s, full_update);
- break;
- case GMODE_GRAPH:
- vga_draw_graphic(s, full_update);
- break;
- case GMODE_BLANK:
- default:
- vga_draw_blank(s, full_update);
- break;
- }
- }
-}
-
-/* force a full display refresh */
-static void vga_invalidate_display(void *opaque)
-{
- VGAState *s = (VGAState *)opaque;
-
- s->last_width = -1;
- s->last_height = -1;
-}
-
-static void vga_reset(VGAState *s)
-{
- memset(s, 0, sizeof(VGAState));
- s->graphic_mode = -1; /* force full update */
-}
-
-static CPUReadMemoryFunc *vga_mem_read[3] = {
- vga_mem_readb,
- vga_mem_readw,
- vga_mem_readl,
-};
-
-static CPUWriteMemoryFunc *vga_mem_write[3] = {
- vga_mem_writeb,
- vga_mem_writew,
- vga_mem_writel,
-};
-
-static void vga_save(QEMUFile *f, void *opaque)
-{
- VGAState *s = opaque;
- int i;
-
- qemu_put_be32s(f, &s->latch);
- qemu_put_8s(f, &s->sr_index);
- qemu_put_buffer(f, s->sr, 8);
- qemu_put_8s(f, &s->gr_index);
- qemu_put_buffer(f, s->gr, 16);
- qemu_put_8s(f, &s->ar_index);
- qemu_put_buffer(f, s->ar, 21);
- qemu_put_be32s(f, &s->ar_flip_flop);
- qemu_put_8s(f, &s->cr_index);
- qemu_put_buffer(f, s->cr, 256);
- qemu_put_8s(f, &s->msr);
- qemu_put_8s(f, &s->fcr);
- qemu_put_8s(f, &s->st00);
- qemu_put_8s(f, &s->st01);
-
- qemu_put_8s(f, &s->dac_state);
- qemu_put_8s(f, &s->dac_sub_index);
- qemu_put_8s(f, &s->dac_read_index);
- qemu_put_8s(f, &s->dac_write_index);
- qemu_put_buffer(f, s->dac_cache, 3);
- qemu_put_buffer(f, s->palette, 768);
-
- qemu_put_be32s(f, &s->bank_offset);
-#ifdef CONFIG_BOCHS_VBE
- qemu_put_byte(f, 1);
- qemu_put_be16s(f, &s->vbe_index);
- for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
- qemu_put_be16s(f, &s->vbe_regs[i]);
- qemu_put_be32s(f, &s->vbe_start_addr);
- qemu_put_be32s(f, &s->vbe_line_offset);
- qemu_put_be32s(f, &s->vbe_bank_mask);
-#else
- qemu_put_byte(f, 0);
-#endif
-}
-
-static int vga_load(QEMUFile *f, void *opaque, int version_id)
-{
- VGAState *s = opaque;
- int is_vbe, i;
-
- if (version_id != 1)
- return -EINVAL;
-
- qemu_get_be32s(f, &s->latch);
- qemu_get_8s(f, &s->sr_index);
- qemu_get_buffer(f, s->sr, 8);
- qemu_get_8s(f, &s->gr_index);
- qemu_get_buffer(f, s->gr, 16);
- qemu_get_8s(f, &s->ar_index);
- qemu_get_buffer(f, s->ar, 21);
- qemu_get_be32s(f, &s->ar_flip_flop);
- qemu_get_8s(f, &s->cr_index);
- qemu_get_buffer(f, s->cr, 256);
- qemu_get_8s(f, &s->msr);
- qemu_get_8s(f, &s->fcr);
- qemu_get_8s(f, &s->st00);
- qemu_get_8s(f, &s->st01);
-
- qemu_get_8s(f, &s->dac_state);
- qemu_get_8s(f, &s->dac_sub_index);
- qemu_get_8s(f, &s->dac_read_index);
- qemu_get_8s(f, &s->dac_write_index);
- qemu_get_buffer(f, s->dac_cache, 3);
- qemu_get_buffer(f, s->palette, 768);
-
- qemu_get_be32s(f, &s->bank_offset);
- is_vbe = qemu_get_byte(f);
-#ifdef CONFIG_BOCHS_VBE
- if (!is_vbe)
- return -EINVAL;
- qemu_get_be16s(f, &s->vbe_index);
- for(i = 0; i < VBE_DISPI_INDEX_NB; i++)
- qemu_get_be16s(f, &s->vbe_regs[i]);
- qemu_get_be32s(f, &s->vbe_start_addr);
- qemu_get_be32s(f, &s->vbe_line_offset);
- qemu_get_be32s(f, &s->vbe_bank_mask);
-#else
- if (is_vbe)
- return -EINVAL;
-#endif
-
- /* force refresh */
- s->graphic_mode = -1;
- return 0;
-}
-
-static void vga_map(PCIDevice *pci_dev, int region_num,
- uint32_t addr, uint32_t size, int type)
-{
- VGAState *s = vga_state;
- if (region_num == PCI_ROM_SLOT) {
- cpu_register_physical_memory(addr, s->bios_size, s->bios_offset);
- } else {
- cpu_register_physical_memory(addr, s->vram_size, s->vram_offset);
- }
-}
-
-void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size)
-{
- int i, j, v, b;
-
- for(i = 0;i < 256; i++) {
- v = 0;
- for(j = 0; j < 8; j++) {
- v |= ((i >> j) & 1) << (j * 4);
- }
- expand4[i] = v;
-
- v = 0;
- for(j = 0; j < 4; j++) {
- v |= ((i >> (2 * j)) & 3) << (j * 4);
- }
- expand2[i] = v;
- }
- for(i = 0; i < 16; i++) {
- v = 0;
- for(j = 0; j < 4; j++) {
- b = ((i >> j) & 1);
- v |= b << (2 * j);
- v |= b << (2 * j + 1);
- }
- expand4to8[i] = v;
- }
-
- vga_reset(s);
-
- s->vram_ptr = vga_ram_base;
- s->vram_offset = vga_ram_offset;
- s->vram_size = vga_ram_size;
- s->ds = ds;
- 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);
- /* XXX: currently needed for display */
- vga_state = s;
-}
-
-
-int vga_initialize(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)
-{
- 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);
-
- register_savevm("vga", 0, 1, vga_save, vga_load, s);
-
- register_ioport_write(0x3c0, 16, 1, vga_ioport_write, s);
-
- register_ioport_write(0x3b4, 2, 1, vga_ioport_write, s);
- register_ioport_write(0x3d4, 2, 1, vga_ioport_write, s);
- register_ioport_write(0x3ba, 1, 1, vga_ioport_write, s);
- register_ioport_write(0x3da, 1, 1, vga_ioport_write, s);
-
- register_ioport_read(0x3c0, 16, 1, vga_ioport_read, s);
-
- register_ioport_read(0x3b4, 2, 1, vga_ioport_read, s);
- register_ioport_read(0x3d4, 2, 1, vga_ioport_read, s);
- register_ioport_read(0x3ba, 1, 1, vga_ioport_read, s);
- register_ioport_read(0x3da, 1, 1, vga_ioport_read, s);
- s->bank_offset = 0;
-
-#ifdef CONFIG_BOCHS_VBE
- s->vbe_regs[VBE_DISPI_INDEX_ID] = VBE_DISPI_ID0;
- s->vbe_bank_mask = ((s->vram_size >> 16) - 1);
-#if defined (TARGET_I386)
- register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
- register_ioport_read(0x1cf, 1, 2, vbe_ioport_read_data, s);
-
- register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
- register_ioport_write(0x1cf, 1, 2, vbe_ioport_write_data, s);
-
- /* old Bochs IO ports */
- register_ioport_read(0xff80, 1, 2, vbe_ioport_read_index, s);
- register_ioport_read(0xff81, 1, 2, vbe_ioport_read_data, s);
-
- register_ioport_write(0xff80, 1, 2, vbe_ioport_write_index, s);
- register_ioport_write(0xff81, 1, 2, vbe_ioport_write_data, s);
-#else
- register_ioport_read(0x1ce, 1, 2, vbe_ioport_read_index, s);
- register_ioport_read(0x1d0, 1, 2, vbe_ioport_read_data, s);
-
- register_ioport_write(0x1ce, 1, 2, vbe_ioport_write_index, s);
- register_ioport_write(0x1d0, 1, 2, vbe_ioport_write_data, s);
-#endif
-#endif /* CONFIG_BOCHS_VBE */
-
- vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
- cpu_register_physical_memory(isa_mem_base + 0x000a0000, 0x20000,
- vga_io_memory);
-
- if (bus) {
- PCIDevice *d;
- uint8_t *pci_conf;
-
- d = pci_register_device(bus, "VGA",
- sizeof(PCIDevice),
- -1, NULL, NULL);
- pci_conf = d->config;
- pci_conf[0x00] = 0x34; // dummy VGA (same as Bochs ID)
- pci_conf[0x01] = 0x12;
- pci_conf[0x02] = 0x11;
- pci_conf[0x03] = 0x11;
- pci_conf[0x0a] = 0x00; // VGA controller
- pci_conf[0x0b] = 0x03;
- pci_conf[0x0e] = 0x00; // header_type
-
- /* XXX: vga_ram_size must be a power of two */
- pci_register_io_region(d, 0, vga_ram_size,
- PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
- if (vga_bios_size != 0) {
- unsigned int bios_total_size;
- s->bios_offset = vga_bios_offset;
- s->bios_size = vga_bios_size;
- /* must be a power of two */
- bios_total_size = 1;
- while (bios_total_size < vga_bios_size)
- bios_total_size <<= 1;
- pci_register_io_region(d, PCI_ROM_SLOT, bios_total_size,
- PCI_ADDRESS_SPACE_MEM_PREFETCH, vga_map);
- }
- } else {
-#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;
-}
-
-/********************************************************/
-/* vga screen dump */
-
-static int vga_save_w, vga_save_h;
-
-static void vga_save_dpy_update(DisplayState *s,
- int x, int y, int w, int h)
-{
-}
-
-static void vga_save_dpy_resize(DisplayState *s, int w, int h)
-{
- s->linesize = w * 4;
- s->data = qemu_malloc(h * s->linesize);
- vga_save_w = w;
- vga_save_h = h;
-}
-
-static void vga_save_dpy_refresh(DisplayState *s)
-{
-}
-
-static int ppm_save(const char *filename, uint8_t *data,
- int w, int h, int linesize)
-{
- FILE *f;
- uint8_t *d, *d1;
- unsigned int v;
- int y, x;
-
- f = fopen(filename, "wb");
- if (!f)
- return -1;
- fprintf(f, "P6\n%d %d\n%d\n",
- w, h, 255);
- d1 = data;
- for(y = 0; y < h; y++) {
- d = d1;
- for(x = 0; x < w; x++) {
- v = *(uint32_t *)d;
- fputc((v >> 16) & 0xff, f);
- fputc((v >> 8) & 0xff, f);
- fputc((v) & 0xff, f);
- d += 4;
- }
- d1 += linesize;
- }
- fclose(f);
- return 0;
-}
-
-/* save the vga display in a PPM image even if no display is
- available */
-static void vga_screen_dump(void *opaque, const char *filename)
-{
- VGAState *s = (VGAState *)opaque;
- DisplayState *saved_ds, ds1, *ds = &ds1;
-
- /* XXX: this is a little hackish */
- vga_invalidate_display(s);
- saved_ds = s->ds;
-
- memset(ds, 0, sizeof(DisplayState));
- ds->dpy_update = vga_save_dpy_update;
- ds->dpy_resize = vga_save_dpy_resize;
- ds->dpy_refresh = vga_save_dpy_refresh;
- ds->depth = 32;
-
- s->ds = ds;
- s->graphic_mode = -1;
- vga_update_display(s);
-
- if (ds->data) {
- ppm_save(filename, ds->data, vga_save_w, vga_save_h,
- s->ds->linesize);
- qemu_free(ds->data);
- }
- s->ds = saved_ds;
-}
diff --git a/hw/vga_int.h b/hw/vga_int.h
deleted file mode 100644
index b33ab57..0000000
--- a/hw/vga_int.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * QEMU internal VGA defines.
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#define MSR_COLOR_EMULATION 0x01
-#define MSR_PAGE_SELECT 0x20
-
-#define ST01_V_RETRACE 0x08
-#define ST01_DISP_ENABLE 0x01
-
-/* bochs VBE support */
-#define CONFIG_BOCHS_VBE
-
-#define VBE_DISPI_MAX_XRES 1600
-#define VBE_DISPI_MAX_YRES 1200
-#define VBE_DISPI_MAX_BPP 32
-
-#define VBE_DISPI_INDEX_ID 0x0
-#define VBE_DISPI_INDEX_XRES 0x1
-#define VBE_DISPI_INDEX_YRES 0x2
-#define VBE_DISPI_INDEX_BPP 0x3
-#define VBE_DISPI_INDEX_ENABLE 0x4
-#define VBE_DISPI_INDEX_BANK 0x5
-#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6
-#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7
-#define VBE_DISPI_INDEX_X_OFFSET 0x8
-#define VBE_DISPI_INDEX_Y_OFFSET 0x9
-#define VBE_DISPI_INDEX_NB 0xa
-
-#define VBE_DISPI_ID0 0xB0C0
-#define VBE_DISPI_ID1 0xB0C1
-#define VBE_DISPI_ID2 0xB0C2
-
-#define VBE_DISPI_DISABLED 0x00
-#define VBE_DISPI_ENABLED 0x01
-#define VBE_DISPI_GETCAPS 0x02
-#define VBE_DISPI_8BIT_DAC 0x20
-#define VBE_DISPI_LFB_ENABLED 0x40
-#define VBE_DISPI_NOCLEARMEM 0x80
-
-#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000
-
-#ifdef CONFIG_BOCHS_VBE
-
-#define VGA_STATE_COMMON_BOCHS_VBE \
- uint16_t vbe_index; \
- uint16_t vbe_regs[VBE_DISPI_INDEX_NB]; \
- uint32_t vbe_start_addr; \
- uint32_t vbe_line_offset; \
- uint32_t vbe_bank_mask;
-
-#else
-
-#define VGA_STATE_COMMON_BOCHS_VBE
-
-#endif /* !CONFIG_BOCHS_VBE */
-
-#define CH_ATTR_SIZE (160 * 100)
-#define VGA_MAX_HEIGHT 2048
-
-#define VGA_STATE_COMMON \
- uint8_t *vram_ptr; \
- unsigned long vram_offset; \
- unsigned int vram_size; \
- unsigned long bios_offset; \
- unsigned int bios_size; \
- uint32_t latch; \
- uint8_t sr_index; \
- uint8_t sr[256]; \
- uint8_t gr_index; \
- uint8_t gr[256]; \
- uint8_t ar_index; \
- uint8_t ar[21]; \
- int ar_flip_flop; \
- uint8_t cr_index; \
- uint8_t cr[256]; /* CRT registers */ \
- uint8_t msr; /* Misc Output Register */ \
- uint8_t fcr; /* Feature Control Register */ \
- uint8_t st00; /* status 0 */ \
- uint8_t st01; /* status 1 */ \
- uint8_t dac_state; \
- uint8_t dac_sub_index; \
- uint8_t dac_read_index; \
- uint8_t dac_write_index; \
- uint8_t dac_cache[3]; /* used when writing */ \
- uint8_t palette[768]; \
- int32_t bank_offset; \
- int (*get_bpp)(struct VGAState *s); \
- void (*get_offsets)(struct VGAState *s, \
- uint32_t *pline_offset, \
- uint32_t *pstart_addr); \
- void (*get_resolution)(struct VGAState *s, \
- int *pwidth, \
- int *pheight); \
- VGA_STATE_COMMON_BOCHS_VBE \
- /* display refresh support */ \
- DisplayState *ds; \
- uint32_t font_offsets[2]; \
- int graphic_mode; \
- uint8_t shift_control; \
- uint8_t double_scan; \
- uint32_t line_offset; \
- uint32_t line_compare; \
- uint32_t start_addr; \
- uint32_t plane_updated; \
- uint8_t last_cw, last_ch; \
- uint32_t last_width, last_height; /* in chars or pixels */ \
- uint32_t last_scr_width, last_scr_height; /* in pixels */ \
- uint8_t cursor_start, cursor_end; \
- uint32_t cursor_offset; \
- unsigned int (*rgb_to_pixel)(unsigned int r, \
- unsigned int g, unsigned b); \
- /* hardware mouse cursor support */ \
- uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \
- void (*cursor_invalidate)(struct VGAState *s); \
- void (*cursor_draw_line)(struct VGAState *s, uint8_t *d, int y); \
- /* tell for each page if it has been updated since the last time */ \
- uint32_t last_palette[256]; \
- uint32_t last_ch_attr[CH_ATTR_SIZE]; /* XXX: make it dynamic */
-
-
-typedef struct VGAState {
- VGA_STATE_COMMON
-} VGAState;
-
-static inline int c6_to_8(int v)
-{
- int b;
- v &= 0x3f;
- b = v & 1;
- return (v << 2) | (b << 1) | b;
-}
-
-void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size);
-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);
-
-void vga_draw_cursor_line_8(uint8_t *d1, const uint8_t *src1,
- int poffset, int w,
- unsigned int color0, unsigned int color1,
- unsigned int color_xor);
-void vga_draw_cursor_line_16(uint8_t *d1, const uint8_t *src1,
- int poffset, int w,
- unsigned int color0, unsigned int color1,
- unsigned int color_xor);
-void vga_draw_cursor_line_32(uint8_t *d1, const uint8_t *src1,
- int poffset, int w,
- unsigned int color0, unsigned int color1,
- unsigned int color_xor);
-
-extern const uint8_t sr_mask[8];
-extern const uint8_t gr_mask[16];
diff --git a/hw/vga_template.h b/hw/vga_template.h
deleted file mode 100644
index e7e8cb8..0000000
--- a/hw/vga_template.h
+++ /dev/null
@@ -1,525 +0,0 @@
-/*
- * QEMU VGA Emulator templates
- *
- * 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.
- */
-
-#if DEPTH == 8
-#define BPP 1
-#define PIXEL_TYPE uint8_t
-#elif DEPTH == 15 || DEPTH == 16
-#define BPP 2
-#define PIXEL_TYPE uint16_t
-#elif DEPTH == 32
-#define BPP 4
-#define PIXEL_TYPE uint32_t
-#else
-#error unsupport depth
-#endif
-
-#ifdef BGR_FORMAT
-#define PIXEL_NAME glue(DEPTH, bgr)
-#else
-#define PIXEL_NAME DEPTH
-#endif /* BGR_FORMAT */
-
-#if DEPTH != 15 && !defined(BGR_FORMAT)
-
-static inline void glue(vga_draw_glyph_line_, DEPTH)(uint8_t *d,
- uint32_t font_data,
- uint32_t xorcol,
- uint32_t bgcol)
-{
-#if BPP == 1
- ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
- ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
-#elif BPP == 2
- ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
- ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
- ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
- ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
-#else
- ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
- ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
-#endif
-}
-
-static void glue(vga_draw_glyph8_, DEPTH)(uint8_t *d, int linesize,
- const uint8_t *font_ptr, int h,
- uint32_t fgcol, uint32_t bgcol)
-{
- uint32_t font_data, xorcol;
-
- xorcol = bgcol ^ fgcol;
- do {
- font_data = font_ptr[0];
- glue(vga_draw_glyph_line_, DEPTH)(d, font_data, xorcol, bgcol);
- font_ptr += 4;
- d += linesize;
- } while (--h);
-}
-
-static void glue(vga_draw_glyph16_, DEPTH)(uint8_t *d, int linesize,
- const uint8_t *font_ptr, int h,
- uint32_t fgcol, uint32_t bgcol)
-{
- uint32_t font_data, xorcol;
-
- xorcol = bgcol ^ fgcol;
- do {
- font_data = font_ptr[0];
- glue(vga_draw_glyph_line_, DEPTH)(d,
- expand4to8[font_data >> 4],
- xorcol, bgcol);
- glue(vga_draw_glyph_line_, DEPTH)(d + 8 * BPP,
- expand4to8[font_data & 0x0f],
- xorcol, bgcol);
- font_ptr += 4;
- d += linesize;
- } while (--h);
-}
-
-static void glue(vga_draw_glyph9_, DEPTH)(uint8_t *d, int linesize,
- const uint8_t *font_ptr, int h,
- uint32_t fgcol, uint32_t bgcol, int dup9)
-{
- uint32_t font_data, xorcol, v;
-
- xorcol = bgcol ^ fgcol;
- do {
- font_data = font_ptr[0];
-#if BPP == 1
- cpu_to_32wu((uint32_t *)d, (dmask16[(font_data >> 4)] & xorcol) ^ bgcol);
- v = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
- cpu_to_32wu(((uint32_t *)d)+1, v);
- if (dup9)
- ((uint8_t *)d)[8] = v >> (24 * (1 - BIG));
- else
- ((uint8_t *)d)[8] = bgcol;
-
-#elif BPP == 2
- cpu_to_32wu(((uint32_t *)d)+0, (dmask4[(font_data >> 6)] & xorcol) ^ bgcol);
- cpu_to_32wu(((uint32_t *)d)+1, (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol);
- cpu_to_32wu(((uint32_t *)d)+2, (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol);
- v = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
- cpu_to_32wu(((uint32_t *)d)+3, v);
- if (dup9)
- ((uint16_t *)d)[8] = v >> (16 * (1 - BIG));
- else
- ((uint16_t *)d)[8] = bgcol;
-#else
- ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
- ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
- v = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
- ((uint32_t *)d)[7] = v;
- if (dup9)
- ((uint32_t *)d)[8] = v;
- else
- ((uint32_t *)d)[8] = bgcol;
-#endif
- font_ptr += 4;
- d += linesize;
- } while (--h);
-}
-
-/*
- * 4 color mode
- */
-static void glue(vga_draw_line2_, DEPTH)(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t plane_mask, *palette, data, v;
- int x;
-
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
- width >>= 3;
- for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
- data &= plane_mask;
- v = expand2[GET_PLANE(data, 0)];
- v |= expand2[GET_PLANE(data, 2)] << 2;
- ((PIXEL_TYPE *)d)[0] = palette[v >> 12];
- ((PIXEL_TYPE *)d)[1] = palette[(v >> 8) & 0xf];
- ((PIXEL_TYPE *)d)[2] = palette[(v >> 4) & 0xf];
- ((PIXEL_TYPE *)d)[3] = palette[(v >> 0) & 0xf];
-
- v = expand2[GET_PLANE(data, 1)];
- v |= expand2[GET_PLANE(data, 3)] << 2;
- ((PIXEL_TYPE *)d)[4] = palette[v >> 12];
- ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
- ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
- ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
- d += BPP * 8;
- s += 4;
- }
-}
-
-#if BPP == 1
-#define PUT_PIXEL2(d, n, v) ((uint16_t *)d)[(n)] = (v)
-#elif BPP == 2
-#define PUT_PIXEL2(d, n, v) ((uint32_t *)d)[(n)] = (v)
-#else
-#define PUT_PIXEL2(d, n, v) \
-((uint32_t *)d)[2*(n)] = ((uint32_t *)d)[2*(n)+1] = (v)
-#endif
-
-/*
- * 4 color mode, dup2 horizontal
- */
-static void glue(vga_draw_line2d2_, DEPTH)(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t plane_mask, *palette, data, v;
- int x;
-
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
- width >>= 3;
- for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
- data &= plane_mask;
- v = expand2[GET_PLANE(data, 0)];
- v |= expand2[GET_PLANE(data, 2)] << 2;
- PUT_PIXEL2(d, 0, palette[v >> 12]);
- PUT_PIXEL2(d, 1, palette[(v >> 8) & 0xf]);
- PUT_PIXEL2(d, 2, palette[(v >> 4) & 0xf]);
- PUT_PIXEL2(d, 3, palette[(v >> 0) & 0xf]);
-
- v = expand2[GET_PLANE(data, 1)];
- v |= expand2[GET_PLANE(data, 3)] << 2;
- PUT_PIXEL2(d, 4, palette[v >> 12]);
- PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
- PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
- PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
- d += BPP * 16;
- s += 4;
- }
-}
-
-/*
- * 16 color mode
- */
-static void glue(vga_draw_line4_, DEPTH)(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t plane_mask, data, v, *palette;
- int x;
-
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
- width >>= 3;
- for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
- data &= plane_mask;
- v = expand4[GET_PLANE(data, 0)];
- v |= expand4[GET_PLANE(data, 1)] << 1;
- v |= expand4[GET_PLANE(data, 2)] << 2;
- v |= expand4[GET_PLANE(data, 3)] << 3;
- ((PIXEL_TYPE *)d)[0] = palette[v >> 28];
- ((PIXEL_TYPE *)d)[1] = palette[(v >> 24) & 0xf];
- ((PIXEL_TYPE *)d)[2] = palette[(v >> 20) & 0xf];
- ((PIXEL_TYPE *)d)[3] = palette[(v >> 16) & 0xf];
- ((PIXEL_TYPE *)d)[4] = palette[(v >> 12) & 0xf];
- ((PIXEL_TYPE *)d)[5] = palette[(v >> 8) & 0xf];
- ((PIXEL_TYPE *)d)[6] = palette[(v >> 4) & 0xf];
- ((PIXEL_TYPE *)d)[7] = palette[(v >> 0) & 0xf];
- d += BPP * 8;
- s += 4;
- }
-}
-
-/*
- * 16 color mode, dup2 horizontal
- */
-static void glue(vga_draw_line4d2_, DEPTH)(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t plane_mask, data, v, *palette;
- int x;
-
- palette = s1->last_palette;
- plane_mask = mask16[s1->ar[0x12] & 0xf];
- width >>= 3;
- for(x = 0; x < width; x++) {
- data = ((uint32_t *)s)[0];
- data &= plane_mask;
- v = expand4[GET_PLANE(data, 0)];
- v |= expand4[GET_PLANE(data, 1)] << 1;
- v |= expand4[GET_PLANE(data, 2)] << 2;
- v |= expand4[GET_PLANE(data, 3)] << 3;
- PUT_PIXEL2(d, 0, palette[v >> 28]);
- PUT_PIXEL2(d, 1, palette[(v >> 24) & 0xf]);
- PUT_PIXEL2(d, 2, palette[(v >> 20) & 0xf]);
- PUT_PIXEL2(d, 3, palette[(v >> 16) & 0xf]);
- PUT_PIXEL2(d, 4, palette[(v >> 12) & 0xf]);
- PUT_PIXEL2(d, 5, palette[(v >> 8) & 0xf]);
- PUT_PIXEL2(d, 6, palette[(v >> 4) & 0xf]);
- PUT_PIXEL2(d, 7, palette[(v >> 0) & 0xf]);
- d += BPP * 16;
- s += 4;
- }
-}
-
-/*
- * 256 color mode, double pixels
- *
- * XXX: add plane_mask support (never used in standard VGA modes)
- */
-static void glue(vga_draw_line8d2_, DEPTH)(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t *palette;
- int x;
-
- palette = s1->last_palette;
- width >>= 3;
- for(x = 0; x < width; x++) {
- PUT_PIXEL2(d, 0, palette[s[0]]);
- PUT_PIXEL2(d, 1, palette[s[1]]);
- PUT_PIXEL2(d, 2, palette[s[2]]);
- PUT_PIXEL2(d, 3, palette[s[3]]);
- d += BPP * 8;
- s += 4;
- }
-}
-
-/*
- * standard 256 color mode
- *
- * XXX: add plane_mask support (never used in standard VGA modes)
- */
-static void glue(vga_draw_line8_, DEPTH)(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- uint32_t *palette;
- int x;
-
- palette = s1->last_palette;
- width >>= 3;
- for(x = 0; x < width; x++) {
- ((PIXEL_TYPE *)d)[0] = palette[s[0]];
- ((PIXEL_TYPE *)d)[1] = palette[s[1]];
- ((PIXEL_TYPE *)d)[2] = palette[s[2]];
- ((PIXEL_TYPE *)d)[3] = palette[s[3]];
- ((PIXEL_TYPE *)d)[4] = palette[s[4]];
- ((PIXEL_TYPE *)d)[5] = palette[s[5]];
- ((PIXEL_TYPE *)d)[6] = palette[s[6]];
- ((PIXEL_TYPE *)d)[7] = palette[s[7]];
- d += BPP * 8;
- s += 8;
- }
-}
-
-void glue(vga_draw_cursor_line_, DEPTH)(uint8_t *d1,
- const uint8_t *src1,
- int poffset, int w,
- unsigned int color0,
- unsigned int color1,
- unsigned int color_xor)
-{
- const uint8_t *plane0, *plane1;
- int x, b0, b1;
- uint8_t *d;
-
- d = d1;
- plane0 = src1;
- plane1 = src1 + poffset;
- for(x = 0; x < w; x++) {
- b0 = (plane0[x >> 3] >> (7 - (x & 7))) & 1;
- b1 = (plane1[x >> 3] >> (7 - (x & 7))) & 1;
-#if DEPTH == 8
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- d[0] ^= color_xor;
- break;
- case 2:
- d[0] = color0;
- break;
- case 3:
- d[0] = color1;
- break;
- }
-#elif DEPTH == 16
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- ((uint16_t *)d)[0] ^= color_xor;
- break;
- case 2:
- ((uint16_t *)d)[0] = color0;
- break;
- case 3:
- ((uint16_t *)d)[0] = color1;
- break;
- }
-#elif DEPTH == 32
- switch(b0 | (b1 << 1)) {
- case 0:
- break;
- case 1:
- ((uint32_t *)d)[0] ^= color_xor;
- break;
- case 2:
- ((uint32_t *)d)[0] = color0;
- break;
- case 3:
- ((uint32_t *)d)[0] = color1;
- break;
- }
-#else
-#error unsupported depth
-#endif
- d += BPP;
- }
-}
-
-#endif /* DEPTH != 15 */
-
-
-/* XXX: optimize */
-
-/*
- * 15 bit color
- */
-static void glue(vga_draw_line15_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
-#if DEPTH == 15 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
- memcpy(d, s, width * 2);
-#else
- int w;
- uint32_t v, r, g, b;
-
- w = width;
- do {
- v = lduw_raw((void *)s);
- r = (v >> 7) & 0xf8;
- g = (v >> 2) & 0xf8;
- b = (v << 3) & 0xf8;
- ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s += 2;
- d += BPP;
- } while (--w != 0);
-#endif
-}
-
-/*
- * 16 bit color
- */
-static void glue(vga_draw_line16_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
-#if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
- memcpy(d, s, width * 2);
-#else
- int w;
- uint32_t v, r, g, b;
-
- w = width;
- do {
- v = lduw_raw((void *)s);
- r = (v >> 8) & 0xf8;
- g = (v >> 3) & 0xfc;
- b = (v << 3) & 0xf8;
- ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s += 2;
- d += BPP;
- } while (--w != 0);
-#endif
-}
-
-/*
- * 24 bit color
- */
-static void glue(vga_draw_line24_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
- int w;
- uint32_t r, g, b;
-
- w = width;
- do {
-#if defined(TARGET_WORDS_BIGENDIAN)
- r = s[0];
- g = s[1];
- b = s[2];
-#else
- b = s[0];
- g = s[1];
- r = s[2];
-#endif
- ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s += 3;
- d += BPP;
- } while (--w != 0);
-}
-
-/*
- * 32 bit color
- */
-static void glue(vga_draw_line32_, PIXEL_NAME)(VGAState *s1, uint8_t *d,
- const uint8_t *s, int width)
-{
-#if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN) && !defined(BGR_FORMAT)
- memcpy(d, s, width * 4);
-#else
- int w;
- uint32_t r, g, b;
-
- w = width;
- do {
-#if defined(TARGET_WORDS_BIGENDIAN)
- r = s[1];
- g = s[2];
- b = s[3];
-#else
- b = s[0];
- g = s[1];
- r = s[2];
-#endif
- ((PIXEL_TYPE *)d)[0] = glue(rgb_to_pixel, PIXEL_NAME)(r, g, b);
- s += 4;
- d += BPP;
- } while (--w != 0);
-#endif
-}
-
-#undef PUT_PIXEL2
-#undef DEPTH
-#undef BPP
-#undef PIXEL_TYPE
-#undef PIXEL_NAME
-#undef BGR_FORMAT
diff --git a/images/android_icon.ico b/images/android_icon.ico
new file mode 100644
index 0000000..bd25179
--- /dev/null
+++ b/images/android_icon.ico
Binary files differ
diff --git a/images/android_icon.rc b/images/android_icon.rc
new file mode 100644
index 0000000..df468ac
--- /dev/null
+++ b/images/android_icon.rc
@@ -0,0 +1,3 @@
+1 ICON "../images/android_icon.ico"
+
+
diff --git a/images/android_icon_16.png b/images/android_icon_16.png
new file mode 100644
index 0000000..0b0744b
--- /dev/null
+++ b/images/android_icon_16.png
Binary files differ
diff --git a/images/android_icon_256.png b/images/android_icon_256.png
new file mode 100644
index 0000000..2d1dc05
--- /dev/null
+++ b/images/android_icon_256.png
Binary files differ
diff --git a/images/android_icon_32.png b/images/android_icon_32.png
new file mode 100644
index 0000000..72aa861
--- /dev/null
+++ b/images/android_icon_32.png
Binary files differ
diff --git a/linux-2.6.9-qemu-fast.patch b/linux-2.6.9-qemu-fast.patch
deleted file mode 100644
index f8ecd0b..0000000
--- a/linux-2.6.9-qemu-fast.patch
+++ /dev/null
@@ -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
diff --git a/linux-user/arm-semi.c b/linux-user/arm-semi.c
deleted file mode 100644
index 250d5b7..0000000
--- a/linux-user/arm-semi.c
+++ /dev/null
@@ -1,203 +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)
-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:
- /* XXX: Not implemented. */
- s = (char *)g2h(ARG(0));
- *s = 0;
- return -1;
- 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();
- }
-}
-
diff --git a/linux-user/arm/syscall.h b/linux-user/arm/syscall.h
deleted file mode 100644
index 1d508f0..0000000
--- a/linux-user/arm/syscall.h
+++ /dev/null
@@ -1,42 +0,0 @@
-
-/* this struct defines the way the registers are stored on the
- stack during a system call. */
-
-struct target_pt_regs {
- target_long uregs[18];
-};
-
-#define ARM_cpsr uregs[16]
-#define ARM_pc uregs[15]
-#define ARM_lr uregs[14]
-#define ARM_sp uregs[13]
-#define ARM_ip uregs[12]
-#define ARM_fp uregs[11]
-#define ARM_r10 uregs[10]
-#define ARM_r9 uregs[9]
-#define ARM_r8 uregs[8]
-#define ARM_r7 uregs[7]
-#define ARM_r6 uregs[6]
-#define ARM_r5 uregs[5]
-#define ARM_r4 uregs[4]
-#define ARM_r3 uregs[3]
-#define ARM_r2 uregs[2]
-#define ARM_r1 uregs[1]
-#define ARM_r0 uregs[0]
-#define ARM_ORIG_r0 uregs[17]
-
-#define ARM_SYSCALL_BASE 0x900000
-#define ARM_THUMB_SYSCALL 0
-
-#define ARM_NR_cacheflush (ARM_SYSCALL_BASE + 0xf0000 + 2)
-
-#define ARM_NR_semihosting 0x123456
-#define ARM_NR_thumb_semihosting 0xAB
-
-#if defined(TARGET_WORDS_BIGENDIAN)
-#define UNAME_MACHINE "armv5teb"
-#else
-#define UNAME_MACHINE "armv5tel"
-#endif
-
-uint32_t do_arm_semihosting(CPUState *);
diff --git a/linux-user/arm/syscall_nr.h b/linux-user/arm/syscall_nr.h
deleted file mode 100644
index 195e459..0000000
--- a/linux-user/arm/syscall_nr.h
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * 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) /* removed */
-#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) /* removed */
- /* 18 was sys_stat */
-#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_pause ( 29)
-#define TARGET_NR_utime ( 30)
-#define TARGET_NR_stty ( 31) /* removed */
-#define TARGET_NR_gtty ( 32) /* removed */
-#define TARGET_NR_access ( 33)
-#define TARGET_NR_nice ( 34)
-#define TARGET_NR_ftime ( 35) /* removed */
-#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) /* removed */
-#define TARGET_NR_brk ( 45)
-#define TARGET_NR_setgid ( 46)
-#define TARGET_NR_getgid ( 47)
-#define TARGET_NR_signal ( 48) /* removed */
-#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) /* removed */
-#define TARGET_NR_ioctl ( 54)
-#define TARGET_NR_fcntl ( 55)
-#define TARGET_NR_mpx ( 56) /* removed */
-#define TARGET_NR_setpgid ( 57)
-#define TARGET_NR_ulimit ( 58) /* removed */
- /* 59 was sys_olduname */
-#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) /* removed */
-#define TARGET_NR_ssetmask ( 69) /* removed */
-#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 compat 2GB 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)
- /* 84 was sys_lstat */
-#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) /* removed */
-#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)
- /* 109 was sys_uname */
- /* 110 was sys_iopl */
-#define TARGET_NR_vhangup (111)
-#define TARGET_NR_idle (112)
-#define TARGET_NR_syscall (113) /* syscall to call a syscall! */
-#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) /* removed */
-#define TARGET_NR_init_module (128)
-#define TARGET_NR_delete_module (129)
-#define TARGET_NR_get_kernel_syms (130) /* removed */
-#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) /* removed */
-#define TARGET_NR_query_module (167) /* removed */
-#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)
- /* 188 reserved */
- /* 189 reserved */
-#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_getdents64 (217)
-#define TARGET_NR_pivot_root (218)
-#define TARGET_NR_mincore (219)
-#define TARGET_NR_madvise (220)
-#define TARGET_NR_fcntl64 (221)
- /* 222 for tux */
- /* 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_io_setup (243)
-#define TARGET_NR_io_destroy (244)
-#define TARGET_NR_io_getevents (245)
-#define TARGET_NR_io_submit (246)
-#define TARGET_NR_io_cancel (247)
-#define TARGET_NR_exit_group (248)
-#define TARGET_NR_lookup_dcookie (249)
-#define TARGET_NR_epoll_create (250)
-#define TARGET_NR_epoll_ctl (251)
-#define TARGET_NR_epoll_wait (252)
-#define TARGET_NR_remap_file_pages (253)
- /* 254 for set_thread_area */
- /* 255 for get_thread_area */
- /* 256 for set_tid_address */
-#define TARGET_NR_utimes (269)
diff --git a/linux-user/arm/termbits.h b/linux-user/arm/termbits.h
deleted file mode 100644
index 36ead08..0000000
--- a/linux-user/arm/termbits.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/* from asm/termbits.h */
-/* NOTE: exactly the same as i386 */
-
-#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 */
-
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
deleted file mode 100644
index 57b5ed2..0000000
--- a/linux-user/elfload.c
+++ /dev/null
@@ -1,1240 +0,0 @@
-/* This is the Linux kernel elf-loading code, ported into user space */
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "qemu.h"
-#include "disas.h"
-
-/* this flag is uneffective under linux too, should be deleted */
-#ifndef MAP_DENYWRITE
-#define MAP_DENYWRITE 0
-#endif
-
-/* should probably go in elf.h */
-#ifndef ELIBBAD
-#define ELIBBAD 80
-#endif
-
-#ifdef TARGET_I386
-
-#define ELF_PLATFORM get_elf_platform()
-
-static const char *get_elf_platform(void)
-{
- static char elf_platform[] = "i386";
- int family = (global_env->cpuid_version >> 8) & 0xff;
- if (family > 6)
- family = 6;
- if (family >= 3)
- elf_platform[1] = '0' + family;
- return elf_platform;
-}
-
-#define ELF_HWCAP get_elf_hwcap()
-
-static uint32_t get_elf_hwcap(void)
-{
- return global_env->cpuid_features;
-}
-
-#define ELF_START_MMAP 0x80000000
-
-/*
- * This is used to ensure we don't load something for the wrong architecture.
- */
-#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) )
-
-/*
- * These are used to set parameters in the core dumps.
- */
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2LSB
-#define ELF_ARCH EM_386
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
- regs->esp = infop->start_stack;
- regs->eip = infop->entry;
-
- /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program
- starts %edx contains a pointer to a function which might be
- registered using `atexit'. This provides a mean for the
- dynamic linker to call DT_FINI functions for shared libraries
- that have been loaded before the code runs.
-
- A value of 0 tells we have no such handler. */
- regs->edx = 0;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-#endif
-
-#ifdef TARGET_ARM
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_ARM )
-
-#define ELF_CLASS ELFCLASS32
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA ELFDATA2MSB
-#else
-#define ELF_DATA ELFDATA2LSB
-#endif
-#define ELF_ARCH EM_ARM
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
- target_long stack = infop->start_stack;
- memset(regs, 0, sizeof(*regs));
- regs->ARM_cpsr = 0x10;
- if (infop->entry & 1)
- regs->ARM_cpsr |= CPSR_T;
- regs->ARM_pc = infop->entry & 0xfffffffe;
- regs->ARM_sp = infop->start_stack;
- regs->ARM_r2 = tgetl(stack + 8); /* envp */
- regs->ARM_r1 = tgetl(stack + 4); /* envp */
- /* XXX: it seems that r0 is zeroed after ! */
- regs->ARM_r0 = 0;
- /* For uClinux PIC binaries. */
- regs->ARM_r10 = infop->start_data;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-enum
-{
- ARM_HWCAP_ARM_SWP = 1 << 0,
- ARM_HWCAP_ARM_HALF = 1 << 1,
- ARM_HWCAP_ARM_THUMB = 1 << 2,
- ARM_HWCAP_ARM_26BIT = 1 << 3,
- ARM_HWCAP_ARM_FAST_MULT = 1 << 4,
- ARM_HWCAP_ARM_FPA = 1 << 5,
- ARM_HWCAP_ARM_VFP = 1 << 6,
- ARM_HWCAP_ARM_EDSP = 1 << 7,
-};
-
-#define ELF_HWCAP (ARM_HWCAP_ARM_SWP | ARM_HWCAP_ARM_HALF \
- | ARM_HWCAP_ARM_THUMB | ARM_HWCAP_ARM_FAST_MULT \
- | ARM_HWCAP_ARM_FPA | ARM_HWCAP_ARM_VFP)
-
-#endif
-
-#ifdef TARGET_SPARC
-#ifdef TARGET_SPARC64
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_SPARCV9 )
-
-#define ELF_CLASS ELFCLASS64
-#define ELF_DATA ELFDATA2MSB
-#define ELF_ARCH EM_SPARCV9
-
-#define STACK_BIAS 2047
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
- regs->tstate = 0;
- regs->pc = infop->entry;
- regs->npc = regs->pc + 4;
- regs->y = 0;
- regs->u_regs[14] = infop->start_stack - 16 * 8 - STACK_BIAS;
-}
-
-#else
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_SPARC )
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2MSB
-#define ELF_ARCH EM_SPARC
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
- regs->psr = 0;
- regs->pc = infop->entry;
- regs->npc = regs->pc + 4;
- regs->y = 0;
- regs->u_regs[14] = infop->start_stack - 16 * 4;
-}
-
-#endif
-#endif
-
-#ifdef TARGET_PPC
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_PPC )
-
-#define ELF_CLASS ELFCLASS32
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA ELFDATA2MSB
-#else
-#define ELF_DATA ELFDATA2LSB
-#endif
-#define ELF_ARCH EM_PPC
-
-/*
- * We need to put in some extra aux table entries to tell glibc what
- * the cache block size is, so it can use the dcbz instruction safely.
- */
-#define AT_DCACHEBSIZE 19
-#define AT_ICACHEBSIZE 20
-#define AT_UCACHEBSIZE 21
-/* A special ignored type value for PPC, for glibc compatibility. */
-#define AT_IGNOREPPC 22
-/*
- * The requirements here are:
- * - keep the final alignment of sp (sp & 0xf)
- * - make sure the 32-bit value at the first 16 byte aligned position of
- * AUXV is greater than 16 for glibc compatibility.
- * AT_IGNOREPPC is used for that.
- * - for compatibility with glibc ARCH_DLINFO must always be defined on PPC,
- * even if DLINFO_ARCH_ITEMS goes to zero or is undefined.
- */
-#define DLINFO_ARCH_ITEMS 5
-#define ARCH_DLINFO \
-do { \
- NEW_AUX_ENT(AT_DCACHEBSIZE, 0x20); \
- NEW_AUX_ENT(AT_ICACHEBSIZE, 0x20); \
- NEW_AUX_ENT(AT_UCACHEBSIZE, 0); \
- /* \
- * Now handle glibc compatibility. \
- */ \
- NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
- NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \
- } while (0)
-
-static inline void init_thread(struct target_pt_regs *_regs, struct image_info *infop)
-{
- target_ulong pos = infop->start_stack;
- target_ulong tmp;
-
- _regs->msr = 1 << MSR_PR; /* Set user mode */
- _regs->gpr[1] = infop->start_stack;
- _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
- * execution of PPC BSD programs.
- */
- _regs->gpr[3] = tgetl(pos);
- pos += sizeof(target_ulong);
- _regs->gpr[4] = pos;
- for (tmp = 1; tmp != 0; pos += sizeof(target_ulong))
- tmp = ldl(pos);
- _regs->gpr[5] = pos;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-#endif
-
-#ifdef TARGET_MIPS
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_MIPS )
-
-#define ELF_CLASS ELFCLASS32
-#ifdef TARGET_WORDS_BIGENDIAN
-#define ELF_DATA ELFDATA2MSB
-#else
-#define ELF_DATA ELFDATA2LSB
-#endif
-#define ELF_ARCH EM_MIPS
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
- regs->cp0_status = CP0St_UM;
- regs->cp0_epc = infop->entry;
- regs->regs[29] = infop->start_stack;
-}
-
-#endif /* TARGET_MIPS */
-
-#ifdef TARGET_SH4
-
-#define ELF_START_MMAP 0x80000000
-
-#define elf_check_arch(x) ( (x) == EM_SH )
-
-#define ELF_CLASS ELFCLASS32
-#define ELF_DATA ELFDATA2LSB
-#define ELF_ARCH EM_SH
-
-static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
- /* Check other registers XXXXX */
- regs->pc = infop->entry;
- regs->regs[15] = infop->start_stack - 16 * 4;
-}
-
-#define USE_ELF_CORE_DUMP
-#define ELF_EXEC_PAGESIZE 4096
-
-#endif
-
-#ifndef ELF_PLATFORM
-#define ELF_PLATFORM (NULL)
-#endif
-
-#ifndef ELF_HWCAP
-#define ELF_HWCAP 0
-#endif
-
-#include "elf.h"
-
-struct exec
-{
- unsigned int a_info; /* Use macros N_MAGIC, etc for access */
- unsigned int a_text; /* length of text, in bytes */
- unsigned int a_data; /* length of data, in bytes */
- unsigned int a_bss; /* length of uninitialized data area, in bytes */
- unsigned int a_syms; /* length of symbol table data in file, in bytes */
- unsigned int a_entry; /* start address */
- unsigned int a_trsize; /* length of relocation info for text, in bytes */
- unsigned int a_drsize; /* length of relocation info for data, in bytes */
-};
-
-
-#define N_MAGIC(exec) ((exec).a_info & 0xffff)
-#define OMAGIC 0407
-#define NMAGIC 0410
-#define ZMAGIC 0413
-#define QMAGIC 0314
-
-/* max code+data+bss space allocated to elf interpreter */
-#define INTERP_MAP_SIZE (32 * 1024 * 1024)
-
-/* max code+data+bss+brk space allocated to ET_DYN executables */
-#define ET_DYN_MAP_SIZE (128 * 1024 * 1024)
-
-/* from personality.h */
-
-/* Flags for bug emulation. These occupy the top three bytes. */
-#define STICKY_TIMEOUTS 0x4000000
-#define WHOLE_SECONDS 0x2000000
-
-/* Personality types. These go in the low byte. Avoid using the top bit,
- * it will conflict with error returns.
- */
-#define PER_MASK (0x00ff)
-#define PER_LINUX (0x0000)
-#define PER_SVR4 (0x0001 | STICKY_TIMEOUTS)
-#define PER_SVR3 (0x0002 | STICKY_TIMEOUTS)
-#define PER_SCOSVR3 (0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS)
-#define PER_WYSEV386 (0x0004 | STICKY_TIMEOUTS)
-#define PER_ISCR4 (0x0005 | STICKY_TIMEOUTS)
-#define PER_BSD (0x0006)
-#define PER_XENIX (0x0007 | STICKY_TIMEOUTS)
-
-/* Necessary parameters */
-#define TARGET_ELF_EXEC_PAGESIZE TARGET_PAGE_SIZE
-#define TARGET_ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(TARGET_ELF_EXEC_PAGESIZE-1))
-#define TARGET_ELF_PAGEOFFSET(_v) ((_v) & (TARGET_ELF_EXEC_PAGESIZE-1))
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-#define DLINFO_ITEMS 12
-
-static inline void memcpy_fromfs(void * to, const void * from, unsigned long n)
-{
- memcpy(to, from, n);
-}
-
-extern unsigned long x86_stack_size;
-
-static int load_aout_interp(void * exptr, int interp_fd);
-
-#ifdef BSWAP_NEEDED
-static void bswap_ehdr(struct elfhdr *ehdr)
-{
- bswap16s(&ehdr->e_type); /* Object file type */
- bswap16s(&ehdr->e_machine); /* Architecture */
- bswap32s(&ehdr->e_version); /* Object file version */
- bswaptls(&ehdr->e_entry); /* Entry point virtual address */
- bswaptls(&ehdr->e_phoff); /* Program header table file offset */
- bswaptls(&ehdr->e_shoff); /* Section header table file offset */
- bswap32s(&ehdr->e_flags); /* Processor-specific flags */
- bswap16s(&ehdr->e_ehsize); /* ELF header size in bytes */
- bswap16s(&ehdr->e_phentsize); /* Program header table entry size */
- bswap16s(&ehdr->e_phnum); /* Program header table entry count */
- bswap16s(&ehdr->e_shentsize); /* Section header table entry size */
- bswap16s(&ehdr->e_shnum); /* Section header table entry count */
- bswap16s(&ehdr->e_shstrndx); /* Section header string table index */
-}
-
-static void bswap_phdr(struct elf_phdr *phdr)
-{
- bswap32s(&phdr->p_type); /* Segment type */
- bswaptls(&phdr->p_offset); /* Segment file offset */
- bswaptls(&phdr->p_vaddr); /* Segment virtual address */
- bswaptls(&phdr->p_paddr); /* Segment physical address */
- bswaptls(&phdr->p_filesz); /* Segment size in file */
- bswaptls(&phdr->p_memsz); /* Segment size in memory */
- bswap32s(&phdr->p_flags); /* Segment flags */
- bswaptls(&phdr->p_align); /* Segment alignment */
-}
-
-static void bswap_shdr(struct elf_shdr *shdr)
-{
- bswap32s(&shdr->sh_name);
- bswap32s(&shdr->sh_type);
- bswaptls(&shdr->sh_flags);
- bswaptls(&shdr->sh_addr);
- bswaptls(&shdr->sh_offset);
- bswaptls(&shdr->sh_size);
- bswap32s(&shdr->sh_link);
- bswap32s(&shdr->sh_info);
- bswaptls(&shdr->sh_addralign);
- bswaptls(&shdr->sh_entsize);
-}
-
-static void bswap_sym(Elf32_Sym *sym)
-{
- bswap32s(&sym->st_name);
- bswap32s(&sym->st_value);
- bswap32s(&sym->st_size);
- bswap16s(&sym->st_shndx);
-}
-#endif
-
-/*
- * 'copy_elf_strings()' copies argument/envelope strings from user
- * memory to free pages in kernel mem. These are in a format ready
- * to be put directly into the top of new user memory.
- *
- */
-static unsigned long copy_elf_strings(int argc,char ** argv, void **page,
- unsigned long p)
-{
- char *tmp, *tmp1, *pag = NULL;
- int len, offset = 0;
-
- if (!p) {
- return 0; /* bullet-proofing */
- }
- while (argc-- > 0) {
- tmp = argv[argc];
- if (!tmp) {
- fprintf(stderr, "VFS: argc is wrong");
- exit(-1);
- }
- tmp1 = tmp;
- while (*tmp++);
- len = tmp - tmp1;
- if (p < len) { /* this shouldn't happen - 128kB */
- return 0;
- }
- while (len) {
- --p; --tmp; --len;
- if (--offset < 0) {
- offset = p % TARGET_PAGE_SIZE;
- pag = (char *)page[p/TARGET_PAGE_SIZE];
- if (!pag) {
- pag = (char *)malloc(TARGET_PAGE_SIZE);
- page[p/TARGET_PAGE_SIZE] = pag;
- if (!pag)
- return 0;
- }
- }
- if (len == 0 || offset == 0) {
- *(pag + offset) = *tmp;
- }
- else {
- int bytes_to_copy = (len > offset) ? offset : len;
- tmp -= bytes_to_copy;
- p -= bytes_to_copy;
- offset -= bytes_to_copy;
- len -= bytes_to_copy;
- memcpy_fromfs(pag + offset, tmp, bytes_to_copy + 1);
- }
- }
- }
- return p;
-}
-
-unsigned long setup_arg_pages(target_ulong p, struct linux_binprm * bprm,
- struct image_info * info)
-{
- target_ulong stack_base, size, error;
- int i;
-
- /* Create enough stack to hold everything. If we don't use
- * it for args, we'll use it for something else...
- */
- size = x86_stack_size;
- if (size < MAX_ARG_PAGES*TARGET_PAGE_SIZE)
- size = MAX_ARG_PAGES*TARGET_PAGE_SIZE;
- error = target_mmap(0,
- size + qemu_host_page_size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0);
- if (error == -1) {
- perror("stk mmap");
- exit(-1);
- }
- /* 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 - MAX_ARG_PAGES*TARGET_PAGE_SIZE;
- p += stack_base;
-
- for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
- if (bprm->page[i]) {
- info->rss++;
-
- memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
- free(bprm->page[i]);
- }
- stack_base += TARGET_PAGE_SIZE;
- }
- return p;
-}
-
-static void set_brk(unsigned long start, unsigned long end)
-{
- /* page-align the start and end addresses... */
- start = HOST_PAGE_ALIGN(start);
- end = HOST_PAGE_ALIGN(end);
- if (end <= start)
- return;
- if(target_mmap(start, end - start,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0) == -1) {
- perror("cannot mmap brk");
- exit(-1);
- }
-}
-
-
-/* We need to explicitly zero any fractional pages after the data
- section (i.e. bss). This would contain the junk from the file that
- should not be in memory. */
-static void padzero(unsigned long elf_bss)
-{
- unsigned long nbyte;
-
- /* XXX: this is really a hack : if the real host page size is
- smaller than the target page size, some pages after the end
- of the file may not be mapped. A better fix would be to
- patch target_mmap(), but it is more complicated as the file
- size must be known */
- if (qemu_real_host_page_size < qemu_host_page_size) {
- unsigned long end_addr, end_addr1;
- end_addr1 = (elf_bss + qemu_real_host_page_size - 1) &
- ~(qemu_real_host_page_size - 1);
- end_addr = HOST_PAGE_ALIGN(elf_bss);
- if (end_addr1 < end_addr) {
- mmap((void *)end_addr1, end_addr - end_addr1,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- }
- }
-
- nbyte = elf_bss & (qemu_host_page_size-1);
- if (nbyte) {
- nbyte = qemu_host_page_size - nbyte;
- do {
- tput8(elf_bss, 0);
- elf_bss++;
- } while (--nbyte);
- }
-}
-
-
-static unsigned long create_elf_tables(target_ulong p, int argc, int envc,
- struct elfhdr * exec,
- unsigned long load_addr,
- unsigned long load_bias,
- unsigned long interp_load_addr, int ibcs,
- struct image_info *info)
-{
- target_ulong sp;
- int size;
- target_ulong u_platform;
- const char *k_platform;
- const int n = sizeof(target_ulong);
-
- sp = p;
- u_platform = 0;
- k_platform = ELF_PLATFORM;
- if (k_platform) {
- size_t len = strlen(k_platform) + 1;
- sp -= (len + n - 1) & ~(n - 1);
- u_platform = sp;
- memcpy_to_target(sp, k_platform, len);
- }
- /*
- * Force 16 byte _final_ alignment here for generality.
- */
- sp = sp &~ (target_ulong)15;
- size = (DLINFO_ITEMS + 1) * 2;
- if (k_platform)
- size += 2;
-#ifdef DLINFO_ARCH_ITEMS
- size += DLINFO_ARCH_ITEMS * 2;
-#endif
- size += envc + argc + 2;
- size += (!ibcs ? 3 : 1); /* argc itself */
- size *= n;
- if (size & 15)
- sp -= 16 - (size & 15);
-
-#define NEW_AUX_ENT(id, val) do { \
- sp -= n; tputl(sp, val); \
- sp -= n; tputl(sp, id); \
- } while(0)
- NEW_AUX_ENT (AT_NULL, 0);
-
- /* There must be exactly DLINFO_ITEMS entries here. */
- NEW_AUX_ENT(AT_PHDR, (target_ulong)(load_addr + exec->e_phoff));
- NEW_AUX_ENT(AT_PHENT, (target_ulong)(sizeof (struct elf_phdr)));
- NEW_AUX_ENT(AT_PHNUM, (target_ulong)(exec->e_phnum));
- NEW_AUX_ENT(AT_PAGESZ, (target_ulong)(TARGET_PAGE_SIZE));
- NEW_AUX_ENT(AT_BASE, (target_ulong)(interp_load_addr));
- NEW_AUX_ENT(AT_FLAGS, (target_ulong)0);
- NEW_AUX_ENT(AT_ENTRY, load_bias + exec->e_entry);
- NEW_AUX_ENT(AT_UID, (target_ulong) getuid());
- NEW_AUX_ENT(AT_EUID, (target_ulong) geteuid());
- NEW_AUX_ENT(AT_GID, (target_ulong) getgid());
- NEW_AUX_ENT(AT_EGID, (target_ulong) getegid());
- NEW_AUX_ENT(AT_HWCAP, (target_ulong) ELF_HWCAP);
- if (k_platform)
- NEW_AUX_ENT(AT_PLATFORM, u_platform);
-#ifdef ARCH_DLINFO
- /*
- * ARCH_DLINFO must come last so platform specific code can enforce
- * special alignment requirements on the AUXV if necessary (eg. PPC).
- */
- ARCH_DLINFO;
-#endif
-#undef NEW_AUX_ENT
-
- sp = loader_build_argptr(envc, argc, sp, p, !ibcs);
- return sp;
-}
-
-
-static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex,
- int interpreter_fd,
- unsigned long *interp_load_addr)
-{
- struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- unsigned long load_addr = 0;
- int load_addr_set = 0;
- int retval;
- unsigned long last_bss, elf_bss;
- unsigned long error;
- int i;
-
- elf_bss = 0;
- last_bss = 0;
- error = 0;
-
-#ifdef BSWAP_NEEDED
- bswap_ehdr(interp_elf_ex);
-#endif
- /* First of all, some simple consistency checks */
- if ((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- !elf_check_arch(interp_elf_ex->e_machine)) {
- return ~0UL;
- }
-
-
- /* Now read in all of the header information */
-
- if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > TARGET_PAGE_SIZE)
- return ~0UL;
-
- elf_phdata = (struct elf_phdr *)
- malloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
-
- if (!elf_phdata)
- return ~0UL;
-
- /*
- * If the size of this structure has changed, then punt, since
- * we will be doing the wrong thing.
- */
- if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) {
- free(elf_phdata);
- return ~0UL;
- }
-
- retval = lseek(interpreter_fd, interp_elf_ex->e_phoff, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,
- (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- }
- if (retval < 0) {
- perror("load_elf_interp");
- exit(-1);
- free (elf_phdata);
- return retval;
- }
-#ifdef BSWAP_NEEDED
- eppnt = elf_phdata;
- for (i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
- bswap_phdr(eppnt);
- }
-#endif
-
- if (interp_elf_ex->e_type == ET_DYN) {
- /* in order to avoid harcoding the interpreter load
- address in qemu, we allocate a big enough memory zone */
- error = target_mmap(0, INTERP_MAP_SIZE,
- PROT_NONE, MAP_PRIVATE | MAP_ANON,
- -1, 0);
- if (error == -1) {
- perror("mmap");
- exit(-1);
- }
- load_addr = error;
- load_addr_set = 1;
- }
-
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
- if (eppnt->p_type == PT_LOAD) {
- int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
- int elf_prot = 0;
- unsigned long vaddr = 0;
- unsigned long k;
-
- if (eppnt->p_flags & PF_R) elf_prot = PROT_READ;
- if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) {
- elf_type |= MAP_FIXED;
- vaddr = eppnt->p_vaddr;
- }
- error = target_mmap(load_addr+TARGET_ELF_PAGESTART(vaddr),
- eppnt->p_filesz + TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr),
- elf_prot,
- elf_type,
- interpreter_fd,
- eppnt->p_offset - TARGET_ELF_PAGEOFFSET(eppnt->p_vaddr));
-
- if (error == -1) {
- /* Real error */
- close(interpreter_fd);
- free(elf_phdata);
- return ~0UL;
- }
-
- if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) {
- load_addr = error;
- load_addr_set = 1;
- }
-
- /*
- * Find the end of the file mapping for this phdr, and keep
- * track of the largest address we see for this.
- */
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if (k > elf_bss) elf_bss = k;
-
- /*
- * Do the same thing for the memory mapping - between
- * elf_bss and last_bss is the bss section.
- */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if (k > last_bss) last_bss = k;
- }
-
- /* Now use mmap to map the library into memory. */
-
- close(interpreter_fd);
-
- /*
- * Now fill out the bss section. First pad the last page up
- * to the page boundary, and then perform a mmap to make sure
- * that there are zeromapped pages up to and including the last
- * bss page.
- */
- padzero(elf_bss);
- elf_bss = TARGET_ELF_PAGESTART(elf_bss + qemu_host_page_size - 1); /* What we have mapped so far */
-
- /* Map the last of the bss segment */
- if (last_bss > elf_bss) {
- target_mmap(elf_bss, last_bss-elf_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- }
- free(elf_phdata);
-
- *interp_load_addr = load_addr;
- return ((unsigned long) interp_elf_ex->e_entry) + load_addr;
-}
-
-/* Best attempt to load symbols from this ELF object. */
-static void load_symbols(struct elfhdr *hdr, int fd)
-{
- unsigned int i;
- struct elf_shdr sechdr, symtab, strtab;
- char *strings;
- struct syminfo *s;
-
- lseek(fd, hdr->e_shoff, SEEK_SET);
- for (i = 0; i < hdr->e_shnum; i++) {
- if (read(fd, &sechdr, sizeof(sechdr)) != sizeof(sechdr))
- return;
-#ifdef BSWAP_NEEDED
- bswap_shdr(&sechdr);
-#endif
- if (sechdr.sh_type == SHT_SYMTAB) {
- symtab = sechdr;
- lseek(fd, hdr->e_shoff
- + sizeof(sechdr) * sechdr.sh_link, SEEK_SET);
- if (read(fd, &strtab, sizeof(strtab))
- != sizeof(strtab))
- return;
-#ifdef BSWAP_NEEDED
- bswap_shdr(&strtab);
-#endif
- goto found;
- }
- }
- return; /* Shouldn't happen... */
-
- found:
- /* Now know where the strtab and symtab are. Snarf them. */
- s = malloc(sizeof(*s));
- s->disas_symtab = malloc(symtab.sh_size);
- s->disas_strtab = strings = malloc(strtab.sh_size);
- if (!s->disas_symtab || !s->disas_strtab)
- return;
-
- lseek(fd, symtab.sh_offset, SEEK_SET);
- if (read(fd, s->disas_symtab, symtab.sh_size) != symtab.sh_size)
- return;
-
-#ifdef BSWAP_NEEDED
- for (i = 0; i < symtab.sh_size / sizeof(struct elf_sym); i++)
- bswap_sym(s->disas_symtab + sizeof(struct elf_sym)*i);
-#endif
-
- lseek(fd, strtab.sh_offset, SEEK_SET);
- if (read(fd, strings, strtab.sh_size) != strtab.sh_size)
- return;
- s->disas_num_syms = symtab.sh_size / sizeof(struct elf_sym);
- s->next = syminfos;
- syminfos = s;
-}
-
-int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
- struct image_info * info)
-{
- struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
- struct exec interp_ex;
- int interpreter_fd = -1; /* avoid warning */
- unsigned long load_addr, load_bias;
- int load_addr_set = 0;
- unsigned int interpreter_type = INTERPRETER_NONE;
- unsigned char ibcs2_interpreter;
- int i;
- unsigned long mapped_addr;
- struct elf_phdr * elf_ppnt;
- struct elf_phdr *elf_phdata;
- unsigned long elf_bss, k, elf_brk;
- int retval;
- char * elf_interpreter;
- unsigned long elf_entry, interp_load_addr = 0;
- int status;
- unsigned long start_code, end_code, end_data;
- unsigned long elf_stack;
- char passed_fileno[6];
-
- ibcs2_interpreter = 0;
- status = 0;
- load_addr = 0;
- load_bias = 0;
- elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-#ifdef BSWAP_NEEDED
- bswap_ehdr(&elf_ex);
-#endif
-
- /* First of all, some simple consistency checks */
- if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) ||
- (! elf_check_arch(elf_ex.e_machine))) {
- return -ENOEXEC;
- }
-
- bprm->p = copy_elf_strings(1, &bprm->filename, bprm->page, bprm->p);
- bprm->p = copy_elf_strings(bprm->envc,bprm->envp,bprm->page,bprm->p);
- bprm->p = copy_elf_strings(bprm->argc,bprm->argv,bprm->page,bprm->p);
- if (!bprm->p) {
- retval = -E2BIG;
- }
-
- /* Now read in all of the header information */
- elf_phdata = (struct elf_phdr *)malloc(elf_ex.e_phentsize*elf_ex.e_phnum);
- if (elf_phdata == NULL) {
- return -ENOMEM;
- }
-
- retval = lseek(bprm->fd, elf_ex.e_phoff, SEEK_SET);
- if(retval > 0) {
- retval = read(bprm->fd, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
- }
-
- if (retval < 0) {
- perror("load_elf_binary");
- exit(-1);
- free (elf_phdata);
- return -errno;
- }
-
-#ifdef BSWAP_NEEDED
- elf_ppnt = elf_phdata;
- for (i=0; i<elf_ex.e_phnum; i++, elf_ppnt++) {
- bswap_phdr(elf_ppnt);
- }
-#endif
- elf_ppnt = elf_phdata;
-
- elf_bss = 0;
- elf_brk = 0;
-
-
- elf_stack = ~0UL;
- elf_interpreter = NULL;
- start_code = ~0UL;
- end_code = 0;
- end_data = 0;
-
- for(i=0;i < elf_ex.e_phnum; i++) {
- if (elf_ppnt->p_type == PT_INTERP) {
- if ( elf_interpreter != NULL )
- {
- free (elf_phdata);
- free(elf_interpreter);
- close(bprm->fd);
- return -EINVAL;
- }
-
- /* This is the program interpreter used for
- * shared libraries - for now assume that this
- * is an a.out format binary
- */
-
- elf_interpreter = (char *)malloc(elf_ppnt->p_filesz);
-
- if (elf_interpreter == NULL) {
- free (elf_phdata);
- close(bprm->fd);
- return -ENOMEM;
- }
-
- retval = lseek(bprm->fd, elf_ppnt->p_offset, SEEK_SET);
- if(retval >= 0) {
- retval = read(bprm->fd, elf_interpreter, elf_ppnt->p_filesz);
- }
- if(retval < 0) {
- perror("load_elf_binary2");
- exit(-1);
- }
-
- /* If the program interpreter is one of these two,
- then assume an iBCS2 image. Otherwise assume
- a native linux image. */
-
- /* JRP - Need to add X86 lib dir stuff here... */
-
- if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
- strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0) {
- ibcs2_interpreter = 1;
- }
-
-#if 0
- printf("Using ELF interpreter %s\n", elf_interpreter);
-#endif
- if (retval >= 0) {
- retval = open(path(elf_interpreter), O_RDONLY);
- if(retval >= 0) {
- interpreter_fd = retval;
- }
- else {
- perror(elf_interpreter);
- exit(-1);
- /* retval = -errno; */
- }
- }
-
- if (retval >= 0) {
- retval = lseek(interpreter_fd, 0, SEEK_SET);
- if(retval >= 0) {
- retval = read(interpreter_fd,bprm->buf,128);
- }
- }
- if (retval >= 0) {
- interp_ex = *((struct exec *) bprm->buf); /* aout exec-header */
- interp_elf_ex=*((struct elfhdr *) bprm->buf); /* elf exec-header */
- }
- if (retval < 0) {
- perror("load_elf_binary3");
- exit(-1);
- free (elf_phdata);
- free(elf_interpreter);
- close(bprm->fd);
- return retval;
- }
- }
- elf_ppnt++;
- }
-
- /* Some simple consistency checks for the interpreter */
- if (elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
-
- /* Now figure out which format our binary is */
- if ((N_MAGIC(interp_ex) != OMAGIC) && (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC)) {
- interpreter_type = INTERPRETER_ELF;
- }
-
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) {
- interpreter_type &= ~INTERPRETER_ELF;
- }
-
- if (!interpreter_type) {
- free(elf_interpreter);
- free(elf_phdata);
- close(bprm->fd);
- return -ELIBBAD;
- }
- }
-
- /* OK, we are done with that, now set up the arg stuff,
- and then start this sucker up */
-
- {
- char * passed_p;
-
- if (interpreter_type == INTERPRETER_AOUT) {
- snprintf(passed_fileno, sizeof(passed_fileno), "%d", bprm->fd);
- passed_p = passed_fileno;
-
- if (elf_interpreter) {
- bprm->p = copy_elf_strings(1,&passed_p,bprm->page,bprm->p);
- bprm->argc++;
- }
- }
- if (!bprm->p) {
- if (elf_interpreter) {
- free(elf_interpreter);
- }
- free (elf_phdata);
- close(bprm->fd);
- return -E2BIG;
- }
- }
-
- /* OK, This is the point of no return */
- info->end_data = 0;
- info->end_code = 0;
- info->start_mmap = (unsigned long)ELF_START_MMAP;
- info->mmap = 0;
- elf_entry = (unsigned long) elf_ex.e_entry;
-
- /* Do this so that we can load the interpreter, if need be. We will
- change some of these later */
- info->rss = 0;
- bprm->p = setup_arg_pages(bprm->p, bprm, info);
- info->start_stack = bprm->p;
-
- /* Now we do a little grungy work by mmaping the ELF image into
- * the correct location in memory. At this point, we assume that
- * the image should be loaded at fixed address, not at a variable
- * address.
- */
-
- for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) {
- int elf_prot = 0;
- int elf_flags = 0;
- unsigned long error;
-
- if (elf_ppnt->p_type != PT_LOAD)
- continue;
-
- if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ;
- if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
- if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
- elf_flags = MAP_PRIVATE | MAP_DENYWRITE;
- if (elf_ex.e_type == ET_EXEC || load_addr_set) {
- elf_flags |= MAP_FIXED;
- } else if (elf_ex.e_type == ET_DYN) {
- /* Try and get dynamic programs out of the way of the default mmap
- base, as well as whatever program they might try to exec. This
- is because the brk will follow the loader, and is not movable. */
- /* NOTE: for qemu, we do a big mmap to get enough space
- without harcoding any address */
- error = target_mmap(0, ET_DYN_MAP_SIZE,
- PROT_NONE, MAP_PRIVATE | MAP_ANON,
- -1, 0);
- if (error == -1) {
- perror("mmap");
- exit(-1);
- }
- load_bias = TARGET_ELF_PAGESTART(error - elf_ppnt->p_vaddr);
- }
-
- error = target_mmap(TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr),
- (elf_ppnt->p_filesz +
- TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)),
- elf_prot,
- (MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE),
- bprm->fd,
- (elf_ppnt->p_offset -
- TARGET_ELF_PAGEOFFSET(elf_ppnt->p_vaddr)));
- if (error == -1) {
- perror("mmap");
- exit(-1);
- }
-
-#ifdef LOW_ELF_STACK
- if (TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack)
- elf_stack = TARGET_ELF_PAGESTART(elf_ppnt->p_vaddr);
-#endif
-
- if (!load_addr_set) {
- load_addr_set = 1;
- load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
- if (elf_ex.e_type == ET_DYN) {
- load_bias += error -
- TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
- load_addr += load_bias;
- }
- }
- k = elf_ppnt->p_vaddr;
- if (k < start_code)
- start_code = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
- if (k > elf_bss)
- elf_bss = k;
- if ((elf_ppnt->p_flags & PF_X) && end_code < k)
- end_code = k;
- if (end_data < k)
- end_data = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
- if (k > elf_brk) elf_brk = k;
- }
-
- elf_entry += load_bias;
- elf_bss += load_bias;
- elf_brk += load_bias;
- start_code += load_bias;
- end_code += load_bias;
- // start_data += load_bias;
- end_data += load_bias;
-
- if (elf_interpreter) {
- if (interpreter_type & 1) {
- elf_entry = load_aout_interp(&interp_ex, interpreter_fd);
- }
- else if (interpreter_type & 2) {
- elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
- &interp_load_addr);
- }
-
- close(interpreter_fd);
- free(elf_interpreter);
-
- if (elf_entry == ~0UL) {
- printf("Unable to load interpreter\n");
- free(elf_phdata);
- exit(-1);
- return 0;
- }
- }
-
- free(elf_phdata);
-
- if (loglevel)
- load_symbols(&elf_ex, bprm->fd);
-
- if (interpreter_type != INTERPRETER_AOUT) close(bprm->fd);
- info->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX);
-
-#ifdef LOW_ELF_STACK
- info->start_stack = bprm->p = elf_stack - 4;
-#endif
- bprm->p = create_elf_tables(bprm->p,
- bprm->argc,
- bprm->envc,
- &elf_ex,
- load_addr, load_bias,
- interp_load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1),
- info);
- info->start_brk = info->brk = elf_brk;
- info->end_code = end_code;
- info->start_code = start_code;
- info->start_data = end_code;
- info->end_data = end_data;
- info->start_stack = bprm->p;
-
- /* Calling set_brk effectively mmaps the pages that we need for the bss and break
- sections */
- set_brk(elf_bss, elf_brk);
-
- padzero(elf_bss);
-
-#if 0
- printf("(start_brk) %x\n" , info->start_brk);
- printf("(end_code) %x\n" , info->end_code);
- printf("(start_code) %x\n" , info->start_code);
- printf("(end_data) %x\n" , info->end_data);
- printf("(start_stack) %x\n" , info->start_stack);
- printf("(brk) %x\n" , info->brk);
-#endif
-
- if ( info->personality == PER_SVR4 )
- {
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- mapped_addr = target_mmap(0, qemu_host_page_size, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, -1, 0);
- }
-
- info->entry = elf_entry;
-
- return 0;
-}
-
-static int load_aout_interp(void * exptr, int interp_fd)
-{
- printf("a.out interpreter not yet supported\n");
- return(0);
-}
-
-void do_init_thread(struct target_pt_regs *regs, struct image_info *infop)
-{
- init_thread(regs, infop);
-}
diff --git a/linux-user/flat.h b/linux-user/flat.h
deleted file mode 100644
index b057b14..0000000
--- a/linux-user/flat.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2002-2003 David McCullough <davidm@snapgear.com>
- * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
- * The Silver Hammer Group, Ltd.
- *
- * This file provides the definitions and structures needed to
- * support uClinux flat-format executables.
- */
-
-#define FLAT_VERSION 0x00000004L
-
-#ifdef CONFIG_BINFMT_SHARED_FLAT
-#define MAX_SHARED_LIBS (4)
-#else
-#define MAX_SHARED_LIBS (1)
-#endif
-
-/*
- * To make everything easier to port and manage cross platform
- * development, all fields are in network byte order.
- */
-
-struct flat_hdr {
- char magic[4];
- unsigned long rev; /* version (as above) */
- unsigned long entry; /* Offset of first executable instruction
- with text segment from beginning of file */
- unsigned long data_start; /* Offset of data segment from beginning of
- file */
- unsigned long data_end; /* Offset of end of data segment
- from beginning of file */
- unsigned long bss_end; /* Offset of end of bss segment from beginning
- of file */
-
- /* (It is assumed that data_end through bss_end forms the bss segment.) */
-
- unsigned long stack_size; /* Size of stack, in bytes */
- unsigned long reloc_start; /* Offset of relocation records from
- beginning of file */
- unsigned long reloc_count; /* Number of relocation records */
- unsigned long flags;
- unsigned long build_date; /* When the program/library was built */
- unsigned long filler[5]; /* Reservered, set to zero */
-};
-
-#define FLAT_FLAG_RAM 0x0001 /* load program entirely into RAM */
-#define FLAT_FLAG_GOTPIC 0x0002 /* program is PIC with GOT */
-#define FLAT_FLAG_GZIP 0x0004 /* all but the header is compressed */
-#define FLAT_FLAG_GZDATA 0x0008 /* only data/relocs are compressed (for XIP) */
-#define FLAT_FLAG_KTRACE 0x0010 /* output useful kernel trace for debugging */
-
-
-/*
- * While it would be nice to keep this header clean, users of older
- * tools still need this support in the kernel. So this section is
- * purely for compatibility with old tool chains.
- *
- * DO NOT make changes or enhancements to the old format please, just work
- * with the format above, except to fix bugs with old format support.
- */
-
-#define OLD_FLAT_VERSION 0x00000002L
-#define OLD_FLAT_RELOC_TYPE_TEXT 0
-#define OLD_FLAT_RELOC_TYPE_DATA 1
-#define OLD_FLAT_RELOC_TYPE_BSS 2
-
-# define OLD_FLAT_FLAG_RAM 0x1 /* load program entirely into RAM */
diff --git a/linux-user/flatload.c b/linux-user/flatload.c
deleted file mode 100644
index bf55be2..0000000
--- a/linux-user/flatload.c
+++ /dev/null
@@ -1,793 +0,0 @@
-/****************************************************************************/
-/*
- * QEMU bFLT binary loader. Based on linux/fs/binfmt_flat.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Copyright (C) 2006 CodeSourcery.
- * Copyright (C) 2000-2003 David McCullough <davidm@snapgear.com>
- * Copyright (C) 2002 Greg Ungerer <gerg@snapgear.com>
- * Copyright (C) 2002 SnapGear, by Paul Dale <pauli@snapgear.com>
- * Copyright (C) 2000, 2001 Lineo, by David McCullough <davidm@lineo.com>
- * based heavily on:
- *
- * linux/fs/binfmt_aout.c:
- * Copyright (C) 1991, 1992, 1996 Linus Torvalds
- * linux/fs/binfmt_flat.c for 2.0 kernel
- * Copyright (C) 1998 Kenneth Albanowski <kjahds@kjahds.com>
- * JAN/99 -- coded full program relocation (gerg@snapgear.com)
- */
-
-/* ??? ZFLAT and shared library support is currently disabled. */
-
-/****************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include "qemu.h"
-#include "flat.h"
-
-//#define DEBUG
-
-#ifdef DEBUG
-#define DBG_FLT(a...) printf(a)
-#else
-#define DBG_FLT(a...)
-#endif
-
-#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
-#define flat_old_ram_flag(flag) (flag)
-#ifdef TARGET_WORDS_BIGENDIAN
-#define flat_get_relocate_addr(relval) (relval)
-#else
-#define flat_get_relocate_addr(relval) bswap32(relval)
-#endif
-
-#define RELOC_FAILED 0xff00ff01 /* Relocation incorrect somewhere */
-#define UNLOADED_LIB 0x7ff000ff /* Placeholder for unused library */
-
-struct lib_info {
- target_ulong start_code; /* Start of text segment */
- target_ulong start_data; /* Start of data segment */
- target_ulong end_data; /* Start of bss section */
- target_ulong start_brk; /* End of data segment */
- target_ulong text_len; /* Length of text segment */
- target_ulong entry; /* Start address for this module */
- target_ulong build_date; /* When this one was compiled */
- short loaded; /* Has this library been loaded? */
-};
-
-#ifdef CONFIG_BINFMT_SHARED_FLAT
-static int load_flat_shared_library(int id, struct lib_info *p);
-#endif
-
-struct linux_binprm;
-
-#define ntohl(x) be32_to_cpu(x)
-
-/****************************************************************************/
-/*
- * create_flat_tables() parses the env- and arg-strings in new user
- * memory and creates the pointer tables from them, and puts their
- * addresses on the "stack", returning the new stack pointer value.
- */
-
-/* Push a block of strings onto the guest stack. */
-static target_ulong copy_strings(target_ulong p, int n, char **s)
-{
- int len;
-
- while (n-- > 0) {
- len = strlen(s[n]) + 1;
- p -= len;
- memcpy_to_target(p, s[n], len);
- }
-
- return p;
-}
-
-int target_pread(int fd, target_ulong ptr, target_ulong len,
- target_ulong offset)
-{
- void *buf;
- int ret;
-
- buf = lock_user(ptr, len, 0);
- ret = pread(fd, buf, len, offset);
- unlock_user(buf, ptr, len);
- return ret;
-}
-/****************************************************************************/
-
-#ifdef CONFIG_BINFMT_ZFLAT
-
-#include <linux/zlib.h>
-
-#define LBUFSIZE 4000
-
-/* gzip flag byte */
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */
-#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */
-#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
-#define COMMENT 0x10 /* bit 4 set: file comment present */
-#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */
-#define RESERVED 0xC0 /* bit 6,7: reserved */
-
-static int decompress_exec(
- struct linux_binprm *bprm,
- unsigned long offset,
- char *dst,
- long len,
- int fd)
-{
- unsigned char *buf;
- z_stream strm;
- loff_t fpos;
- int ret, retval;
-
- DBG_FLT("decompress_exec(offset=%x,buf=%x,len=%x)\n",(int)offset, (int)dst, (int)len);
-
- memset(&strm, 0, sizeof(strm));
- strm.workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
- if (strm.workspace == NULL) {
- DBG_FLT("binfmt_flat: no memory for decompress workspace\n");
- return -ENOMEM;
- }
- buf = kmalloc(LBUFSIZE, GFP_KERNEL);
- if (buf == NULL) {
- DBG_FLT("binfmt_flat: no memory for read buffer\n");
- retval = -ENOMEM;
- goto out_free;
- }
-
- /* Read in first chunk of data and parse gzip header. */
- fpos = offset;
- ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
-
- strm.next_in = buf;
- strm.avail_in = ret;
- strm.total_in = 0;
-
- retval = -ENOEXEC;
-
- /* Check minimum size -- gzip header */
- if (ret < 10) {
- DBG_FLT("binfmt_flat: file too small?\n");
- goto out_free_buf;
- }
-
- /* Check gzip magic number */
- if ((buf[0] != 037) || ((buf[1] != 0213) && (buf[1] != 0236))) {
- DBG_FLT("binfmt_flat: unknown compression magic?\n");
- goto out_free_buf;
- }
-
- /* Check gzip method */
- if (buf[2] != 8) {
- DBG_FLT("binfmt_flat: unknown compression method?\n");
- goto out_free_buf;
- }
- /* Check gzip flags */
- if ((buf[3] & ENCRYPTED) || (buf[3] & CONTINUATION) ||
- (buf[3] & RESERVED)) {
- DBG_FLT("binfmt_flat: unknown flags?\n");
- goto out_free_buf;
- }
-
- ret = 10;
- if (buf[3] & EXTRA_FIELD) {
- ret += 2 + buf[10] + (buf[11] << 8);
- if (unlikely(LBUFSIZE == ret)) {
- DBG_FLT("binfmt_flat: buffer overflow (EXTRA)?\n");
- goto out_free_buf;
- }
- }
- if (buf[3] & ORIG_NAME) {
- for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
- ;
- if (unlikely(LBUFSIZE == ret)) {
- DBG_FLT("binfmt_flat: buffer overflow (ORIG_NAME)?\n");
- goto out_free_buf;
- }
- }
- if (buf[3] & COMMENT) {
- for (; ret < LBUFSIZE && (buf[ret] != 0); ret++)
- ;
- if (unlikely(LBUFSIZE == ret)) {
- DBG_FLT("binfmt_flat: buffer overflow (COMMENT)?\n");
- goto out_free_buf;
- }
- }
-
- strm.next_in += ret;
- strm.avail_in -= ret;
-
- strm.next_out = dst;
- strm.avail_out = len;
- strm.total_out = 0;
-
- if (zlib_inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
- DBG_FLT("binfmt_flat: zlib init failed?\n");
- goto out_free_buf;
- }
-
- while ((ret = zlib_inflate(&strm, Z_NO_FLUSH)) == Z_OK) {
- ret = bprm->file->f_op->read(bprm->file, buf, LBUFSIZE, &fpos);
- if (ret <= 0)
- break;
- if (ret >= (unsigned long) -4096)
- break;
- len -= ret;
-
- strm.next_in = buf;
- strm.avail_in = ret;
- strm.total_in = 0;
- }
-
- if (ret < 0) {
- DBG_FLT("binfmt_flat: decompression failed (%d), %s\n",
- ret, strm.msg);
- goto out_zlib;
- }
-
- retval = 0;
-out_zlib:
- zlib_inflateEnd(&strm);
-out_free_buf:
- kfree(buf);
-out_free:
- kfree(strm.workspace);
-out:
- return retval;
-}
-
-#endif /* CONFIG_BINFMT_ZFLAT */
-
-/****************************************************************************/
-
-static target_ulong
-calc_reloc(target_ulong r, struct lib_info *p, int curid, int internalp)
-{
- target_ulong addr;
- int id;
- target_ulong start_brk;
- target_ulong start_data;
- target_ulong text_len;
- target_ulong start_code;
-
-#ifdef CONFIG_BINFMT_SHARED_FLAT
-#error needs checking
- if (r == 0)
- id = curid; /* Relocs of 0 are always self referring */
- else {
- id = (r >> 24) & 0xff; /* Find ID for this reloc */
- r &= 0x00ffffff; /* Trim ID off here */
- }
- if (id >= MAX_SHARED_LIBS) {
- fprintf(stderr, "BINFMT_FLAT: reference 0x%x to shared library %d\n",
- (unsigned) r, id);
- goto failed;
- }
- if (curid != id) {
- if (internalp) {
- fprintf(stderr, "BINFMT_FLAT: reloc address 0x%x not "
- "in same module (%d != %d)\n",
- (unsigned) r, curid, id);
- goto failed;
- } else if ( ! p[id].loaded &&
- load_flat_shared_library(id, p) > (unsigned long) -4096) {
- fprintf(stderr, "BINFMT_FLAT: failed to load library %d\n", id);
- goto failed;
- }
- /* Check versioning information (i.e. time stamps) */
- if (p[id].build_date && p[curid].build_date
- && p[curid].build_date < p[id].build_date) {
- fprintf(stderr, "BINFMT_FLAT: library %d is younger than %d\n",
- id, curid);
- goto failed;
- }
- }
-#else
- id = 0;
-#endif
-
- start_brk = p[id].start_brk;
- start_data = p[id].start_data;
- start_code = p[id].start_code;
- text_len = p[id].text_len;
-
- if (!flat_reloc_valid(r, start_brk - start_data + text_len)) {
- fprintf(stderr, "BINFMT_FLAT: reloc outside program 0x%x "
- "(0 - 0x%x/0x%x)\n",
- (int) r,(int)(start_brk-start_code),(int)text_len);
- goto failed;
- }
-
- if (r < text_len) /* In text segment */
- addr = r + start_code;
- else /* In data segment */
- addr = r - text_len + start_data;
-
- /* Range checked already above so doing the range tests is redundant...*/
- return(addr);
-
-failed:
- abort();
- return RELOC_FAILED;
-}
-
-/****************************************************************************/
-
-/* ??? This does not handle endianness correctly. */
-void old_reloc(struct lib_info *libinfo, uint32_t rl)
-{
-#ifdef DEBUG
- char *segment[] = { "TEXT", "DATA", "BSS", "*UNKNOWN*" };
-#endif
- uint32_t *ptr;
- uint32_t offset;
- int reloc_type;
-
- offset = rl & 0x3fffffff;
- reloc_type = rl >> 30;
- /* ??? How to handle this? */
-#if defined(CONFIG_COLDFIRE)
- ptr = (uint32_t *) (libinfo->start_code + offset);
-#else
- ptr = (uint32_t *) (libinfo->start_data + offset);
-#endif
-
-#ifdef DEBUG
- fprintf(stderr, "Relocation of variable at DATASEG+%x "
- "(address %p, currently %x) into segment %s\n",
- offset, ptr, (int)*ptr, segment[reloc_type]);
-#endif
-
- switch (reloc_type) {
- case OLD_FLAT_RELOC_TYPE_TEXT:
- *ptr += libinfo->start_code;
- break;
- case OLD_FLAT_RELOC_TYPE_DATA:
- *ptr += libinfo->start_data;
- break;
- case OLD_FLAT_RELOC_TYPE_BSS:
- *ptr += libinfo->end_data;
- break;
- default:
- fprintf(stderr, "BINFMT_FLAT: Unknown relocation type=%x\n",
- reloc_type);
- break;
- }
- DBG_FLT("Relocation became %x\n", (int)*ptr);
-}
-
-/****************************************************************************/
-
-static int load_flat_file(struct linux_binprm * bprm,
- struct lib_info *libinfo, int id, target_ulong *extra_stack)
-{
- struct flat_hdr * hdr;
- target_ulong textpos = 0, datapos = 0, result;
- target_ulong realdatastart = 0;
- target_ulong text_len, data_len, bss_len, stack_len, flags;
- target_ulong memp = 0; /* for finding the brk area */
- target_ulong extra;
- target_ulong reloc = 0, rp;
- int i, rev, relocs = 0;
- target_ulong fpos;
- target_ulong start_code, end_code;
-
- hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */
-
- text_len = ntohl(hdr->data_start);
- data_len = ntohl(hdr->data_end) - ntohl(hdr->data_start);
- bss_len = ntohl(hdr->bss_end) - ntohl(hdr->data_end);
- stack_len = ntohl(hdr->stack_size);
- if (extra_stack) {
- stack_len += *extra_stack;
- *extra_stack = stack_len;
- }
- relocs = ntohl(hdr->reloc_count);
- flags = ntohl(hdr->flags);
- rev = ntohl(hdr->rev);
-
- DBG_FLT("BINFMT_FLAT: Loading file: %s\n", bprm->filename);
-
- if (rev != FLAT_VERSION && rev != OLD_FLAT_VERSION) {
- fprintf(stderr, "BINFMT_FLAT: bad magic/rev (0x%x, need 0x%x)\n",
- rev, (int) FLAT_VERSION);
- return -ENOEXEC;
- }
-
- /* Don't allow old format executables to use shared libraries */
- if (rev == OLD_FLAT_VERSION && id != 0) {
- fprintf(stderr, "BINFMT_FLAT: shared libraries are not available\n");
- return -ENOEXEC;
- }
-
- /*
- * fix up the flags for the older format, there were all kinds
- * of endian hacks, this only works for the simple cases
- */
- if (rev == OLD_FLAT_VERSION && flat_old_ram_flag(flags))
- flags = FLAT_FLAG_RAM;
-
-#ifndef CONFIG_BINFMT_ZFLAT
- if (flags & (FLAT_FLAG_GZIP|FLAT_FLAG_GZDATA)) {
- fprintf(stderr, "Support for ZFLAT executables is not enabled\n");
- return -ENOEXEC;
- }
-#endif
-
- /*
- * calculate the extra space we need to map in
- */
- extra = relocs * sizeof(target_ulong);
- if (extra < bss_len + stack_len)
- extra = bss_len + stack_len;
-
- /*
- * there are a couple of cases here, the separate code/data
- * case, and then the fully copied to RAM case which lumps
- * it all together.
- */
- if ((flags & (FLAT_FLAG_RAM|FLAT_FLAG_GZIP)) == 0) {
- /*
- * this should give us a ROM ptr, but if it doesn't we don't
- * really care
- */
- DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
-
- textpos = target_mmap(0, text_len, PROT_READ|PROT_EXEC,
- MAP_PRIVATE, bprm->fd, 0);
- if (textpos == -1) {
- fprintf(stderr, "Unable to mmap process text\n");
- return -1;
- }
-
- realdatastart = target_mmap(0, data_len + extra +
- MAX_SHARED_LIBS * sizeof(target_ulong),
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-
- if (realdatastart == -1) {
- fprintf(stderr, "Unable to allocate RAM for process data\n");
- return realdatastart;
- }
- datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
-
- DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
- (int)(data_len + bss_len + stack_len), (int)datapos);
-
- fpos = ntohl(hdr->data_start);
-#ifdef CONFIG_BINFMT_ZFLAT
- if (flags & FLAT_FLAG_GZDATA) {
- result = decompress_exec(bprm, fpos, (char *) datapos,
- data_len + (relocs * sizeof(target_ulong)))
- } else
-#endif
- {
- result = target_pread(bprm->fd, datapos,
- data_len + (relocs * sizeof(target_ulong)),
- fpos);
- }
- if (result < 0) {
- fprintf(stderr, "Unable to read data+bss\n");
- return result;
- }
-
- reloc = datapos + (ntohl(hdr->reloc_start) - text_len);
- memp = realdatastart;
-
- } else {
-
- textpos = target_mmap(0, text_len + data_len + extra +
- MAX_SHARED_LIBS * sizeof(target_ulong),
- PROT_READ | PROT_EXEC | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (textpos == -1 ) {
- fprintf(stderr, "Unable to allocate RAM for process text/data\n");
- return -1;
- }
-
- 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));
- memp = textpos;
-
-#ifdef CONFIG_BINFMT_ZFLAT
-#error code needs checking
- /*
- * load it all in and treat it like a RAM load from now on
- */
- if (flags & FLAT_FLAG_GZIP) {
- result = decompress_exec(bprm, sizeof (struct flat_hdr),
- (((char *) textpos) + sizeof (struct flat_hdr)),
- (text_len + data_len + (relocs * sizeof(unsigned long))
- - sizeof (struct flat_hdr)),
- 0);
- memmove((void *) datapos, (void *) realdatastart,
- data_len + (relocs * sizeof(unsigned long)));
- } else if (flags & FLAT_FLAG_GZDATA) {
- fpos = 0;
- result = bprm->file->f_op->read(bprm->file,
- (char *) textpos, text_len, &fpos);
- if (result < (unsigned long) -4096)
- result = decompress_exec(bprm, text_len, (char *) datapos,
- data_len + (relocs * sizeof(unsigned long)), 0);
- }
- else
-#endif
- {
- result = target_pread(bprm->fd, textpos,
- text_len, 0);
- if (result >= 0) {
- result = target_pread(bprm->fd, datapos,
- data_len + (relocs * sizeof(target_ulong)),
- ntohl(hdr->data_start));
- }
- }
- if (result < 0) {
- fprintf(stderr, "Unable to read code+data+bss\n");
- return result;
- }
- }
-
- DBG_FLT("Mapping is 0x%x, Entry point is 0x%x, data_start is 0x%x\n",
- (int)textpos, 0x00ffffff&ntohl(hdr->entry),
- ntohl(hdr->data_start));
-
- /* The main program needs a little extra setup in the task structure */
- start_code = textpos + sizeof (struct flat_hdr);
- end_code = textpos + text_len;
-
- DBG_FLT("%s %s: TEXT=%x-%x DATA=%x-%x BSS=%x-%x\n",
- id ? "Lib" : "Load", bprm->filename,
- (int) start_code, (int) end_code,
- (int) datapos,
- (int) (datapos + data_len),
- (int) (datapos + data_len),
- (int) (((datapos + data_len + bss_len) + 3) & ~3));
-
- text_len -= sizeof(struct flat_hdr); /* the real code len */
-
- /* Store the current module values into the global library structure */
- libinfo[id].start_code = start_code;
- libinfo[id].start_data = datapos;
- libinfo[id].end_data = datapos + data_len;
- libinfo[id].start_brk = datapos + data_len + bss_len;
- libinfo[id].text_len = text_len;
- libinfo[id].loaded = 1;
- libinfo[id].entry = (0x00ffffff & ntohl(hdr->entry)) + textpos;
- libinfo[id].build_date = ntohl(hdr->build_date);
-
- /*
- * We just load the allocations into some temporary memory to
- * help simplify all this mumbo jumbo
- *
- * We've got two different sections of relocation entries.
- * The first is the GOT which resides at the begining of the data segment
- * and is terminated with a -1. This one can be relocated in place.
- * The second is the extra relocation entries tacked after the image's
- * data segment. These require a little more processing as the entry is
- * really an offset into the image which contains an offset into the
- * image.
- */
- if (flags & FLAT_FLAG_GOTPIC) {
- rp = datapos;
- while (1) {
- target_ulong addr;
- addr = tgetl(rp);
- if (addr == -1)
- break;
- if (addr) {
- addr = calc_reloc(addr, libinfo, id, 0);
- if (addr == RELOC_FAILED)
- return -ENOEXEC;
- tputl(rp, addr);
- }
- rp += sizeof(target_ulong);
- }
- }
-
- /*
- * Now run through the relocation entries.
- * We've got to be careful here as C++ produces relocatable zero
- * entries in the constructor and destructor tables which are then
- * tested for being not zero (which will always occur unless we're
- * based from address zero). This causes an endless loop as __start
- * is at zero. The solution used is to not relocate zero addresses.
- * This has the negative side effect of not allowing a global data
- * reference to be statically initialised to _stext (I've moved
- * __start to address 4 so that is okay).
- */
- if (rev > OLD_FLAT_VERSION) {
- for (i = 0; i < relocs; i++) {
- target_ulong addr, relval;
-
- /* Get the address of the pointer to be
- relocated (of course, the address has to be
- relocated first). */
- relval = tgetl(reloc + i * sizeof (target_ulong));
- addr = flat_get_relocate_addr(relval);
- rp = calc_reloc(addr, libinfo, id, 1);
- if (rp == RELOC_FAILED)
- return -ENOEXEC;
-
- /* Get the pointer's value. */
- addr = tgetl(rp);
- if (addr != 0) {
- /*
- * Do the relocation. PIC relocs in the data section are
- * already in target order
- */
-
-#ifndef TARGET_WORDS_BIGENDIAN
- if ((flags & FLAT_FLAG_GOTPIC) == 0)
- addr = bswap32(addr);
-#endif
- addr = calc_reloc(addr, libinfo, id, 0);
- if (addr == RELOC_FAILED)
- return -ENOEXEC;
-
- /* Write back the relocated pointer. */
- tputl(rp, addr);
- }
- }
- } else {
- for (i = 0; i < relocs; i++) {
- target_ulong relval;
- relval = tgetl(reloc + i * sizeof (target_ulong));
- old_reloc(&libinfo[0], relval);
- }
- }
-
- /* zero the BSS. */
- memset((void*)(datapos + data_len), 0, bss_len);
-
- return 0;
-}
-
-
-/****************************************************************************/
-#ifdef CONFIG_BINFMT_SHARED_FLAT
-
-/*
- * Load a shared library into memory. The library gets its own data
- * segment (including bss) but not argv/argc/environ.
- */
-
-static int load_flat_shared_library(int id, struct lib_info *libs)
-{
- struct linux_binprm bprm;
- int res;
- char buf[16];
-
- /* Create the file name */
- sprintf(buf, "/lib/lib%d.so", id);
-
- /* Open the file up */
- bprm.filename = buf;
- bprm.file = open_exec(bprm.filename);
- res = PTR_ERR(bprm.file);
- if (IS_ERR(bprm.file))
- return res;
-
- res = prepare_binprm(&bprm);
-
- if (res <= (unsigned long)-4096)
- res = load_flat_file(&bprm, libs, id, NULL);
- if (bprm.file) {
- allow_write_access(bprm.file);
- fput(bprm.file);
- bprm.file = NULL;
- }
- return(res);
-}
-
-#endif /* CONFIG_BINFMT_SHARED_FLAT */
-
-int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
- struct image_info * info)
-{
- struct lib_info libinfo[MAX_SHARED_LIBS];
- target_ulong p = bprm->p;
- target_ulong stack_len;
- target_ulong start_addr;
- target_ulong sp;
- int res;
- int i, j;
-
- memset(libinfo, 0, sizeof(libinfo));
- /*
- * We have to add the size of our arguments to our stack size
- * otherwise it's too easy for users to create stack overflows
- * by passing in a huge argument list. And yes, we have to be
- * pedantic and include space for the argv/envp array as it may have
- * a lot of entries.
- */
-#define TOP_OF_ARGS (TARGET_PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *))
- stack_len = TOP_OF_ARGS - bprm->p; /* the strings */
- stack_len += (bprm->argc + 1) * 4; /* the argv array */
- stack_len += (bprm->envc + 1) * 4; /* the envp array */
-
-
- res = load_flat_file(bprm, libinfo, 0, &stack_len);
- if (res > (unsigned long)-4096)
- return res;
-
- /* Update data segment pointers for all libraries */
- for (i=0; i<MAX_SHARED_LIBS; i++) {
- if (libinfo[i].loaded) {
- target_ulong p;
- p = libinfo[i].start_data;
- for (j=0; j<MAX_SHARED_LIBS; j++) {
- p -= 4;
- tput32(p, libinfo[j].loaded
- ? libinfo[j].start_data
- : UNLOADED_LIB);
- }
- }
- }
-
- p = ((libinfo[0].start_brk + stack_len + 3) & ~3) - 4;
- DBG_FLT("p=%x\n", (int)p);
-
- /* Copy argv/envp. */
- p = copy_strings(p, bprm->argc, bprm->argv);
- p = copy_strings(p, bprm->envc, bprm->envp);
- /* Align stack. */
- sp = p & ~(target_ulong)(sizeof(target_ulong) - 1);
- sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
-
- /* Fake some return addresses to ensure the call chain will
- * initialise library in order for us. We are required to call
- * lib 1 first, then 2, ... and finally the main program (id 0).
- */
- start_addr = libinfo[0].entry;
-
-#ifdef CONFIG_BINFMT_SHARED_FLAT
-#error here
- for (i = MAX_SHARED_LIBS-1; i>0; i--) {
- if (libinfo[i].loaded) {
- /* Push previos first to call address */
- --sp; put_user(start_addr, sp);
- start_addr = libinfo[i].entry;
- }
- }
-#endif
-
- /* Stash our initial stack pointer into the mm structure */
- info->start_code = libinfo[0].start_code;
- info->end_code = libinfo[0].start_code = libinfo[0].text_len;
- info->start_data = libinfo[0].start_data;
- info->end_data = libinfo[0].end_data;
- info->start_brk = libinfo[0].start_brk;
- info->start_stack = sp;
- info->entry = start_addr;
- info->code_offset = info->start_code;
- info->data_offset = info->start_data - libinfo[0].text_len;
-
- DBG_FLT("start_thread(entry=0x%x, start_stack=0x%x)\n",
- (int)info->entry, (int)info->start_stack);
-
- return 0;
-}
diff --git a/linux-user/i386/syscall.h b/linux-user/i386/syscall.h
deleted file mode 100644
index cc0942b..0000000
--- a/linux-user/i386/syscall.h
+++ /dev/null
@@ -1,221 +0,0 @@
-/* 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"
diff --git a/linux-user/i386/syscall_nr.h b/linux-user/i386/syscall_nr.h
deleted file mode 100644
index 9fa6be9..0000000
--- a/linux-user/i386/syscall_nr.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * 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
diff --git a/linux-user/i386/termbits.h b/linux-user/i386/termbits.h
deleted file mode 100644
index adff802..0000000
--- a/linux-user/i386/termbits.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/* 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 */
-
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
deleted file mode 100644
index dae3efa..0000000
--- a/linux-user/ioctls.h
+++ /dev/null
@@ -1,302 +0,0 @@
- /* emulated ioctl list */
-
- IOCTL(TCGETS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
- IOCTL(TCSETS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
- IOCTL(TCSETSF, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
- IOCTL(TCSETSW, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
- IOCTL(TIOCGWINSZ, IOC_R, MK_PTR(MK_STRUCT(STRUCT_winsize)))
- IOCTL(TIOCSWINSZ, IOC_W, MK_PTR(MK_STRUCT(STRUCT_winsize)))
- IOCTL(FIONREAD, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(TCGETA, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(TCSETA, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TCSETAW, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TCSETAF, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TCSBRK, 0, TYPE_INT)
- IOCTL(TCSBRKP, 0, TYPE_INT)
- IOCTL(TCXONC, 0, TYPE_INT)
- IOCTL(TCFLSH, 0, TYPE_INT)
- IOCTL(TIOCEXCL, 0, TYPE_NULL)
- IOCTL(TIOCNXCL, 0, TYPE_NULL)
- IOCTL(TIOCSCTTY, 0, TYPE_INT)
- IOCTL(TIOCGPGRP, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(TIOCSPGRP, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCOUTQ, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(TIOCSTI, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCMGET, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(TIOCMBIS, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCMBIC, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCMSET, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCGSOFTCAR, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(TIOCSSOFTCAR, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCLINUX, IOC_R | IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCCONS, 0, TYPE_NULL)
- IOCTL(TIOCGSERIAL, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(TIOCSSERIAL, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCPKT, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(FIONBIO, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCNOTTY, 0, TYPE_NULL)
- IOCTL(TIOCGETD, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(TIOCSETD, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCGPTN, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(TIOCSPTLCK, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(FIOCLEX, 0, TYPE_NULL)
- IOCTL(FIONCLEX, 0, TYPE_NULL)
- IOCTL(FIOASYNC, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(TIOCGLCKTRMIOS, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
- IOCTL(TIOCSLCKTRMIOS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
- IOCTL(TIOCSERCONFIG, 0, TYPE_NULL)
- IOCTL(TIOCSERGETLSR, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(TIOCSERGETMULTI, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_multiport_struct)))
- IOCTL(TIOCSERSETMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_serial_multiport_struct)))
- IOCTL(TIOCMIWAIT, 0, TYPE_INT)
- IOCTL(TIOCGICOUNT, IOC_R, MK_PTR(MK_STRUCT(STRUCT_serial_icounter_struct)))
-
- IOCTL(KIOCSOUND, 0, TYPE_INT)
- IOCTL(KDMKTONE, 0, TYPE_INT)
- IOCTL(KDGKBTYPE, IOC_R, MK_PTR(TYPE_CHAR))
- IOCTL(KDGKBENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbentry)))
- IOCTL(KDGKBSENT, IOC_RW, MK_PTR(MK_STRUCT(STRUCT_kbsentry)))
-
- IOCTL(BLKROSET, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(BLKROGET, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(BLKRRPART, 0, TYPE_NULL)
- IOCTL(BLKGETSIZE, IOC_R, MK_PTR(TYPE_ULONG))
-#ifdef BLKGETSIZE64
- IOCTL(BLKGETSIZE64, IOC_R, MK_PTR(TYPE_ULONGLONG))
-#endif
- IOCTL(BLKFLSBUF, 0, TYPE_NULL)
- IOCTL(BLKRASET, 0, TYPE_INT)
- IOCTL(BLKRAGET, IOC_R, MK_PTR(TYPE_LONG))
-#ifdef FIBMAP
- IOCTL(FIBMAP, IOC_W | IOC_R, MK_PTR(TYPE_LONG))
-#endif
-#ifdef FIGETBSZ
- IOCTL(FIGETBSZ, IOC_R, MK_PTR(TYPE_LONG))
-#endif
-
- IOCTL(SIOCATMARK, 0, TYPE_NULL)
- IOCTL(SIOCADDRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
- IOCTL(SIOCDELRT, IOC_W, MK_PTR(MK_STRUCT(STRUCT_rtentry)))
- IOCTL(SIOCGIFNAME, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SIOCGIFFLAGS, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
- IOCTL(SIOCSIFFLAGS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_short_ifreq)))
- IOCTL(SIOCGIFADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCSIFADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCGIFBRDADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCSIFBRDADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCGIFDSTADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCSIFDSTADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCGIFNETMASK, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCSIFNETMASK, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCGIFHWADDR, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCSIFHWADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCGIFTXQLEN, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCSIFTXQLEN, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCGIFMETRIC, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
- IOCTL(SIOCSIFMETRIC, IOC_W, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
- IOCTL(SIOCGIFMTU, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
- IOCTL(SIOCSIFMTU, IOC_W, MK_PTR(MK_STRUCT(STRUCT_int_ifreq)))
- IOCTL(SIOCGIFMAP, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifmap_ifreq)))
- IOCTL(SIOCSIFMAP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ifmap_ifreq)))
- IOCTL(SIOCGIFSLAVE, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_char_ifreq)))
- IOCTL(SIOCSIFSLAVE, IOC_W, MK_PTR(MK_STRUCT(STRUCT_char_ifreq)))
- IOCTL(SIOCGIFMEM, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ptr_ifreq)))
- IOCTL(SIOCSIFMEM, IOC_W, MK_PTR(MK_STRUCT(STRUCT_ptr_ifreq)))
- IOCTL(SIOCADDMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCDELMULTI, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq)))
- IOCTL(SIOCSIFLINK, 0, TYPE_NULL)
- IOCTL(SIOCGIFCONF, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_ifconf)))
- IOCTL(SIOCGIFENCAP, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SIOCSIFENCAP, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SIOCDARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
- IOCTL(SIOCSARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
- IOCTL(SIOCGARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
- IOCTL(SIOCDRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
- IOCTL(SIOCSRARP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
- IOCTL(SIOCGRARP, IOC_R, MK_PTR(MK_STRUCT(STRUCT_arpreq)))
-
- IOCTL(CDROMPAUSE, 0, TYPE_NULL)
- IOCTL(CDROMSTART, 0, TYPE_NULL)
- IOCTL(CDROMSTOP, 0, TYPE_NULL)
- IOCTL(CDROMRESUME, 0, TYPE_NULL)
- IOCTL(CDROMEJECT, 0, TYPE_NULL)
- IOCTL(CDROMEJECT_SW, 0, TYPE_INT)
- IOCTL(CDROMCLOSETRAY, 0, TYPE_NULL)
- IOCTL(CDROMRESET, 0, TYPE_NULL)
- IOCTL(CDROMPLAYMSF, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(CDROMPLAYTRKIND, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(CDROMREADTOCHDR, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(CDROMREADTOCENTRY, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(CDROMVOLCTRL, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(CDROMSUBCHNL, IOC_RW, MK_PTR(TYPE_INT))
- /* XXX: incorrect (need specific handling) */
- IOCTL(CDROMREADAUDIO, IOC_W, MK_PTR(MK_STRUCT(STRUCT_cdrom_read_audio)))
- IOCTL(CDROMREADCOOKED, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(CDROMREADRAW, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(CDROMREADMODE1, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(CDROMREADMODE2, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(CDROMREADALL, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(CDROMMULTISESSION, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(CDROM_GET_UPC, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(CDROMVOLREAD, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(CDROMSEEK, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(CDROMPLAYBLK, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(CDROM_MEDIA_CHANGED, 0, TYPE_NULL)
- IOCTL(CDROM_SET_OPTIONS, 0, TYPE_INT)
- IOCTL(CDROM_CLEAR_OPTIONS, 0, TYPE_INT)
- IOCTL(CDROM_SELECT_SPEED, 0, TYPE_INT)
- IOCTL(CDROM_SELECT_DISC, 0, TYPE_INT)
- IOCTL(CDROM_DRIVE_STATUS, 0, TYPE_NULL)
- IOCTL(CDROM_DISC_STATUS, 0, TYPE_NULL)
- IOCTL(CDROMAUDIOBUFSIZ, 0, TYPE_INT)
-
-#if 0
- IOCTL(SNDCTL_COPR_HALT, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_COPR_LOAD, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_COPR_RCODE, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_COPR_RCVMSG, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_COPR_RDATA, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_COPR_RESET, 0, TYPE_NULL)
- IOCTL(SNDCTL_COPR_RUN, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_COPR_SENDMSG, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_COPR_WCODE, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_COPR_WDATA, IOC_W, MK_PTR(TYPE_INT))
-#endif
- IOCTL(SNDCTL_DSP_CHANNELS, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_GETBLKSIZE, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_GETCAPS, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_GETFMTS, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_GETIPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
- IOCTL(SNDCTL_DSP_GETOPTR, IOC_R, MK_PTR(MK_STRUCT(STRUCT_count_info)))
- IOCTL(SNDCTL_DSP_GETISPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
- IOCTL(SNDCTL_DSP_GETOSPACE, IOC_R, MK_PTR(MK_STRUCT(STRUCT_audio_buf_info)))
- IOCTL(SNDCTL_DSP_GETTRIGGER, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_MAPINBUF, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_MAPOUTBUF, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_NONBLOCK, 0, TYPE_NULL)
- IOCTL(SNDCTL_DSP_POST, 0, TYPE_NULL)
- IOCTL(SNDCTL_DSP_RESET, 0, TYPE_NULL)
- IOCTL(SNDCTL_DSP_SETDUPLEX, 0, TYPE_NULL)
- IOCTL(SNDCTL_DSP_SETFMT, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_SETFRAGMENT, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_SETSYNCRO, 0, TYPE_NULL)
- IOCTL(SNDCTL_DSP_SETTRIGGER, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_SPEED, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_STEREO, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_SUBDIVIDE, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_DSP_SYNC, 0, TYPE_NULL)
-#if 0
- IOCTL(SNDCTL_FM_4OP_ENABLE, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_FM_LOAD_INSTR, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_MIDI_INFO, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_MIDI_MPUCMD, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_MIDI_MPUMODE, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_MIDI_PRETIME, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SEQ_CTRLRATE, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SEQ_GETINCOUNT, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SEQ_GETOUTCOUNT, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SEQ_NRMIDIS, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SEQ_NRSYNTHS, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SEQ_OUTOFBAND, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SEQ_PANIC, 0, TYPE_NULL)
- IOCTL(SNDCTL_SEQ_PERCMODE, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SEQ_RESET, 0, TYPE_NULL)
- IOCTL(SNDCTL_SEQ_RESETSAMPLES, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SEQ_SYNC, 0, TYPE_NULL)
- IOCTL(SNDCTL_SEQ_TESTMIDI, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SEQ_THRESHOLD, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SYNTH_INFO, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_SYNTH_MEMAVL, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_TMR_CONTINUE, 0, TYPE_NULL)
- IOCTL(SNDCTL_TMR_METRONOME, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_TMR_SELECT, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_TMR_SOURCE, IOC_RW, MK_PTR(TYPE_INT))
-#if 0
- /* we invalidate these defines because they have a same number as
- termios ioctls */
- IOCTL(SNDCTL_TMR_START, 0, TYPE_NULL)
- IOCTL(SNDCTL_TMR_STOP, 0, TYPE_NULL)
-#endif
- IOCTL(SNDCTL_TMR_TEMPO, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SNDCTL_TMR_TIMEBASE, IOC_RW, MK_PTR(TYPE_INT))
-
- IOCTL(SOUND_PCM_WRITE_FILTER, IOC_W | IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_PCM_READ_RATE, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_PCM_READ_CHANNELS, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_PCM_READ_BITS, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_PCM_READ_FILTER, IOC_R, MK_PTR(TYPE_INT))
-#endif
- IOCTL(SOUND_MIXER_INFO, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_ACCESS, 0, TYPE_PTRVOID)
- IOCTL(SOUND_MIXER_PRIVATE1, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_PRIVATE2, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_PRIVATE3, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_PRIVATE4, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_PRIVATE5, IOC_RW, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_VOLUME, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_BASS, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_TREBLE, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_SYNTH, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_PCM, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_SPEAKER, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_LINE, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_MIC, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_CD, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_IMIX, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_ALTPCM, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_RECLEV, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_IGAIN, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_OGAIN, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_LINE1, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_LINE2, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_LINE3, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_MUTE, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_ENHANCE, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_LOUD, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_RECSRC, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_DEVMASK, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_RECMASK, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_STEREODEVS, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_READ_CAPS, IOC_R, MK_PTR(TYPE_INT))
-
- IOCTL(SOUND_MIXER_WRITE_VOLUME, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_BASS, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_TREBLE, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_SYNTH, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_PCM, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_SPEAKER, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_LINE, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_MIC, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_CD, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_IMIX, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_ALTPCM, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_RECLEV, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_IGAIN, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_OGAIN, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_LINE1, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_LINE2, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_LINE3, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_MUTE, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_ENHANCE, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_LOUD, IOC_W, MK_PTR(TYPE_INT))
- IOCTL(SOUND_MIXER_WRITE_RECSRC, IOC_W, MK_PTR(TYPE_INT))
-
- IOCTL(HDIO_GETGEO, IOC_R, MK_PTR(MK_STRUCT(STRUCT_hd_geometry)))
- IOCTL(HDIO_GET_UNMASKINTR, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(HDIO_GET_MULTCOUNT, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(HDIO_GET_IDENTITY, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(HDIO_GET_KEEPSETTINGS, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(HDIO_GET_NOWERR, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(HDIO_GET_DMA, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(HDIO_GET_32BIT, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(HDIO_DRIVE_CMD, IOC_R, MK_PTR(TYPE_INT))
- IOCTL(HDIO_SET_UNMASKINTR, 0, TYPE_INT)
- IOCTL(HDIO_SET_MULTCOUNT, 0, TYPE_INT)
- IOCTL(HDIO_SET_KEEPSETTINGS, 0, TYPE_INT)
- IOCTL(HDIO_SET_NOWERR, 0, TYPE_INT)
- IOCTL(HDIO_SET_DMA, 0, TYPE_INT)
- IOCTL(HDIO_SET_32BIT, 0, TYPE_INT)
- IOCTL(HDIO_SET_PIO_MODE, 0, TYPE_INT)
-
- IOCTL(VFAT_IOCTL_READDIR_BOTH, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2)))
- IOCTL(VFAT_IOCTL_READDIR_SHORT, IOC_R, MK_PTR(MK_ARRAY(MK_STRUCT(STRUCT_dirent), 2)))
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
deleted file mode 100644
index ef5409b..0000000
--- a/linux-user/linuxload.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/* Code for loading Linux executables. Mostly linux kenrel code. */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "qemu.h"
-
-#define NGROUPS 32
-
-/* ??? This should really be somewhere else. */
-void memcpy_to_target(target_ulong dest, const void *src,
- unsigned long len)
-{
- void *host_ptr;
-
- host_ptr = lock_user(dest, len, 0);
- memcpy(host_ptr, src, len);
- unlock_user(host_ptr, dest, 1);
-}
-
-static int in_group_p(gid_t g)
-{
- /* return TRUE if we're in the specified group, FALSE otherwise */
- int ngroup;
- int i;
- gid_t grouplist[NGROUPS];
-
- ngroup = getgroups(NGROUPS, grouplist);
- for(i = 0; i < ngroup; i++) {
- if(grouplist[i] == g) {
- return 1;
- }
- }
- return 0;
-}
-
-static int count(char ** vec)
-{
- int i;
-
- for(i = 0; *vec; i++) {
- vec++;
- }
-
- return(i);
-}
-
-static int prepare_binprm(struct linux_binprm *bprm)
-{
- struct stat st;
- int mode;
- int retval, id_change;
-
- if(fstat(bprm->fd, &st) < 0) {
- return(-errno);
- }
-
- mode = st.st_mode;
- if(!S_ISREG(mode)) { /* Must be regular file */
- return(-EACCES);
- }
- if(!(mode & 0111)) { /* Must have at least one execute bit set */
- return(-EACCES);
- }
-
- bprm->e_uid = geteuid();
- bprm->e_gid = getegid();
- id_change = 0;
-
- /* Set-uid? */
- if(mode & S_ISUID) {
- bprm->e_uid = st.st_uid;
- if(bprm->e_uid != geteuid()) {
- id_change = 1;
- }
- }
-
- /* Set-gid? */
- /*
- * If setgid is set but no group execute bit then this
- * is a candidate for mandatory locking, not a setgid
- * executable.
- */
- if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
- bprm->e_gid = st.st_gid;
- if (!in_group_p(bprm->e_gid)) {
- id_change = 1;
- }
- }
-
- memset(bprm->buf, 0, sizeof(bprm->buf));
- retval = lseek(bprm->fd, 0L, SEEK_SET);
- if(retval >= 0) {
- retval = read(bprm->fd, bprm->buf, 128);
- }
- if(retval < 0) {
- perror("prepare_binprm");
- exit(-1);
- /* return(-errno); */
- }
- else {
- return(retval);
- }
-}
-
-/* Construct the envp and argv tables on the target stack. */
-target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
- target_ulong stringp, int push_ptr)
-{
- int n = sizeof(target_ulong);
- target_ulong envp;
- target_ulong argv;
-
- sp -= (envc + 1) * n;
- envp = sp;
- sp -= (argc + 1) * n;
- argv = sp;
- if (push_ptr) {
- sp -= n; tputl(sp, envp);
- sp -= n; tputl(sp, argv);
- }
- sp -= n; tputl(sp, argc);
-
- while (argc-- > 0) {
- tputl(argv, stringp); argv += n;
- stringp += target_strlen(stringp) + 1;
- }
- tputl(argv, 0);
- while (envc-- > 0) {
- tputl(envp, stringp); envp += n;
- stringp += target_strlen(stringp) + 1;
- }
- tputl(envp, 0);
-
- return sp;
-}
-
-int loader_exec(const char * filename, char ** argv, char ** envp,
- struct target_pt_regs * regs, struct image_info *infop)
-{
- struct linux_binprm bprm;
- int retval;
- int i;
-
- bprm.p = TARGET_PAGE_SIZE*MAX_ARG_PAGES-sizeof(unsigned int);
- for (i=0 ; i<MAX_ARG_PAGES ; i++) /* clear page-table */
- bprm.page[i] = 0;
- retval = open(filename, O_RDONLY);
- if (retval < 0)
- return retval;
- bprm.fd = retval;
- bprm.filename = (char *)filename;
- bprm.argc = count(argv);
- bprm.argv = argv;
- bprm.envc = count(envp);
- bprm.envp = envp;
-
- retval = prepare_binprm(&bprm);
-
- if(retval>=0) {
- if (bprm.buf[0] == 0x7f
- && bprm.buf[1] == 'E'
- && bprm.buf[2] == 'L'
- && bprm.buf[3] == 'F') {
- retval = load_elf_binary(&bprm,regs,infop);
-#if defined(TARGET_HAS_BFLT)
- } else if (bprm.buf[0] == 'b'
- && bprm.buf[1] == 'F'
- && bprm.buf[2] == 'L'
- && bprm.buf[3] == 'T') {
- retval = load_flt_binary(&bprm,regs,infop);
-#endif
- } else {
- fprintf(stderr, "Unknown binary format\n");
- return -1;
- }
- }
-
- if(retval>=0) {
- /* success. Initialize important registers */
- do_init_thread(regs, infop);
- return retval;
- }
-
- /* Something went wrong, return the inode and free the argument pages*/
- for (i=0 ; i<MAX_ARG_PAGES ; i++) {
- free(bprm.page[i]);
- }
- return(retval);
-}
diff --git a/linux-user/main.c b/linux-user/main.c
deleted file mode 100644
index d169311..0000000
--- a/linux-user/main.c
+++ /dev/null
@@ -1,1716 +0,0 @@
-/*
- * qemu user main
- *
- * 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 <errno.h>
-#include <unistd.h>
-
-#include "qemu.h"
-
-#define DEBUG_LOGFILE "/tmp/qemu.log"
-
-#ifdef __APPLE__
-#include <crt_externs.h>
-# define environ (*_NSGetEnviron())
-#endif
-
-static const char *interp_prefix = CONFIG_QEMU_PREFIX;
-const char *qemu_uname_release = CONFIG_UNAME_RELEASE;
-
-#if defined(__i386__) && !defined(CONFIG_STATIC)
-/* Force usage of an ELF interpreter even if it is an ELF shared
- object ! */
-const char interp[] __attribute__((section(".interp"))) = "/lib/ld-linux.so.2";
-#endif
-
-/* for recent libc, we add these dummy symbols which are not declared
- when generating a linked object (bug in ld ?) */
-#if (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined(CONFIG_STATIC)
-long __preinit_array_start[0];
-long __preinit_array_end[0];
-long __init_array_start[0];
-long __init_array_end[0];
-long __fini_array_start[0];
-long __fini_array_end[0];
-#endif
-
-/* 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 x86_stack_size = 512 * 1024;
-
-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;
-}
-
-/* timers for rdtsc */
-
-#if 0
-
-static uint64_t emu_time;
-
-int64_t cpu_get_real_ticks(void)
-{
- return emu_time++;
-}
-
-#endif
-
-#ifdef TARGET_I386
-/***********************************************************/
-/* CPUX86 core interface */
-
-uint64_t cpu_get_tsc(CPUX86State *env)
-{
- return cpu_get_real_ticks();
-}
-
-static void write_dt(void *ptr, unsigned long addr, unsigned long limit,
- int flags)
-{
- unsigned int e1, e2;
- uint32_t *p;
- e1 = (addr << 16) | (limit & 0xffff);
- e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
- e2 |= flags;
- p = ptr;
- p[0] = tswapl(e1);
- p[1] = tswapl(e2);
-}
-
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
- unsigned long addr, unsigned int sel)
-{
- unsigned int e1, e2;
- uint32_t *p;
- e1 = (addr & 0xffff) | (sel << 16);
- e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
- p = ptr;
- p[0] = tswapl(e1);
- p[1] = tswapl(e2);
-}
-
-uint64_t gdt_table[6];
-uint64_t idt_table[256];
-
-/* 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);
-}
-
-void cpu_loop(CPUX86State *env)
-{
- int trapnr;
- target_ulong pc;
- target_siginfo_t info;
-
- for(;;) {
- trapnr = cpu_x86_exec(env);
- switch(trapnr) {
- case 0x80:
- /* linux syscall */
- env->regs[R_EAX] = do_syscall(env,
- env->regs[R_EAX],
- env->regs[R_EBX],
- env->regs[R_ECX],
- env->regs[R_EDX],
- env->regs[R_ESI],
- env->regs[R_EDI],
- env->regs[R_EBP]);
- break;
- case EXCP0B_NOSEG:
- case EXCP0C_STACK:
- info.si_signo = SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- queue_signal(info.si_signo, &info);
- break;
- case EXCP0D_GPF:
- if (env->eflags & VM_MASK) {
- handle_vm86_fault(env);
- } else {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- 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 = TARGET_SEGV_MAPERR;
- else
- info.si_code = TARGET_SEGV_ACCERR;
- info._sifields._sigfault._addr = env->cr[2];
- queue_signal(info.si_signo, &info);
- break;
- case EXCP00_DIVZ:
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
- } else {
- /* division by zero */
- info.si_signo = SIGFPE;
- info.si_errno = 0;
- info.si_code = TARGET_FPE_INTDIV;
- info._sifields._sigfault._addr = env->eip;
- queue_signal(info.si_signo, &info);
- }
- break;
- case EXCP01_SSTP:
- case EXCP03_INT3:
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
- } else {
- info.si_signo = SIGTRAP;
- info.si_errno = 0;
- if (trapnr == EXCP01_SSTP) {
- info.si_code = TARGET_TRAP_BRKPT;
- info._sifields._sigfault._addr = env->eip;
- } else {
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- }
- queue_signal(info.si_signo, &info);
- }
- break;
- case EXCP04_INTO:
- case EXCP05_BOUND:
- if (env->eflags & VM_MASK) {
- handle_vm86_trap(env, trapnr);
- } else {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SI_KERNEL;
- info._sifields._sigfault._addr = 0;
- queue_signal(info.si_signo, &info);
- }
- break;
- case EXCP06_ILLOP:
- info.si_signo = SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->eip;
- 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, 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:
- pc = 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
-
-#ifdef TARGET_ARM
-
-/* XXX: find a better solution */
-extern void tb_invalidate_page_range(target_ulong start, target_ulong end);
-
-static void arm_cache_flush(target_ulong start, target_ulong last)
-{
- target_ulong addr, last1;
-
- if (last < start)
- return;
- addr = start;
- for(;;) {
- last1 = ((addr + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK) - 1;
- if (last1 > last)
- last1 = last;
- tb_invalidate_page_range(addr, last1 + 1);
- if (last1 == last)
- break;
- addr = last1 + 1;
- }
-}
-
-void cpu_loop(CPUARMState *env)
-{
- int trapnr;
- unsigned int n, insn;
- target_siginfo_t info;
- uint32_t addr;
-
- for(;;) {
- trapnr = cpu_arm_exec(env);
- switch(trapnr) {
- case EXCP_UDEF:
- {
- TaskState *ts = env->opaque;
- uint32_t opcode;
-
- /* we handle the FPU emulation here, as Linux */
- /* we get the opcode */
- opcode = tget32(env->regs[15]);
-
- if (EmulateAll(opcode, &ts->fpa, env) == 0) {
- info.si_signo = SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLOPN;
- info._sifields._sigfault._addr = env->regs[15];
- queue_signal(info.si_signo, &info);
- } else {
- /* increment PC */
- env->regs[15] += 4;
- }
- }
- break;
- case EXCP_SWI:
- case EXCP_BKPT:
- {
- env->eabi = 1;
- /* system call */
- if (trapnr == EXCP_BKPT) {
- if (env->thumb) {
- insn = tget16(env->regs[15]);
- n = insn & 0xff;
- env->regs[15] += 2;
- } else {
- insn = tget32(env->regs[15]);
- n = (insn & 0xf) | ((insn >> 4) & 0xff0);
- env->regs[15] += 4;
- }
- } else {
- if (env->thumb) {
- insn = tget16(env->regs[15] - 2);
- n = insn & 0xff;
- } else {
- insn = tget32(env->regs[15] - 4);
- n = insn & 0xffffff;
- }
- }
-
- if (n == ARM_NR_cacheflush) {
- arm_cache_flush(env->regs[0], env->regs[1]);
- } else if (n == ARM_NR_semihosting
- || n == ARM_NR_thumb_semihosting) {
- env->regs[0] = do_arm_semihosting (env);
- } else if (n == 0 || n >= ARM_SYSCALL_BASE
- || (env->thumb && n == ARM_THUMB_SYSCALL)) {
- /* linux syscall */
- if (env->thumb || n == 0) {
- n = env->regs[7];
- } else {
- n -= ARM_SYSCALL_BASE;
- env->eabi = 0;
- }
- env->regs[0] = do_syscall(env,
- n,
- env->regs[0],
- env->regs[1],
- env->regs[2],
- env->regs[3],
- env->regs[4],
- env->regs[5]);
- } else {
- goto error;
- }
- }
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- case EXCP_PREFETCH_ABORT:
- addr = env->cp15.c6_data;
- goto do_segv;
- case EXCP_DATA_ABORT:
- addr = env->cp15.c6_insn;
- goto do_segv;
- do_segv:
- {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = addr;
- queue_signal(info.si_signo, &info);
- }
- 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:
- error:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
- trapnr);
- cpu_dump_state(env, stderr, fprintf, 0);
- abort();
- }
- process_pending_signals(env);
- }
-}
-
-#endif
-
-#ifdef TARGET_SPARC
-
-//#define DEBUG_WIN
-
-/* WARNING: dealing with register windows _is_ complicated. More info
- can be found at http://www.sics.se/~psm/sparcstack.html */
-static inline int get_reg_index(CPUSPARCState *env, int cwp, int index)
-{
- index = (index + cwp * 16) & (16 * NWINDOWS - 1);
- /* wrap handling : if cwp is on the last window, then we use the
- registers 'after' the end */
- if (index < 8 && env->cwp == (NWINDOWS - 1))
- index += (16 * NWINDOWS);
- return index;
-}
-
-/* save the register window 'cwp1' */
-static inline void save_window_offset(CPUSPARCState *env, int cwp1)
-{
- unsigned int i;
- target_ulong sp_ptr;
-
- sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#if defined(DEBUG_WIN)
- printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n",
- (int)sp_ptr, cwp1);
-#endif
- for(i = 0; i < 16; i++) {
- tputl(sp_ptr, env->regbase[get_reg_index(env, cwp1, 8 + i)]);
- sp_ptr += sizeof(target_ulong);
- }
-}
-
-static void save_window(CPUSPARCState *env)
-{
-#ifndef TARGET_SPARC64
- unsigned int new_wim;
- new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) &
- ((1LL << NWINDOWS) - 1);
- save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1));
- env->wim = new_wim;
-#else
- save_window_offset(env, (env->cwp - 2) & (NWINDOWS - 1));
- env->cansave++;
- env->canrestore--;
-#endif
-}
-
-static void restore_window(CPUSPARCState *env)
-{
- unsigned int new_wim, i, cwp1;
- target_ulong sp_ptr;
-
- new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) &
- ((1LL << NWINDOWS) - 1);
-
- /* restore the invalid window */
- cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
- sp_ptr = env->regbase[get_reg_index(env, cwp1, 6)];
-#if defined(DEBUG_WIN)
- printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n",
- (int)sp_ptr, cwp1);
-#endif
- for(i = 0; i < 16; i++) {
- env->regbase[get_reg_index(env, cwp1, 8 + i)] = tgetl(sp_ptr);
- sp_ptr += sizeof(target_ulong);
- }
- env->wim = new_wim;
-#ifdef TARGET_SPARC64
- env->canrestore++;
- if (env->cleanwin < NWINDOWS - 1)
- env->cleanwin++;
- env->cansave--;
-#endif
-}
-
-static void flush_windows(CPUSPARCState *env)
-{
- int offset, cwp1;
-
- offset = 1;
- for(;;) {
- /* if restore would invoke restore_window(), then we can stop */
- cwp1 = (env->cwp + offset) & (NWINDOWS - 1);
- if (env->wim & (1 << cwp1))
- break;
- save_window_offset(env, cwp1);
- offset++;
- }
- /* set wim so that restore will reload the registers */
- cwp1 = (env->cwp + 1) & (NWINDOWS - 1);
- env->wim = 1 << cwp1;
-#if defined(DEBUG_WIN)
- printf("flush_windows: nb=%d\n", offset - 1);
-#endif
-}
-
-void cpu_loop (CPUSPARCState *env)
-{
- int trapnr, ret;
- target_siginfo_t info;
-
- while (1) {
- trapnr = cpu_sparc_exec (env);
-
- switch (trapnr) {
-#ifndef TARGET_SPARC64
- case 0x88:
- case 0x90:
-#else
- case 0x16d:
-#endif
- ret = do_syscall (env, env->gregs[1],
- env->regwptr[0], env->regwptr[1],
- env->regwptr[2], env->regwptr[3],
- env->regwptr[4], env->regwptr[5]);
- if ((unsigned int)ret >= (unsigned int)(-515)) {
- env->psr |= PSR_CARRY;
- ret = -ret;
- } else {
- env->psr &= ~PSR_CARRY;
- }
- env->regwptr[0] = ret;
- /* next instruction */
- env->pc = env->npc;
- env->npc = env->npc + 4;
- break;
- case 0x83: /* flush windows */
- flush_windows(env);
- /* next instruction */
- env->pc = env->npc;
- env->npc = env->npc + 4;
- break;
-#ifndef TARGET_SPARC64
- case TT_WIN_OVF: /* window overflow */
- save_window(env);
- break;
- case TT_WIN_UNF: /* window underflow */
- restore_window(env);
- break;
- case TT_TFAULT:
- case TT_DFAULT:
- {
- info.si_signo = SIGSEGV;
- info.si_errno = 0;
- /* XXX: check env->error_code */
- info.si_code = TARGET_SEGV_MAPERR;
- info._sifields._sigfault._addr = env->mmuregs[4];
- queue_signal(info.si_signo, &info);
- }
- break;
-#else
- case TT_SPILL: /* window overflow */
- save_window(env);
- break;
- case TT_FILL: /* window underflow */
- restore_window(env);
- break;
- // XXX
-#endif
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- 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
-
-#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)
-{
- target_siginfo_t info;
- int trapnr;
- uint32_t ret;
-
- 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 */
- /* WARNING:
- * PPC ABI uses overflow flag in cr0 to signal an error
- * in syscalls.
- */
-#if 0
- printf("syscall %d 0x%08x 0x%08x 0x%08x 0x%08x\n", env->gpr[0],
- env->gpr[3], env->gpr[4], env->gpr[5], env->gpr[6]);
-#endif
- env->crf[0] &= ~0x1;
- ret = do_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
- env->gpr[5], env->gpr[6], env->gpr[7],
- env->gpr[8]);
- if (ret > (uint32_t)(-515)) {
- env->crf[0] |= 0x1;
- ret = -ret;
- }
- env->gpr[3] = ret;
-#if 0
- printf("syscall returned 0x%08x (%d)\n", ret, ret);
-#endif
- 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 = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_BUS_OBJERR;
- 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",
- env->spr[SPR_DAR]);
- if (loglevel) {
- fprintf(logfile, "Invalid data memory access: 0x%08x\n",
- env->spr[SPR_DAR]);
- }
- switch (env->error_code & 0xFF000000) {
- case 0x40000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- case 0x04000000:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_ILLADR;
- break;
- case 0x08000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_ACCERR;
- break;
- default:
- /* Let's send a regular segfault... */
- fprintf(stderr, "Invalid segfault errno (%02x)\n",
- env->error_code);
- if (loglevel) {
- fprintf(logfile, "Invalid segfault errno (%02x)\n",
- env->error_code);
- }
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- }
- info._sifields._sigfault._addr = 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");
- switch (env->error_code & 0xFF000000) {
- case 0x40000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- case 0x10000000:
- case 0x08000000:
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_ACCERR;
- break;
- default:
- /* Let's send a regular segfault... */
- fprintf(stderr, "Invalid segfault errno (%02x)\n",
- env->error_code);
- if (loglevel) {
- fprintf(logfile, "Invalid segfault errno (%02x)\n",
- env->error_code);
- }
- info.si_signo = TARGET_SIGSEGV;
- info.si_errno = 0;
- info.si_code = TARGET_SEGV_MAPERR;
- break;
- }
- info._sifields._sigfault._addr = 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 = TARGET_SIGBUS;
- info.si_errno = 0;
- info.si_code = TARGET_BUS_ADRALN;
- info._sifields._sigfault._addr = 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 = TARGET_SIGFPE;
- info.si_errno = 0;
- switch (env->error_code & 0xF) {
- case EXCP_FP_OX:
- info.si_code = TARGET_FPE_FLTOVF;
- break;
- case EXCP_FP_UX:
- info.si_code = TARGET_FPE_FLTUND;
- break;
- case EXCP_FP_ZX:
- case EXCP_FP_VXZDZ:
- info.si_code = TARGET_FPE_FLTDIV;
- break;
- case EXCP_FP_XX:
- info.si_code = TARGET_FPE_FLTRES;
- break;
- case EXCP_FP_VXSOFT:
- info.si_code = TARGET_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 = TARGET_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 = TARGET_SIGILL;
- info.si_errno = 0;
- switch (env->error_code & 0xF) {
- case EXCP_INVAL_INVAL:
- info.si_code = TARGET_ILL_ILLOPC;
- break;
- case EXCP_INVAL_LSWX:
- info.si_code = TARGET_ILL_ILLOPN;
- break;
- case EXCP_INVAL_SPR:
- info.si_code = TARGET_ILL_PRVREG;
- break;
- case EXCP_INVAL_FP:
- info.si_code = TARGET_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 = TARGET_ILL_ILLADR;
- break;
- }
- break;
- case EXCP_PRIV:
- fprintf(stderr, "Privilege violation\n");
- if (loglevel)
- fprintf(logfile, "Privilege violation\n");
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- switch (env->error_code & 0xF) {
- case EXCP_PRIV_OPC:
- info.si_code = TARGET_ILL_PRVOPC;
- break;
- case EXCP_PRIV_REG:
- info.si_code = TARGET_ILL_PRVREG;
- break;
- default:
- fprintf(stderr, "Unknown privilege violation (%02x)\n",
- env->error_code & 0xF);
- info.si_code = TARGET_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._sifields._sigfault._addr = 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 = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = TARGET_ILL_COPROC;
- info._sifields._sigfault._addr = 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:
- /* Do nothing: we use this to trace execution */
- 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... */
- 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:
- 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_MIPS
-
-#define MIPS_SYS(name, args) args,
-
-static const uint8_t mips_syscall_args[] = {
- MIPS_SYS(sys_syscall , 0) /* 4000 */
- MIPS_SYS(sys_exit , 1)
- MIPS_SYS(sys_fork , 0)
- MIPS_SYS(sys_read , 3)
- MIPS_SYS(sys_write , 3)
- MIPS_SYS(sys_open , 3) /* 4005 */
- MIPS_SYS(sys_close , 1)
- MIPS_SYS(sys_waitpid , 3)
- MIPS_SYS(sys_creat , 2)
- MIPS_SYS(sys_link , 2)
- MIPS_SYS(sys_unlink , 1) /* 4010 */
- MIPS_SYS(sys_execve , 0)
- MIPS_SYS(sys_chdir , 1)
- MIPS_SYS(sys_time , 1)
- MIPS_SYS(sys_mknod , 3)
- MIPS_SYS(sys_chmod , 2) /* 4015 */
- MIPS_SYS(sys_lchown , 3)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_stat */
- MIPS_SYS(sys_lseek , 3)
- MIPS_SYS(sys_getpid , 0) /* 4020 */
- MIPS_SYS(sys_mount , 5)
- MIPS_SYS(sys_oldumount , 1)
- MIPS_SYS(sys_setuid , 1)
- MIPS_SYS(sys_getuid , 0)
- MIPS_SYS(sys_stime , 1) /* 4025 */
- MIPS_SYS(sys_ptrace , 4)
- MIPS_SYS(sys_alarm , 1)
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_fstat */
- MIPS_SYS(sys_pause , 0)
- MIPS_SYS(sys_utime , 2) /* 4030 */
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_access , 2)
- MIPS_SYS(sys_nice , 1)
- MIPS_SYS(sys_ni_syscall , 0) /* 4035 */
- MIPS_SYS(sys_sync , 0)
- MIPS_SYS(sys_kill , 2)
- MIPS_SYS(sys_rename , 2)
- MIPS_SYS(sys_mkdir , 2)
- MIPS_SYS(sys_rmdir , 1) /* 4040 */
- MIPS_SYS(sys_dup , 1)
- MIPS_SYS(sys_pipe , 0)
- MIPS_SYS(sys_times , 1)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_brk , 1) /* 4045 */
- MIPS_SYS(sys_setgid , 1)
- MIPS_SYS(sys_getgid , 0)
- MIPS_SYS(sys_ni_syscall , 0) /* was signal(2) */
- MIPS_SYS(sys_geteuid , 0)
- MIPS_SYS(sys_getegid , 0) /* 4050 */
- MIPS_SYS(sys_acct , 0)
- MIPS_SYS(sys_umount , 2)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_ioctl , 3)
- MIPS_SYS(sys_fcntl , 3) /* 4055 */
- MIPS_SYS(sys_ni_syscall , 2)
- MIPS_SYS(sys_setpgid , 2)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_olduname , 1)
- MIPS_SYS(sys_umask , 1) /* 4060 */
- MIPS_SYS(sys_chroot , 1)
- MIPS_SYS(sys_ustat , 2)
- MIPS_SYS(sys_dup2 , 2)
- MIPS_SYS(sys_getppid , 0)
- MIPS_SYS(sys_getpgrp , 0) /* 4065 */
- MIPS_SYS(sys_setsid , 0)
- MIPS_SYS(sys_sigaction , 3)
- MIPS_SYS(sys_sgetmask , 0)
- MIPS_SYS(sys_ssetmask , 1)
- MIPS_SYS(sys_setreuid , 2) /* 4070 */
- MIPS_SYS(sys_setregid , 2)
- MIPS_SYS(sys_sigsuspend , 0)
- MIPS_SYS(sys_sigpending , 1)
- MIPS_SYS(sys_sethostname , 2)
- MIPS_SYS(sys_setrlimit , 2) /* 4075 */
- MIPS_SYS(sys_getrlimit , 2)
- MIPS_SYS(sys_getrusage , 2)
- MIPS_SYS(sys_gettimeofday, 2)
- MIPS_SYS(sys_settimeofday, 2)
- MIPS_SYS(sys_getgroups , 2) /* 4080 */
- MIPS_SYS(sys_setgroups , 2)
- MIPS_SYS(sys_ni_syscall , 0) /* old_select */
- MIPS_SYS(sys_symlink , 2)
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_lstat */
- MIPS_SYS(sys_readlink , 3) /* 4085 */
- MIPS_SYS(sys_uselib , 1)
- MIPS_SYS(sys_swapon , 2)
- MIPS_SYS(sys_reboot , 3)
- MIPS_SYS(old_readdir , 3)
- MIPS_SYS(old_mmap , 6) /* 4090 */
- MIPS_SYS(sys_munmap , 2)
- MIPS_SYS(sys_truncate , 2)
- MIPS_SYS(sys_ftruncate , 2)
- MIPS_SYS(sys_fchmod , 2)
- MIPS_SYS(sys_fchown , 3) /* 4095 */
- MIPS_SYS(sys_getpriority , 2)
- MIPS_SYS(sys_setpriority , 3)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_statfs , 2)
- MIPS_SYS(sys_fstatfs , 2) /* 4100 */
- MIPS_SYS(sys_ni_syscall , 0) /* was ioperm(2) */
- MIPS_SYS(sys_socketcall , 2)
- MIPS_SYS(sys_syslog , 3)
- MIPS_SYS(sys_setitimer , 3)
- MIPS_SYS(sys_getitimer , 2) /* 4105 */
- MIPS_SYS(sys_newstat , 2)
- MIPS_SYS(sys_newlstat , 2)
- MIPS_SYS(sys_newfstat , 2)
- MIPS_SYS(sys_uname , 1)
- MIPS_SYS(sys_ni_syscall , 0) /* 4110 was iopl(2) */
- MIPS_SYS(sys_vhangup , 0)
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_idle() */
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_vm86 */
- MIPS_SYS(sys_wait4 , 4)
- MIPS_SYS(sys_swapoff , 1) /* 4115 */
- MIPS_SYS(sys_sysinfo , 1)
- MIPS_SYS(sys_ipc , 6)
- MIPS_SYS(sys_fsync , 1)
- MIPS_SYS(sys_sigreturn , 0)
- MIPS_SYS(sys_clone , 0) /* 4120 */
- MIPS_SYS(sys_setdomainname, 2)
- MIPS_SYS(sys_newuname , 1)
- MIPS_SYS(sys_ni_syscall , 0) /* sys_modify_ldt */
- MIPS_SYS(sys_adjtimex , 1)
- MIPS_SYS(sys_mprotect , 3) /* 4125 */
- MIPS_SYS(sys_sigprocmask , 3)
- MIPS_SYS(sys_ni_syscall , 0) /* was create_module */
- MIPS_SYS(sys_init_module , 5)
- MIPS_SYS(sys_delete_module, 1)
- MIPS_SYS(sys_ni_syscall , 0) /* 4130 was get_kernel_syms */
- MIPS_SYS(sys_quotactl , 0)
- MIPS_SYS(sys_getpgid , 1)
- MIPS_SYS(sys_fchdir , 1)
- MIPS_SYS(sys_bdflush , 2)
- MIPS_SYS(sys_sysfs , 3) /* 4135 */
- MIPS_SYS(sys_personality , 1)
- MIPS_SYS(sys_ni_syscall , 0) /* for afs_syscall */
- MIPS_SYS(sys_setfsuid , 1)
- MIPS_SYS(sys_setfsgid , 1)
- MIPS_SYS(sys_llseek , 5) /* 4140 */
- MIPS_SYS(sys_getdents , 3)
- MIPS_SYS(sys_select , 5)
- MIPS_SYS(sys_flock , 2)
- MIPS_SYS(sys_msync , 3)
- MIPS_SYS(sys_readv , 3) /* 4145 */
- MIPS_SYS(sys_writev , 3)
- MIPS_SYS(sys_cacheflush , 3)
- MIPS_SYS(sys_cachectl , 3)
- MIPS_SYS(sys_sysmips , 4)
- MIPS_SYS(sys_ni_syscall , 0) /* 4150 */
- MIPS_SYS(sys_getsid , 1)
- MIPS_SYS(sys_fdatasync , 0)
- MIPS_SYS(sys_sysctl , 1)
- MIPS_SYS(sys_mlock , 2)
- MIPS_SYS(sys_munlock , 2) /* 4155 */
- MIPS_SYS(sys_mlockall , 1)
- MIPS_SYS(sys_munlockall , 0)
- MIPS_SYS(sys_sched_setparam, 2)
- MIPS_SYS(sys_sched_getparam, 2)
- MIPS_SYS(sys_sched_setscheduler, 3) /* 4160 */
- MIPS_SYS(sys_sched_getscheduler, 1)
- MIPS_SYS(sys_sched_yield , 0)
- MIPS_SYS(sys_sched_get_priority_max, 1)
- MIPS_SYS(sys_sched_get_priority_min, 1)
- MIPS_SYS(sys_sched_rr_get_interval, 2) /* 4165 */
- MIPS_SYS(sys_nanosleep, 2)
- MIPS_SYS(sys_mremap , 4)
- MIPS_SYS(sys_accept , 3)
- MIPS_SYS(sys_bind , 3)
- MIPS_SYS(sys_connect , 3) /* 4170 */
- MIPS_SYS(sys_getpeername , 3)
- MIPS_SYS(sys_getsockname , 3)
- MIPS_SYS(sys_getsockopt , 5)
- MIPS_SYS(sys_listen , 2)
- MIPS_SYS(sys_recv , 4) /* 4175 */
- MIPS_SYS(sys_recvfrom , 6)
- MIPS_SYS(sys_recvmsg , 3)
- MIPS_SYS(sys_send , 4)
- MIPS_SYS(sys_sendmsg , 3)
- MIPS_SYS(sys_sendto , 6) /* 4180 */
- MIPS_SYS(sys_setsockopt , 5)
- MIPS_SYS(sys_shutdown , 2)
- MIPS_SYS(sys_socket , 3)
- MIPS_SYS(sys_socketpair , 4)
- MIPS_SYS(sys_setresuid , 3) /* 4185 */
- MIPS_SYS(sys_getresuid , 3)
- MIPS_SYS(sys_ni_syscall , 0) /* was sys_query_module */
- MIPS_SYS(sys_poll , 3)
- MIPS_SYS(sys_nfsservctl , 3)
- MIPS_SYS(sys_setresgid , 3) /* 4190 */
- MIPS_SYS(sys_getresgid , 3)
- MIPS_SYS(sys_prctl , 5)
- MIPS_SYS(sys_rt_sigreturn, 0)
- MIPS_SYS(sys_rt_sigaction, 4)
- MIPS_SYS(sys_rt_sigprocmask, 4) /* 4195 */
- MIPS_SYS(sys_rt_sigpending, 2)
- MIPS_SYS(sys_rt_sigtimedwait, 4)
- MIPS_SYS(sys_rt_sigqueueinfo, 3)
- MIPS_SYS(sys_rt_sigsuspend, 0)
- MIPS_SYS(sys_pread64 , 6) /* 4200 */
- MIPS_SYS(sys_pwrite64 , 6)
- MIPS_SYS(sys_chown , 3)
- MIPS_SYS(sys_getcwd , 2)
- MIPS_SYS(sys_capget , 2)
- MIPS_SYS(sys_capset , 2) /* 4205 */
- MIPS_SYS(sys_sigaltstack , 0)
- MIPS_SYS(sys_sendfile , 4)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_mmap2 , 6) /* 4210 */
- MIPS_SYS(sys_truncate64 , 4)
- MIPS_SYS(sys_ftruncate64 , 4)
- MIPS_SYS(sys_stat64 , 2)
- MIPS_SYS(sys_lstat64 , 2)
- MIPS_SYS(sys_fstat64 , 2) /* 4215 */
- MIPS_SYS(sys_pivot_root , 2)
- MIPS_SYS(sys_mincore , 3)
- MIPS_SYS(sys_madvise , 3)
- MIPS_SYS(sys_getdents64 , 3)
- MIPS_SYS(sys_fcntl64 , 3) /* 4220 */
- MIPS_SYS(sys_ni_syscall , 0)
- MIPS_SYS(sys_gettid , 0)
- MIPS_SYS(sys_readahead , 5)
- MIPS_SYS(sys_setxattr , 5)
- MIPS_SYS(sys_lsetxattr , 5) /* 4225 */
- MIPS_SYS(sys_fsetxattr , 5)
- MIPS_SYS(sys_getxattr , 4)
- MIPS_SYS(sys_lgetxattr , 4)
- MIPS_SYS(sys_fgetxattr , 4)
- MIPS_SYS(sys_listxattr , 3) /* 4230 */
- MIPS_SYS(sys_llistxattr , 3)
- MIPS_SYS(sys_flistxattr , 3)
- MIPS_SYS(sys_removexattr , 2)
- MIPS_SYS(sys_lremovexattr, 2)
- MIPS_SYS(sys_fremovexattr, 2) /* 4235 */
- MIPS_SYS(sys_tkill , 2)
- MIPS_SYS(sys_sendfile64 , 5)
- MIPS_SYS(sys_futex , 2)
- MIPS_SYS(sys_sched_setaffinity, 3)
- MIPS_SYS(sys_sched_getaffinity, 3) /* 4240 */
- MIPS_SYS(sys_io_setup , 2)
- MIPS_SYS(sys_io_destroy , 1)
- MIPS_SYS(sys_io_getevents, 5)
- MIPS_SYS(sys_io_submit , 3)
- MIPS_SYS(sys_io_cancel , 3) /* 4245 */
- MIPS_SYS(sys_exit_group , 1)
- MIPS_SYS(sys_lookup_dcookie, 3)
- MIPS_SYS(sys_epoll_create, 1)
- MIPS_SYS(sys_epoll_ctl , 4)
- MIPS_SYS(sys_epoll_wait , 3) /* 4250 */
- MIPS_SYS(sys_remap_file_pages, 5)
- MIPS_SYS(sys_set_tid_address, 1)
- MIPS_SYS(sys_restart_syscall, 0)
- MIPS_SYS(sys_fadvise64_64, 7)
- MIPS_SYS(sys_statfs64 , 3) /* 4255 */
- MIPS_SYS(sys_fstatfs64 , 2)
- MIPS_SYS(sys_timer_create, 3)
- MIPS_SYS(sys_timer_settime, 4)
- MIPS_SYS(sys_timer_gettime, 2)
- MIPS_SYS(sys_timer_getoverrun, 1) /* 4260 */
- MIPS_SYS(sys_timer_delete, 1)
- MIPS_SYS(sys_clock_settime, 2)
- MIPS_SYS(sys_clock_gettime, 2)
- MIPS_SYS(sys_clock_getres, 2)
- MIPS_SYS(sys_clock_nanosleep, 4) /* 4265 */
- MIPS_SYS(sys_tgkill , 3)
- MIPS_SYS(sys_utimes , 2)
- MIPS_SYS(sys_mbind , 4)
- MIPS_SYS(sys_ni_syscall , 0) /* sys_get_mempolicy */
- MIPS_SYS(sys_ni_syscall , 0) /* 4270 sys_set_mempolicy */
- MIPS_SYS(sys_mq_open , 4)
- MIPS_SYS(sys_mq_unlink , 1)
- MIPS_SYS(sys_mq_timedsend, 5)
- MIPS_SYS(sys_mq_timedreceive, 5)
- MIPS_SYS(sys_mq_notify , 2) /* 4275 */
- MIPS_SYS(sys_mq_getsetattr, 3)
- MIPS_SYS(sys_ni_syscall , 0) /* sys_vserver */
- MIPS_SYS(sys_waitid , 4)
- MIPS_SYS(sys_ni_syscall , 0) /* available, was setaltroot */
- MIPS_SYS(sys_add_key , 5)
- MIPS_SYS(sys_request_key , 4)
- MIPS_SYS(sys_keyctl , 5)
-};
-
-#undef MIPS_SYS
-
-void cpu_loop(CPUMIPSState *env)
-{
- target_siginfo_t info;
- int trapnr, ret, nb_args;
- unsigned int syscall_num;
- target_ulong arg5, arg6, sp_reg;
-
- for(;;) {
- trapnr = cpu_mips_exec(env);
- switch(trapnr) {
- case EXCP_SYSCALL:
- {
- syscall_num = env->gpr[2] - 4000;
- env->PC += 4;
- if (syscall_num >= sizeof(mips_syscall_args)) {
- ret = -ENOSYS;
- } else {
- nb_args = mips_syscall_args[syscall_num];
- if (nb_args >= 5) {
- sp_reg = env->gpr[29];
- /* these arguments are taken from the stack */
- arg5 = tgetl(sp_reg + 16);
- if (nb_args >= 6) {
- arg6 = tgetl(sp_reg + 20);
- } else {
- arg6 = 0;
- }
- } else {
- arg5 = 0;
- arg6 = 0;
- }
- ret = do_syscall(env,
- env->gpr[2],
- env->gpr[4],
- env->gpr[5],
- env->gpr[6],
- env->gpr[7],
- arg5,
- arg6);
- }
- if ((unsigned int)ret >= (unsigned int)(-1133)) {
- env->gpr[7] = 1; /* error flag */
- ret = -ret;
- env->gpr[0] = ret;
- env->gpr[2] = ret;
- } else {
- env->gpr[7] = 0; /* error flag */
- env->gpr[2] = ret;
- }
- }
- break;
- case EXCP_CpU:
- case EXCP_RI:
- info.si_signo = TARGET_SIGILL;
- info.si_errno = 0;
- info.si_code = 0;
- queue_signal(info.si_signo, &info);
- break;
- case EXCP_INTERRUPT:
- /* just indicate that signals should be handled asap */
- break;
- default:
- // error:
- fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
- trapnr);
- cpu_dump_state(env, stderr, fprintf, 0);
- abort();
- }
- process_pending_signals(env);
- }
-}
-#endif
-
-#ifdef TARGET_SH4
-void cpu_loop (CPUState *env)
-{
- int trapnr, ret;
- target_siginfo_t info;
-
- while (1) {
- trapnr = cpu_sh4_exec (env);
-
- switch (trapnr) {
- case 0x160:
- ret = do_syscall(env,
- env->gregs[3],
- env->gregs[4],
- env->gregs[5],
- env->gregs[6],
- env->gregs[7],
- env->gregs[0],
- 0);
- env->gregs[0] = ret;
- env->pc += 2;
- 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
-
-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"
- "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"
- "\n"
- "debug options:\n"
-#ifdef USE_CODE_COPY
- "-no-code-copy disable code copy acceleration\n"
-#endif
- "-d options activate log (logfile=%s)\n"
- "-p pagesize set the host page size to 'pagesize'\n",
- TARGET_ARCH,
- interp_prefix,
- x86_stack_size,
- DEBUG_LOGFILE);
- _exit(1);
-}
-
-/* XXX: currently only used for async signals (see signal.c) */
-CPUState *global_env;
-
-/* used to free thread contexts */
-TaskState *first_task_state;
-
-int main(int argc, char **argv)
-{
- const char *filename;
- struct target_pt_regs regs1, *regs = &regs1;
- struct image_info info1, *info = &info1;
- TaskState ts1, *ts = &ts1;
- CPUState *env;
- int optind;
- const char *r;
- int gdbstub_port = 0;
-
- 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++];
- x86_stack_size = strtol(r, (char **)&r, 0);
- if (x86_stack_size <= 0)
- usage();
- if (*r == 'M')
- x86_stack_size *= 1024 * 1024;
- else if (*r == 'k' || *r == 'K')
- x86_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")) {
- gdbstub_port = atoi(argv[optind++]);
- } else if (!strcmp(r, "r")) {
- qemu_uname_release = argv[optind++];
- } 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));
-
- /* Zero out image_info */
- memset(info, 0, sizeof(struct image_info));
-
- /* Scan interp_prefix dir for replacement files. */
- init_paths(interp_prefix);
-
- /* NOTE: we need to init the CPU at this stage to get
- qemu_host_page_size */
- env = cpu_init();
- global_env = env;
-
- if (loader_exec(filename, argv+optind, environ, regs, info) != 0) {
- printf("Error loading %s\n", filename);
- _exit(1);
- }
-
- if (loglevel) {
- page_dump(logfile);
-
- fprintf(logfile, "start_brk 0x%08lx\n" , info->start_brk);
- fprintf(logfile, "end_code 0x%08lx\n" , info->end_code);
- fprintf(logfile, "start_code 0x%08lx\n" , info->start_code);
- fprintf(logfile, "start_data 0x%08lx\n" , info->start_data);
- fprintf(logfile, "end_data 0x%08lx\n" , info->end_data);
- fprintf(logfile, "start_stack 0x%08lx\n" , info->start_stack);
- fprintf(logfile, "brk 0x%08lx\n" , info->brk);
- fprintf(logfile, "entry 0x%08lx\n" , info->entry);
- }
-
- target_set_brk(info->brk);
- syscall_init();
- signal_init();
-
- /* build Task State */
- memset(ts, 0, sizeof(TaskState));
- env->opaque = ts;
- ts->used = 1;
- ts->info = info;
- 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;
-
- /* linux 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;
-
- /* linux interrupt setup */
- env->idt.base = h2g(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);
- set_idt(0x80, 3);
-
- /* linux segment setup */
- env->gdt.base = h2g(gdt_table);
- env->gdt.limit = sizeof(gdt_table) - 1;
- write_dt(&gdt_table[__USER_CS >> 3], 0, 0xfffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
- (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
- write_dt(&gdt_table[__USER_DS >> 3], 0, 0xfffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
- (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
- 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_ARM)
- {
- int i;
- cpu_arm_set_model(env, ARM_CPUID_ARM1026);
- cpsr_write(env, regs->uregs[16], 0xffffffff);
- for(i = 0; i < 16; i++) {
- env->regs[i] = regs->uregs[i];
- }
- ts->stack_base = info->start_stack;
- ts->heap_base = info->brk;
- /* This will be filled in on the first SYS_HEAPINFO call. */
- ts->heap_limit = 0;
- }
-#elif defined(TARGET_SPARC)
- {
- int i;
- env->pc = regs->pc;
- env->npc = regs->npc;
- env->y = regs->y;
- for(i = 0; i < 8; i++)
- env->gregs[i] = regs->u_regs[i];
- for(i = 0; i < 8; i++)
- env->regwptr[i] = regs->u_regs[i + 8];
- }
-#elif defined(TARGET_PPC)
- {
- ppc_def_t *def;
- 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 (def == NULL) {
- cpu_abort(env,
- "Unable to find PowerPC CPU definition\n");
- }
- cpu_ppc_register(env, def);
-
- for (i = 0; i < 32; i++) {
- if (i != 12 && i != 6 && i != 13)
- env->msr[i] = (regs->msr >> i) & 1;
- }
- env->nip = regs->nip;
- for(i = 0; i < 32; i++) {
- env->gpr[i] = regs->gpr[i];
- }
- }
-#elif defined(TARGET_MIPS)
- {
- int i;
-
- 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
- }
-#elif defined(TARGET_SH4)
- {
- int i;
-
- for(i = 0; i < 16; i++) {
- env->gregs[i] = regs->regs[i];
- }
- env->pc = regs->pc;
- }
-#else
-#error unsupported target CPU
-#endif
-
- if (gdbstub_port) {
- gdbserver_start (gdbstub_port);
- gdb_handlesig(env, 0);
- }
- cpu_loop(env);
- /* never exits */
- return 0;
-}
diff --git a/linux-user/mips/syscall.h b/linux-user/mips/syscall.h
deleted file mode 100644
index 4b3c7d6..0000000
--- a/linux-user/mips/syscall.h
+++ /dev/null
@@ -1,23 +0,0 @@
-
-/* this struct defines the way the registers are stored on the
- stack during a system call. */
-
-struct target_pt_regs {
-#if 1
- /* Pad bytes for argument save space on the stack. */
- target_ulong pad0[6];
-#endif
-
- /* Saved main processor registers. */
- target_ulong regs[32];
-
- /* Saved special registers. */
- target_ulong cp0_status;
- target_ulong lo;
- target_ulong hi;
- target_ulong cp0_badvaddr;
- target_ulong cp0_cause;
- target_ulong cp0_epc;
-};
-
-#define UNAME_MACHINE "mips"
diff --git a/linux-user/mips/syscall_nr.h b/linux-user/mips/syscall_nr.h
deleted file mode 100644
index 3593e65..0000000
--- a/linux-user/mips/syscall_nr.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Linux o32 style syscalls are in the range from 4000 to 4999.
- */
-#define TARGET_NR_Linux 4000
-#define TARGET_NR_syscall (TARGET_NR_Linux + 0)
-#define TARGET_NR_exit (TARGET_NR_Linux + 1)
-#define TARGET_NR_fork (TARGET_NR_Linux + 2)
-#define TARGET_NR_read (TARGET_NR_Linux + 3)
-#define TARGET_NR_write (TARGET_NR_Linux + 4)
-#define TARGET_NR_open (TARGET_NR_Linux + 5)
-#define TARGET_NR_close (TARGET_NR_Linux + 6)
-#define TARGET_NR_waitpid (TARGET_NR_Linux + 7)
-#define TARGET_NR_creat (TARGET_NR_Linux + 8)
-#define TARGET_NR_link (TARGET_NR_Linux + 9)
-#define TARGET_NR_unlink (TARGET_NR_Linux + 10)
-#define TARGET_NR_execve (TARGET_NR_Linux + 11)
-#define TARGET_NR_chdir (TARGET_NR_Linux + 12)
-#define TARGET_NR_time (TARGET_NR_Linux + 13)
-#define TARGET_NR_mknod (TARGET_NR_Linux + 14)
-#define TARGET_NR_chmod (TARGET_NR_Linux + 15)
-#define TARGET_NR_lchown32 (TARGET_NR_Linux + 16)
-#define TARGET_NR_break (TARGET_NR_Linux + 17)
-#define TARGET_NR_unused18 (TARGET_NR_Linux + 18)
-#define TARGET_NR_lseek (TARGET_NR_Linux + 19)
-#define TARGET_NR_getpid (TARGET_NR_Linux + 20)
-#define TARGET_NR_mount (TARGET_NR_Linux + 21)
-#define TARGET_NR_umount (TARGET_NR_Linux + 22)
-#define TARGET_NR_setuid32 (TARGET_NR_Linux + 23)
-#define TARGET_NR_getuid32 (TARGET_NR_Linux + 24)
-#define TARGET_NR_stime (TARGET_NR_Linux + 25)
-#define TARGET_NR_ptrace (TARGET_NR_Linux + 26)
-#define TARGET_NR_alarm (TARGET_NR_Linux + 27)
-#define TARGET_NR_unused28 (TARGET_NR_Linux + 28)
-#define TARGET_NR_pause (TARGET_NR_Linux + 29)
-#define TARGET_NR_utime (TARGET_NR_Linux + 30)
-#define TARGET_NR_stty (TARGET_NR_Linux + 31)
-#define TARGET_NR_gtty (TARGET_NR_Linux + 32)
-#define TARGET_NR_access (TARGET_NR_Linux + 33)
-#define TARGET_NR_nice (TARGET_NR_Linux + 34)
-#define TARGET_NR_ftime (TARGET_NR_Linux + 35)
-#define TARGET_NR_sync (TARGET_NR_Linux + 36)
-#define TARGET_NR_kill (TARGET_NR_Linux + 37)
-#define TARGET_NR_rename (TARGET_NR_Linux + 38)
-#define TARGET_NR_mkdir (TARGET_NR_Linux + 39)
-#define TARGET_NR_rmdir (TARGET_NR_Linux + 40)
-#define TARGET_NR_dup (TARGET_NR_Linux + 41)
-#define TARGET_NR_pipe (TARGET_NR_Linux + 42)
-#define TARGET_NR_times (TARGET_NR_Linux + 43)
-#define TARGET_NR_prof (TARGET_NR_Linux + 44)
-#define TARGET_NR_brk (TARGET_NR_Linux + 45)
-#define TARGET_NR_setgid32 (TARGET_NR_Linux + 46)
-#define TARGET_NR_getgid32 (TARGET_NR_Linux + 47)
-#define TARGET_NR_signal (TARGET_NR_Linux + 48)
-#define TARGET_NR_geteuid32 (TARGET_NR_Linux + 49)
-#define TARGET_NR_getegid32 (TARGET_NR_Linux + 50)
-#define TARGET_NR_acct (TARGET_NR_Linux + 51)
-#define TARGET_NR_umount2 (TARGET_NR_Linux + 52)
-#define TARGET_NR_lock (TARGET_NR_Linux + 53)
-#define TARGET_NR_ioctl (TARGET_NR_Linux + 54)
-#define TARGET_NR_fcntl (TARGET_NR_Linux + 55)
-#define TARGET_NR_mpx (TARGET_NR_Linux + 56)
-#define TARGET_NR_setpgid (TARGET_NR_Linux + 57)
-#define TARGET_NR_ulimit (TARGET_NR_Linux + 58)
-#define TARGET_NR_unused59 (TARGET_NR_Linux + 59)
-#define TARGET_NR_umask (TARGET_NR_Linux + 60)
-#define TARGET_NR_chroot (TARGET_NR_Linux + 61)
-#define TARGET_NR_ustat (TARGET_NR_Linux + 62)
-#define TARGET_NR_dup2 (TARGET_NR_Linux + 63)
-#define TARGET_NR_getppid (TARGET_NR_Linux + 64)
-#define TARGET_NR_getpgrp (TARGET_NR_Linux + 65)
-#define TARGET_NR_setsid (TARGET_NR_Linux + 66)
-#define TARGET_NR_sigaction (TARGET_NR_Linux + 67)
-#define TARGET_NR_sgetmask (TARGET_NR_Linux + 68)
-#define TARGET_NR_ssetmask (TARGET_NR_Linux + 69)
-#define TARGET_NR_setreuid32 (TARGET_NR_Linux + 70)
-#define TARGET_NR_setregid32 (TARGET_NR_Linux + 71)
-#define TARGET_NR_sigsuspend (TARGET_NR_Linux + 72)
-#define TARGET_NR_sigpending (TARGET_NR_Linux + 73)
-#define TARGET_NR_sethostname (TARGET_NR_Linux + 74)
-#define TARGET_NR_setrlimit (TARGET_NR_Linux + 75)
-#define TARGET_NR_getrlimit (TARGET_NR_Linux + 76)
-#define TARGET_NR_getrusage (TARGET_NR_Linux + 77)
-#define TARGET_NR_gettimeofday (TARGET_NR_Linux + 78)
-#define TARGET_NR_settimeofday (TARGET_NR_Linux + 79)
-#define TARGET_NR_getgroups32 (TARGET_NR_Linux + 80)
-#define TARGET_NR_setgroups32 (TARGET_NR_Linux + 81)
-#define TARGET_NR_reserved82 (TARGET_NR_Linux + 82)
-#define TARGET_NR_symlink (TARGET_NR_Linux + 83)
-#define TARGET_NR_unused84 (TARGET_NR_Linux + 84)
-#define TARGET_NR_readlink (TARGET_NR_Linux + 85)
-#define TARGET_NR_uselib (TARGET_NR_Linux + 86)
-#define TARGET_NR_swapon (TARGET_NR_Linux + 87)
-#define TARGET_NR_reboot (TARGET_NR_Linux + 88)
-#define TARGET_NR_readdir (TARGET_NR_Linux + 89)
-#define TARGET_NR_mmap (TARGET_NR_Linux + 90)
-#define TARGET_NR_munmap (TARGET_NR_Linux + 91)
-#define TARGET_NR_truncate (TARGET_NR_Linux + 92)
-#define TARGET_NR_ftruncate (TARGET_NR_Linux + 93)
-#define TARGET_NR_fchmod (TARGET_NR_Linux + 94)
-#define TARGET_NR_fchown32 (TARGET_NR_Linux + 95)
-#define TARGET_NR_getpriority (TARGET_NR_Linux + 96)
-#define TARGET_NR_setpriority (TARGET_NR_Linux + 97)
-#define TARGET_NR_profil (TARGET_NR_Linux + 98)
-#define TARGET_NR_statfs (TARGET_NR_Linux + 99)
-#define TARGET_NR_fstatfs (TARGET_NR_Linux + 100)
-#define TARGET_NR_ioperm (TARGET_NR_Linux + 101)
-#define TARGET_NR_socketcall (TARGET_NR_Linux + 102)
-#define TARGET_NR_syslog (TARGET_NR_Linux + 103)
-#define TARGET_NR_setitimer (TARGET_NR_Linux + 104)
-#define TARGET_NR_getitimer (TARGET_NR_Linux + 105)
-#define TARGET_NR_stat (TARGET_NR_Linux + 106)
-#define TARGET_NR_lstat (TARGET_NR_Linux + 107)
-#define TARGET_NR_fstat (TARGET_NR_Linux + 108)
-#define TARGET_NR_unused109 (TARGET_NR_Linux + 109)
-#define TARGET_NR_iopl (TARGET_NR_Linux + 110)
-#define TARGET_NR_vhangup (TARGET_NR_Linux + 111)
-#define TARGET_NR_idle (TARGET_NR_Linux + 112)
-#define TARGET_NR_vm86 (TARGET_NR_Linux + 113)
-#define TARGET_NR_wait4 (TARGET_NR_Linux + 114)
-#define TARGET_NR_swapoff (TARGET_NR_Linux + 115)
-#define TARGET_NR_sysinfo (TARGET_NR_Linux + 116)
-#define TARGET_NR_ipc (TARGET_NR_Linux + 117)
-#define TARGET_NR_fsync (TARGET_NR_Linux + 118)
-#define TARGET_NR_sigreturn (TARGET_NR_Linux + 119)
-#define TARGET_NR_clone (TARGET_NR_Linux + 120)
-#define TARGET_NR_setdomainname (TARGET_NR_Linux + 121)
-#define TARGET_NR_uname (TARGET_NR_Linux + 122)
-#define TARGET_NR_modify_ldt (TARGET_NR_Linux + 123)
-#define TARGET_NR_adjtimex (TARGET_NR_Linux + 124)
-#define TARGET_NR_mprotect (TARGET_NR_Linux + 125)
-#define TARGET_NR_sigprocmask (TARGET_NR_Linux + 126)
-#define TARGET_NR_create_module (TARGET_NR_Linux + 127)
-#define TARGET_NR_init_module (TARGET_NR_Linux + 128)
-#define TARGET_NR_delete_module (TARGET_NR_Linux + 129)
-#define TARGET_NR_get_kernel_syms (TARGET_NR_Linux + 130)
-#define TARGET_NR_quotactl (TARGET_NR_Linux + 131)
-#define TARGET_NR_getpgid (TARGET_NR_Linux + 132)
-#define TARGET_NR_fchdir (TARGET_NR_Linux + 133)
-#define TARGET_NR_bdflush (TARGET_NR_Linux + 134)
-#define TARGET_NR_sysfs (TARGET_NR_Linux + 135)
-#define TARGET_NR_personality (TARGET_NR_Linux + 136)
-#define TARGET_NR_afs_syscall (TARGET_NR_Linux + 137) /* Syscall for Andrew File System */
-#define TARGET_NR_setfsuid32 (TARGET_NR_Linux + 138)
-#define TARGET_NR_setfsgid32 (TARGET_NR_Linux + 139)
-#define TARGET_NR__llseek (TARGET_NR_Linux + 140)
-#define TARGET_NR_getdents (TARGET_NR_Linux + 141)
-#define TARGET_NR__newselect (TARGET_NR_Linux + 142)
-#define TARGET_NR_flock (TARGET_NR_Linux + 143)
-#define TARGET_NR_msync (TARGET_NR_Linux + 144)
-#define TARGET_NR_readv (TARGET_NR_Linux + 145)
-#define TARGET_NR_writev (TARGET_NR_Linux + 146)
-#define TARGET_NR_cacheflush (TARGET_NR_Linux + 147)
-#define TARGET_NR_cachectl (TARGET_NR_Linux + 148)
-#define TARGET_NR_sysmips (TARGET_NR_Linux + 149)
-#define TARGET_NR_unused150 (TARGET_NR_Linux + 150)
-#define TARGET_NR_getsid (TARGET_NR_Linux + 151)
-#define TARGET_NR_fdatasync (TARGET_NR_Linux + 152)
-#define TARGET_NR__sysctl (TARGET_NR_Linux + 153)
-#define TARGET_NR_mlock (TARGET_NR_Linux + 154)
-#define TARGET_NR_munlock (TARGET_NR_Linux + 155)
-#define TARGET_NR_mlockall (TARGET_NR_Linux + 156)
-#define TARGET_NR_munlockall (TARGET_NR_Linux + 157)
-#define TARGET_NR_sched_setparam (TARGET_NR_Linux + 158)
-#define TARGET_NR_sched_getparam (TARGET_NR_Linux + 159)
-#define TARGET_NR_sched_setscheduler (TARGET_NR_Linux + 160)
-#define TARGET_NR_sched_getscheduler (TARGET_NR_Linux + 161)
-#define TARGET_NR_sched_yield (TARGET_NR_Linux + 162)
-#define TARGET_NR_sched_get_priority_max (TARGET_NR_Linux + 163)
-#define TARGET_NR_sched_get_priority_min (TARGET_NR_Linux + 164)
-#define TARGET_NR_sched_rr_get_interval (TARGET_NR_Linux + 165)
-#define TARGET_NR_nanosleep (TARGET_NR_Linux + 166)
-#define TARGET_NR_mremap (TARGET_NR_Linux + 167)
-#define TARGET_NR_accept (TARGET_NR_Linux + 168)
-#define TARGET_NR_bind (TARGET_NR_Linux + 169)
-#define TARGET_NR_connect (TARGET_NR_Linux + 170)
-#define TARGET_NR_getpeername (TARGET_NR_Linux + 171)
-#define TARGET_NR_getsockname (TARGET_NR_Linux + 172)
-#define TARGET_NR_getsockopt (TARGET_NR_Linux + 173)
-#define TARGET_NR_listen (TARGET_NR_Linux + 174)
-#define TARGET_NR_recv (TARGET_NR_Linux + 175)
-#define TARGET_NR_recvfrom (TARGET_NR_Linux + 176)
-#define TARGET_NR_recvmsg (TARGET_NR_Linux + 177)
-#define TARGET_NR_send (TARGET_NR_Linux + 178)
-#define TARGET_NR_sendmsg (TARGET_NR_Linux + 179)
-#define TARGET_NR_sendto (TARGET_NR_Linux + 180)
-#define TARGET_NR_setsockopt (TARGET_NR_Linux + 181)
-#define TARGET_NR_shutdown (TARGET_NR_Linux + 182)
-#define TARGET_NR_socket (TARGET_NR_Linux + 183)
-#define TARGET_NR_socketpair (TARGET_NR_Linux + 184)
-#define TARGET_NR_setresuid32 (TARGET_NR_Linux + 185)
-#define TARGET_NR_getresuid32 (TARGET_NR_Linux + 186)
-#define TARGET_NR_query_module (TARGET_NR_Linux + 187)
-#define TARGET_NR_poll (TARGET_NR_Linux + 188)
-#define TARGET_NR_nfsservctl (TARGET_NR_Linux + 189)
-#define TARGET_NR_setresgid32 (TARGET_NR_Linux + 190)
-#define TARGET_NR_getresgid32 (TARGET_NR_Linux + 191)
-#define TARGET_NR_prctl (TARGET_NR_Linux + 192)
-#define TARGET_NR_rt_sigreturn (TARGET_NR_Linux + 193)
-#define TARGET_NR_rt_sigaction (TARGET_NR_Linux + 194)
-#define TARGET_NR_rt_sigprocmask (TARGET_NR_Linux + 195)
-#define TARGET_NR_rt_sigpending (TARGET_NR_Linux + 196)
-#define TARGET_NR_rt_sigtimedwait (TARGET_NR_Linux + 197)
-#define TARGET_NR_rt_sigqueueinfo (TARGET_NR_Linux + 198)
-#define TARGET_NR_rt_sigsuspend (TARGET_NR_Linux + 199)
-#define TARGET_NR_pread64 (TARGET_NR_Linux + 200)
-#define TARGET_NR_pwrite64 (TARGET_NR_Linux + 201)
-#define TARGET_NR_chown32 (TARGET_NR_Linux + 202)
-#define TARGET_NR_getcwd (TARGET_NR_Linux + 203)
-#define TARGET_NR_capget (TARGET_NR_Linux + 204)
-#define TARGET_NR_capset (TARGET_NR_Linux + 205)
-#define TARGET_NR_sigaltstack (TARGET_NR_Linux + 206)
-#define TARGET_NR_sendfile (TARGET_NR_Linux + 207)
-#define TARGET_NR_getpmsg (TARGET_NR_Linux + 208)
-#define TARGET_NR_putpmsg (TARGET_NR_Linux + 209)
-#define TARGET_NR_mmap2 (TARGET_NR_Linux + 210)
-#define TARGET_NR_truncate64 (TARGET_NR_Linux + 211)
-#define TARGET_NR_ftruncate64 (TARGET_NR_Linux + 212)
-#define TARGET_NR_stat64 (TARGET_NR_Linux + 213)
-#define TARGET_NR_lstat64 (TARGET_NR_Linux + 214)
-#define TARGET_NR_fstat64 (TARGET_NR_Linux + 215)
-#define TARGET_NR_pivot_root (TARGET_NR_Linux + 216)
-#define TARGET_NR_mincore (TARGET_NR_Linux + 217)
-#define TARGET_NR_madvise (TARGET_NR_Linux + 218)
-#define TARGET_NR_getdents64 (TARGET_NR_Linux + 219)
-#define TARGET_NR_fcntl64 (TARGET_NR_Linux + 220)
-#define TARGET_NR_reserved221 (TARGET_NR_Linux + 221)
-#define TARGET_NR_gettid (TARGET_NR_Linux + 222)
-#define TARGET_NR_readahead (TARGET_NR_Linux + 223)
-#define TARGET_NR_setxattr (TARGET_NR_Linux + 224)
-#define TARGET_NR_lsetxattr (TARGET_NR_Linux + 225)
-#define TARGET_NR_fsetxattr (TARGET_NR_Linux + 226)
-#define TARGET_NR_getxattr (TARGET_NR_Linux + 227)
-#define TARGET_NR_lgetxattr (TARGET_NR_Linux + 228)
-#define TARGET_NR_fgetxattr (TARGET_NR_Linux + 229)
-#define TARGET_NR_listxattr (TARGET_NR_Linux + 230)
-#define TARGET_NR_llistxattr (TARGET_NR_Linux + 231)
-#define TARGET_NR_flistxattr (TARGET_NR_Linux + 232)
-#define TARGET_NR_removexattr (TARGET_NR_Linux + 233)
-#define TARGET_NR_lremovexattr (TARGET_NR_Linux + 234)
-#define TARGET_NR_fremovexattr (TARGET_NR_Linux + 235)
-#define TARGET_NR_tkill (TARGET_NR_Linux + 236)
-#define TARGET_NR_sendfile64 (TARGET_NR_Linux + 237)
-#define TARGET_NR_futex (TARGET_NR_Linux + 238)
-#define TARGET_NR_sched_setaffinity (TARGET_NR_Linux + 239)
-#define TARGET_NR_sched_getaffinity (TARGET_NR_Linux + 240)
-#define TARGET_NR_io_setup (TARGET_NR_Linux + 241)
-#define TARGET_NR_io_destroy (TARGET_NR_Linux + 242)
-#define TARGET_NR_io_getevents (TARGET_NR_Linux + 243)
-#define TARGET_NR_io_submit (TARGET_NR_Linux + 244)
-#define TARGET_NR_io_cancel (TARGET_NR_Linux + 245)
-#define TARGET_NR_exit_group (TARGET_NR_Linux + 246)
-#define TARGET_NR_lookup_dcookie (TARGET_NR_Linux + 247)
-#define TARGET_NR_epoll_create (TARGET_NR_Linux + 248)
-#define TARGET_NR_epoll_ctl (TARGET_NR_Linux + 249)
-#define TARGET_NR_epoll_wait (TARGET_NR_Linux + 250)
-#define TARGET_NR_remap_file_pages (TARGET_NR_Linux + 251)
-#define TARGET_NR_set_tid_address (TARGET_NR_Linux + 252)
-#define TARGET_NR_restart_syscall (TARGET_NR_Linux + 253)
-#define TARGET_NR_fadvise64 (TARGET_NR_Linux + 254)
-#define TARGET_NR_statfs64 (TARGET_NR_Linux + 255)
-#define TARGET_NR_fstatfs64 (TARGET_NR_Linux + 256)
-#define TARGET_NR_timer_create (TARGET_NR_Linux + 257)
-#define TARGET_NR_timer_settime (TARGET_NR_Linux + 258)
-#define TARGET_NR_timer_gettime (TARGET_NR_Linux + 259)
-#define TARGET_NR_timer_getoverrun (TARGET_NR_Linux + 260)
-#define TARGET_NR_timer_delete (TARGET_NR_Linux + 261)
-#define TARGET_NR_clock_settime (TARGET_NR_Linux + 262)
-#define TARGET_NR_clock_gettime (TARGET_NR_Linux + 263)
-#define TARGET_NR_clock_getres (TARGET_NR_Linux + 264)
-#define TARGET_NR_clock_nanosleep (TARGET_NR_Linux + 265)
-#define TARGET_NR_tgkill (TARGET_NR_Linux + 266)
-#define TARGET_NR_utimes (TARGET_NR_Linux + 267)
-#define TARGET_NR_mbind (TARGET_NR_Linux + 268)
-#define TARGET_NR_get_mempolicy (TARGET_NR_Linux + 269)
-#define TARGET_NR_set_mempolicy (TARGET_NR_Linux + 270)
-#define TARGET_NR_mq_open (TARGET_NR_Linux + 271)
-#define TARGET_NR_mq_unlink (TARGET_NR_Linux + 272)
-#define TARGET_NR_mq_timedsend (TARGET_NR_Linux + 273)
-#define TARGET_NR_mq_timedreceive (TARGET_NR_Linux + 274)
-#define TARGET_NR_mq_notify (TARGET_NR_Linux + 275)
-#define TARGET_NR_mq_getsetattr (TARGET_NR_Linux + 276)
-#define TARGET_NR_vserver (TARGET_NR_Linux + 277)
-#define TARGET_NR_waitid (TARGET_NR_Linux + 278)
-/* #define TARGET_NR_sys_setaltroot (TARGET_NR_Linux + 279) */
-#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)
-
diff --git a/linux-user/mips/termbits.h b/linux-user/mips/termbits.h
deleted file mode 100644
index fea7940..0000000
--- a/linux-user/mips/termbits.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/* from asm/termbits.h */
-
-#define TARGET_NCCS 23
-
-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_TCGETA 0x5401
-#define TARGET_TCSETA 0x5402 /* Clashes with SNDCTL_TMR_START sound ioctl */
-#define TARGET_TCSETAW 0x5403
-#define TARGET_TCSETAF 0x5404
-
-#define TARGET_TCSBRK 0x5405
-#define TARGET_TCXONC 0x5406
-#define TARGET_TCFLSH 0x5407
-
-#define TARGET_TCGETS 0x540d
-#define TARGET_TCSETS 0x540e
-#define TARGET_TCSETSW 0x540f
-#define TARGET_TCSETSF 0x5410
-
-#define TARGET_TIOCEXCL 0x740d /* set exclusive use of tty */
-#define TARGET_TIOCNXCL 0x740e /* reset exclusive use of tty */
-#define TARGET_TIOCOUTQ 0x7472 /* output queue size */
-#define TARGET_TIOCSTI 0x5472 /* simulate terminal input */
-#define TARGET_TIOCMGET 0x741d /* get all modem bits */
-#define TARGET_TIOCMBIS 0x741b /* bis modem bits */
-#define TARGET_TIOCMBIC 0x741c /* bic modem bits */
-#define TARGET_TIOCMSET 0x741a /* set all modem bits */
-#define TARGET_TIOCPKT 0x5470 /* pty: set/clear packet mode */
-#define TARGET_TIOCPKT_DATA 0x00 /* data packet */
-#define TARGET_TIOCPKT_FLUSHREAD 0x01 /* flush packet */
-#define TARGET_TIOCPKT_FLUSHWRITE 0x02 /* flush packet */
-#define TARGET_TIOCPKT_STOP 0x04 /* stop output */
-#define TARGET_TIOCPKT_START 0x08 /* start output */
-#define TARGET_TIOCPKT_NOSTOP 0x10 /* no more ^S, ^Q */
-#define TARGET_TIOCPKT_DOSTOP 0x20 /* now do ^S ^Q */
-/* #define TIOCPKT_IOCTL 0x40 state change of pty driver */
-#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize) /* set window size */
-#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize) /* get window size */
-#define TARGET_TIOCNOTTY 0x5471 /* void tty association */
-#define TARGET_TIOCSETD 0x7401
-#define TARGET_TIOCGETD 0x7400
-
-#define TARGET_FIOCLEX 0x6601
-#define TARGET_FIONCLEX 0x6602
-#define TARGET_FIOASYNC 0x667d
-#define TARGET_FIONBIO 0x667e
-#define TARGET_FIOQSIZE 0x667f
-
-#define TARGET_TIOCGLTC 0x7474 /* get special local chars */
-#define TARGET_TIOCSLTC 0x7475 /* set special local chars */
-#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int) /* set pgrp of tty */
-#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int) /* get pgrp of tty */
-#define TARGET_TIOCCONS TARGET_IOW('t', 120, int) /* become virtual console */
-
-#define TARGET_FIONREAD 0x467f
-#define TARGET_TIOCINQ TARGET_FIONREAD
-
-#define TARGET_TIOCGETP 0x7408
-#define TARGET_TIOCSETP 0x7409
-#define TARGET_TIOCSETN 0x740a /* TIOCSETP wo flush */
-
-/* #define TARGET_TIOCSETA TARGET_IOW('t', 20, struct termios) set termios struct */
-/* #define TARGET_TIOCSETAW TARGET_IOW('t', 21, struct termios) drain output, set */
-/* #define TARGET_TIOCSETAF TARGET_IOW('t', 22, struct termios) drn out, fls in, set */
-/* #define TARGET_TIOCGETD TARGET_IOR('t', 26, int) get line discipline */
-/* #define TARGET_TIOCSETD TARGET_IOW('t', 27, int) set line discipline */
- /* 127-124 compat */
-
-#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
-#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
-#define TARGET_TIOCGSID 0x7416 /* 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 */
-
-/* I hope the range from 0x5480 on is free ... */
-#define TARGET_TIOCSCTTY 0x5480 /* become controlling tty */
-#define TARGET_TIOCGSOFTCAR 0x5481
-#define TARGET_TIOCSSOFTCAR 0x5482
-#define TARGET_TIOCLINUX 0x5483
-#define TARGET_TIOCGSERIAL 0x5484
-#define TARGET_TIOCSSERIAL 0x5485
-#define TARGET_TCSBRKP 0x5486 /* Needed for POSIX tcsendbreak() */
-#define TARGET_TIOCSERCONFIG 0x5488
-#define TARGET_TIOCSERGWILD 0x5489
-#define TARGET_TIOCSERSWILD 0x548a
-#define TARGET_TIOCGLCKTRMIOS 0x548b
-#define TARGET_TIOCSLCKTRMIOS 0x548c
-#define TARGET_TIOCSERGSTRUCT 0x548d /* For debugging only */
-#define TARGET_TIOCSERGETLSR 0x548e /* Get line status register */
-#define TARGET_TIOCSERGETMULTI 0x548f /* Get multiport config */
-#define TARGET_TIOCSERSETMULTI 0x5490 /* Set multiport config */
-#define TARGET_TIOCMIWAIT 0x5491 /* wait for a change on serial input line(s) */
-#define TARGET_TIOCGICOUNT 0x5492 /* read serial port inline interrupt counts */
-#define TARGET_TIOCGHAYESESP 0x5493 /* Get Hayes ESP configuration */
-#define TARGET_TIOCSHAYESESP 0x5494 /* Set Hayes ESP configuration */
diff --git a/linux-user/mmap.c b/linux-user/mmap.c
deleted file mode 100644
index 0c90625..0000000
--- a/linux-user/mmap.c
+++ /dev/null
@@ -1,417 +0,0 @@
-/*
- * 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, but addresses are target. */
-int target_mprotect(target_ulong start, target_ulong len, int prot)
-{
- target_ulong 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(g2h(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(g2h(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(g2h(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 */
-static int mmap_frag(target_ulong real_start,
- target_ulong start, target_ulong end,
- int prot, int flags, int fd, target_ulong offset)
-{
- target_ulong real_end, ret, addr;
- void *host_start;
- int prot1, prot_new;
-
- real_end = real_start + qemu_host_page_size;
- host_start = g2h(real_start);
-
- /* get the protection of the target pages outside the mapping */
- prot1 = 0;
- for(addr = real_start; addr < real_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(host_start, qemu_host_page_size, prot,
- flags | MAP_ANONYMOUS, -1, 0);
- if (ret == -1)
- return ret;
- prot1 = prot;
- }
- 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 */
- if ((flags & MAP_TYPE) == MAP_SHARED &&
- (prot & PROT_WRITE))
- return -EINVAL;
-
- /* adjust protection to be able to read */
- if (!(prot1 & PROT_WRITE))
- mprotect(host_start, qemu_host_page_size, prot1 | PROT_WRITE);
-
- /* read the corresponding file data */
- pread(fd, g2h(start), end - start, offset);
-
- /* put final protection */
- if (prot_new != (prot1 | PROT_WRITE))
- mprotect(host_start, qemu_host_page_size, prot_new);
- } else {
- /* just update the protection */
- if (prot_new != prot1) {
- mprotect(host_start, qemu_host_page_size, prot_new);
- }
- }
- return 0;
-}
-
-/* NOTE: all the constants are the HOST ones */
-long target_mmap(target_ulong start, target_ulong len, int prot,
- int flags, int fd, target_ulong offset)
-{
- target_ulong ret, end, real_start, real_end, retaddr, host_offset, host_len;
- long host_start;
-#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \
- defined(__ia64)
- static target_ulong last_start = 0x40000000;
-#elif defined(__CYGWIN__)
- /* Cygwin doesn't have a whole lot of address space. */
- static target_ulong last_start = 0x18000000;
-#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 ");
- 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) {
- errno = EINVAL;
- return -1;
- }
-
- len = TARGET_PAGE_ALIGN(len);
- if (len == 0)
- return start;
- real_start = start & qemu_host_page_mask;
-
- if (!(flags & MAP_FIXED)) {
-#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__) || \
- defined(__ia64) || defined(__CYGWIN__)
- /* tell the kenel to search at the same place as i386 */
- if (real_start == 0) {
- real_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 */
- /* ??? Can also occur when TARGET_PAGE_SIZE > host page size. */
- /* reserve a memory area */
- /* ??? This needs fixing for remapping. */
-abort();
- host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
- real_start = (long)mmap(g2h(real_start), host_len, PROT_NONE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (real_start == -1)
- return real_start;
- real_end = real_start + host_len;
- start = HOST_PAGE_ALIGN(real_start);
- end = start + HOST_PAGE_ALIGN(len);
- if (start > real_start)
- munmap((void *)real_start, start - real_start);
- if (end < real_end)
- munmap((void *)end, real_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;
- host_start = (long)mmap(real_start ? g2h(real_start) : NULL,
- host_len, prot, flags, fd, host_offset);
- if (host_start == -1)
- return host_start;
- /* update start so that it points to the file position at 'offset' */
- if (!(flags & MAP_ANONYMOUS))
- host_start += offset - host_offset;
- start = h2g(host_start);
- goto the_end1;
- }
- }
-
- if (start & ~TARGET_PAGE_MASK) {
- errno = EINVAL;
- return -1;
- }
- end = start + len;
- real_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 */
- if ((flags & MAP_TYPE) == MAP_SHARED &&
- (prot & PROT_WRITE)) {
- errno = EINVAL;
- return -1;
- }
- retaddr = target_mmap(start, len, prot | PROT_WRITE,
- MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0);
- if (retaddr == -1)
- return retaddr;
- pread(fd, g2h(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 > real_start) {
- if (real_end == real_start + qemu_host_page_size) {
- /* one single host page */
- ret = mmap_frag(real_start, start, end,
- prot, flags, fd, offset);
- if (ret == -1)
- return ret;
- goto the_end1;
- }
- ret = mmap_frag(real_start, start, real_start + qemu_host_page_size,
- prot, flags, fd, offset);
- if (ret == -1)
- return ret;
- real_start += qemu_host_page_size;
- }
- /* handle the end of the mapping */
- if (end < real_end) {
- ret = mmap_frag(real_end - qemu_host_page_size,
- real_end - qemu_host_page_size, real_end,
- prot, flags, fd,
- offset + real_end - qemu_host_page_size - start);
- if (ret == -1)
- return ret;
- real_end -= qemu_host_page_size;
- }
-
- /* map the middle (easier) */
- if (real_start < real_end) {
- unsigned long offset1;
- if (flags & MAP_ANONYMOUS)
- offset1 = 0;
- else
- offset1 = offset + real_start - start;
- ret = (long)mmap(g2h(real_start), real_end - real_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("ret=0x%lx\n", (long)start);
- page_dump(stdout);
- printf("\n");
-#endif
- return start;
-}
-
-int target_munmap(target_ulong start, target_ulong len)
-{
- target_ulong end, real_start, real_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;
- real_start = start & qemu_host_page_mask;
- real_end = HOST_PAGE_ALIGN(end);
-
- if (start > real_start) {
- /* handle host page containing start */
- prot = 0;
- for(addr = real_start; addr < start; addr += TARGET_PAGE_SIZE) {
- prot |= page_get_flags(addr);
- }
- if (real_end == real_start + qemu_host_page_size) {
- for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
- prot |= page_get_flags(addr);
- }
- end = real_end;
- }
- if (prot != 0)
- real_start += qemu_host_page_size;
- }
- if (end < real_end) {
- prot = 0;
- for(addr = end; addr < real_end; addr += TARGET_PAGE_SIZE) {
- prot |= page_get_flags(addr);
- }
- if (prot != 0)
- real_end -= qemu_host_page_size;
- }
-
- /* unmap what we can */
- if (real_start < real_end) {
- ret = munmap((void *)real_start, real_end - real_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(target_ulong old_addr, target_ulong old_size,
- target_ulong new_size, unsigned long flags,
- target_ulong new_addr)
-{
- int prot;
-
- /* XXX: use 5 args syscall */
- new_addr = (long)mremap(g2h(old_addr), old_size, new_size, flags);
- if (new_addr == -1)
- return new_addr;
- new_addr = h2g(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;
-}
-
-int target_msync(target_ulong start, target_ulong len, int flags)
-{
- target_ulong 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(g2h(start), end - start, flags);
-}
-
diff --git a/linux-user/path.c b/linux-user/path.c
deleted file mode 100644
index 7680970..0000000
--- a/linux-user/path.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/* Code to mangle pathnames into those matching a given prefix.
- eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so");
-
- The assumption is that this area does not change.
-*/
-#include <sys/types.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include "qemu.h"
-
-struct pathelem
-{
- /* Name of this, eg. lib */
- char *name;
- /* Full path name, eg. /usr/gnemul/x86-linux/lib. */
- char *pathname;
- struct pathelem *parent;
- /* Children */
- unsigned int num_entries;
- struct pathelem *entries[0];
-};
-
-static struct pathelem *base;
-
-/* First N chars of S1 match S2, and S2 is N chars long. */
-static int strneq(const char *s1, unsigned int n, const char *s2)
-{
- unsigned int i;
-
- for (i = 0; i < n; i++)
- if (s1[i] != s2[i])
- return 0;
- return s2[i] == 0;
-}
-
-static struct pathelem *add_entry(struct pathelem *root, const char *name);
-
-static struct pathelem *new_entry(const char *root,
- struct pathelem *parent,
- const char *name)
-{
- struct pathelem *new = malloc(sizeof(*new));
- new->name = strdup(name);
- asprintf(&new->pathname, "%s/%s", root, name);
- new->num_entries = 0;
- return new;
-}
-
-#define streq(a,b) (strcmp((a), (b)) == 0)
-
-static struct pathelem *add_dir_maybe(struct pathelem *path)
-{
- DIR *dir;
-
- if ((dir = opendir(path->pathname)) != NULL) {
- struct dirent *dirent;
-
- while ((dirent = readdir(dir)) != NULL) {
- if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
- path = add_entry(path, dirent->d_name);
- }
- }
- closedir(dir);
- }
- return path;
-}
-
-static struct pathelem *add_entry(struct pathelem *root, const char *name)
-{
- root->num_entries++;
-
- root = realloc(root, sizeof(*root)
- + sizeof(root->entries[0])*root->num_entries);
-
- root->entries[root->num_entries-1] = new_entry(root->pathname, root, name);
- root->entries[root->num_entries-1]
- = add_dir_maybe(root->entries[root->num_entries-1]);
- return root;
-}
-
-/* This needs to be done after tree is stabalized (ie. no more reallocs!). */
-static void set_parents(struct pathelem *child, struct pathelem *parent)
-{
- unsigned int i;
-
- child->parent = parent;
- for (i = 0; i < child->num_entries; i++)
- set_parents(child->entries[i], child);
-}
-
-void init_paths(const char *prefix)
-{
- if (prefix[0] != '/' ||
- prefix[0] == '\0' ||
- !strcmp(prefix, "/"))
- return;
-
- base = new_entry("", NULL, prefix+1);
- base = add_dir_maybe(base);
- if (base->num_entries == 0) {
- free (base);
- base = NULL;
- } else {
- set_parents(base, base);
- }
-}
-
-/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
-static const char *
-follow_path(const struct pathelem *cursor, const char *name)
-{
- unsigned int i, namelen;
-
- name += strspn(name, "/");
- namelen = strcspn(name, "/");
-
- if (namelen == 0)
- return cursor->pathname;
-
- if (strneq(name, namelen, ".."))
- return follow_path(cursor->parent, name + namelen);
-
- if (strneq(name, namelen, "."))
- return follow_path(cursor, name + namelen);
-
- for (i = 0; i < cursor->num_entries; i++)
- if (strneq(name, namelen, cursor->entries[i]->name))
- return follow_path(cursor->entries[i], name + namelen);
-
- /* Not found */
- return NULL;
-}
-
-/* Look for path in emulation dir, otherwise return name. */
-const char *path(const char *name)
-{
- /* Only do absolute paths: quick and dirty, but should mostly be OK.
- Could do relative by tracking cwd. */
- if (!base || name[0] != '/')
- return name;
-
- return follow_path(base, name) ?: name;
-}
diff --git a/linux-user/ppc/syscall.h b/linux-user/ppc/syscall.h
deleted file mode 100644
index eea8a7c..0000000
--- a/linux-user/ppc/syscall.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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"
diff --git a/linux-user/ppc/syscall_nr.h b/linux-user/ppc/syscall_nr.h
deleted file mode 100644
index b97189a..0000000
--- a/linux-user/ppc/syscall_nr.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * 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
diff --git a/linux-user/ppc/termbits.h b/linux-user/ppc/termbits.h
deleted file mode 100644
index 6326747..0000000
--- a/linux-user/ppc/termbits.h
+++ /dev/null
@@ -1,235 +0,0 @@
-/* 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 */
- 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 */
-
diff --git a/linux-user/qemu.h b/linux-user/qemu.h
deleted file mode 100644
index 218e846..0000000
--- a/linux-user/qemu.h
+++ /dev/null
@@ -1,308 +0,0 @@
-#ifndef QEMU_H
-#define QEMU_H
-
-#include "thunk.h"
-
-#include <signal.h>
-#include <string.h>
-#include "syscall_defs.h"
-
-#include "cpu.h"
-#include "syscall.h"
-#include "gdbstub.h"
-
-/* This struct is used to hold certain information about the image.
- * Basically, it replicates in user space what would be certain
- * task_struct fields in the kernel
- */
-struct image_info {
- unsigned long start_code;
- unsigned long end_code;
- unsigned long start_data;
- unsigned long end_data;
- unsigned long start_brk;
- unsigned long brk;
- unsigned long start_mmap;
- unsigned long mmap;
- unsigned long rss;
- unsigned long start_stack;
- unsigned long entry;
- target_ulong code_offset;
- target_ulong data_offset;
- int personality;
-};
-
-#ifdef TARGET_I386
-/* Information about the current linux thread */
-struct vm86_saved_state {
- uint32_t eax; /* return code */
- uint32_t ebx;
- uint32_t ecx;
- uint32_t edx;
- uint32_t esi;
- uint32_t edi;
- uint32_t ebp;
- uint32_t esp;
- uint32_t eflags;
- uint32_t eip;
- uint16_t cs, ss, ds, es, fs, gs;
-};
-#endif
-
-#ifdef TARGET_ARM
-/* FPU emulator */
-#include "nwfpe/fpa11.h"
-#endif
-
-/* NOTE: we force a big alignment so that the stack stored after is
- aligned too */
-typedef struct TaskState {
- struct TaskState *next;
-#ifdef TARGET_ARM
- /* FPA state */
- FPA11 fpa;
- /* Extra fields for semihosted binaries. */
- uint32_t stack_base;
- uint32_t heap_base;
- uint32_t heap_limit;
- int swi_errno;
-#endif
-#ifdef TARGET_I386
- target_ulong target_v86;
- struct vm86_saved_state vm86_saved_regs;
- struct target_vm86plus_struct vm86plus;
- uint32_t v86flags;
- uint32_t v86mask;
-#endif
- int used; /* non zero if used */
- struct image_info *info;
- uint8_t stack[0];
-} __attribute__((aligned(16))) TaskState;
-
-extern TaskState *first_task_state;
-extern const char *qemu_uname_release;
-
-/* ??? See if we can avoid exposing so much of the loader internals. */
-/*
- * MAX_ARG_PAGES defines the number of pages allocated for arguments
- * and envelope for the new program. 32 should suffice, this gives
- * a maximum env+arg of 128kB w/4KB pages!
- */
-#define MAX_ARG_PAGES 32
-
-/*
- * This structure is used to hold the arguments that are
- * used when loading binaries.
- */
-struct linux_binprm {
- char buf[128];
- void *page[MAX_ARG_PAGES];
- unsigned long p;
- int fd;
- int e_uid, e_gid;
- int argc, envc;
- char **argv;
- char **envp;
- char * filename; /* Name of binary */
-};
-
-void do_init_thread(struct target_pt_regs *regs, struct image_info *infop);
-target_ulong loader_build_argptr(int envc, int argc, target_ulong sp,
- target_ulong stringp, int push_ptr);
-int loader_exec(const char * filename, char ** argv, char ** envp,
- struct target_pt_regs * regs, struct image_info *infop);
-
-int load_elf_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
- struct image_info * info);
-int load_flt_binary(struct linux_binprm * bprm, struct target_pt_regs * regs,
- struct image_info * info);
-
-void memcpy_to_target(target_ulong dest, const void *src,
- unsigned long len);
-void target_set_brk(target_ulong new_brk);
-long do_brk(target_ulong new_brk);
-void syscall_init(void);
-long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6);
-void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
-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;
-
-/* 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);
-long do_rt_sigreturn(CPUState *env);
-
-#ifdef TARGET_I386
-/* vm86.c */
-void save_v86_state(CPUX86State *env);
-void handle_vm86_trap(CPUX86State *env, int trapno);
-void handle_vm86_fault(CPUX86State *env);
-int do_vm86(CPUX86State *env, long subfunction, target_ulong v86_addr);
-#endif
-
-/* mmap.c */
-int target_mprotect(target_ulong start, target_ulong len, int prot);
-long target_mmap(target_ulong start, target_ulong len, int prot,
- int flags, int fd, target_ulong offset);
-int target_munmap(target_ulong start, target_ulong len);
-long target_mremap(target_ulong old_addr, target_ulong old_size,
- target_ulong new_size, unsigned long flags,
- target_ulong new_addr);
-int target_msync(target_ulong start, target_ulong len, int flags);
-
-/* user access */
-
-#define VERIFY_READ 0
-#define VERIFY_WRITE 1
-
-#define access_ok(type,addr,size) (1)
-
-/* NOTE get_user and put_user use host addresses. */
-#define __put_user(x,ptr)\
-({\
- int size = sizeof(*ptr);\
- switch(size) {\
- case 1:\
- *(uint8_t *)(ptr) = (typeof(*ptr))(x);\
- break;\
- case 2:\
- *(uint16_t *)(ptr) = tswap16((typeof(*ptr))(x));\
- break;\
- case 4:\
- *(uint32_t *)(ptr) = tswap32((typeof(*ptr))(x));\
- break;\
- case 8:\
- *(uint64_t *)(ptr) = tswap64((typeof(*ptr))(x));\
- break;\
- default:\
- abort();\
- }\
- 0;\
-})
-
-#define __get_user(x, ptr) \
-({\
- int size = sizeof(*ptr);\
- switch(size) {\
- case 1:\
- x = (typeof(*ptr))*(uint8_t *)(ptr);\
- break;\
- case 2:\
- x = (typeof(*ptr))tswap16(*(uint16_t *)(ptr));\
- break;\
- case 4:\
- x = (typeof(*ptr))tswap32(*(uint32_t *)(ptr));\
- break;\
- case 8:\
- x = (typeof(*ptr))tswap64(*(uint64_t *)(ptr));\
- break;\
- default:\
- abort();\
- }\
- 0;\
-})
-
-#define put_user(x,ptr)\
-({\
- int __ret;\
- if (access_ok(VERIFY_WRITE, ptr, sizeof(*ptr)))\
- __ret = __put_user(x, ptr);\
- else\
- __ret = -EFAULT;\
- __ret;\
-})
-
-#define get_user(x,ptr)\
-({\
- int __ret;\
- if (access_ok(VERIFY_READ, ptr, sizeof(*ptr)))\
- __ret = __get_user(x, ptr);\
- else\
- __ret = -EFAULT;\
- __ret;\
-})
-
-/* Functions for accessing guest memory. The tget and tput functions
- read/write single values, byteswapping as neccessary. The lock_user
- gets a pointer to a contiguous area of guest memory, but does not perform
- and byteswapping. lock_user may return either a pointer to the guest
- memory, or a temporary buffer. */
-
-/* Lock an area of guest memory into the host. If copy is true then the
- host area will have the same contents as the guest. */
-static inline void *lock_user(target_ulong guest_addr, long len, int copy)
-{
-#ifdef DEBUG_REMAP
- void *addr;
- addr = malloc(len);
- if (copy)
- memcpy(addr, g2h(guest_addr), len);
- else
- memset(addr, 0, len);
- return addr;
-#else
- return g2h(guest_addr);
-#endif
-}
-
-/* Unlock an area of guest memory. The first LEN bytes must be flushed back
- to guest memory. */
-static inline void unlock_user(void *host_addr, target_ulong guest_addr,
- long len)
-{
-#ifdef DEBUG_REMAP
- if (host_addr == g2h(guest_addr))
- return;
- if (len > 0)
- memcpy(g2h(guest_addr), host_addr, len);
- free(host_addr);
-#endif
-}
-
-/* Return the length of a string in target memory. */
-static inline int target_strlen(target_ulong ptr)
-{
- return strlen(g2h(ptr));
-}
-
-/* Like lock_user but for null terminated strings. */
-static inline void *lock_user_string(target_ulong guest_addr)
-{
- long len;
- len = target_strlen(guest_addr) + 1;
- return lock_user(guest_addr, len, 1);
-}
-
-/* Helper macros for locking/ulocking a target struct. */
-#define lock_user_struct(host_ptr, guest_addr, copy) \
- host_ptr = lock_user(guest_addr, sizeof(*host_ptr), copy)
-#define unlock_user_struct(host_ptr, guest_addr, copy) \
- unlock_user(host_ptr, guest_addr, (copy) ? sizeof(*host_ptr) : 0)
-
-#define tget8(addr) ldub(addr)
-#define tput8(addr, val) stb(addr, val)
-#define tget16(addr) lduw(addr)
-#define tput16(addr, val) stw(addr, val)
-#define tget32(addr) ldl(addr)
-#define tput32(addr, val) stl(addr, val)
-#define tget64(addr) ldq(addr)
-#define tput64(addr, val) stq(addr, val)
-#if TARGET_LONG_BITS == 64
-#define tgetl(addr) ldq(addr)
-#define tputl(addr, val) stq(addr, val)
-#else
-#define tgetl(addr) ldl(addr)
-#define tputl(addr, val) stl(addr, val)
-#endif
-
-#endif /* QEMU_H */
diff --git a/linux-user/sh4/syscall.h b/linux-user/sh4/syscall.h
deleted file mode 100644
index 014bf58..0000000
--- a/linux-user/sh4/syscall.h
+++ /dev/null
@@ -1,12 +0,0 @@
-struct target_pt_regs {
- unsigned long regs[16];
- unsigned long pc;
- unsigned long pr;
- unsigned long sr;
- unsigned long gbr;
- unsigned long mach;
- unsigned long macl;
- long tra;
-};
-
-#define UNAME_MACHINE "sh4"
diff --git a/linux-user/sh4/syscall_nr.h b/linux-user/sh4/syscall_nr.h
deleted file mode 100644
index c91ba1b..0000000
--- a/linux-user/sh4/syscall_nr.h
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * 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_pread64 180
-#define TARGET_NR_pwrite64 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_streams1 188 /* some people actually want it */
-#define TARGET_NR_streams2 189 /* some people actually want it */
-#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_getdents64 220
-#define TARGET_NR_fcntl64 221
-/* 223 is unused */
-#define TARGET_NR_gettid 224
-#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_statfs64 268
-#define TARGET_NR_fstatfs64 269
-#define TARGET_NR_tgkill 270
-#define TARGET_NR_utimes 271
-#define TARGET_NR_fadvise64_64 272
-#define TARGET_NR_vserver 273
-#define TARGET_NR_mbind 274
-#define TARGET_NR_get_mempolicy 275
-#define TARGET_NR_set_mempolicy 276
-#define TARGET_NR_mq_open 277
-#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1)
-#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2)
-#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3)
-#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4)
-#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5)
-#define TARGET_NR_sys_kexec_load 283
-#define TARGET_NR_waitid 284
-#define TARGET_NR_add_key 285
-#define TARGET_NR_request_key 286
-#define TARGET_NR_keyctl 287
-
-#define TARGET_NR_readahead 225 /* XXXXX */
diff --git a/linux-user/sh4/termbits.h b/linux-user/sh4/termbits.h
deleted file mode 100644
index 6dd5845..0000000
--- a/linux-user/sh4/termbits.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/* 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_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_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 (not used) */
-#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */
-#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
-
-/* 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_TARGET_TCSAFLUSH 2
-
-/* ioctl */
-#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 0x5401
-#define TARGET_TCSETS 0x5402
-#define TARGET_TCSETSW 0x5403
-#define TARGET_TCSETSF 0x5404
-#define TARGET_TCGETA TARGET_IOR('t', 23, struct termio)
-#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize)
-#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct 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_TIOCSPGRP TARGET_IOW('t', 118, int)
-#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int)
-
-#define TARGET_TCSETA TARGET_IOW('t', 24, struct termio)
-#define TARGET_TCSETAW TARGET_IOW('t', 25, struct termio)
-#define TARGET_TCSETAF TARGET_IOW('t', 28, struct 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 winsize)
-#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct 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_TIOCSPGRP TARGET_IOW('t', 118, int)
-#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int)
-#define TARGET_TIOCEXCL TARGET_IO('T', 12) /* 0x540C */
-#define TARGET_TIOCNXCL TARGET_IO('T', 13) /* 0x540D */
-#define TARGET_TIOCSCTTY TARGET_IO('T', 14) /* 0x540E */
-
-#define TARGET_TIOCSTI TARGET_IOW('T', 18, char) /* 0x5412 */
-#define TARGET_TIOCMGET TARGET_IOR('T', 21, unsigned int) /* 0x5415 */
-#define TARGET_TIOCMBIS TARGET_IOW('T', 22, unsigned int) /* 0x5416 */
-#define TARGET_TIOCMBIC TARGET_IOW('T', 23, unsigned int) /* 0x5417 */
-#define TARGET_TIOCMSET TARGET_IOW('T', 24, unsigned int) /* 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 TARGET_TIOCM_CAR
-#define TARGET_TIOCM_RI TARGET_TIOCM_RNG
-
-#define TARGET_TIOCGSOFTCAR TARGET_IOR('T', 25, unsigned int) /* 0x5419 */
-#define TARGET_TIOCSSOFTCAR TARGET_IOW('T', 26, unsigned int) /* 0x541A */
-#define TARGET_TIOCLINUX TARGET_IOW('T', 28, char) /* 0x541C */
-#define TARGET_TIOCCONS TARGET_IO('T', 29) /* 0x541D */
-#define TARGET_TIOCGSERIAL TARGET_IOR('T', 30, int) /* 0x541E */
-#define TARGET_TIOCSSERIAL TARGET_IOW('T', 31, int) /* 0x541F */
-#define TARGET_TIOCPKT TARGET_IOW('T', 32, int) /* 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 TARGET_IO('T', 34) /* 0x5422 */
-#define TARGET_TIOCSETD TARGET_IOW('T', 35, int) /* 0x5423 */
-#define TARGET_TIOCGETD TARGET_IOR('T', 36, int) /* 0x5424 */
-#define TARGET_TCSBRKP TARGET_IOW('T', 37, int) /* 0x5425 */ /* Needed for POSIX tcse
-ndbreak() */
-#define TARGET_TIOCSBRK TARGET_IO('T', 39) /* 0x5427 */ /* BSD compatibility */
-#define TARGET_TIOCCBRK TARGET_IO('T', 40) /* 0x5428 */ /* BSD compatibility */
-#define TARGET_TIOCGSID TARGET_IOR('T', 41, pid_t) /* 0x5429 */ /* Return the session
-ID of FD */
-#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-m
-ux device) */
-#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
-
-
-#define TARGET_TIOCSERCONFIG TARGET_IO('T', 83) /* 0x5453 */
-#define TARGET_TIOCSERGWILD TARGET_IOR('T', 84, int) /* 0x5454 */
-#define TARGET_TIOCSERSWILD TARGET_IOW('T', 85, int) /* 0x5455 */
-#define TARGET_TIOCGLCKTRMIOS 0x5456
-#define TARGET_TIOCSLCKTRMIOS 0x5457
-#define TARGET_TIOCSERGSTRUCT TARGET_IOR('T', 88, int) /* 0x5458 */ /* For d
-ebugging only */
-#define TARGET_TIOCSERGETLSR TARGET_IOR('T', 89, unsigned int) /* 0x5459 */ /* Get line sta
-tus register */
- /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
-# define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
-#define TARGET_TIOCSERGETMULTI TARGET_IOR('T', 90, int) /* 0x545A
-*/ /* Get multiport config */
-#define TARGET_TIOCSERSETMULTI TARGET_IOW('T', 91, int) /* 0x545B
-*/ /* Set multiport config */
-
-#define TARGET_TIOCMIWAIT TARGET_IO('T', 92) /* 0x545C */ /* wait for a change on
-serial input line(s) */
-#define TARGET_TIOCGICOUNT TARGET_IOR('T', 93, int) /* 0x545D */ /* read
-serial port inline interrupt counts */
diff --git a/linux-user/signal.c b/linux-user/signal.c
deleted file mode 100644
index 60f9eb7..0000000
--- a/linux-user/signal.c
+++ /dev/null
@@ -1,2067 +0,0 @@
-/*
- * 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>
-
-#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 */
-};
-
-static struct emulated_sigaction sigact_table[TARGET_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 uint8_t host_to_target_signal_table[65] = {
- [SIGHUP] = TARGET_SIGHUP,
- [SIGINT] = TARGET_SIGINT,
- [SIGQUIT] = TARGET_SIGQUIT,
- [SIGILL] = TARGET_SIGILL,
- [SIGTRAP] = TARGET_SIGTRAP,
- [SIGABRT] = TARGET_SIGABRT,
-/* [SIGIOT] = TARGET_SIGIOT,*/
- [SIGBUS] = TARGET_SIGBUS,
- [SIGFPE] = TARGET_SIGFPE,
- [SIGKILL] = TARGET_SIGKILL,
- [SIGUSR1] = TARGET_SIGUSR1,
- [SIGSEGV] = TARGET_SIGSEGV,
- [SIGUSR2] = TARGET_SIGUSR2,
- [SIGPIPE] = TARGET_SIGPIPE,
- [SIGALRM] = TARGET_SIGALRM,
- [SIGTERM] = TARGET_SIGTERM,
-#ifdef SIGSTKFLT
- [SIGSTKFLT] = TARGET_SIGSTKFLT,
-#endif
- [SIGCHLD] = TARGET_SIGCHLD,
- [SIGCONT] = TARGET_SIGCONT,
- [SIGSTOP] = TARGET_SIGSTOP,
- [SIGTSTP] = TARGET_SIGTSTP,
- [SIGTTIN] = TARGET_SIGTTIN,
- [SIGTTOU] = TARGET_SIGTTOU,
- [SIGURG] = TARGET_SIGURG,
- [SIGXCPU] = TARGET_SIGXCPU,
- [SIGXFSZ] = TARGET_SIGXFSZ,
- [SIGVTALRM] = TARGET_SIGVTALRM,
- [SIGPROF] = TARGET_SIGPROF,
- [SIGWINCH] = TARGET_SIGWINCH,
- [SIGIO] = TARGET_SIGIO,
- [SIGPWR] = TARGET_SIGPWR,
- [SIGSYS] = TARGET_SIGSYS,
- /* next signals stay the same */
-};
-static uint8_t target_to_host_signal_table[65];
-
-static inline int host_to_target_signal(int sig)
-{
- return host_to_target_signal_table[sig];
-}
-
-static inline int target_to_host_signal(int sig)
-{
- return target_to_host_signal_table[sig];
-}
-
-static void host_to_target_sigset_internal(target_sigset_t *d,
- const sigset_t *s)
-{
- int i;
- unsigned long sigmask;
- uint32_t target_sigmask;
-
- sigmask = ((unsigned long *)s)[0];
- target_sigmask = 0;
- for(i = 0; i < 32; i++) {
- if (sigmask & (1 << i))
- target_sigmask |= 1 << (host_to_target_signal(i + 1) - 1);
- }
-#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
- d->sig[0] = target_sigmask;
- for(i = 1;i < TARGET_NSIG_WORDS; i++) {
- d->sig[i] = ((unsigned long *)s)[i];
- }
-#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
- d->sig[0] = target_sigmask;
- d->sig[1] = sigmask >> 32;
-#else
-#warning host_to_target_sigset
-#endif
-}
-
-void host_to_target_sigset(target_sigset_t *d, const sigset_t *s)
-{
- target_sigset_t d1;
- int i;
-
- host_to_target_sigset_internal(&d1, s);
- for(i = 0;i < TARGET_NSIG_WORDS; i++)
- d->sig[i] = tswapl(d1.sig[i]);
-}
-
-void target_to_host_sigset_internal(sigset_t *d, const target_sigset_t *s)
-{
- int i;
- unsigned long sigmask;
- target_ulong target_sigmask;
-
- target_sigmask = s->sig[0];
- sigmask = 0;
- for(i = 0; i < 32; i++) {
- if (target_sigmask & (1 << i))
- sigmask |= 1 << (target_to_host_signal(i + 1) - 1);
- }
-#if TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 32
- ((unsigned long *)d)[0] = sigmask;
- for(i = 1;i < TARGET_NSIG_WORDS; i++) {
- ((unsigned long *)d)[i] = s->sig[i];
- }
-#elif TARGET_LONG_BITS == 32 && HOST_LONG_BITS == 64 && TARGET_NSIG_WORDS == 2
- ((unsigned long *)d)[0] = sigmask | ((unsigned long)(s->sig[1]) << 32);
-#else
-#warning target_to_host_sigset
-#endif /* TARGET_LONG_BITS */
-}
-
-void target_to_host_sigset(sigset_t *d, const target_sigset_t *s)
-{
- target_sigset_t s1;
- int i;
-
- for(i = 0;i < TARGET_NSIG_WORDS; i++)
- s1.sig[i] = tswapl(s->sig[i]);
- target_to_host_sigset_internal(d, &s1);
-}
-
-void host_to_target_old_sigset(target_ulong *old_sigset,
- const sigset_t *sigset)
-{
- target_sigset_t d;
- host_to_target_sigset(&d, sigset);
- *old_sigset = d.sig[0];
-}
-
-void target_to_host_old_sigset(sigset_t *sigset,
- const target_ulong *old_sigset)
-{
- target_sigset_t d;
- int i;
-
- d.sig[0] = *old_sigset;
- for(i = 1;i < TARGET_NSIG_WORDS; i++)
- d.sig[i] = 0;
- target_to_host_sigset(sigset, &d);
-}
-
-/* siginfo conversion */
-
-static inline void host_to_target_siginfo_noswap(target_siginfo_t *tinfo,
- const siginfo_t *info)
-{
- int sig;
- sig = host_to_target_signal(info->si_signo);
- tinfo->si_signo = sig;
- tinfo->si_errno = 0;
- tinfo->si_code = 0;
- if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
- sig == SIGBUS || sig == SIGTRAP) {
- /* should never come here, but who knows. The information for
- the target is irrelevant */
- tinfo->_sifields._sigfault._addr = 0;
- } else if (sig >= TARGET_SIGRTMIN) {
- tinfo->_sifields._rt._pid = info->si_pid;
- tinfo->_sifields._rt._uid = info->si_uid;
- /* XXX: potential problem if 64 bit */
- tinfo->_sifields._rt._sigval.sival_ptr =
- (target_ulong)info->si_value.sival_ptr;
- }
-}
-
-static void tswap_siginfo(target_siginfo_t *tinfo,
- const target_siginfo_t *info)
-{
- int sig;
- sig = info->si_signo;
- tinfo->si_signo = tswap32(sig);
- tinfo->si_errno = tswap32(info->si_errno);
- tinfo->si_code = tswap32(info->si_code);
- if (sig == SIGILL || sig == SIGFPE || sig == SIGSEGV ||
- sig == SIGBUS || sig == SIGTRAP) {
- tinfo->_sifields._sigfault._addr =
- tswapl(info->_sifields._sigfault._addr);
- } else if (sig >= TARGET_SIGRTMIN) {
- tinfo->_sifields._rt._pid = tswap32(info->_sifields._rt._pid);
- tinfo->_sifields._rt._uid = tswap32(info->_sifields._rt._uid);
- tinfo->_sifields._rt._sigval.sival_ptr =
- tswapl(info->_sifields._rt._sigval.sival_ptr);
- }
-}
-
-
-void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
-{
- host_to_target_siginfo_noswap(tinfo, info);
- tswap_siginfo(tinfo, tinfo);
-}
-
-/* XXX: we support only POSIX RT signals are used. */
-/* XXX: find a solution for 64 bit (additionnal malloced data is needed) */
-void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
-{
- info->si_signo = tswap32(tinfo->si_signo);
- info->si_errno = tswap32(tinfo->si_errno);
- info->si_code = tswap32(tinfo->si_code);
- info->si_pid = tswap32(tinfo->_sifields._rt._pid);
- info->si_uid = tswap32(tinfo->_sifields._rt._uid);
- info->si_value.sival_ptr =
- (void *)tswapl(tinfo->_sifields._rt._sigval.sival_ptr);
-}
-
-void signal_init(void)
-{
- struct sigaction act;
- int i, j;
-
- /* generate signal conversion tables */
- for(i = 1; i <= 64; i++) {
- if (host_to_target_signal_table[i] == 0)
- host_to_target_signal_table[i] = i;
- }
- for(i = 1; i <= 64; i++) {
- j = host_to_target_signal_table[i];
- target_to_host_signal_table[j] = 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));
-#if 1
- _exit(-host_sig);
-#else
- {
- struct sigaction act;
- sigemptyset(&act.sa_mask);
- act.sa_flags = SA_SIGINFO;
- act.sa_sigaction = SIG_DFL;
- sigaction(SIGABRT, &act, NULL);
- abort();
- }
-#endif
-}
-
-/* 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 = k->sa._sa_handler;
- if (handler == TARGET_SIG_DFL) {
- /* default handler : ignore some signal. The other are fatal */
- if (sig != TARGET_SIGCHLD &&
- sig != TARGET_SIGURG &&
- sig != TARGET_SIGWINCH) {
- force_sig(sig);
- } else {
- return 0; /* indicate ignored */
- }
- } else if (handler == TARGET_SIG_IGN) {
- /* ignore signal */
- return 0;
- } else if (handler == TARGET_SIG_ERR) {
- force_sig(sig);
- } else {
- pq = &k->first;
- if (sig < TARGET_SIGRTMIN) {
- /* if non real time signal, we queue exactly one signal */
- if (!k->pending)
- q = &k->info;
- else
- return 0;
- } else {
- 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, info, puc))
- return;
- }
-
- /* get target signal number */
- sig = host_to_target_signal(host_signum);
- if (sig < 1 || sig > TARGET_NSIG)
- return;
-#if defined(DEBUG_SIGNAL)
- fprintf(stderr, "qemu: got signal %d\n", sig);
-#endif
- host_to_target_siginfo_noswap(&tinfo, info);
- if (queue_signal(sig, &tinfo) == 1) {
- /* interrupt the virtual CPU as soon as possible */
- cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
- }
-}
-
-int do_sigaction(int sig, const struct target_sigaction *act,
- struct target_sigaction *oact)
-{
- struct emulated_sigaction *k;
- struct sigaction act1;
- int host_sig;
-
- if (sig < 1 || sig > TARGET_NSIG)
- return -EINVAL;
- k = &sigact_table[sig - 1];
-#if defined(DEBUG_SIGNAL)
- fprintf(stderr, "sigaction sig=%d act=0x%08x, oact=0x%08x\n",
- sig, (int)act, (int)oact);
-#endif
- if (oact) {
- oact->_sa_handler = tswapl(k->sa._sa_handler);
- oact->sa_flags = tswapl(k->sa.sa_flags);
- #if !defined(TARGET_MIPS)
- oact->sa_restorer = tswapl(k->sa.sa_restorer);
- #endif
- oact->sa_mask = k->sa.sa_mask;
- }
- if (act) {
- k->sa._sa_handler = tswapl(act->_sa_handler);
- k->sa.sa_flags = tswapl(act->sa_flags);
- #if !defined(TARGET_MIPS)
- k->sa.sa_restorer = tswapl(act->sa_restorer);
- #endif
- k->sa.sa_mask = act->sa_mask;
-
- /* we update the host linux signal state */
- host_sig = target_to_host_signal(sig);
- if (host_sig != SIGSEGV && host_sig != SIGBUS) {
- sigfillset(&act1.sa_mask);
- act1.sa_flags = SA_SIGINFO;
- if (k->sa.sa_flags & TARGET_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 == TARGET_SIG_IGN) {
- act1.sa_sigaction = (void *)SIG_IGN;
- } else if (k->sa._sa_handler == TARGET_SIG_DFL) {
- act1.sa_sigaction = (void *)SIG_DFL;
- } else {
- act1.sa_sigaction = host_signal_handler;
- }
- sigaction(host_sig, &act1, NULL);
- }
- }
- return 0;
-}
-
-#ifndef offsetof
-#define offsetof(type, field) ((size_t) &((type *)0)->field)
-#endif
-
-static inline int copy_siginfo_to_user(target_siginfo_t *tinfo,
- const target_siginfo_t *info)
-{
- tswap_siginfo(tinfo, info);
- return 0;
-}
-
-#ifdef TARGET_I386
-
-/* from the Linux kernel */
-
-struct target_fpreg {
- uint16_t significand[4];
- uint16_t exponent;
-};
-
-struct target_fpxreg {
- uint16_t significand[4];
- uint16_t exponent;
- uint16_t padding[3];
-};
-
-struct target_xmmreg {
- target_ulong element[4];
-};
-
-struct target_fpstate {
- /* Regular FPU environment */
- target_ulong cw;
- target_ulong sw;
- target_ulong tag;
- target_ulong ipoff;
- target_ulong cssel;
- target_ulong dataoff;
- target_ulong datasel;
- struct target_fpreg _st[8];
- uint16_t status;
- uint16_t magic; /* 0xffff = regular FPU data only */
-
- /* FXSR FPU environment */
- target_ulong _fxsr_env[6]; /* FXSR FPU env is ignored */
- target_ulong mxcsr;
- target_ulong reserved;
- struct target_fpxreg _fxsr_st[8]; /* FXSR FPU reg data is ignored */
- struct target_xmmreg _xmm[8];
- target_ulong padding[56];
-};
-
-#define X86_FXSR_MAGIC 0x0000
-
-struct target_sigcontext {
- uint16_t gs, __gsh;
- uint16_t fs, __fsh;
- uint16_t es, __esh;
- uint16_t ds, __dsh;
- target_ulong edi;
- target_ulong esi;
- target_ulong ebp;
- target_ulong esp;
- target_ulong ebx;
- target_ulong edx;
- target_ulong ecx;
- target_ulong eax;
- target_ulong trapno;
- target_ulong err;
- target_ulong eip;
- uint16_t cs, __csh;
- target_ulong eflags;
- target_ulong esp_at_signal;
- uint16_t ss, __ssh;
- target_ulong fpstate; /* pointer */
- target_ulong oldmask;
- target_ulong cr2;
-};
-
-typedef struct target_sigaltstack {
- target_ulong ss_sp;
- int ss_flags;
- target_ulong ss_size;
-} target_stack_t;
-
-struct target_ucontext {
- target_ulong tuc_flags;
- target_ulong tuc_link;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
-};
-
-struct sigframe
-{
- target_ulong pretcode;
- int sig;
- struct target_sigcontext sc;
- struct target_fpstate fpstate;
- target_ulong extramask[TARGET_NSIG_WORDS-1];
- char retcode[8];
-};
-
-struct rt_sigframe
-{
- target_ulong pretcode;
- int sig;
- target_ulong pinfo;
- target_ulong puc;
- struct target_siginfo info;
- struct target_ucontext uc;
- struct target_fpstate fpstate;
- char retcode[8];
-};
-
-/*
- * Set up a signal frame.
- */
-
-/* XXX: save x87 state */
-static int
-setup_sigcontext(struct target_sigcontext *sc, struct target_fpstate *fpstate,
- CPUX86State *env, unsigned long mask)
-{
- int err = 0;
-
- err |= __put_user(env->segs[R_GS].selector, (unsigned int *)&sc->gs);
- err |= __put_user(env->segs[R_FS].selector, (unsigned int *)&sc->fs);
- err |= __put_user(env->segs[R_ES].selector, (unsigned int *)&sc->es);
- err |= __put_user(env->segs[R_DS].selector, (unsigned int *)&sc->ds);
- err |= __put_user(env->regs[R_EDI], &sc->edi);
- err |= __put_user(env->regs[R_ESI], &sc->esi);
- err |= __put_user(env->regs[R_EBP], &sc->ebp);
- err |= __put_user(env->regs[R_ESP], &sc->esp);
- err |= __put_user(env->regs[R_EBX], &sc->ebx);
- err |= __put_user(env->regs[R_EDX], &sc->edx);
- err |= __put_user(env->regs[R_ECX], &sc->ecx);
- err |= __put_user(env->regs[R_EAX], &sc->eax);
- err |= __put_user(env->exception_index, &sc->trapno);
- err |= __put_user(env->error_code, &sc->err);
- err |= __put_user(env->eip, &sc->eip);
- err |= __put_user(env->segs[R_CS].selector, (unsigned int *)&sc->cs);
- err |= __put_user(env->eflags, &sc->eflags);
- err |= __put_user(env->regs[R_ESP], &sc->esp_at_signal);
- err |= __put_user(env->segs[R_SS].selector, (unsigned int *)&sc->ss);
-
- cpu_x86_fsave(env, (void *)fpstate, 1);
- fpstate->status = fpstate->sw;
- err |= __put_user(0xffff, &fpstate->magic);
- err |= __put_user(fpstate, &sc->fpstate);
-
- /* non-iBCS2 extensions.. */
- err |= __put_user(mask, &sc->oldmask);
- err |= __put_user(env->cr[2], &sc->cr2);
- return err;
-}
-
-/*
- * Determine which stack to use..
- */
-
-static inline void *
-get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
-{
- unsigned long esp;
-
- /* Default to using normal stack */
- esp = env->regs[R_ESP];
-#if 0
- /* This is the X/Open sanctioned signal stack switching. */
- if (ka->sa.sa_flags & SA_ONSTACK) {
- if (sas_ss_flags(esp) == 0)
- esp = current->sas_ss_sp + current->sas_ss_size;
- }
-
- /* This is the legacy signal stack switching. */
- else
-#endif
- if ((env->segs[R_SS].selector & 0xffff) != __USER_DS &&
- !(ka->sa.sa_flags & TARGET_SA_RESTORER) &&
- ka->sa.sa_restorer) {
- esp = (unsigned long) ka->sa.sa_restorer;
- }
- return g2h((esp - frame_size) & -8ul);
-}
-
-static void setup_frame(int sig, struct emulated_sigaction *ka,
- target_sigset_t *set, CPUX86State *env)
-{
- struct sigframe *frame;
- int i, err = 0;
-
- frame = get_sigframe(ka, env, sizeof(*frame));
-
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
- err |= __put_user((/*current->exec_domain
- && current->exec_domain->signal_invmap
- && sig < 32
- ? current->exec_domain->signal_invmap[sig]
- : */ sig),
- &frame->sig);
- if (err)
- goto give_sigsegv;
-
- setup_sigcontext(&frame->sc, &frame->fpstate, env, set->sig[0]);
- if (err)
- goto give_sigsegv;
-
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- if (__put_user(set->sig[i], &frame->extramask[i - 1]))
- goto give_sigsegv;
- }
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
- err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
- } else {
- err |= __put_user(frame->retcode, &frame->pretcode);
- /* This is popl %eax ; movl $,%eax ; int $0x80 */
- err |= __put_user(0xb858, (short *)(frame->retcode+0));
- err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
- err |= __put_user(0x80cd, (short *)(frame->retcode+6));
- }
-
- if (err)
- goto give_sigsegv;
-
- /* Set up registers for signal handler */
- env->regs[R_ESP] = h2g(frame);
- env->eip = (unsigned long) ka->sa._sa_handler;
-
- 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_CS, __USER_CS);
- env->eflags &= ~TF_MASK;
-
- return;
-
-give_sigsegv:
- if (sig == TARGET_SIGSEGV)
- ka->sa._sa_handler = TARGET_SIG_DFL;
- force_sig(TARGET_SIGSEGV /* , current */);
-}
-
-static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUX86State *env)
-{
- struct rt_sigframe *frame;
- int i, err = 0;
-
- frame = get_sigframe(ka, env, sizeof(*frame));
-
- if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
- goto give_sigsegv;
-
- err |= __put_user((/*current->exec_domain
- && current->exec_domain->signal_invmap
- && sig < 32
- ? current->exec_domain->signal_invmap[sig]
- : */sig),
- &frame->sig);
- err |= __put_user((target_ulong)&frame->info, &frame->pinfo);
- err |= __put_user((target_ulong)&frame->uc, &frame->puc);
- err |= copy_siginfo_to_user(&frame->info, info);
- if (err)
- goto give_sigsegv;
-
- /* Create the ucontext. */
- err |= __put_user(0, &frame->uc.tuc_flags);
- err |= __put_user(0, &frame->uc.tuc_link);
- err |= __put_user(/*current->sas_ss_sp*/ 0,
- &frame->uc.tuc_stack.ss_sp);
- err |= __put_user(/* sas_ss_flags(regs->esp) */ 0,
- &frame->uc.tuc_stack.ss_flags);
- err |= __put_user(/* current->sas_ss_size */ 0,
- &frame->uc.tuc_stack.ss_size);
- err |= setup_sigcontext(&frame->uc.tuc_mcontext, &frame->fpstate,
- env, set->sig[0]);
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
- goto give_sigsegv;
- }
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
- err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
- } else {
- err |= __put_user(frame->retcode, &frame->pretcode);
- /* This is movl $,%eax ; int $0x80 */
- err |= __put_user(0xb8, (char *)(frame->retcode+0));
- err |= __put_user(TARGET_NR_rt_sigreturn, (int *)(frame->retcode+1));
- err |= __put_user(0x80cd, (short *)(frame->retcode+5));
- }
-
- if (err)
- goto give_sigsegv;
-
- /* Set up registers for signal handler */
- env->regs[R_ESP] = (unsigned long) frame;
- env->eip = (unsigned long) ka->sa._sa_handler;
-
- 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_CS, __USER_CS);
- env->eflags &= ~TF_MASK;
-
- return;
-
-give_sigsegv:
- if (sig == TARGET_SIGSEGV)
- ka->sa._sa_handler = TARGET_SIG_DFL;
- force_sig(TARGET_SIGSEGV /* , current */);
-}
-
-static int
-restore_sigcontext(CPUX86State *env, struct target_sigcontext *sc, int *peax)
-{
- unsigned int err = 0;
-
- cpu_x86_load_seg(env, R_GS, lduw(&sc->gs));
- cpu_x86_load_seg(env, R_FS, lduw(&sc->fs));
- cpu_x86_load_seg(env, R_ES, lduw(&sc->es));
- cpu_x86_load_seg(env, R_DS, lduw(&sc->ds));
-
- env->regs[R_EDI] = ldl(&sc->edi);
- env->regs[R_ESI] = ldl(&sc->esi);
- env->regs[R_EBP] = ldl(&sc->ebp);
- env->regs[R_ESP] = ldl(&sc->esp);
- env->regs[R_EBX] = ldl(&sc->ebx);
- env->regs[R_EDX] = ldl(&sc->edx);
- env->regs[R_ECX] = ldl(&sc->ecx);
- env->eip = ldl(&sc->eip);
-
- cpu_x86_load_seg(env, R_CS, lduw(&sc->cs) | 3);
- cpu_x86_load_seg(env, R_SS, lduw(&sc->ss) | 3);
-
- {
- unsigned int tmpflags;
- tmpflags = ldl(&sc->eflags);
- env->eflags = (env->eflags & ~0x40DD5) | (tmpflags & 0x40DD5);
- // regs->orig_eax = -1; /* disable syscall checks */
- }
-
- {
- struct _fpstate * buf;
- buf = (void *)ldl(&sc->fpstate);
- if (buf) {
-#if 0
- if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
- goto badframe;
-#endif
- cpu_x86_frstor(env, (void *)buf, 1);
- }
- }
-
- *peax = ldl(&sc->eax);
- return err;
-#if 0
-badframe:
- return 1;
-#endif
-}
-
-long do_sigreturn(CPUX86State *env)
-{
- struct sigframe *frame = (struct sigframe *)g2h(env->regs[R_ESP] - 8);
- target_sigset_t target_set;
- sigset_t set;
- int eax, i;
-
-#if defined(DEBUG_SIGNAL)
- fprintf(stderr, "do_sigreturn\n");
-#endif
- /* set blocked signals */
- if (__get_user(target_set.sig[0], &frame->sc.oldmask))
- goto badframe;
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- if (__get_user(target_set.sig[i], &frame->extramask[i - 1]))
- goto badframe;
- }
-
- target_to_host_sigset_internal(&set, &target_set);
- sigprocmask(SIG_SETMASK, &set, NULL);
-
- /* restore registers */
- if (restore_sigcontext(env, &frame->sc, &eax))
- goto badframe;
- return eax;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return 0;
-}
-
-long do_rt_sigreturn(CPUX86State *env)
-{
- struct rt_sigframe *frame = (struct rt_sigframe *)g2h(env->regs[R_ESP] - 4);
- sigset_t set;
- // stack_t st;
- int eax;
-
-#if 0
- if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
- goto badframe;
-#endif
- target_to_host_sigset(&set, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &set, NULL);
-
- if (restore_sigcontext(env, &frame->uc.tuc_mcontext, &eax))
- goto badframe;
-
-#if 0
- if (__copy_from_user(&st, &frame->uc.tuc_stack, sizeof(st)))
- goto badframe;
- /* It is more difficult to avoid calling this function than to
- call it and ignore errors. */
- do_sigaltstack(&st, NULL, regs->esp);
-#endif
- return eax;
-
-badframe:
- force_sig(TARGET_SIGSEGV);
- return 0;
-}
-
-#elif defined(TARGET_ARM)
-
-struct target_sigcontext {
- target_ulong trap_no;
- target_ulong error_code;
- target_ulong oldmask;
- target_ulong arm_r0;
- target_ulong arm_r1;
- target_ulong arm_r2;
- target_ulong arm_r3;
- target_ulong arm_r4;
- target_ulong arm_r5;
- target_ulong arm_r6;
- target_ulong arm_r7;
- target_ulong arm_r8;
- target_ulong arm_r9;
- target_ulong arm_r10;
- target_ulong arm_fp;
- target_ulong arm_ip;
- target_ulong arm_sp;
- target_ulong arm_lr;
- target_ulong arm_pc;
- target_ulong arm_cpsr;
- target_ulong fault_address;
-};
-
-typedef struct target_sigaltstack {
- target_ulong ss_sp;
- int ss_flags;
- target_ulong ss_size;
-} target_stack_t;
-
-struct target_ucontext {
- target_ulong tuc_flags;
- target_ulong tuc_link;
- target_stack_t tuc_stack;
- struct target_sigcontext tuc_mcontext;
- target_sigset_t tuc_sigmask; /* mask last for extensibility */
-};
-
-struct sigframe
-{
- struct target_sigcontext sc;
- target_ulong extramask[TARGET_NSIG_WORDS-1];
- target_ulong retcode;
-};
-
-struct rt_sigframe
-{
- struct target_siginfo *pinfo;
- void *puc;
- struct target_siginfo info;
- struct target_ucontext uc;
- target_ulong retcode;
-};
-
-#define TARGET_CONFIG_CPU_32 1
-
-/*
- * For ARM syscalls, we encode the syscall number into the instruction.
- */
-#define SWI_SYS_SIGRETURN (0xef000000|(TARGET_NR_sigreturn + ARM_SYSCALL_BASE))
-#define SWI_SYS_RT_SIGRETURN (0xef000000|(TARGET_NR_rt_sigreturn + ARM_SYSCALL_BASE))
-
-/*
- * For Thumb syscalls, we pass the syscall number via r7. We therefore
- * need two 16-bit instructions.
- */
-#define SWI_THUMB_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_sigreturn))
-#define SWI_THUMB_RT_SIGRETURN (0xdf00 << 16 | 0x2700 | (TARGET_NR_rt_sigreturn))
-
-static const target_ulong retcodes[4] = {
- SWI_SYS_SIGRETURN, SWI_THUMB_SIGRETURN,
- SWI_SYS_RT_SIGRETURN, SWI_THUMB_RT_SIGRETURN
-};
-
-
-#define __put_user_error(x,p,e) __put_user(x, p)
-#define __get_user_error(x,p,e) __get_user(x, p)
-
-static inline int valid_user_regs(CPUState *regs)
-{
- return 1;
-}
-
-static int
-setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
- CPUState *env, unsigned long mask)
-{
- int err = 0;
-
- __put_user_error(env->regs[0], &sc->arm_r0, err);
- __put_user_error(env->regs[1], &sc->arm_r1, err);
- __put_user_error(env->regs[2], &sc->arm_r2, err);
- __put_user_error(env->regs[3], &sc->arm_r3, err);
- __put_user_error(env->regs[4], &sc->arm_r4, err);
- __put_user_error(env->regs[5], &sc->arm_r5, err);
- __put_user_error(env->regs[6], &sc->arm_r6, err);
- __put_user_error(env->regs[7], &sc->arm_r7, err);
- __put_user_error(env->regs[8], &sc->arm_r8, err);
- __put_user_error(env->regs[9], &sc->arm_r9, err);
- __put_user_error(env->regs[10], &sc->arm_r10, err);
- __put_user_error(env->regs[11], &sc->arm_fp, err);
- __put_user_error(env->regs[12], &sc->arm_ip, err);
- __put_user_error(env->regs[13], &sc->arm_sp, err);
- __put_user_error(env->regs[14], &sc->arm_lr, err);
- __put_user_error(env->regs[15], &sc->arm_pc, err);
-#ifdef TARGET_CONFIG_CPU_32
- __put_user_error(cpsr_read(env), &sc->arm_cpsr, err);
-#endif
-
- __put_user_error(/* current->thread.trap_no */ 0, &sc->trap_no, err);
- __put_user_error(/* current->thread.error_code */ 0, &sc->error_code, err);
- __put_user_error(/* current->thread.address */ 0, &sc->fault_address, err);
- __put_user_error(mask, &sc->oldmask, err);
-
- return err;
-}
-
-static inline void *
-get_sigframe(struct emulated_sigaction *ka, CPUState *regs, int framesize)
-{
- unsigned long sp = regs->regs[13];
-
-#if 0
- /*
- * This is the X/Open sanctioned signal stack switching.
- */
- if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp))
- sp = current->sas_ss_sp + current->sas_ss_size;
-#endif
- /*
- * ATPCS B01 mandates 8-byte alignment
- */
- return g2h((sp - framesize) & ~7);
-}
-
-static int
-setup_return(CPUState *env, struct emulated_sigaction *ka,
- target_ulong *rc, void *frame, int usig)
-{
- target_ulong handler = (target_ulong)ka->sa._sa_handler;
- target_ulong retcode;
- int thumb = 0;
-#if defined(TARGET_CONFIG_CPU_32)
-#if 0
- target_ulong cpsr = env->cpsr;
-
- /*
- * Maybe we need to deliver a 32-bit signal to a 26-bit task.
- */
- if (ka->sa.sa_flags & SA_THIRTYTWO)
- cpsr = (cpsr & ~MODE_MASK) | USR_MODE;
-
-#ifdef CONFIG_ARM_THUMB
- if (elf_hwcap & HWCAP_THUMB) {
- /*
- * The LSB of the handler determines if we're going to
- * be using THUMB or ARM mode for this signal handler.
- */
- thumb = handler & 1;
-
- if (thumb)
- cpsr |= T_BIT;
- else
- cpsr &= ~T_BIT;
- }
-#endif
-#endif
-#endif /* TARGET_CONFIG_CPU_32 */
-
- if (ka->sa.sa_flags & TARGET_SA_RESTORER) {
- retcode = (target_ulong)ka->sa.sa_restorer;
- } else {
- unsigned int idx = thumb;
-
- if (ka->sa.sa_flags & TARGET_SA_SIGINFO)
- idx += 2;
-
- if (__put_user(retcodes[idx], rc))
- return 1;
-#if 0
- flush_icache_range((target_ulong)rc,
- (target_ulong)(rc + 1));
-#endif
- retcode = ((target_ulong)rc) + thumb;
- }
-
- env->regs[0] = usig;
- env->regs[13] = h2g(frame);
- env->regs[14] = retcode;
- env->regs[15] = handler & (thumb ? ~1 : ~3);
-
-#if 0
-#ifdef TARGET_CONFIG_CPU_32
- env->cpsr = cpsr;
-#endif
-#endif
-
- return 0;
-}
-
-static void setup_frame(int usig, struct emulated_sigaction *ka,
- target_sigset_t *set, CPUState *regs)
-{
- struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame));
- int i, err = 0;
-
- err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]);
-
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- if (__put_user(set->sig[i], &frame->extramask[i - 1]))
- return;
- }
-
- if (err == 0)
- err = setup_return(regs, ka, &frame->retcode, frame, usig);
- // return err;
-}
-
-static void setup_rt_frame(int usig, struct emulated_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUState *env)
-{
- struct rt_sigframe *frame = get_sigframe(ka, env, sizeof(*frame));
- int i, err = 0;
-
- if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
- return /* 1 */;
-
- __put_user_error(&frame->info, (target_ulong *)&frame->pinfo, err);
- __put_user_error(&frame->uc, (target_ulong *)&frame->puc, err);
- err |= copy_siginfo_to_user(&frame->info, info);
-
- /* Clear all the bits of the ucontext we don't use. */
- memset(&frame->uc, 0, offsetof(struct target_ucontext, tuc_mcontext));
-
- err |= setup_sigcontext(&frame->uc.tuc_mcontext, /*&frame->fpstate,*/
- env, set->sig[0]);
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- if (__put_user(set->sig[i], &frame->uc.tuc_sigmask.sig[i]))
- return;
- }
-
- if (err == 0)
- err = setup_return(env, ka, &frame->retcode, frame, usig);
-
- if (err == 0) {
- /*
- * For realtime signals we must also set the second and third
- * arguments for the signal handler.
- * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
- */
- env->regs[1] = (target_ulong)frame->pinfo;
- env->regs[2] = (target_ulong)frame->puc;
- }
-
- // return err;
-}
-
-static int
-restore_sigcontext(CPUState *env, struct target_sigcontext *sc)
-{
- int err = 0;
- uint32_t cpsr;
-
- __get_user_error(env->regs[0], &sc->arm_r0, err);
- __get_user_error(env->regs[1], &sc->arm_r1, err);
- __get_user_error(env->regs[2], &sc->arm_r2, err);
- __get_user_error(env->regs[3], &sc->arm_r3, err);
- __get_user_error(env->regs[4], &sc->arm_r4, err);
- __get_user_error(env->regs[5], &sc->arm_r5, err);
- __get_user_error(env->regs[6], &sc->arm_r6, err);
- __get_user_error(env->regs[7], &sc->arm_r7, err);
- __get_user_error(env->regs[8], &sc->arm_r8, err);
- __get_user_error(env->regs[9], &sc->arm_r9, err);
- __get_user_error(env->regs[10], &sc->arm_r10, err);
- __get_user_error(env->regs[11], &sc->arm_fp, err);
- __get_user_error(env->regs[12], &sc->arm_ip, err);
- __get_user_error(env->regs[13], &sc->arm_sp, err);
- __get_user_error(env->regs[14], &sc->arm_lr, err);
- __get_user_error(env->regs[15], &sc->arm_pc, err);
-#ifdef TARGET_CONFIG_CPU_32
- __get_user_error(cpsr, &sc->arm_cpsr, err);
- cpsr_write(env, cpsr, 0xffffffff);
-#endif
-
- err |= !valid_user_regs(env);
-
- return err;
-}
-
-long do_sigreturn(CPUState *env)
-{
- struct sigframe *frame;
- target_sigset_t set;
- sigset_t host_set;
- int i;
-
- /*
- * Since we stacked the signal on a 64-bit boundary,
- * then 'sp' should be word aligned here. If it's
- * not, then the user is trying to mess with us.
- */
- if (env->regs[13] & 7)
- goto badframe;
-
- frame = (struct sigframe *)g2h(env->regs[13]);
-
-#if 0
- if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
- goto badframe;
-#endif
- if (__get_user(set.sig[0], &frame->sc.oldmask))
- goto badframe;
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- if (__get_user(set.sig[i], &frame->extramask[i - 1]))
- goto badframe;
- }
-
- target_to_host_sigset_internal(&host_set, &set);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
-
- if (restore_sigcontext(env, &frame->sc))
- goto badframe;
-
-#if 0
- /* Send SIGTRAP if we're single-stepping */
- if (ptrace_cancel_bpt(current))
- send_sig(SIGTRAP, current, 1);
-#endif
- return env->regs[0];
-
-badframe:
- force_sig(SIGSEGV /* , current */);
- return 0;
-}
-
-long do_rt_sigreturn(CPUState *env)
-{
- struct rt_sigframe *frame;
- sigset_t host_set;
-
- /*
- * Since we stacked the signal on a 64-bit boundary,
- * then 'sp' should be word aligned here. If it's
- * not, then the user is trying to mess with us.
- */
- if (env->regs[13] & 7)
- goto badframe;
-
- frame = (struct rt_sigframe *)env->regs[13];
-
-#if 0
- if (verify_area(VERIFY_READ, frame, sizeof (*frame)))
- goto badframe;
-#endif
- target_to_host_sigset(&host_set, &frame->uc.tuc_sigmask);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
-
- if (restore_sigcontext(env, &frame->uc.tuc_mcontext))
- goto badframe;
-
-#if 0
- /* Send SIGTRAP if we're single-stepping */
- if (ptrace_cancel_bpt(current))
- send_sig(SIGTRAP, current, 1);
-#endif
- return env->regs[0];
-
-badframe:
- force_sig(SIGSEGV /* , current */);
- return 0;
-}
-
-#elif defined(TARGET_SPARC)
-
-#define __SUNOS_MAXWIN 31
-
-/* This is what SunOS does, so shall I. */
-struct target_sigcontext {
- target_ulong sigc_onstack; /* state to restore */
-
- target_ulong sigc_mask; /* sigmask to restore */
- target_ulong sigc_sp; /* stack pointer */
- target_ulong sigc_pc; /* program counter */
- target_ulong sigc_npc; /* next program counter */
- target_ulong sigc_psr; /* for condition codes etc */
- target_ulong sigc_g1; /* User uses these two registers */
- target_ulong sigc_o0; /* within the trampoline code. */
-
- /* Now comes information regarding the users window set
- * at the time of the signal.
- */
- target_ulong sigc_oswins; /* outstanding windows */
-
- /* stack ptrs for each regwin buf */
- char *sigc_spbuf[__SUNOS_MAXWIN];
-
- /* Windows to restore after signal */
- struct {
- target_ulong locals[8];
- target_ulong ins[8];
- } sigc_wbuf[__SUNOS_MAXWIN];
-};
-/* A Sparc stack frame */
-struct sparc_stackf {
- target_ulong locals[8];
- target_ulong ins[6];
- struct sparc_stackf *fp;
- target_ulong callers_pc;
- char *structptr;
- target_ulong xargs[6];
- target_ulong xxargs[1];
-};
-
-typedef struct {
- struct {
- target_ulong psr;
- target_ulong pc;
- target_ulong npc;
- target_ulong y;
- target_ulong u_regs[16]; /* globals and ins */
- } si_regs;
- int si_mask;
-} __siginfo_t;
-
-typedef struct {
- unsigned long si_float_regs [32];
- unsigned long si_fsr;
- unsigned long si_fpqdepth;
- struct {
- unsigned long *insn_addr;
- unsigned long insn;
- } si_fpqueue [16];
-} qemu_siginfo_fpu_t;
-
-
-struct target_signal_frame {
- struct sparc_stackf ss;
- __siginfo_t info;
- qemu_siginfo_fpu_t *fpu_save;
- target_ulong insns[2] __attribute__ ((aligned (8)));
- target_ulong extramask[TARGET_NSIG_WORDS - 1];
- target_ulong extra_size; /* Should be 0 */
- qemu_siginfo_fpu_t fpu_state;
-};
-struct target_rt_signal_frame {
- struct sparc_stackf ss;
- siginfo_t info;
- target_ulong regs[20];
- sigset_t mask;
- qemu_siginfo_fpu_t *fpu_save;
- unsigned int insns[2];
- stack_t stack;
- unsigned int extra_size; /* Should be 0 */
- qemu_siginfo_fpu_t fpu_state;
-};
-
-#define UREG_O0 16
-#define UREG_O6 22
-#define UREG_I0 0
-#define UREG_I1 1
-#define UREG_I2 2
-#define UREG_I6 6
-#define UREG_I7 7
-#define UREG_L0 8
-#define UREG_FP UREG_I6
-#define UREG_SP UREG_O6
-
-static inline void *get_sigframe(struct emulated_sigaction *sa, CPUState *env, unsigned long framesize)
-{
- unsigned long sp;
-
- sp = env->regwptr[UREG_FP];
-#if 0
-
- /* This is the X/Open sanctioned signal stack switching. */
- if (sa->sa_flags & TARGET_SA_ONSTACK) {
- if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7))
- sp = current->sas_ss_sp + current->sas_ss_size;
- }
-#endif
- return g2h(sp - framesize);
-}
-
-static int
-setup___siginfo(__siginfo_t *si, CPUState *env, target_ulong mask)
-{
- int err = 0, i;
-
- err |= __put_user(env->psr, &si->si_regs.psr);
- err |= __put_user(env->pc, &si->si_regs.pc);
- err |= __put_user(env->npc, &si->si_regs.npc);
- err |= __put_user(env->y, &si->si_regs.y);
- for (i=0; i < 8; i++) {
- err |= __put_user(env->gregs[i], &si->si_regs.u_regs[i]);
- }
- for (i=0; i < 8; i++) {
- err |= __put_user(env->regwptr[UREG_I0 + i], &si->si_regs.u_regs[i+8]);
- }
- err |= __put_user(mask, &si->si_mask);
- return err;
-}
-
-#if 0
-static int
-setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
- CPUState *env, unsigned long mask)
-{
- int err = 0;
-
- err |= __put_user(mask, &sc->sigc_mask);
- err |= __put_user(env->regwptr[UREG_SP], &sc->sigc_sp);
- err |= __put_user(env->pc, &sc->sigc_pc);
- err |= __put_user(env->npc, &sc->sigc_npc);
- err |= __put_user(env->psr, &sc->sigc_psr);
- err |= __put_user(env->gregs[1], &sc->sigc_g1);
- err |= __put_user(env->regwptr[UREG_O0], &sc->sigc_o0);
-
- return err;
-}
-#endif
-#define NF_ALIGNEDSZ (((sizeof(struct target_signal_frame) + 7) & (~7)))
-
-static void setup_frame(int sig, struct emulated_sigaction *ka,
- target_sigset_t *set, CPUState *env)
-{
- struct target_signal_frame *sf;
- int sigframe_size, err, i;
-
- /* 1. Make sure everything is clean */
- //synchronize_user_stack();
-
- sigframe_size = NF_ALIGNEDSZ;
-
- sf = (struct target_signal_frame *)
- get_sigframe(ka, env, sigframe_size);
-
- //fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
-#if 0
- if (invalid_frame_pointer(sf, sigframe_size))
- goto sigill_and_return;
-#endif
- /* 2. Save the current process state */
- err = setup___siginfo(&sf->info, env, set->sig[0]);
- err |= __put_user(0, &sf->extra_size);
-
- //err |= save_fpu_state(regs, &sf->fpu_state);
- //err |= __put_user(&sf->fpu_state, &sf->fpu_save);
-
- err |= __put_user(set->sig[0], &sf->info.si_mask);
- for (i = 0; i < TARGET_NSIG_WORDS - 1; i++) {
- err |= __put_user(set->sig[i + 1], &sf->extramask[i]);
- }
-
- for (i = 0; i < 8; i++) {
- err |= __put_user(env->regwptr[i + UREG_L0], &sf->ss.locals[i]);
- }
- for (i = 0; i < 8; i++) {
- err |= __put_user(env->regwptr[i + UREG_I0], &sf->ss.ins[i]);
- }
- if (err)
- goto sigsegv;
-
- /* 3. signal handler back-trampoline and parameters */
- env->regwptr[UREG_FP] = h2g(sf);
- env->regwptr[UREG_I0] = sig;
- env->regwptr[UREG_I1] = h2g(&sf->info);
- env->regwptr[UREG_I2] = h2g(&sf->info);
-
- /* 4. signal handler */
- env->pc = (unsigned long) ka->sa._sa_handler;
- env->npc = (env->pc + 4);
- /* 5. return to kernel instructions */
- if (ka->sa.sa_restorer)
- env->regwptr[UREG_I7] = (unsigned long)ka->sa.sa_restorer;
- else {
- env->regwptr[UREG_I7] = h2g(&(sf->insns[0]) - 2);
-
- /* mov __NR_sigreturn, %g1 */
- err |= __put_user(0x821020d8, &sf->insns[0]);
-
- /* t 0x10 */
- err |= __put_user(0x91d02010, &sf->insns[1]);
- if (err)
- goto sigsegv;
-
- /* Flush instruction space. */
- //flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0]));
- // tb_flush(env);
- }
- return;
-
- //sigill_and_return:
- force_sig(TARGET_SIGILL);
-sigsegv:
- //fprintf(stderr, "force_sig\n");
- force_sig(TARGET_SIGSEGV);
-}
-static inline int
-restore_fpu_state(CPUState *env, qemu_siginfo_fpu_t *fpu)
-{
- int err;
-#if 0
-#ifdef CONFIG_SMP
- if (current->flags & PF_USEDFPU)
- regs->psr &= ~PSR_EF;
-#else
- if (current == last_task_used_math) {
- last_task_used_math = 0;
- regs->psr &= ~PSR_EF;
- }
-#endif
- current->used_math = 1;
- current->flags &= ~PF_USEDFPU;
-#endif
-#if 0
- if (verify_area (VERIFY_READ, fpu, sizeof(*fpu)))
- return -EFAULT;
-#endif
-
- err = __copy_from_user(&env->fpr[0], &fpu->si_float_regs[0],
- (sizeof(unsigned long) * 32));
- err |= __get_user(env->fsr, &fpu->si_fsr);
-#if 0
- err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth);
- if (current->thread.fpqdepth != 0)
- err |= __copy_from_user(&current->thread.fpqueue[0],
- &fpu->si_fpqueue[0],
- ((sizeof(unsigned long) +
- (sizeof(unsigned long *)))*16));
-#endif
- return err;
-}
-
-
-static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUState *env)
-{
- fprintf(stderr, "setup_rt_frame: not implemented\n");
-}
-
-long do_sigreturn(CPUState *env)
-{
- struct target_signal_frame *sf;
- uint32_t up_psr, pc, npc;
- target_sigset_t set;
- sigset_t host_set;
- target_ulong fpu_save;
- int err, i;
-
- sf = (struct target_signal_frame *)g2h(env->regwptr[UREG_FP]);
-#if 0
- fprintf(stderr, "sigreturn\n");
- fprintf(stderr, "sf: %x pc %x fp %x sp %x\n", sf, env->pc, env->regwptr[UREG_FP], env->regwptr[UREG_SP]);
-#endif
- //cpu_dump_state(env, stderr, fprintf, 0);
-
- /* 1. Make sure we are not getting garbage from the user */
-#if 0
- if (verify_area (VERIFY_READ, sf, sizeof (*sf)))
- goto segv_and_exit;
-#endif
-
- if (((uint) sf) & 3)
- goto segv_and_exit;
-
- err = __get_user(pc, &sf->info.si_regs.pc);
- err |= __get_user(npc, &sf->info.si_regs.npc);
-
- if ((pc | npc) & 3)
- goto segv_and_exit;
-
- /* 2. Restore the state */
- err |= __get_user(up_psr, &sf->info.si_regs.psr);
-
- /* User can only change condition codes and FPU enabling in %psr. */
- env->psr = (up_psr & (PSR_ICC /* | PSR_EF */))
- | (env->psr & ~(PSR_ICC /* | PSR_EF */));
-
- env->pc = pc;
- env->npc = npc;
- err |= __get_user(env->y, &sf->info.si_regs.y);
- for (i=0; i < 8; i++) {
- err |= __get_user(env->gregs[i], &sf->info.si_regs.u_regs[i]);
- }
- for (i=0; i < 8; i++) {
- err |= __get_user(env->regwptr[i + UREG_I0], &sf->info.si_regs.u_regs[i+8]);
- }
-
- err |= __get_user(fpu_save, (target_ulong *)&sf->fpu_save);
-
- //if (fpu_save)
- // err |= restore_fpu_state(env, fpu_save);
-
- /* This is pretty much atomic, no amount locking would prevent
- * the races which exist anyways.
- */
- err |= __get_user(set.sig[0], &sf->info.si_mask);
- for(i = 1; i < TARGET_NSIG_WORDS; i++) {
- err |= (__get_user(set.sig[i], &sf->extramask[i - 1]));
- }
-
- target_to_host_sigset_internal(&host_set, &set);
- sigprocmask(SIG_SETMASK, &host_set, NULL);
-
- if (err)
- goto segv_and_exit;
-
- return env->regwptr[0];
-
-segv_and_exit:
- force_sig(TARGET_SIGSEGV);
-}
-
-long do_rt_sigreturn(CPUState *env)
-{
- fprintf(stderr, "do_rt_sigreturn: not implemented\n");
- return -ENOSYS;
-}
-
-#elif defined(TARGET_MIPS)
-
-struct target_sigcontext {
- uint32_t sc_regmask; /* Unused */
- uint32_t sc_status;
- uint64_t sc_pc;
- uint64_t sc_regs[32];
- uint64_t sc_fpregs[32];
- uint32_t sc_ownedfp; /* Unused */
- uint32_t sc_fpc_csr;
- uint32_t sc_fpc_eir; /* Unused */
- uint32_t sc_used_math;
- uint32_t sc_dsp; /* dsp status, was sc_ssflags */
- uint64_t sc_mdhi;
- uint64_t sc_mdlo;
- target_ulong sc_hi1; /* Was sc_cause */
- target_ulong sc_lo1; /* Was sc_badvaddr */
- target_ulong sc_hi2; /* Was sc_sigset[4] */
- target_ulong sc_lo2;
- target_ulong sc_hi3;
- target_ulong sc_lo3;
-};
-
-struct sigframe {
- uint32_t sf_ass[4]; /* argument save space for o32 */
- uint32_t sf_code[2]; /* signal trampoline */
- struct target_sigcontext sf_sc;
- target_sigset_t sf_mask;
-};
-
-/* Install trampoline to jump back from signal handler */
-static inline int install_sigtramp(unsigned int *tramp, unsigned int syscall)
-{
- int err;
-
- /*
- * Set up the return code ...
- *
- * li v0, __NR__foo_sigreturn
- * syscall
- */
-
- err = __put_user(0x24020000 + syscall, tramp + 0);
- err |= __put_user(0x0000000c , tramp + 1);
- /* flush_cache_sigtramp((unsigned long) tramp); */
- return err;
-}
-
-static inline int
-setup_sigcontext(CPUState *regs, struct target_sigcontext *sc)
-{
- int err = 0;
-
- err |= __put_user(regs->PC, &sc->sc_pc);
-
- #define save_gp_reg(i) do { \
- err |= __put_user(regs->gpr[i], &sc->sc_regs[i]); \
- } while(0)
- __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
- save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
- save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
- save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
- save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
- save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
- save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
- save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
- save_gp_reg(31);
- #undef save_gp_reg
-
- err |= __put_user(regs->HI, &sc->sc_mdhi);
- err |= __put_user(regs->LO, &sc->sc_mdlo);
-
- /* Not used yet, but might be useful if we ever have DSP suppport */
-#if 0
- if (cpu_has_dsp) {
- err |= __put_user(mfhi1(), &sc->sc_hi1);
- err |= __put_user(mflo1(), &sc->sc_lo1);
- err |= __put_user(mfhi2(), &sc->sc_hi2);
- err |= __put_user(mflo2(), &sc->sc_lo2);
- err |= __put_user(mfhi3(), &sc->sc_hi3);
- err |= __put_user(mflo3(), &sc->sc_lo3);
- err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
- }
- /* same with 64 bit */
- #ifdef CONFIG_64BIT
- err |= __put_user(regs->hi, &sc->sc_hi[0]);
- err |= __put_user(regs->lo, &sc->sc_lo[0]);
- if (cpu_has_dsp) {
- err |= __put_user(mfhi1(), &sc->sc_hi[1]);
- err |= __put_user(mflo1(), &sc->sc_lo[1]);
- err |= __put_user(mfhi2(), &sc->sc_hi[2]);
- err |= __put_user(mflo2(), &sc->sc_lo[2]);
- err |= __put_user(mfhi3(), &sc->sc_hi[3]);
- err |= __put_user(mflo3(), &sc->sc_lo[3]);
- err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
- }
- #endif
-
-
- #endif
-
-
- #if 0
- err |= __put_user(!!used_math(), &sc->sc_used_math);
-
- if (!used_math())
- goto out;
-
- /*
- * Save FPU state to signal context. Signal handler will "inherit"
- * current FPU state.
- */
- preempt_disable();
-
- if (!is_fpu_owner()) {
- own_fpu();
- restore_fp(current);
- }
- err |= save_fp_context(sc);
-
- preempt_enable();
- out:
-#endif
- return err;
-}
-
-static inline int
-restore_sigcontext(CPUState *regs, struct target_sigcontext *sc)
-{
- int err = 0;
-
- err |= __get_user(regs->CP0_EPC, &sc->sc_pc);
-
- err |= __get_user(regs->HI, &sc->sc_mdhi);
- err |= __get_user(regs->LO, &sc->sc_mdlo);
-
- #define restore_gp_reg(i) do { \
- err |= __get_user(regs->gpr[i], &sc->sc_regs[i]); \
- } while(0)
- restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
- restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
- restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
- restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
- restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
- restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
- restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
- restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
- restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
- restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
- restore_gp_reg(31);
- #undef restore_gp_reg
-
-#if 0
- if (cpu_has_dsp) {
- err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
- err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
- err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
- err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
- err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
- err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
- err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
- }
- #ifdef CONFIG_64BIT
- err |= __get_user(regs->hi, &sc->sc_hi[0]);
- err |= __get_user(regs->lo, &sc->sc_lo[0]);
- if (cpu_has_dsp) {
- err |= __get_user(treg, &sc->sc_hi[1]); mthi1(treg);
- err |= __get_user(treg, &sc->sc_lo[1]); mthi1(treg);
- err |= __get_user(treg, &sc->sc_hi[2]); mthi2(treg);
- err |= __get_user(treg, &sc->sc_lo[2]); mthi2(treg);
- err |= __get_user(treg, &sc->sc_hi[3]); mthi3(treg);
- err |= __get_user(treg, &sc->sc_lo[3]); mthi3(treg);
- err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
- }
- #endif
-
- err |= __get_user(used_math, &sc->sc_used_math);
- conditional_used_math(used_math);
-
- preempt_disable();
-
- if (used_math()) {
- /* restore fpu context if we have used it before */
- own_fpu();
- err |= restore_fp_context(sc);
- } else {
- /* signal handler may have used FPU. Give it up. */
- lose_fpu();
- }
-
- preempt_enable();
-#endif
- return err;
-}
-/*
- * Determine which stack to use..
- */
-static inline void *
-get_sigframe(struct emulated_sigaction *ka, CPUState *regs, size_t frame_size)
-{
- unsigned long sp;
-
- /* Default to using normal stack */
- sp = regs->gpr[29];
-
- /*
- * FPU emulator may have it's own trampoline active just
- * above the user stack, 16-bytes before the next lowest
- * 16 byte boundary. Try to avoid trashing it.
- */
- sp -= 32;
-
-#if 0
- /* This is the X/Open sanctioned signal stack switching. */
- if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
- sp = current->sas_ss_sp + current->sas_ss_size;
-#endif
-
- return g2h((sp - frame_size) & ~7);
-}
-
-static void setup_frame(int sig, struct emulated_sigaction * ka,
- target_sigset_t *set, CPUState *regs)
-{
- struct sigframe *frame;
- int i;
-
- frame = get_sigframe(ka, regs, sizeof(*frame));
- if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
- goto give_sigsegv;
-
- install_sigtramp(frame->sf_code, TARGET_NR_sigreturn);
-
- if(setup_sigcontext(regs, &frame->sf_sc))
- goto give_sigsegv;
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- if(__put_user(set->sig[i], &frame->sf_mask.sig[i]))
- goto give_sigsegv;
- }
-
- /*
- * Arguments to signal handler:
- *
- * a0 = signal number
- * a1 = 0 (should be cause)
- * a2 = pointer to struct sigcontext
- *
- * $25 and PC point to the signal handler, $29 points to the
- * struct sigframe.
- */
- regs->gpr[ 4] = sig;
- regs->gpr[ 5] = 0;
- regs->gpr[ 6] = h2g(&frame->sf_sc);
- regs->gpr[29] = h2g(frame);
- regs->gpr[31] = h2g(frame->sf_code);
- /* The original kernel code sets CP0_EPC to the handler
- * since it returns to userland using eret
- * we cannot do this here, and we must set PC directly */
- regs->PC = regs->gpr[25] = ka->sa._sa_handler;
- return;
-
-give_sigsegv:
- force_sig(TARGET_SIGSEGV/*, current*/);
- return;
-}
-
-long do_sigreturn(CPUState *regs)
-{
- struct sigframe *frame;
- sigset_t blocked;
- target_sigset_t target_set;
- int i;
-
-#if defined(DEBUG_SIGNAL)
- fprintf(stderr, "do_sigreturn\n");
-#endif
- frame = (struct sigframe *) regs->gpr[29];
- if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
- goto badframe;
-
- for(i = 0; i < TARGET_NSIG_WORDS; i++) {
- if(__get_user(target_set.sig[i], &frame->sf_mask.sig[i]))
- goto badframe;
- }
-
- target_to_host_sigset_internal(&blocked, &target_set);
- sigprocmask(SIG_SETMASK, &blocked, NULL);
-
- if (restore_sigcontext(regs, &frame->sf_sc))
- goto badframe;
-
-#if 0
- /*
- * Don't let your children do this ...
- */
- __asm__ __volatile__(
- "move\t$29, %0\n\t"
- "j\tsyscall_exit"
- :/* no outputs */
- :"r" (&regs));
- /* Unreached */
-#endif
-
- regs->PC = regs->CP0_EPC;
- /* I am not sure this is right, but it seems to work
- * maybe a problem with nested signals ? */
- regs->CP0_EPC = 0;
- return 0;
-
-badframe:
- force_sig(TARGET_SIGSEGV/*, current*/);
- return 0;
-
-}
-
-static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUState *env)
-{
- fprintf(stderr, "setup_rt_frame: not implemented\n");
-}
-
-long do_rt_sigreturn(CPUState *env)
-{
- fprintf(stderr, "do_rt_sigreturn: not implemented\n");
- return -ENOSYS;
-}
-
-#else
-
-static void setup_frame(int sig, struct emulated_sigaction *ka,
- target_sigset_t *set, CPUState *env)
-{
- fprintf(stderr, "setup_frame: not implemented\n");
-}
-
-static void setup_rt_frame(int sig, struct emulated_sigaction *ka,
- target_siginfo_t *info,
- target_sigset_t *set, CPUState *env)
-{
- fprintf(stderr, "setup_rt_frame: not implemented\n");
-}
-
-long do_sigreturn(CPUState *env)
-{
- fprintf(stderr, "do_sigreturn: not implemented\n");
- return -ENOSYS;
-}
-
-long do_rt_sigreturn(CPUState *env)
-{
- fprintf(stderr, "do_rt_sigreturn: not implemented\n");
- return -ENOSYS;
-}
-
-#endif
-
-void process_pending_signals(void *cpu_env)
-{
- int sig;
- target_ulong handler;
- sigset_t set, old_set;
- target_sigset_t target_old_set;
- struct emulated_sigaction *k;
- struct sigqueue *q;
-
- if (!signal_pending)
- return;
-
- k = sigact_table;
- for(sig = 1; sig <= TARGET_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 == TARGET_SIG_DFL) {
- /* default handler : ignore some signal. The other are fatal */
- if (sig != TARGET_SIGCHLD &&
- sig != TARGET_SIGURG &&
- sig != TARGET_SIGWINCH) {
- force_sig(sig);
- }
- } else if (handler == TARGET_SIG_IGN) {
- /* ignore sig */
- } else if (handler == TARGET_SIG_ERR) {
- force_sig(sig);
- } else {
- /* compute the blocked signals during the handler execution */
- target_to_host_sigset(&set, &k->sa.sa_mask);
- /* SA_NODEFER indicates that the current signal should not be
- blocked during the handler */
- if (!(k->sa.sa_flags & TARGET_SA_NODEFER))
- sigaddset(&set, target_to_host_signal(sig));
-
- /* block signals in the handler using Linux */
- sigprocmask(SIG_BLOCK, &set, &old_set);
- /* save the previous blocked signal state to restore it at the
- end of the signal execution (see do_sigreturn) */
- 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
- {
- CPUX86State *env = cpu_env;
- if (env->eflags & VM_MASK)
- save_v86_state(env);
- }
-#endif
- /* prepare the stack frame of the virtual CPU */
- if (k->sa.sa_flags & TARGET_SA_SIGINFO)
- setup_rt_frame(sig, k, &q->info, &target_old_set, cpu_env);
- else
- setup_frame(sig, k, &target_old_set, cpu_env);
- if (k->sa.sa_flags & TARGET_SA_RESETHAND)
- k->sa._sa_handler = TARGET_SIG_DFL;
- }
- if (q != &k->info)
- free_sigqueue(q);
-}
-
-
diff --git a/linux-user/socket.h b/linux-user/socket.h
deleted file mode 100644
index f13ca45..0000000
--- a/linux-user/socket.h
+++ /dev/null
@@ -1,138 +0,0 @@
-
-#if defined(TARGET_MIPS)
- // MIPS special values for constants
-
- /*
- * For setsockopt(2)
- *
- * This defines are ABI conformant as far as Linux supports these ...
- */
- #define TARGET_SOL_SOCKET 0xffff
-
- #define TARGET_SO_DEBUG 0x0001 /* Record debugging information. */
- #define TARGET_SO_REUSEADDR 0x0004 /* Allow reuse of local addresses. */
- #define TARGET_SO_KEEPALIVE 0x0008 /* Keep connections alive and send
- SIGPIPE when they die. */
- #define TARGET_SO_DONTROUTE 0x0010 /* Don't do local routing. */
- #define TARGET_SO_BROADCAST 0x0020 /* Allow transmission of
- broadcast messages. */
- #define TARGET_SO_LINGER 0x0080 /* Block on close of a reliable
- socket to transmit pending data. */
- #define TARGET_SO_OOBINLINE 0x0100 /* Receive out-of-band data in-band. */
- #if 0
- To add: #define TARGET_SO_REUSEPORT 0x0200 /* Allow local address and port reuse. */
- #endif
-
- #define TARGET_SO_TYPE 0x1008 /* Compatible name for SO_STYLE. */
- #define TARGET_SO_STYLE SO_TYPE /* Synonym */
- #define TARGET_SO_ERROR 0x1007 /* get error status and clear */
- #define TARGET_SO_SNDBUF 0x1001 /* Send buffer size. */
- #define TARGET_SO_RCVBUF 0x1002 /* Receive buffer. */
- #define TARGET_SO_SNDLOWAT 0x1003 /* send low-water mark */
- #define TARGET_SO_RCVLOWAT 0x1004 /* receive low-water mark */
- #define TARGET_SO_SNDTIMEO 0x1005 /* send timeout */
- #define TARGET_SO_RCVTIMEO 0x1006 /* receive timeout */
- #define TARGET_SO_ACCEPTCONN 0x1009
-
- /* linux-specific, might as well be the same as on i386 */
- #define TARGET_SO_NO_CHECK 11
- #define TARGET_SO_PRIORITY 12
- #define TARGET_SO_BSDCOMPAT 14
-
- #define TARGET_SO_PASSCRED 17
- #define TARGET_SO_PEERCRED 18
-
- /* Security levels - as per NRL IPv6 - don't actually do anything */
- #define TARGET_SO_SECURITY_AUTHENTICATION 22
- #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23
- #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24
-
- #define TARGET_SO_BINDTODEVICE 25
-
- /* Socket filtering */
- #define TARGET_SO_ATTACH_FILTER 26
- #define TARGET_SO_DETACH_FILTER 27
-
- #define TARGET_SO_PEERNAME 28
- #define TARGET_SO_TIMESTAMP 29
- #define SCM_TIMESTAMP SO_TIMESTAMP
-
- #define TARGET_SO_PEERSEC 30
- #define TARGET_SO_SNDBUFFORCE 31
- #define TARGET_SO_RCVBUFFORCE 33
-
- /** sock_type - Socket types
- *
- * Please notice that for binary compat reasons MIPS has to
- * override the enum sock_type in include/linux/net.h, so
- * we define ARCH_HAS_SOCKET_TYPES here.
- *
- * @SOCK_DGRAM - datagram (conn.less) socket
- * @SOCK_STREAM - stream (connection) socket
- * @SOCK_RAW - raw socket
- * @SOCK_RDM - reliably-delivered message
- * @SOCK_SEQPACKET - sequential packet socket
- * @SOCK_PACKET - linux specific way of getting packets at the dev level.
- * For writing rarp and other similar things on the user level.
- */
- enum sock_type {
- TARGET_SOCK_DGRAM = 1,
- TARGET_SOCK_STREAM = 2,
- TARGET_SOCK_RAW = 3,
- TARGET_SOCK_RDM = 4,
- TARGET_SOCK_SEQPACKET = 5,
- TARGET_SOCK_DCCP = 6,
- TARGET_SOCK_PACKET = 10,
- };
-
- #define TARGET_SOCK_MAX (SOCK_PACKET + 1)
-
-#else
-
- /* For setsockopt(2) */
- #define TARGET_SOL_SOCKET 1
-
- #define TARGET_SO_DEBUG 1
- #define TARGET_SO_REUSEADDR 2
- #define TARGET_SO_TYPE 3
- #define TARGET_SO_ERROR 4
- #define TARGET_SO_DONTROUTE 5
- #define TARGET_SO_BROADCAST 6
- #define TARGET_SO_SNDBUF 7
- #define TARGET_SO_RCVBUF 8
- #define TARGET_SO_SNDBUFFORCE 32
- #define TARGET_SO_RCVBUFFORCE 33
- #define TARGET_SO_KEEPALIVE 9
- #define TARGET_SO_OOBINLINE 10
- #define TARGET_SO_NO_CHECK 11
- #define TARGET_SO_PRIORITY 12
- #define TARGET_SO_LINGER 13
- #define TARGET_SO_BSDCOMPAT 14
- /* To add :#define TARGET_SO_REUSEPORT 15 */
- #define TARGET_SO_PASSCRED 16
- #define TARGET_SO_PEERCRED 17
- #define TARGET_SO_RCVLOWAT 18
- #define TARGET_SO_SNDLOWAT 19
- #define TARGET_SO_RCVTIMEO 20
- #define TARGET_SO_SNDTIMEO 21
-
- /* Security levels - as per NRL IPv6 - don't actually do anything */
- #define TARGET_SO_SECURITY_AUTHENTICATION 22
- #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 23
- #define TARGET_SO_SECURITY_ENCRYPTION_NETWORK 24
-
- #define TARGET_SO_BINDTODEVICE 25
-
- /* Socket filtering */
- #define TARGET_SO_ATTACH_FILTER 26
- #define TARGET_SO_DETACH_FILTER 27
-
- #define TARGET_SO_PEERNAME 28
- #define TARGET_SO_TIMESTAMP 29
- #define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP
-
- #define TARGET_SO_ACCEPTCONN 30
-
- #define TARGET_SO_PEERSEC 31
-
-#endif
diff --git a/linux-user/sparc/syscall.h b/linux-user/sparc/syscall.h
deleted file mode 100644
index 5be90fa..0000000
--- a/linux-user/sparc/syscall.h
+++ /dev/null
@@ -1,9 +0,0 @@
-struct target_pt_regs {
- target_ulong psr;
- target_ulong pc;
- target_ulong npc;
- target_ulong y;
- target_ulong u_regs[16];
-};
-
-#define UNAME_MACHINE "sun4"
diff --git a/linux-user/sparc/syscall_nr.h b/linux-user/sparc/syscall_nr.h
deleted file mode 100644
index afb364f..0000000
--- a/linux-user/sparc/syscall_nr.h
+++ /dev/null
@@ -1,220 +0,0 @@
-#define TARGET_NR_exit 1 /* Common */
-#define TARGET_NR_fork 2 /* Common */
-#define TARGET_NR_read 3 /* Common */
-#define TARGET_NR_write 4 /* Common */
-#define TARGET_NR_open 5 /* Common */
-#define TARGET_NR_close 6 /* Common */
-#define TARGET_NR_wait4 7 /* Common */
-#define TARGET_NR_creat 8 /* Common */
-#define TARGET_NR_link 9 /* Common */
-#define TARGET_NR_unlink 10 /* Common */
-#define TARGET_NR_execv 11 /* SunOS Specific */
-#define TARGET_NR_chdir 12 /* Common */
-#define TARGET_NR_chown 13 /* Common */
-#define TARGET_NR_mknod 14 /* Common */
-#define TARGET_NR_chmod 15 /* Common */
-#define TARGET_NR_lchown 16 /* Common */
-#define TARGET_NR_brk 17 /* Common */
-#define TARGET_NR_perfctr 18 /* Performance counter operations */
-#define TARGET_NR_lseek 19 /* Common */
-#define TARGET_NR_getpid 20 /* Common */
-#define TARGET_NR_capget 21 /* Linux Specific */
-#define TARGET_NR_capset 22 /* Linux Specific */
-#define TARGET_NR_setuid 23 /* Implemented via setreuid in SunOS */
-#define TARGET_NR_getuid 24 /* Common */
-#define TARGET_NR_ptrace 26 /* Common */
-#define TARGET_NR_alarm 27 /* Implemented via setitimer in SunOS */
-#define TARGET_NR_sigaltstack 28 /* Common */
-#define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
-#define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */
-#define TARGET_NR_lchown32 31 /* Linux sparc32 specific */
-#define TARGET_NR_fchown32 32 /* Linux sparc32 specific */
-#define TARGET_NR_access 33 /* Common */
-#define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */
-#define TARGET_NR_chown32 35 /* Linux sparc32 specific */
-#define TARGET_NR_sync 36 /* Common */
-#define TARGET_NR_kill 37 /* Common */
-#define TARGET_NR_stat 38 /* Common */
-#define TARGET_NR_sendfile 39 /* Linux Specific */
-#define TARGET_NR_lstat 40 /* Common */
-#define TARGET_NR_dup 41 /* Common */
-#define TARGET_NR_pipe 42 /* Common */
-#define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */
-#define TARGET_NR_getuid32 44 /* Linux sparc32 specific */
-#define TARGET_NR_umount2 45 /* Linux Specific */
-#define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */
-#define TARGET_NR_getgid 47 /* Common */
-#define TARGET_NR_signal 48 /* Implemented via sigvec() in SunOS */
-#define TARGET_NR_geteuid 49 /* SunOS calls getuid() */
-#define TARGET_NR_getegid 50 /* SunOS calls getgid() */
-#define TARGET_NR_acct 51 /* Common */
-#define TARGET_NR_getgid32 53 /* Linux sparc32 specific */
-#define TARGET_NR_ioctl 54 /* Common */
-#define TARGET_NR_reboot 55 /* Common */
-#define TARGET_NR_mmap2 56 /* Linux sparc32 Specific */
-#define TARGET_NR_symlink 57 /* Common */
-#define TARGET_NR_readlink 58 /* Common */
-#define TARGET_NR_execve 59 /* Common */
-#define TARGET_NR_umask 60 /* Common */
-#define TARGET_NR_chroot 61 /* Common */
-#define TARGET_NR_fstat 62 /* Common */
-#define TARGET_NR_fstat64 63 /* Linux sparc32 Specific */
-#define TARGET_NR_getpagesize 64 /* Common */
-#define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */
-#define TARGET_NR_vfork 66 /* Common */
-#define TARGET_NR_pread 67 /* Linux Specific */
-#define TARGET_NR_pwrite 68 /* Linux Specific */
-#define TARGET_NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */
-#define TARGET_NR_getegid32 70 /* Linux sparc32, sstk under SunOS */
-#define TARGET_NR_mmap 71 /* Common */
-#define TARGET_NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */
-#define TARGET_NR_munmap 73 /* Common */
-#define TARGET_NR_mprotect 74 /* Common */
-#define TARGET_NR_madvise 75 /* Common */
-#define TARGET_NR_vhangup 76 /* Common */
-#define TARGET_NR_truncate64 77 /* Linux sparc32 Specific */
-#define TARGET_NR_mincore 78 /* Common */
-#define TARGET_NR_getgroups 79 /* Common */
-#define TARGET_NR_setgroups 80 /* Common */
-#define TARGET_NR_getpgrp 81 /* Common */
-#define TARGET_NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */
-#define TARGET_NR_setitimer 83 /* Common */
-#define TARGET_NR_ftruncate64 84 /* Linux sparc32 Specific */
-#define TARGET_NR_swapon 85 /* Common */
-#define TARGET_NR_getitimer 86 /* Common */
-#define TARGET_NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */
-#define TARGET_NR_sethostname 88 /* Common */
-#define TARGET_NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */
-#define TARGET_NR_dup2 90 /* Common */
-#define TARGET_NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */
-#define TARGET_NR_fcntl 92 /* Common */
-#define TARGET_NR_select 93 /* Common */
-#define TARGET_NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */
-#define TARGET_NR_fsync 95 /* Common */
-#define TARGET_NR_setpriority 96 /* Common */
-#define TARGET_NR_socket 97 /* Common */
-#define TARGET_NR_connect 98 /* Common */
-#define TARGET_NR_accept 99 /* Common */
-#define TARGET_NR_getpriority 100 /* Common */
-#define TARGET_NR_rt_sigreturn 101 /* Linux Specific */
-#define TARGET_NR_rt_sigaction 102 /* Linux Specific */
-#define TARGET_NR_rt_sigprocmask 103 /* Linux Specific */
-#define TARGET_NR_rt_sigpending 104 /* Linux Specific */
-#define TARGET_NR_rt_sigtimedwait 105 /* Linux Specific */
-#define TARGET_NR_rt_sigqueueinfo 106 /* Linux Specific */
-#define TARGET_NR_rt_sigsuspend 107 /* Linux Specific */
-#define TARGET_NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */
-#define TARGET_NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */
-#define TARGET_NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */
-#define TARGET_NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */
-#define TARGET_NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */
-#define TARGET_NR_recvmsg 113 /* Common */
-#define TARGET_NR_sendmsg 114 /* Common */
-#define TARGET_NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */
-#define TARGET_NR_gettimeofday 116 /* Common */
-#define TARGET_NR_getrusage 117 /* Common */
-#define TARGET_NR_getsockopt 118 /* Common */
-#define TARGET_NR_getcwd 119 /* Linux Specific */
-#define TARGET_NR_readv 120 /* Common */
-#define TARGET_NR_writev 121 /* Common */
-#define TARGET_NR_settimeofday 122 /* Common */
-#define TARGET_NR_fchown 123 /* Common */
-#define TARGET_NR_fchmod 124 /* Common */
-#define TARGET_NR_recvfrom 125 /* Common */
-#define TARGET_NR_setreuid 126 /* Common */
-#define TARGET_NR_setregid 127 /* Common */
-#define TARGET_NR_rename 128 /* Common */
-#define TARGET_NR_truncate 129 /* Common */
-#define TARGET_NR_ftruncate 130 /* Common */
-#define TARGET_NR_flock 131 /* Common */
-#define TARGET_NR_lstat64 132 /* Linux sparc32 Specific */
-#define TARGET_NR_sendto 133 /* Common */
-#define TARGET_NR_shutdown 134 /* Common */
-#define TARGET_NR_socketpair 135 /* Common */
-#define TARGET_NR_mkdir 136 /* Common */
-#define TARGET_NR_rmdir 137 /* Common */
-#define TARGET_NR_utimes 138 /* SunOS Specific */
-#define TARGET_NR_stat64 139 /* Linux sparc32 Specific */
-#define TARGET_NR_getpeername 141 /* Common */
-#define TARGET_NR_gettid 143 /* ENOSYS under SunOS */
-#define TARGET_NR_getrlimit 144 /* Common */
-#define TARGET_NR_setrlimit 145 /* Common */
-#define TARGET_NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
-#define TARGET_NR_prctl 147 /* ENOSYS under SunOS */
-#define TARGET_NR_pciconfig_read 148 /* ENOSYS under SunOS */
-#define TARGET_NR_pciconfig_write 149 /* ENOSYS under SunOS */
-#define TARGET_NR_getsockname 150 /* Common */
-#define TARGET_NR_poll 153 /* Common */
-#define TARGET_NR_getdents64 154 /* Linux specific */
-#define TARGET_NR_fcntl64 155 /* Linux sparc32 Specific */
-#define TARGET_NR_statfs 157 /* Common */
-#define TARGET_NR_fstatfs 158 /* Common */
-#define TARGET_NR_umount 159 /* Common */
-#define TARGET_NR_getdomainname 162 /* SunOS Specific */
-#define TARGET_NR_setdomainname 163 /* Common */
-#define TARGET_NR_quotactl 165 /* Common */
-#define TARGET_NR_mount 167 /* Common */
-#define TARGET_NR_ustat 168 /* Common */
-#define TARGET_NR_getdents 174 /* Common */
-#define TARGET_NR_setsid 175 /* Common */
-#define TARGET_NR_fchdir 176 /* Common */
-#define TARGET_NR_sigpending 183 /* Common */
-#define TARGET_NR_query_module 184 /* Linux Specific */
-#define TARGET_NR_setpgid 185 /* Common */
-#define TARGET_NR_tkill 187 /* SunOS: fpathconf */
-#define TARGET_NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
-#define TARGET_NR_uname 189 /* Linux Specific */
-#define TARGET_NR_init_module 190 /* Linux Specific */
-#define TARGET_NR_personality 191 /* Linux Specific */
-#define TARGET_NR_getppid 197 /* Linux Specific */
-#define TARGET_NR_sigaction 198 /* Linux Specific */
-#define TARGET_NR_sgetmask 199 /* Linux Specific */
-#define TARGET_NR_ssetmask 200 /* Linux Specific */
-#define TARGET_NR_sigsuspend 201 /* Linux Specific */
-#define TARGET_NR_oldlstat 202 /* Linux Specific */
-#define TARGET_NR_uselib 203 /* Linux Specific */
-#define TARGET_NR_readdir 204 /* Linux Specific */
-#define TARGET_NR_readahead 205 /* Linux Specific */
-#define TARGET_NR_socketcall 206 /* Linux Specific */
-#define TARGET_NR_syslog 207 /* Linux Specific */
-#define TARGET_NR_waitpid 212 /* Linux Specific */
-#define TARGET_NR_swapoff 213 /* Linux Specific */
-#define TARGET_NR_sysinfo 214 /* Linux Specific */
-#define TARGET_NR_ipc 215 /* Linux Specific */
-#define TARGET_NR_sigreturn 216 /* Linux Specific */
-#define TARGET_NR_clone 217 /* Linux Specific */
-#define TARGET_NR_adjtimex 219 /* Linux Specific */
-#define TARGET_NR_sigprocmask 220 /* Linux Specific */
-#define TARGET_NR_create_module 221 /* Linux Specific */
-#define TARGET_NR_delete_module 222 /* Linux Specific */
-#define TARGET_NR_get_kernel_syms 223 /* Linux Specific */
-#define TARGET_NR_getpgid 224 /* Linux Specific */
-#define TARGET_NR_bdflush 225 /* Linux Specific */
-#define TARGET_NR_sysfs 226 /* Linux Specific */
-#define TARGET_NR_afs_syscall 227 /* Linux Specific */
-#define TARGET_NR_setfsuid 228 /* Linux Specific */
-#define TARGET_NR_setfsgid 229 /* Linux Specific */
-#define TARGET_NR__newselect 230 /* Linux Specific */
-#define TARGET_NR_time 231 /* Linux Specific */
-#define TARGET_NR_stime 233 /* Linux Specific */
-#define TARGET_NR__llseek 236 /* Linux Specific */
-#define TARGET_NR_mlock 237
-#define TARGET_NR_munlock 238
-#define TARGET_NR_mlockall 239
-#define TARGET_NR_munlockall 240
-#define TARGET_NR_sched_setparam 241
-#define TARGET_NR_sched_getparam 242
-#define TARGET_NR_sched_setscheduler 243
-#define TARGET_NR_sched_getscheduler 244
-#define TARGET_NR_sched_yield 245
-#define TARGET_NR_sched_get_priority_max 246
-#define TARGET_NR_sched_get_priority_min 247
-#define TARGET_NR_sched_rr_get_interval 248
-#define TARGET_NR_nanosleep 249
-#define TARGET_NR_mremap 250
-#define TARGET_NR__sysctl 251
-#define TARGET_NR_getsid 252
-#define TARGET_NR_fdatasync 253
-#define TARGET_NR_nfsservctl 254
-#define TARGET_NR_aplib 255
-#define TARGET_NR__exit TARGET_NR_exit
diff --git a/linux-user/sparc/termbits.h b/linux-user/sparc/termbits.h
deleted file mode 100644
index cad45b2..0000000
--- a/linux-user/sparc/termbits.h
+++ /dev/null
@@ -1,279 +0,0 @@
-/* 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_cc characters */
-#define TARGET_VINTR 0
-#define TARGET_VQUIT 1
-#define TARGET_VERASE 2
-#define TARGET_VKILL 3
-#define TARGET_VEOF 4
-#define TARGET_VEOL 5
-#define TARGET_VEOL2 6
-#define TARGET_VSWTC 7
-#define TARGET_VSTART 8
-#define TARGET_VSTOP 9
-
-#define TARGET_VSUSP 10
-#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */
-#define TARGET_VREPRINT 12
-#define TARGET_VDISCARD 13
-#define TARGET_VWERASE 14
-#define TARGET_VLNEXT 15
-
-/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
- * shared with eof/eol
- */
-#define TARGET_VMIN TARGET_VEOF
-#define TARGET_VTIME TARGET_VEOL
-
-/* c_iflag bits */
-#define TARGET_IGNBRK 0x00000001
-#define TARGET_BRKINT 0x00000002
-#define TARGET_IGNPAR 0x00000004
-#define TARGET_PARMRK 0x00000008
-#define TARGET_INPCK 0x00000010
-#define TARGET_ISTRIP 0x00000020
-#define TARGET_INLCR 0x00000040
-#define TARGET_IGNCR 0x00000080
-#define TARGET_ICRNL 0x00000100
-#define TARGET_IUCLC 0x00000200
-#define TARGET_IXON 0x00000400
-#define TARGET_IXANY 0x00000800
-#define TARGET_IXOFF 0x00001000
-#define TARGET_IMAXBEL 0x00002000
-
-/* c_oflag bits */
-#define TARGET_OPOST 0x00000001
-#define TARGET_OLCUC 0x00000002
-#define TARGET_ONLCR 0x00000004
-#define TARGET_OCRNL 0x00000008
-#define TARGET_ONOCR 0x00000010
-#define TARGET_ONLRET 0x00000020
-#define TARGET_OFILL 0x00000040
-#define TARGET_OFDEL 0x00000080
-#define TARGET_NLDLY 0x00000100
-#define TARGET_NL0 0x00000000
-#define TARGET_NL1 0x00000100
-#define TARGET_CRDLY 0x00000600
-#define TARGET_CR0 0x00000000
-#define TARGET_CR1 0x00000200
-#define TARGET_CR2 0x00000400
-#define TARGET_CR3 0x00000600
-#define TARGET_TABDLY 0x00001800
-#define TARGET_TAB0 0x00000000
-#define TARGET_TAB1 0x00000800
-#define TARGET_TAB2 0x00001000
-#define TARGET_TAB3 0x00001800
-#define TARGET_XTABS 0x00001800
-#define TARGET_BSDLY 0x00002000
-#define TARGET_BS0 0x00000000
-#define TARGET_BS1 0x00002000
-#define TARGET_VTDLY 0x00004000
-#define TARGET_VT0 0x00000000
-#define TARGET_VT1 0x00004000
-#define TARGET_FFDLY 0x00008000
-#define TARGET_FF0 0x00000000
-#define TARGET_FF1 0x00008000
-#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */
-#define TARGET_WRAP 0x00020000 /* SUNOS specific */
-
-/* c_cflag bit meaning */
-#define TARGET_CBAUD 0x0000100f
-#define TARGET_B0 0x00000000 /* hang up */
-#define TARGET_B50 0x00000001
-#define TARGET_B75 0x00000002
-#define TARGET_B110 0x00000003
-#define TARGET_B134 0x00000004
-#define TARGET_B150 0x00000005
-#define TARGET_B200 0x00000006
-#define TARGET_B300 0x00000007
-#define TARGET_B600 0x00000008
-#define TARGET_B1200 0x00000009
-#define TARGET_B1800 0x0000000a
-#define TARGET_B2400 0x0000000b
-#define TARGET_B4800 0x0000000c
-#define TARGET_B9600 0x0000000d
-#define TARGET_B19200 0x0000000e
-#define TARGET_B38400 0x0000000f
-#define TARGET_EXTA B19200
-#define TARGET_EXTB B38400
-#define TARGET_CSIZE 0x00000030
-#define TARGET_CS5 0x00000000
-#define TARGET_CS6 0x00000010
-#define TARGET_CS7 0x00000020
-#define TARGET_CS8 0x00000030
-#define TARGET_CSTOPB 0x00000040
-#define TARGET_CREAD 0x00000080
-#define TARGET_PARENB 0x00000100
-#define TARGET_PARODD 0x00000200
-#define TARGET_HUPCL 0x00000400
-#define TARGET_CLOCAL 0x00000800
-#define TARGET_CBAUDEX 0x00001000
-/* We'll never see these speeds with the Zilogs, but for completeness... */
-#define TARGET_B57600 0x00001001
-#define TARGET_B115200 0x00001002
-#define TARGET_B230400 0x00001003
-#define TARGET_B460800 0x00001004
-/* This is what we can do with the Zilogs. */
-#define TARGET_B76800 0x00001005
-/* This is what we can do with the SAB82532. */
-#define TARGET_B153600 0x00001006
-#define TARGET_B307200 0x00001007
-#define TARGET_B614400 0x00001008
-#define TARGET_B921600 0x00001009
-/* And these are the rest... */
-#define TARGET_B500000 0x0000100a
-#define TARGET_B576000 0x0000100b
-#define TARGET_B1000000 0x0000100c
-#define TARGET_B1152000 0x0000100d
-#define TARGET_B1500000 0x0000100e
-#define TARGET_B2000000 0x0000100f
-/* These have totally bogus values and nobody uses them
- so far. Later on we'd have to use say 0x10000x and
- adjust CBAUD constant and drivers accordingly.
-#define B2500000 0x00001010
-#define B3000000 0x00001011
-#define B3500000 0x00001012
-#define B4000000 0x00001013 */
-#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */
-#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */
-#define TARGET_CRTSCTS 0x80000000 /* flow control */
-
-/* c_lflag bits */
-#define TARGET_ISIG 0x00000001
-#define TARGET_ICANON 0x00000002
-#define TARGET_XCASE 0x00000004
-#define TARGET_ECHO 0x00000008
-#define TARGET_ECHOE 0x00000010
-#define TARGET_ECHOK 0x00000020
-#define TARGET_ECHONL 0x00000040
-#define TARGET_NOFLSH 0x00000080
-#define TARGET_TOSTOP 0x00000100
-#define TARGET_ECHOCTL 0x00000200
-#define TARGET_ECHOPRT 0x00000400
-#define TARGET_ECHOKE 0x00000800
-#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */
-#define TARGET_FLUSHO 0x00002000
-#define TARGET_PENDIN 0x00004000
-#define TARGET_IEXTEN 0x00008000
-
-/* ioctls */
-
-/* Big T */
-#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio)
-#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio)
-#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio)
-#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio)
-#define TARGET_TCSBRK TARGET_IO('T', 5)
-#define TARGET_TCXONC TARGET_IO('T', 6)
-#define TARGET_TCFLSH TARGET_IO('T', 7)
-#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios)
-#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios)
-#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios)
-#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios)
-
-/* Note that all the ioctls that are not available in Linux have a
- * double underscore on the front to: a) avoid some programs to
- * thing we support some ioctls under Linux (autoconfiguration stuff)
- */
-/* Little t */
-#define TARGET_TIOCGETD TARGET_IOR('t', 0, int)
-#define TARGET_TIOCSETD TARGET_IOW('t', 1, int)
-//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */
-//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */
-//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */
-//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */
-//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */
-//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */
-#define TARGET_TIOCEXCL TARGET_IO('t', 13)
-#define TARGET_TIOCNXCL TARGET_IO('t', 14)
-//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */
-//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */
-//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */
-//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */
-//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */
-//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */
-//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */
-#define TARGET_TIOCCONS TARGET_IO('t', 36)
-//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */
-//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */
-#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int)
-#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int)
-//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */
-#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize)
-#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize)
-//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */
-#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
-#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int)
-#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int)
-#define TARGET_TIOCMSET TARGET_IOW('t', 109, int)
-#define TARGET_TIOCSTART TARGET_IO('t', 110)
-#define TARGET_TIOCSTOP TARGET_IO('t', 111)
-#define TARGET_TIOCPKT TARGET_IOW('t', 112, int)
-#define TARGET_TIOCNOTTY TARGET_IO('t', 113)
-#define TARGET_TIOCSTI TARGET_IOW('t', 114, char)
-#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)
-//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */
-//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */
-/* 118 is the non-posix setpgrp tty ioctl */
-/* 119 is the non-posix getpgrp tty ioctl */
-//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */
-//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */
-#define TARGET_TIOCCBRK TARGET_IO('t', 122)
-#define TARGET_TIOCSBRK TARGET_IO('t', 123)
-//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */
-//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */
-//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */
-//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */
-//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */
-//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */
-#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int)
-#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int)
-#define TARGET_TIOCSCTTY TARGET_IO('t', 132)
-#define TARGET_TIOCGSID TARGET_IOR('t', 133, int)
-/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
-#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */
-#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */
-
-/* Little f */
-#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
-
-/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
- * someday. This is completely bogus, I know...
- */
-//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */
-//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */
-
-/* Linux specific, no SunOS equivalent. */
-#define TARGET_TIOCLINUX 0x541C
-#define TARGET_TIOCGSERIAL 0x541E
-#define TARGET_TIOCSSERIAL 0x541F
-#define TARGET_TCSBRKP 0x5425
-#define TARGET_TIOCTTYGSTRUCT 0x5426
-#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 input */
-#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */
-
diff --git a/linux-user/sparc64/syscall.h b/linux-user/sparc64/syscall.h
deleted file mode 100644
index c361558..0000000
--- a/linux-user/sparc64/syscall.h
+++ /dev/null
@@ -1,10 +0,0 @@
-struct target_pt_regs {
- target_ulong u_regs[16];
- target_ulong tstate;
- target_ulong pc;
- target_ulong npc;
- target_ulong y;
- target_ulong fprs;
-};
-
-#define UNAME_MACHINE "sun4u"
diff --git a/linux-user/sparc64/syscall_nr.h b/linux-user/sparc64/syscall_nr.h
deleted file mode 100644
index 9274c85..0000000
--- a/linux-user/sparc64/syscall_nr.h
+++ /dev/null
@@ -1,286 +0,0 @@
-#define TARGET_NR_restart_syscall 0 /* Linux Specific */
-#define TARGET_NR_exit 1 /* Common */
-#define TARGET_NR_fork 2 /* Common */
-#define TARGET_NR_read 3 /* Common */
-#define TARGET_NR_write 4 /* Common */
-#define TARGET_NR_open 5 /* Common */
-#define TARGET_NR_close 6 /* Common */
-#define TARGET_NR_wait4 7 /* Common */
-#define TARGET_NR_creat 8 /* Common */
-#define TARGET_NR_link 9 /* Common */
-#define TARGET_NR_unlink 10 /* Common */
-#define TARGET_NR_execv 11 /* SunOS Specific */
-#define TARGET_NR_chdir 12 /* Common */
-#define TARGET_NR_chown 13 /* Common */
-#define TARGET_NR_mknod 14 /* Common */
-#define TARGET_NR_chmod 15 /* Common */
-#define TARGET_NR_lchown 16 /* Common */
-#define TARGET_NR_brk 17 /* Common */
-#define TARGET_NR_perfctr 18 /* Performance counter operations */
-#define TARGET_NR_lseek 19 /* Common */
-#define TARGET_NR_getpid 20 /* Common */
-#define TARGET_NR_capget 21 /* Linux Specific */
-#define TARGET_NR_capset 22 /* Linux Specific */
-#define TARGET_NR_setuid 23 /* Implemented via setreuid in SunOS */
-#define TARGET_NR_getuid 24 /* Common */
-/* #define TARGET_NR_time alias 25 ENOSYS under SunOS */
-#define TARGET_NR_ptrace 26 /* Common */
-#define TARGET_NR_alarm 27 /* Implemented via setitimer in SunOS */
-#define TARGET_NR_sigaltstack 28 /* Common */
-#define TARGET_NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
-#define TARGET_NR_utime 30 /* Implemented via utimes() under SunOS */
-/* #define TARGET_NR_lchown32 31 Linux sparc32 specific */
-/* #define TARGET_NR_fchown32 32 Linux sparc32 specific */
-#define TARGET_NR_access 33 /* Common */
-#define TARGET_NR_nice 34 /* Implemented via get/setpriority() in SunOS */
-/* #define TARGET_NR_chown32 35 Linux sparc32 specific */
-#define TARGET_NR_sync 36 /* Common */
-#define TARGET_NR_kill 37 /* Common */
-#define TARGET_NR_stat 38 /* Common */
-#define TARGET_NR_sendfile 39 /* Linux Specific */
-#define TARGET_NR_lstat 40 /* Common */
-#define TARGET_NR_dup 41 /* Common */
-#define TARGET_NR_pipe 42 /* Common */
-#define TARGET_NR_times 43 /* Implemented via getrusage() in SunOS */
-/* #define TARGET_NR_getuid32 44 Linux sparc32 specific */
-#define TARGET_NR_umount2 45 /* Linux Specific */
-#define TARGET_NR_setgid 46 /* Implemented via setregid() in SunOS */
-#define TARGET_NR_getgid 47 /* Common */
-#define TARGET_NR_signal 48 /* Implemented via sigvec() in SunOS */
-#define TARGET_NR_geteuid 49 /* SunOS calls getuid() */
-#define TARGET_NR_getegid 50 /* SunOS calls getgid() */
-#define TARGET_NR_acct 51 /* Common */
-#define TARGET_NR_memory_ordering 52 /* Linux Specific */
-/* #define TARGET_NR_getgid32 53 Linux sparc32 specific */
-#define TARGET_NR_ioctl 54 /* Common */
-#define TARGET_NR_reboot 55 /* Common */
-/* #define TARGET_NR_mmap2 56 Linux sparc32 Specific */
-#define TARGET_NR_symlink 57 /* Common */
-#define TARGET_NR_readlink 58 /* Common */
-#define TARGET_NR_execve 59 /* Common */
-#define TARGET_NR_umask 60 /* Common */
-#define TARGET_NR_chroot 61 /* Common */
-#define TARGET_NR_fstat 62 /* Common */
-/* #define TARGET_NR_fstat64 63 Linux sparc32 Specific */
-#define TARGET_NR_getpagesize 64 /* Common */
-#define TARGET_NR_msync 65 /* Common in newer 1.3.x revs... */
-#define TARGET_NR_vfork 66 /* Common */
-#define TARGET_NR_pread64 67 /* Linux Specific */
-#define TARGET_NR_pwrite64 68 /* Linux Specific */
-/* #define TARGET_NR_geteuid32 69 Linux sparc32, sbrk under SunOS */
-/* #define TARGET_NR_getegid32 70 Linux sparc32, sstk under SunOS */
-#define TARGET_NR_mmap 71 /* Common */
-/* #define TARGET_NR_setreuid32 72 Linux sparc32, vadvise under SunOS */
-#define TARGET_NR_munmap 73 /* Common */
-#define TARGET_NR_mprotect 74 /* Common */
-#define TARGET_NR_madvise 75 /* Common */
-#define TARGET_NR_vhangup 76 /* Common */
-/* #define TARGET_NR_truncate64 77 Linux sparc32 Specific */
-#define TARGET_NR_mincore 78 /* Common */
-#define TARGET_NR_getgroups 79 /* Common */
-#define TARGET_NR_setgroups 80 /* Common */
-#define TARGET_NR_getpgrp 81 /* Common */
-/* #define TARGET_NR_setgroups32 82 Linux sparc32, setpgrp under SunOS */
-#define TARGET_NR_setitimer 83 /* Common */
-/* #define TARGET_NR_ftruncate64 84 Linux sparc32 Specific */
-#define TARGET_NR_swapon 85 /* Common */
-#define TARGET_NR_getitimer 86 /* Common */
-/* #define TARGET_NR_setuid32 87 Linux sparc32, gethostname under SunOS */
-#define TARGET_NR_sethostname 88 /* Common */
-/* #define TARGET_NR_setgid32 89 Linux sparc32, getdtablesize under SunOS */
-#define TARGET_NR_dup2 90 /* Common */
-/* #define TARGET_NR_setfsuid32 91 Linux sparc32, getdopt under SunOS */
-#define TARGET_NR_fcntl 92 /* Common */
-#define TARGET_NR_select 93 /* Common */
-/* #define TARGET_NR_setfsgid32 94 Linux sparc32, setdopt under SunOS */
-#define TARGET_NR_fsync 95 /* Common */
-#define TARGET_NR_setpriority 96 /* Common */
-#define TARGET_NR_socket 97 /* Common */
-#define TARGET_NR_connect 98 /* Common */
-#define TARGET_NR_accept 99 /* Common */
-#define TARGET_NR_getpriority 100 /* Common */
-#define TARGET_NR_rt_sigreturn 101 /* Linux Specific */
-#define TARGET_NR_rt_sigaction 102 /* Linux Specific */
-#define TARGET_NR_rt_sigprocmask 103 /* Linux Specific */
-#define TARGET_NR_rt_sigpending 104 /* Linux Specific */
-#define TARGET_NR_rt_sigtimedwait 105 /* Linux Specific */
-#define TARGET_NR_rt_sigqueueinfo 106 /* Linux Specific */
-#define TARGET_NR_rt_sigsuspend 107 /* Linux Specific */
-#define TARGET_NR_setresuid 108 /* Linux Specific, sigvec under SunOS */
-#define TARGET_NR_getresuid 109 /* Linux Specific, sigblock under SunOS */
-#define TARGET_NR_setresgid 110 /* Linux Specific, sigsetmask under SunOS */
-#define TARGET_NR_getresgid 111 /* Linux Specific, sigpause under SunOS */
-/* #define TARGET_NR_setregid32 75 Linux sparc32, sigstack under SunOS */
-#define TARGET_NR_recvmsg 113 /* Common */
-#define TARGET_NR_sendmsg 114 /* Common */
-/* #define TARGET_NR_getgroups32 115 Linux sparc32, vtrace under SunOS */
-#define TARGET_NR_gettimeofday 116 /* Common */
-#define TARGET_NR_getrusage 117 /* Common */
-#define TARGET_NR_getsockopt 118 /* Common */
-#define TARGET_NR_getcwd 119 /* Linux Specific */
-#define TARGET_NR_readv 120 /* Common */
-#define TARGET_NR_writev 121 /* Common */
-#define TARGET_NR_settimeofday 122 /* Common */
-#define TARGET_NR_fchown 123 /* Common */
-#define TARGET_NR_fchmod 124 /* Common */
-#define TARGET_NR_recvfrom 125 /* Common */
-#define TARGET_NR_setreuid 126 /* Common */
-#define TARGET_NR_setregid 127 /* Common */
-#define TARGET_NR_rename 128 /* Common */
-#define TARGET_NR_truncate 129 /* Common */
-#define TARGET_NR_ftruncate 130 /* Common */
-#define TARGET_NR_flock 131 /* Common */
-/* #define TARGET_NR_lstat64 132 Linux sparc32 Specific */
-#define TARGET_NR_sendto 133 /* Common */
-#define TARGET_NR_shutdown 134 /* Common */
-#define TARGET_NR_socketpair 135 /* Common */
-#define TARGET_NR_mkdir 136 /* Common */
-#define TARGET_NR_rmdir 137 /* Common */
-#define TARGET_NR_utimes 138 /* SunOS Specific */
-/* #define TARGET_NR_stat64 139 Linux sparc32 Specific */
-#define TARGET_NR_sendfile64 140 /* adjtime under SunOS */
-#define TARGET_NR_getpeername 141 /* Common */
-#define TARGET_NR_futex 142 /* gethostid under SunOS */
-#define TARGET_NR_gettid 143 /* ENOSYS under SunOS */
-#define TARGET_NR_getrlimit 144 /* Common */
-#define TARGET_NR_setrlimit 145 /* Common */
-#define TARGET_NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
-#define TARGET_NR_prctl 147 /* ENOSYS under SunOS */
-#define TARGET_NR_pciconfig_read 148 /* ENOSYS under SunOS */
-#define TARGET_NR_pciconfig_write 149 /* ENOSYS under SunOS */
-#define TARGET_NR_getsockname 150 /* Common */
-/* #define TARGET_NR_getmsg 151 SunOS Specific */
-/* #define TARGET_NR_putmsg 152 SunOS Specific */
-#define TARGET_NR_poll 153 /* Common */
-#define TARGET_NR_getdents64 154 /* Linux specific */
-/* #define TARGET_NR_fcntl64 155 Linux sparc32 Specific */
-/* #define TARGET_NR_getdirentries 156 SunOS Specific */
-#define TARGET_NR_statfs 157 /* Common */
-#define TARGET_NR_fstatfs 158 /* Common */
-#define TARGET_NR_umount 159 /* Common */
-#define TARGET_NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS */
-#define TARGET_NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS */
-#define TARGET_NR_getdomainname 162 /* SunOS Specific */
-#define TARGET_NR_setdomainname 163 /* Common */
-#define TARGET_NR_utrap_install 164 /* SYSV ABI/v9 required */
-#define TARGET_NR_quotactl 165 /* Common */
-#define TARGET_NR_set_tid_address 166 /* Linux specific, exportfs under SunOS */
-#define TARGET_NR_mount 167 /* Common */
-#define TARGET_NR_ustat 168 /* Common */
-#define TARGET_NR_setxattr 169 /* SunOS: semsys */
-#define TARGET_NR_lsetxattr 170 /* SunOS: msgsys */
-#define TARGET_NR_fsetxattr 171 /* SunOS: shmsys */
-#define TARGET_NR_getxattr 172 /* SunOS: auditsys */
-#define TARGET_NR_lgetxattr 173 /* SunOS: rfssys */
-#define TARGET_NR_getdents 174 /* Common */
-#define TARGET_NR_setsid 175 /* Common */
-#define TARGET_NR_fchdir 176 /* Common */
-#define TARGET_NR_fgetxattr 177 /* SunOS: fchroot */
-#define TARGET_NR_listxattr 178 /* SunOS: vpixsys */
-#define TARGET_NR_llistxattr 179 /* SunOS: aioread */
-#define TARGET_NR_flistxattr 180 /* SunOS: aiowrite */
-#define TARGET_NR_removexattr 181 /* SunOS: aiowait */
-#define TARGET_NR_lremovexattr 182 /* SunOS: aiocancel */
-#define TARGET_NR_sigpending 183 /* Common */
-#define TARGET_NR_query_module 184 /* Linux Specific */
-#define TARGET_NR_setpgid 185 /* Common */
-#define TARGET_NR_fremovexattr 186 /* SunOS: pathconf */
-#define TARGET_NR_tkill 187 /* SunOS: fpathconf */
-#define TARGET_NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
-#define TARGET_NR_uname 189 /* Linux Specific */
-#define TARGET_NR_init_module 190 /* Linux Specific */
-#define TARGET_NR_personality 191 /* Linux Specific */
-#define TARGET_NR_remap_file_pages 192 /* Linux Specific */
-#define TARGET_NR_epoll_create 193 /* Linux Specific */
-#define TARGET_NR_epoll_ctl 194 /* Linux Specific */
-#define TARGET_NR_epoll_wait 195 /* Linux Specific */
-/* #define TARGET_NR_ulimit 196 Linux Specific */
-#define TARGET_NR_getppid 197 /* Linux Specific */
-#define TARGET_NR_sigaction 198 /* Linux Specific */
-#define TARGET_NR_sgetmask 199 /* Linux Specific */
-#define TARGET_NR_ssetmask 200 /* Linux Specific */
-#define TARGET_NR_sigsuspend 201 /* Linux Specific */
-#define TARGET_NR_oldlstat 202 /* Linux Specific */
-#define TARGET_NR_uselib 203 /* Linux Specific */
-#define TARGET_NR_readdir 204 /* Linux Specific */
-#define TARGET_NR_readahead 205 /* Linux Specific */
-#define TARGET_NR_socketcall 206 /* Linux Specific */
-#define TARGET_NR_syslog 207 /* Linux Specific */
-#define TARGET_NR_lookup_dcookie 208 /* Linux Specific */
-#define TARGET_NR_fadvise64 209 /* Linux Specific */
-#define TARGET_NR_fadvise64_64 210 /* Linux Specific */
-#define TARGET_NR_tgkill 211 /* Linux Specific */
-#define TARGET_NR_waitpid 212 /* Linux Specific */
-#define TARGET_NR_swapoff 213 /* Linux Specific */
-#define TARGET_NR_sysinfo 214 /* Linux Specific */
-#define TARGET_NR_ipc 215 /* Linux Specific */
-#define TARGET_NR_sigreturn 216 /* Linux Specific */
-#define TARGET_NR_clone 217 /* Linux Specific */
-/* #define TARGET_NR_modify_ldt 218 Linux Specific - i386 specific, unused */
-#define TARGET_NR_adjtimex 219 /* Linux Specific */
-#define TARGET_NR_sigprocmask 220 /* Linux Specific */
-#define TARGET_NR_create_module 221 /* Linux Specific */
-#define TARGET_NR_delete_module 222 /* Linux Specific */
-#define TARGET_NR_get_kernel_syms 223 /* Linux Specific */
-#define TARGET_NR_getpgid 224 /* Linux Specific */
-#define TARGET_NR_bdflush 225 /* Linux Specific */
-#define TARGET_NR_sysfs 226 /* Linux Specific */
-#define TARGET_NR_afs_syscall 227 /* Linux Specific */
-#define TARGET_NR_setfsuid 228 /* Linux Specific */
-#define TARGET_NR_setfsgid 229 /* Linux Specific */
-#define TARGET_NR__newselect 230 /* Linux Specific */
-#ifdef __KERNEL__
-#define TARGET_NR_time 231 /* Linux sparc32 */
-#endif
-/* #define TARGET_NR_oldstat 232 Linux Specific */
-#define TARGET_NR_stime 233 /* Linux Specific */
-#define TARGET_NR_statfs64 234 /* Linux Specific */
-#define TARGET_NR_fstatfs64 235 /* Linux Specific */
-#define TARGET_NR__llseek 236 /* Linux Specific */
-#define TARGET_NR_mlock 237
-#define TARGET_NR_munlock 238
-#define TARGET_NR_mlockall 239
-#define TARGET_NR_munlockall 240
-#define TARGET_NR_sched_setparam 241
-#define TARGET_NR_sched_getparam 242
-#define TARGET_NR_sched_setscheduler 243
-#define TARGET_NR_sched_getscheduler 244
-#define TARGET_NR_sched_yield 245
-#define TARGET_NR_sched_get_priority_max 246
-#define TARGET_NR_sched_get_priority_min 247
-#define TARGET_NR_sched_rr_get_interval 248
-#define TARGET_NR_nanosleep 249
-#define TARGET_NR_mremap 250
-#define TARGET_NR__sysctl 251
-#define TARGET_NR_getsid 252
-#define TARGET_NR_fdatasync 253
-#define TARGET_NR_nfsservctl 254
-#define TARGET_NR_aplib 255
-#define TARGET_NR_clock_settime 256
-#define TARGET_NR_clock_gettime 257
-#define TARGET_NR_clock_getres 258
-#define TARGET_NR_clock_nanosleep 259
-#define TARGET_NR_sched_getaffinity 260
-#define TARGET_NR_sched_setaffinity 261
-#define TARGET_NR_timer_settime 262
-#define TARGET_NR_timer_gettime 263
-#define TARGET_NR_timer_getoverrun 264
-#define TARGET_NR_timer_delete 265
-#define TARGET_NR_timer_create 266
-/* #define TARGET_NR_vserver 267 Reserved for VSERVER */
-#define TARGET_NR_io_setup 268
-#define TARGET_NR_io_destroy 269
-#define TARGET_NR_io_submit 270
-#define TARGET_NR_io_cancel 271
-#define TARGET_NR_io_getevents 272
-#define TARGET_NR_mq_open 273
-#define TARGET_NR_mq_unlink 274
-#define TARGET_NR_mq_timedsend 275
-#define TARGET_NR_mq_timedreceive 276
-#define TARGET_NR_mq_notify 277
-#define TARGET_NR_mq_getsetattr 278
-#define TARGET_NR_waitid 279
-/*#define TARGET_NR_sys_setaltroot 280 available (was setaltroot) */
-#define TARGET_NR_add_key 281
-#define TARGET_NR_request_key 282
-#define TARGET_NR_keyctl 283
diff --git a/linux-user/sparc64/termbits.h b/linux-user/sparc64/termbits.h
deleted file mode 100644
index cad45b2..0000000
--- a/linux-user/sparc64/termbits.h
+++ /dev/null
@@ -1,279 +0,0 @@
-/* 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_cc characters */
-#define TARGET_VINTR 0
-#define TARGET_VQUIT 1
-#define TARGET_VERASE 2
-#define TARGET_VKILL 3
-#define TARGET_VEOF 4
-#define TARGET_VEOL 5
-#define TARGET_VEOL2 6
-#define TARGET_VSWTC 7
-#define TARGET_VSTART 8
-#define TARGET_VSTOP 9
-
-#define TARGET_VSUSP 10
-#define TARGET_VDSUSP 11 /* SunOS POSIX nicety I do believe... */
-#define TARGET_VREPRINT 12
-#define TARGET_VDISCARD 13
-#define TARGET_VWERASE 14
-#define TARGET_VLNEXT 15
-
-/* Kernel keeps vmin/vtime separated, user apps assume vmin/vtime is
- * shared with eof/eol
- */
-#define TARGET_VMIN TARGET_VEOF
-#define TARGET_VTIME TARGET_VEOL
-
-/* c_iflag bits */
-#define TARGET_IGNBRK 0x00000001
-#define TARGET_BRKINT 0x00000002
-#define TARGET_IGNPAR 0x00000004
-#define TARGET_PARMRK 0x00000008
-#define TARGET_INPCK 0x00000010
-#define TARGET_ISTRIP 0x00000020
-#define TARGET_INLCR 0x00000040
-#define TARGET_IGNCR 0x00000080
-#define TARGET_ICRNL 0x00000100
-#define TARGET_IUCLC 0x00000200
-#define TARGET_IXON 0x00000400
-#define TARGET_IXANY 0x00000800
-#define TARGET_IXOFF 0x00001000
-#define TARGET_IMAXBEL 0x00002000
-
-/* c_oflag bits */
-#define TARGET_OPOST 0x00000001
-#define TARGET_OLCUC 0x00000002
-#define TARGET_ONLCR 0x00000004
-#define TARGET_OCRNL 0x00000008
-#define TARGET_ONOCR 0x00000010
-#define TARGET_ONLRET 0x00000020
-#define TARGET_OFILL 0x00000040
-#define TARGET_OFDEL 0x00000080
-#define TARGET_NLDLY 0x00000100
-#define TARGET_NL0 0x00000000
-#define TARGET_NL1 0x00000100
-#define TARGET_CRDLY 0x00000600
-#define TARGET_CR0 0x00000000
-#define TARGET_CR1 0x00000200
-#define TARGET_CR2 0x00000400
-#define TARGET_CR3 0x00000600
-#define TARGET_TABDLY 0x00001800
-#define TARGET_TAB0 0x00000000
-#define TARGET_TAB1 0x00000800
-#define TARGET_TAB2 0x00001000
-#define TARGET_TAB3 0x00001800
-#define TARGET_XTABS 0x00001800
-#define TARGET_BSDLY 0x00002000
-#define TARGET_BS0 0x00000000
-#define TARGET_BS1 0x00002000
-#define TARGET_VTDLY 0x00004000
-#define TARGET_VT0 0x00000000
-#define TARGET_VT1 0x00004000
-#define TARGET_FFDLY 0x00008000
-#define TARGET_FF0 0x00000000
-#define TARGET_FF1 0x00008000
-#define TARGET_PAGEOUT 0x00010000 /* SUNOS specific */
-#define TARGET_WRAP 0x00020000 /* SUNOS specific */
-
-/* c_cflag bit meaning */
-#define TARGET_CBAUD 0x0000100f
-#define TARGET_B0 0x00000000 /* hang up */
-#define TARGET_B50 0x00000001
-#define TARGET_B75 0x00000002
-#define TARGET_B110 0x00000003
-#define TARGET_B134 0x00000004
-#define TARGET_B150 0x00000005
-#define TARGET_B200 0x00000006
-#define TARGET_B300 0x00000007
-#define TARGET_B600 0x00000008
-#define TARGET_B1200 0x00000009
-#define TARGET_B1800 0x0000000a
-#define TARGET_B2400 0x0000000b
-#define TARGET_B4800 0x0000000c
-#define TARGET_B9600 0x0000000d
-#define TARGET_B19200 0x0000000e
-#define TARGET_B38400 0x0000000f
-#define TARGET_EXTA B19200
-#define TARGET_EXTB B38400
-#define TARGET_CSIZE 0x00000030
-#define TARGET_CS5 0x00000000
-#define TARGET_CS6 0x00000010
-#define TARGET_CS7 0x00000020
-#define TARGET_CS8 0x00000030
-#define TARGET_CSTOPB 0x00000040
-#define TARGET_CREAD 0x00000080
-#define TARGET_PARENB 0x00000100
-#define TARGET_PARODD 0x00000200
-#define TARGET_HUPCL 0x00000400
-#define TARGET_CLOCAL 0x00000800
-#define TARGET_CBAUDEX 0x00001000
-/* We'll never see these speeds with the Zilogs, but for completeness... */
-#define TARGET_B57600 0x00001001
-#define TARGET_B115200 0x00001002
-#define TARGET_B230400 0x00001003
-#define TARGET_B460800 0x00001004
-/* This is what we can do with the Zilogs. */
-#define TARGET_B76800 0x00001005
-/* This is what we can do with the SAB82532. */
-#define TARGET_B153600 0x00001006
-#define TARGET_B307200 0x00001007
-#define TARGET_B614400 0x00001008
-#define TARGET_B921600 0x00001009
-/* And these are the rest... */
-#define TARGET_B500000 0x0000100a
-#define TARGET_B576000 0x0000100b
-#define TARGET_B1000000 0x0000100c
-#define TARGET_B1152000 0x0000100d
-#define TARGET_B1500000 0x0000100e
-#define TARGET_B2000000 0x0000100f
-/* These have totally bogus values and nobody uses them
- so far. Later on we'd have to use say 0x10000x and
- adjust CBAUD constant and drivers accordingly.
-#define B2500000 0x00001010
-#define B3000000 0x00001011
-#define B3500000 0x00001012
-#define B4000000 0x00001013 */
-#define TARGET_CIBAUD 0x100f0000 /* input baud rate (not used) */
-#define TARGET_CMSPAR 0x40000000 /* mark or space (stick) parity */
-#define TARGET_CRTSCTS 0x80000000 /* flow control */
-
-/* c_lflag bits */
-#define TARGET_ISIG 0x00000001
-#define TARGET_ICANON 0x00000002
-#define TARGET_XCASE 0x00000004
-#define TARGET_ECHO 0x00000008
-#define TARGET_ECHOE 0x00000010
-#define TARGET_ECHOK 0x00000020
-#define TARGET_ECHONL 0x00000040
-#define TARGET_NOFLSH 0x00000080
-#define TARGET_TOSTOP 0x00000100
-#define TARGET_ECHOCTL 0x00000200
-#define TARGET_ECHOPRT 0x00000400
-#define TARGET_ECHOKE 0x00000800
-#define TARGET_DEFECHO 0x00001000 /* SUNOS thing, what is it? */
-#define TARGET_FLUSHO 0x00002000
-#define TARGET_PENDIN 0x00004000
-#define TARGET_IEXTEN 0x00008000
-
-/* ioctls */
-
-/* Big T */
-#define TARGET_TCGETA TARGET_IOR('T', 1, struct target_termio)
-#define TARGET_TCSETA TARGET_IOW('T', 2, struct target_termio)
-#define TARGET_TCSETAW TARGET_IOW('T', 3, struct target_termio)
-#define TARGET_TCSETAF TARGET_IOW('T', 4, struct target_termio)
-#define TARGET_TCSBRK TARGET_IO('T', 5)
-#define TARGET_TCXONC TARGET_IO('T', 6)
-#define TARGET_TCFLSH TARGET_IO('T', 7)
-#define TARGET_TCGETS TARGET_IOR('T', 8, struct target_termios)
-#define TARGET_TCSETS TARGET_IOW('T', 9, struct target_termios)
-#define TARGET_TCSETSW TARGET_IOW('T', 10, struct target_termios)
-#define TARGET_TCSETSF TARGET_IOW('T', 11, struct target_termios)
-
-/* Note that all the ioctls that are not available in Linux have a
- * double underscore on the front to: a) avoid some programs to
- * thing we support some ioctls under Linux (autoconfiguration stuff)
- */
-/* Little t */
-#define TARGET_TIOCGETD TARGET_IOR('t', 0, int)
-#define TARGET_TIOCSETD TARGET_IOW('t', 1, int)
-//#define __TIOCHPCL _IO('t', 2) /* SunOS Specific */
-//#define __TIOCMODG _IOR('t', 3, int) /* SunOS Specific */
-//#define __TIOCMODS _IOW('t', 4, int) /* SunOS Specific */
-//#define __TIOCGETP _IOR('t', 8, struct sgttyb) /* SunOS Specific */
-//#define __TIOCSETP _IOW('t', 9, struct sgttyb) /* SunOS Specific */
-//#define __TIOCSETN _IOW('t', 10, struct sgttyb) /* SunOS Specific */
-#define TARGET_TIOCEXCL TARGET_IO('t', 13)
-#define TARGET_TIOCNXCL TARGET_IO('t', 14)
-//#define __TIOCFLUSH _IOW('t', 16, int) /* SunOS Specific */
-//#define __TIOCSETC _IOW('t', 17, struct tchars) /* SunOS Specific */
-//#define __TIOCGETC _IOR('t', 18, struct tchars) /* SunOS Specific */
-//#define __TIOCTCNTL _IOW('t', 32, int) /* SunOS Specific */
-//#define __TIOCSIGNAL _IOW('t', 33, int) /* SunOS Specific */
-//#define __TIOCSETX _IOW('t', 34, int) /* SunOS Specific */
-//#define __TIOCGETX _IOR('t', 35, int) /* SunOS Specific */
-#define TARGET_TIOCCONS TARGET_IO('t', 36)
-//#define __TIOCSSIZE _IOW('t', 37, struct sunos_ttysize) /* SunOS Specific */
-//#define __TIOCGSIZE _IOR('t', 38, struct sunos_ttysize) /* SunOS Specific */
-#define TARGET_TIOCGSOFTCAR TARGET_IOR('t', 100, int)
-#define TARGET_TIOCSSOFTCAR TARGET_IOW('t', 101, int)
-//#define __TIOCUCNTL _IOW('t', 102, int) /* SunOS Specific */
-#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct winsize)
-#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct winsize)
-//#define __TIOCREMOTE _IOW('t', 105, int) /* SunOS Specific */
-#define TARGET_TIOCMGET TARGET_IOR('t', 106, int)
-#define TARGET_TIOCMBIC TARGET_IOW('t', 107, int)
-#define TARGET_TIOCMBIS TARGET_IOW('t', 108, int)
-#define TARGET_TIOCMSET TARGET_IOW('t', 109, int)
-#define TARGET_TIOCSTART TARGET_IO('t', 110)
-#define TARGET_TIOCSTOP TARGET_IO('t', 111)
-#define TARGET_TIOCPKT TARGET_IOW('t', 112, int)
-#define TARGET_TIOCNOTTY TARGET_IO('t', 113)
-#define TARGET_TIOCSTI TARGET_IOW('t', 114, char)
-#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int)
-//#define __TIOCGLTC _IOR('t', 116, struct ltchars) /* SunOS Specific */
-//#define __TIOCSLTC _IOW('t', 117, struct ltchars) /* SunOS Specific */
-/* 118 is the non-posix setpgrp tty ioctl */
-/* 119 is the non-posix getpgrp tty ioctl */
-//#define __TIOCCDTR TARGET_IO('t', 120) /* SunOS Specific */
-//#define __TIOCSDTR TARGET_IO('t', 121) /* SunOS Specific */
-#define TARGET_TIOCCBRK TARGET_IO('t', 122)
-#define TARGET_TIOCSBRK TARGET_IO('t', 123)
-//#define __TIOCLGET TARGET_IOW('t', 124, int) /* SunOS Specific */
-//#define __TIOCLSET TARGET_IOW('t', 125, int) /* SunOS Specific */
-//#define __TIOCLBIC TARGET_IOW('t', 126, int) /* SunOS Specific */
-//#define __TIOCLBIS TARGET_IOW('t', 127, int) /* SunOS Specific */
-//#define __TIOCISPACE TARGET_IOR('t', 128, int) /* SunOS Specific */
-//#define __TIOCISIZE TARGET_IOR('t', 129, int) /* SunOS Specific */
-#define TARGET_TIOCSPGRP TARGET_IOW('t', 130, int)
-#define TARGET_TIOCGPGRP TARGET_IOR('t', 131, int)
-#define TARGET_TIOCSCTTY TARGET_IO('t', 132)
-#define TARGET_TIOCGSID TARGET_IOR('t', 133, int)
-/* Get minor device of a pty master's FD -- Solaris equiv is ISPTM */
-#define TARGET_TIOCGPTN TARGET_IOR('t', 134, unsigned int) /* Get Pty Number */
-#define TARGET_TIOCSPTLCK TARGET_IOW('t', 135, int) /* Lock/unlock PTY */
-
-/* Little f */
-#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
-
-/* SCARY Rutgers local SunOS kernel hackery, perhaps I will support it
- * someday. This is completely bogus, I know...
- */
-//#define __TCGETSTAT TARGET_IO('T', 200) /* Rutgers specific */
-//#define __TCSETSTAT TARGET_IO('T', 201) /* Rutgers specific */
-
-/* Linux specific, no SunOS equivalent. */
-#define TARGET_TIOCLINUX 0x541C
-#define TARGET_TIOCGSERIAL 0x541E
-#define TARGET_TIOCSSERIAL 0x541F
-#define TARGET_TCSBRKP 0x5425
-#define TARGET_TIOCTTYGSTRUCT 0x5426
-#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 input */
-#define TARGET_TIOCGICOUNT 0x545D /* Read serial port inline interrupt counts */
-
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
deleted file mode 100644
index 60ed9a6..0000000
--- a/linux-user/syscall.c
+++ /dev/null
@@ -1,3841 +0,0 @@
-/*
- * Linux syscalls
- *
- * 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 <elf.h>
-#include <endian.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
-#include <sys/resource.h>
-#include <sys/mman.h>
-#include <sys/swap.h>
-#include <signal.h>
-#include <sched.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-#include <sys/poll.h>
-#include <sys/times.h>
-#include <sys/shm.h>
-#include <sys/statfs.h>
-#include <utime.h>
-#include <sys/sysinfo.h>
-//#include <sys/user.h>
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
-
-#define termios host_termios
-#define winsize host_winsize
-#define termio host_termio
-#define sgttyb host_sgttyb /* same as target */
-#define tchars host_tchars /* same as target */
-#define ltchars host_ltchars /* same as target */
-
-#include <linux/termios.h>
-#include <linux/unistd.h>
-#include <linux/utsname.h>
-#include <linux/cdrom.h>
-#include <linux/hdreg.h>
-#include <linux/soundcard.h>
-#include <linux/dirent.h>
-#include <linux/kd.h>
-
-#include "qemu.h"
-
-//#define DEBUG
-
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC)
-/* 16 bit uid wrappers emulation */
-#define USE_UID16
-#endif
-
-//#include <linux/msdos_fs.h>
-#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
-#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct dirent [2])
-
-
-#undef _syscall0
-#undef _syscall1
-#undef _syscall2
-#undef _syscall3
-#undef _syscall4
-#undef _syscall5
-#undef _syscall6
-
-#define _syscall0(type,name) \
-type name (void) \
-{ \
- return syscall(__NR_##name); \
-}
-
-#define _syscall1(type,name,type1,arg1) \
-type name (type1 arg1) \
-{ \
- return syscall(__NR_##name, arg1); \
-}
-
-#define _syscall2(type,name,type1,arg1,type2,arg2) \
-type name (type1 arg1,type2 arg2) \
-{ \
- return syscall(__NR_##name, arg1, arg2); \
-}
-
-#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
-type name (type1 arg1,type2 arg2,type3 arg3) \
-{ \
- return syscall(__NR_##name, arg1, arg2, arg3); \
-}
-
-#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
-type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
-{ \
- return syscall(__NR_##name, arg1, arg2, arg3, arg4); \
-}
-
-#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5) \
-type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
-{ \
- return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5); \
-}
-
-
-#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
- type5,arg5,type6,arg6) \
-type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
-{ \
- return syscall(__NR_##name, arg1, arg2, arg3, arg4, arg5, arg6); \
-}
-
-
-#define __NR_sys_uname __NR_uname
-#define __NR_sys_getcwd1 __NR_getcwd
-#define __NR_sys_getdents __NR_getdents
-#define __NR_sys_getdents64 __NR_getdents64
-#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
-
-#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
-#define __NR__llseek __NR_lseek
-#endif
-
-#ifdef __NR_gettid
-_syscall0(int, gettid)
-#else
-static int gettid(void) {
- return -ENOSYS;
-}
-#endif
-_syscall1(int,sys_uname,struct new_utsname *,buf)
-_syscall2(int,sys_getcwd1,char *,buf,size_t,size)
-_syscall3(int, sys_getdents, uint, fd, struct dirent *, dirp, uint, count);
-_syscall3(int, sys_getdents64, uint, fd, struct dirent64 *, dirp, uint, count);
-_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)
-#ifdef __NR_exit_group
-_syscall1(int,exit_group,int,error_code)
-#endif
-
-extern int personality(int);
-extern int flock(int, int);
-extern int setfsuid(int);
-extern int setfsgid(int);
-extern int setresuid(uid_t, uid_t, uid_t);
-extern int getresuid(uid_t *, uid_t *, uid_t *);
-extern int setresgid(gid_t, gid_t, gid_t);
-extern int getresgid(gid_t *, gid_t *, gid_t *);
-extern int setgroups(int, gid_t *);
-
-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);
-}
-
-static target_ulong target_brk;
-static target_ulong target_original_brk;
-
-void target_set_brk(target_ulong new_brk)
-{
- target_original_brk = target_brk = new_brk;
-}
-
-long do_brk(target_ulong new_brk)
-{
- target_ulong brk_page;
- long mapped_addr;
- int new_alloc_size;
-
- if (!new_brk)
- return target_brk;
- if (new_brk < target_original_brk)
- return -ENOMEM;
-
- brk_page = HOST_PAGE_ALIGN(target_brk);
-
- /* If the new brk is less than this, set it and we're done... */
- if (new_brk < brk_page) {
- target_brk = new_brk;
- return target_brk;
- }
-
- /* We need to allocate more memory after the brk... */
- new_alloc_size = HOST_PAGE_ALIGN(new_brk - brk_page + 1);
- mapped_addr = get_errno(target_mmap(brk_page, new_alloc_size,
- PROT_READ|PROT_WRITE,
- MAP_ANON|MAP_FIXED|MAP_PRIVATE, 0, 0));
- if (is_error(mapped_addr)) {
- return mapped_addr;
- } else {
- target_brk = new_brk;
- return target_brk;
- }
-}
-
-static inline fd_set *target_to_host_fds(fd_set *fds,
- target_long *target_fds, int n)
-{
-#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
- return (fd_set *)target_fds;
-#else
- int i, b;
- if (target_fds) {
- FD_ZERO(fds);
- for(i = 0;i < n; i++) {
- b = (tswapl(target_fds[i / TARGET_LONG_BITS]) >>
- (i & (TARGET_LONG_BITS - 1))) & 1;
- if (b)
- FD_SET(i, fds);
- }
- return fds;
- } else {
- return NULL;
- }
-#endif
-}
-
-static inline void host_to_target_fds(target_long *target_fds,
- fd_set *fds, int n)
-{
-#if !defined(BSWAP_NEEDED) && !defined(WORDS_BIGENDIAN)
- /* nothing to do */
-#else
- int i, nw, j, k;
- target_long v;
-
- if (target_fds) {
- nw = (n + TARGET_LONG_BITS - 1) / TARGET_LONG_BITS;
- k = 0;
- for(i = 0;i < nw; i++) {
- v = 0;
- for(j = 0; j < TARGET_LONG_BITS; j++) {
- v |= ((FD_ISSET(k, fds) != 0) << j);
- k++;
- }
- target_fds[i] = tswapl(v);
- }
- }
-#endif
-}
-
-#if defined(__alpha__)
-#define HOST_HZ 1024
-#else
-#define HOST_HZ 100
-#endif
-
-static inline long host_to_target_clock_t(long ticks)
-{
-#if HOST_HZ == TARGET_HZ
- return ticks;
-#else
- return ((int64_t)ticks * TARGET_HZ) / HOST_HZ;
-#endif
-}
-
-static inline void host_to_target_rusage(target_ulong target_addr,
- const struct rusage *rusage)
-{
- struct target_rusage *target_rusage;
-
- lock_user_struct(target_rusage, target_addr, 0);
- target_rusage->ru_utime.tv_sec = tswapl(rusage->ru_utime.tv_sec);
- target_rusage->ru_utime.tv_usec = tswapl(rusage->ru_utime.tv_usec);
- target_rusage->ru_stime.tv_sec = tswapl(rusage->ru_stime.tv_sec);
- target_rusage->ru_stime.tv_usec = tswapl(rusage->ru_stime.tv_usec);
- target_rusage->ru_maxrss = tswapl(rusage->ru_maxrss);
- target_rusage->ru_ixrss = tswapl(rusage->ru_ixrss);
- target_rusage->ru_idrss = tswapl(rusage->ru_idrss);
- target_rusage->ru_isrss = tswapl(rusage->ru_isrss);
- target_rusage->ru_minflt = tswapl(rusage->ru_minflt);
- target_rusage->ru_majflt = tswapl(rusage->ru_majflt);
- target_rusage->ru_nswap = tswapl(rusage->ru_nswap);
- target_rusage->ru_inblock = tswapl(rusage->ru_inblock);
- target_rusage->ru_oublock = tswapl(rusage->ru_oublock);
- target_rusage->ru_msgsnd = tswapl(rusage->ru_msgsnd);
- target_rusage->ru_msgrcv = tswapl(rusage->ru_msgrcv);
- target_rusage->ru_nsignals = tswapl(rusage->ru_nsignals);
- target_rusage->ru_nvcsw = tswapl(rusage->ru_nvcsw);
- target_rusage->ru_nivcsw = tswapl(rusage->ru_nivcsw);
- unlock_user_struct(target_rusage, target_addr, 1);
-}
-
-static inline void target_to_host_timeval(struct timeval *tv,
- target_ulong target_addr)
-{
- struct target_timeval *target_tv;
-
- lock_user_struct(target_tv, target_addr, 1);
- tv->tv_sec = tswapl(target_tv->tv_sec);
- tv->tv_usec = tswapl(target_tv->tv_usec);
- unlock_user_struct(target_tv, target_addr, 0);
-}
-
-static inline void host_to_target_timeval(target_ulong target_addr,
- const struct timeval *tv)
-{
- struct target_timeval *target_tv;
-
- lock_user_struct(target_tv, target_addr, 0);
- target_tv->tv_sec = tswapl(tv->tv_sec);
- target_tv->tv_usec = tswapl(tv->tv_usec);
- unlock_user_struct(target_tv, target_addr, 1);
-}
-
-
-static long do_select(long n,
- target_ulong rfd_p, target_ulong wfd_p,
- target_ulong efd_p, target_ulong target_tv)
-{
- fd_set rfds, wfds, efds;
- fd_set *rfds_ptr, *wfds_ptr, *efds_ptr;
- target_long *target_rfds, *target_wfds, *target_efds;
- struct timeval tv, *tv_ptr;
- long ret;
- int ok;
-
- if (rfd_p) {
- target_rfds = lock_user(rfd_p, sizeof(target_long) * n, 1);
- rfds_ptr = target_to_host_fds(&rfds, target_rfds, n);
- } else {
- target_rfds = NULL;
- rfds_ptr = NULL;
- }
- if (wfd_p) {
- target_wfds = lock_user(wfd_p, sizeof(target_long) * n, 1);
- wfds_ptr = target_to_host_fds(&wfds, target_wfds, n);
- } else {
- target_wfds = NULL;
- wfds_ptr = NULL;
- }
- if (efd_p) {
- target_efds = lock_user(efd_p, sizeof(target_long) * n, 1);
- efds_ptr = target_to_host_fds(&efds, target_efds, n);
- } else {
- target_efds = NULL;
- efds_ptr = NULL;
- }
-
- if (target_tv) {
- target_to_host_timeval(&tv, target_tv);
- tv_ptr = &tv;
- } else {
- tv_ptr = NULL;
- }
- ret = get_errno(select(n, rfds_ptr, wfds_ptr, efds_ptr, tv_ptr));
- ok = !is_error(ret);
-
- if (ok) {
- host_to_target_fds(target_rfds, rfds_ptr, n);
- host_to_target_fds(target_wfds, wfds_ptr, n);
- host_to_target_fds(target_efds, efds_ptr, n);
-
- if (target_tv) {
- host_to_target_timeval(target_tv, &tv);
- }
- }
- if (target_rfds)
- unlock_user(target_rfds, rfd_p, ok ? sizeof(target_long) * n : 0);
- if (target_wfds)
- unlock_user(target_wfds, wfd_p, ok ? sizeof(target_long) * n : 0);
- if (target_efds)
- unlock_user(target_efds, efd_p, ok ? sizeof(target_long) * n : 0);
-
- return ret;
-}
-
-static inline void target_to_host_sockaddr(struct sockaddr *addr,
- target_ulong target_addr,
- socklen_t len)
-{
- struct target_sockaddr *target_saddr;
-
- target_saddr = lock_user(target_addr, len, 1);
- memcpy(addr, target_saddr, len);
- addr->sa_family = tswap16(target_saddr->sa_family);
- unlock_user(target_saddr, target_addr, 0);
-}
-
-static inline void host_to_target_sockaddr(target_ulong target_addr,
- struct sockaddr *addr,
- socklen_t len)
-{
- struct target_sockaddr *target_saddr;
-
- target_saddr = lock_user(target_addr, len, 0);
- memcpy(target_saddr, addr, len);
- target_saddr->sa_family = tswap16(addr->sa_family);
- unlock_user(target_saddr, target_addr, len);
-}
-
-/* ??? Should this also swap msgh->name? */
-static inline void target_to_host_cmsg(struct msghdr *msgh,
- struct target_msghdr *target_msgh)
-{
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
- struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh);
- socklen_t space = 0;
-
- while (cmsg && target_cmsg) {
- void *data = CMSG_DATA(cmsg);
- void *target_data = TARGET_CMSG_DATA(target_cmsg);
-
- int len = tswapl(target_cmsg->cmsg_len)
- - TARGET_CMSG_ALIGN(sizeof (struct target_cmsghdr));
-
- space += CMSG_SPACE(len);
- if (space > msgh->msg_controllen) {
- space -= CMSG_SPACE(len);
- gemu_log("Host cmsg overflow\n");
- break;
- }
-
- cmsg->cmsg_level = tswap32(target_cmsg->cmsg_level);
- cmsg->cmsg_type = tswap32(target_cmsg->cmsg_type);
- cmsg->cmsg_len = CMSG_LEN(len);
-
- if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
- gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
- memcpy(data, target_data, len);
- } else {
- int *fd = (int *)data;
- int *target_fd = (int *)target_data;
- int i, numfds = len / sizeof(int);
-
- for (i = 0; i < numfds; i++)
- fd[i] = tswap32(target_fd[i]);
- }
-
- cmsg = CMSG_NXTHDR(msgh, cmsg);
- target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
- }
-
- msgh->msg_controllen = space;
-}
-
-/* ??? Should this also swap msgh->name? */
-static inline void host_to_target_cmsg(struct target_msghdr *target_msgh,
- struct msghdr *msgh)
-{
- struct cmsghdr *cmsg = CMSG_FIRSTHDR(msgh);
- struct target_cmsghdr *target_cmsg = TARGET_CMSG_FIRSTHDR(target_msgh);
- socklen_t space = 0;
-
- while (cmsg && target_cmsg) {
- void *data = CMSG_DATA(cmsg);
- void *target_data = TARGET_CMSG_DATA(target_cmsg);
-
- int len = cmsg->cmsg_len - CMSG_ALIGN(sizeof (struct cmsghdr));
-
- space += TARGET_CMSG_SPACE(len);
- if (space > tswapl(target_msgh->msg_controllen)) {
- space -= TARGET_CMSG_SPACE(len);
- gemu_log("Target cmsg overflow\n");
- break;
- }
-
- target_cmsg->cmsg_level = tswap32(cmsg->cmsg_level);
- target_cmsg->cmsg_type = tswap32(cmsg->cmsg_type);
- target_cmsg->cmsg_len = tswapl(TARGET_CMSG_LEN(len));
-
- if (cmsg->cmsg_level != TARGET_SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
- gemu_log("Unsupported ancillary data: %d/%d\n", cmsg->cmsg_level, cmsg->cmsg_type);
- memcpy(target_data, data, len);
- } else {
- int *fd = (int *)data;
- int *target_fd = (int *)target_data;
- int i, numfds = len / sizeof(int);
-
- for (i = 0; i < numfds; i++)
- target_fd[i] = tswap32(fd[i]);
- }
-
- cmsg = CMSG_NXTHDR(msgh, cmsg);
- target_cmsg = TARGET_CMSG_NXTHDR(target_msgh, target_cmsg);
- }
-
- msgh->msg_controllen = tswapl(space);
-}
-
-static long do_setsockopt(int sockfd, int level, int optname,
- target_ulong optval, socklen_t optlen)
-{
- int val, ret;
-
- switch(level) {
- case SOL_TCP:
- /* TCP options all take an 'int' value. */
- if (optlen < sizeof(uint32_t))
- return -EINVAL;
-
- val = tget32(optval);
- ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
- break;
- case SOL_IP:
- switch(optname) {
- case IP_TOS:
- case IP_TTL:
- case IP_HDRINCL:
- case IP_ROUTER_ALERT:
- case IP_RECVOPTS:
- case IP_RETOPTS:
- case IP_PKTINFO:
- case IP_MTU_DISCOVER:
- case IP_RECVERR:
- case IP_RECVTOS:
-#ifdef IP_FREEBIND
- case IP_FREEBIND:
-#endif
- case IP_MULTICAST_TTL:
- case IP_MULTICAST_LOOP:
- val = 0;
- if (optlen >= sizeof(uint32_t)) {
- val = tget32(optval);
- } else if (optlen >= 1) {
- val = tget8(optval);
- }
- ret = get_errno(setsockopt(sockfd, level, optname, &val, sizeof(val)));
- break;
- default:
- goto unimplemented;
- }
- break;
- case TARGET_SOL_SOCKET:
- switch (optname) {
- /* Options with 'int' argument. */
- case TARGET_SO_DEBUG:
- optname = SO_DEBUG;
- break;
- case TARGET_SO_REUSEADDR:
- optname = SO_REUSEADDR;
- break;
- case TARGET_SO_TYPE:
- optname = SO_TYPE;
- break;
- case TARGET_SO_ERROR:
- optname = SO_ERROR;
- break;
- case TARGET_SO_DONTROUTE:
- optname = SO_DONTROUTE;
- break;
- case TARGET_SO_BROADCAST:
- optname = SO_BROADCAST;
- break;
- case TARGET_SO_SNDBUF:
- optname = SO_SNDBUF;
- break;
- case TARGET_SO_RCVBUF:
- optname = SO_RCVBUF;
- break;
- case TARGET_SO_KEEPALIVE:
- optname = SO_KEEPALIVE;
- break;
- case TARGET_SO_OOBINLINE:
- optname = SO_OOBINLINE;
- break;
- case TARGET_SO_NO_CHECK:
- optname = SO_NO_CHECK;
- break;
- case TARGET_SO_PRIORITY:
- optname = SO_PRIORITY;
- break;
-#ifdef SO_BSDCOMPAT
- case TARGET_SO_BSDCOMPAT:
- optname = SO_BSDCOMPAT;
- break;
-#endif
- case TARGET_SO_PASSCRED:
- optname = SO_PASSCRED;
- break;
- case TARGET_SO_TIMESTAMP:
- optname = SO_TIMESTAMP;
- break;
- case TARGET_SO_RCVLOWAT:
- optname = SO_RCVLOWAT;
- break;
- case TARGET_SO_RCVTIMEO:
- optname = SO_RCVTIMEO;
- break;
- case TARGET_SO_SNDTIMEO:
- optname = SO_SNDTIMEO;
- break;
- break;
- default:
- goto unimplemented;
- }
- if (optlen < sizeof(uint32_t))
- return -EINVAL;
-
- val = tget32(optval);
- ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(val)));
- break;
- default:
- unimplemented:
- gemu_log("Unsupported setsockopt level=%d optname=%d \n", level, optname);
- ret = -ENOSYS;
- }
- return ret;
-}
-
-static long do_getsockopt(int sockfd, int level, int optname,
- target_ulong optval, target_ulong optlen)
-{
- int len, lv, val, ret;
-
- switch(level) {
- case TARGET_SOL_SOCKET:
- level = SOL_SOCKET;
- switch (optname) {
- case TARGET_SO_LINGER:
- case TARGET_SO_RCVTIMEO:
- case TARGET_SO_SNDTIMEO:
- case TARGET_SO_PEERCRED:
- case TARGET_SO_PEERNAME:
- /* These don't just return a single integer */
- goto unimplemented;
- default:
- goto int_case;
- }
- break;
- case SOL_TCP:
- /* TCP options all take an 'int' value. */
- int_case:
- len = tget32(optlen);
- if (len < 0)
- return -EINVAL;
- lv = sizeof(int);
- ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
- if (ret < 0)
- return ret;
- val = tswap32(val);
- if (len > lv)
- len = lv;
- if (len == 4)
- tput32(optval, val);
- else
- tput8(optval, val);
- tput32(optlen, len);
- break;
- case SOL_IP:
- switch(optname) {
- case IP_TOS:
- case IP_TTL:
- case IP_HDRINCL:
- case IP_ROUTER_ALERT:
- case IP_RECVOPTS:
- case IP_RETOPTS:
- case IP_PKTINFO:
- case IP_MTU_DISCOVER:
- case IP_RECVERR:
- case IP_RECVTOS:
-#ifdef IP_FREEBIND
- case IP_FREEBIND:
-#endif
- case IP_MULTICAST_TTL:
- case IP_MULTICAST_LOOP:
- len = tget32(optlen);
- if (len < 0)
- return -EINVAL;
- lv = sizeof(int);
- ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
- if (ret < 0)
- return ret;
- if (len < sizeof(int) && len > 0 && val >= 0 && val < 255) {
- len = 1;
- tput32(optlen, len);
- tput8(optval, val);
- } else {
- if (len > sizeof(int))
- len = sizeof(int);
- tput32(optlen, len);
- tput32(optval, val);
- }
- break;
- default:
- goto unimplemented;
- }
- break;
- default:
- unimplemented:
- gemu_log("getsockopt level=%d optname=%d not yet supported\n",
- level, optname);
- ret = -ENOSYS;
- break;
- }
- return ret;
-}
-
-static void lock_iovec(struct iovec *vec, target_ulong target_addr,
- int count, int copy)
-{
- struct target_iovec *target_vec;
- target_ulong base;
- int i;
-
- target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1);
- for(i = 0;i < count; i++) {
- base = tswapl(target_vec[i].iov_base);
- vec[i].iov_len = tswapl(target_vec[i].iov_len);
- vec[i].iov_base = lock_user(base, vec[i].iov_len, copy);
- }
- unlock_user (target_vec, target_addr, 0);
-}
-
-static void unlock_iovec(struct iovec *vec, target_ulong target_addr,
- int count, int copy)
-{
- struct target_iovec *target_vec;
- target_ulong base;
- int i;
-
- target_vec = lock_user(target_addr, count * sizeof(struct target_iovec), 1);
- for(i = 0;i < count; i++) {
- base = tswapl(target_vec[i].iov_base);
- unlock_user(vec[i].iov_base, base, copy ? vec[i].iov_len : 0);
- }
- unlock_user (target_vec, target_addr, 0);
-}
-
-static long do_socket(int domain, int type, int protocol)
-{
-#if defined(TARGET_MIPS)
- switch(type) {
- case TARGET_SOCK_DGRAM:
- type = SOCK_DGRAM;
- break;
- case TARGET_SOCK_STREAM:
- type = SOCK_STREAM;
- break;
- case TARGET_SOCK_RAW:
- type = SOCK_RAW;
- break;
- case TARGET_SOCK_RDM:
- type = SOCK_RDM;
- break;
- case TARGET_SOCK_SEQPACKET:
- type = SOCK_SEQPACKET;
- break;
- case TARGET_SOCK_PACKET:
- type = SOCK_PACKET;
- break;
- }
-#endif
- return get_errno(socket(domain, type, protocol));
-}
-
-static long do_bind(int sockfd, target_ulong target_addr,
- socklen_t addrlen)
-{
- void *addr = alloca(addrlen);
-
- target_to_host_sockaddr(addr, target_addr, addrlen);
- return get_errno(bind(sockfd, addr, addrlen));
-}
-
-static long do_connect(int sockfd, target_ulong target_addr,
- socklen_t addrlen)
-{
- void *addr = alloca(addrlen);
-
- target_to_host_sockaddr(addr, target_addr, addrlen);
- return get_errno(connect(sockfd, addr, addrlen));
-}
-
-static long do_sendrecvmsg(int fd, target_ulong target_msg,
- int flags, int send)
-{
- long ret;
- struct target_msghdr *msgp;
- struct msghdr msg;
- int count;
- struct iovec *vec;
- target_ulong target_vec;
-
- lock_user_struct(msgp, target_msg, 1);
- if (msgp->msg_name) {
- msg.msg_namelen = tswap32(msgp->msg_namelen);
- msg.msg_name = alloca(msg.msg_namelen);
- target_to_host_sockaddr(msg.msg_name, tswapl(msgp->msg_name),
- msg.msg_namelen);
- } else {
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
- }
- msg.msg_controllen = 2 * tswapl(msgp->msg_controllen);
- msg.msg_control = alloca(msg.msg_controllen);
- msg.msg_flags = tswap32(msgp->msg_flags);
-
- count = tswapl(msgp->msg_iovlen);
- vec = alloca(count * sizeof(struct iovec));
- target_vec = tswapl(msgp->msg_iov);
- lock_iovec(vec, target_vec, count, send);
- msg.msg_iovlen = count;
- msg.msg_iov = vec;
-
- if (send) {
- target_to_host_cmsg(&msg, msgp);
- ret = get_errno(sendmsg(fd, &msg, flags));
- } else {
- ret = get_errno(recvmsg(fd, &msg, flags));
- if (!is_error(ret))
- host_to_target_cmsg(msgp, &msg);
- }
- unlock_iovec(vec, target_vec, count, !send);
- return ret;
-}
-
-static long do_socketcall(int num, target_ulong vptr)
-{
- long ret;
- const int n = sizeof(target_ulong);
-
- switch(num) {
- case SOCKOP_socket:
- {
- int domain = tgetl(vptr);
- int type = tgetl(vptr + n);
- int protocol = tgetl(vptr + 2 * n);
- ret = do_socket(domain, type, protocol);
- }
- break;
- case SOCKOP_bind:
- {
- int sockfd = tgetl(vptr);
- target_ulong target_addr = tgetl(vptr + n);
- socklen_t addrlen = tgetl(vptr + 2 * n);
- ret = do_bind(sockfd, target_addr, addrlen);
- }
- break;
- case SOCKOP_connect:
- {
- int sockfd = tgetl(vptr);
- target_ulong target_addr = tgetl(vptr + n);
- socklen_t addrlen = tgetl(vptr + 2 * n);
- ret = do_connect(sockfd, target_addr, addrlen);
- }
- break;
- case SOCKOP_listen:
- {
- int sockfd = tgetl(vptr);
- int backlog = tgetl(vptr + n);
- ret = get_errno(listen(sockfd, backlog));
- }
- break;
- case SOCKOP_accept:
- {
- int sockfd = tgetl(vptr);
- target_ulong target_addr = tgetl(vptr + n);
- target_ulong target_addrlen = tgetl(vptr + 2 * n);
- socklen_t addrlen = tget32(target_addrlen);
- void *addr = alloca(addrlen);
-
- ret = get_errno(accept(sockfd, addr, &addrlen));
- if (!is_error(ret)) {
- host_to_target_sockaddr(target_addr, addr, addrlen);
- tput32(target_addrlen, addrlen);
- }
- }
- break;
- case SOCKOP_getsockname:
- {
- int sockfd = tgetl(vptr);
- target_ulong target_addr = tgetl(vptr + n);
- target_ulong target_addrlen = tgetl(vptr + 2 * n);
- socklen_t addrlen = tget32(target_addrlen);
- void *addr = alloca(addrlen);
-
- ret = get_errno(getsockname(sockfd, addr, &addrlen));
- if (!is_error(ret)) {
- host_to_target_sockaddr(target_addr, addr, addrlen);
- tput32(target_addrlen, addrlen);
- }
- }
- break;
- case SOCKOP_getpeername:
- {
- int sockfd = tgetl(vptr);
- target_ulong target_addr = tgetl(vptr + n);
- target_ulong target_addrlen = tgetl(vptr + 2 * n);
- socklen_t addrlen = tget32(target_addrlen);
- void *addr = alloca(addrlen);
-
- ret = get_errno(getpeername(sockfd, addr, &addrlen));
- if (!is_error(ret)) {
- host_to_target_sockaddr(target_addr, addr, addrlen);
- tput32(target_addrlen, addrlen);
- }
- }
- break;
- case SOCKOP_socketpair:
- {
- int domain = tgetl(vptr);
- int type = tgetl(vptr + n);
- int protocol = tgetl(vptr + 2 * n);
- target_ulong target_tab = tgetl(vptr + 3 * n);
- int tab[2];
-
- ret = get_errno(socketpair(domain, type, protocol, tab));
- if (!is_error(ret)) {
- tput32(target_tab, tab[0]);
- tput32(target_tab + 4, tab[1]);
- }
- }
- break;
- case SOCKOP_send:
- {
- int sockfd = tgetl(vptr);
- target_ulong msg = tgetl(vptr + n);
- size_t len = tgetl(vptr + 2 * n);
- int flags = tgetl(vptr + 3 * n);
- void *host_msg;
-
- host_msg = lock_user(msg, len, 1);
- ret = get_errno(send(sockfd, host_msg, len, flags));
- unlock_user(host_msg, msg, 0);
- }
- break;
- case SOCKOP_recv:
- {
- int sockfd = tgetl(vptr);
- target_ulong msg = tgetl(vptr + n);
- size_t len = tgetl(vptr + 2 * n);
- int flags = tgetl(vptr + 3 * n);
- void *host_msg;
-
- host_msg = lock_user(msg, len, 0);
- ret = get_errno(recv(sockfd, host_msg, len, flags));
- unlock_user(host_msg, msg, ret);
- }
- break;
- case SOCKOP_sendto:
- {
- int sockfd = tgetl(vptr);
- target_ulong msg = tgetl(vptr + n);
- size_t len = tgetl(vptr + 2 * n);
- int flags = tgetl(vptr + 3 * n);
- target_ulong target_addr = tgetl(vptr + 4 * n);
- socklen_t addrlen = tgetl(vptr + 5 * n);
- void *addr = alloca(addrlen);
- void *host_msg;
-
- host_msg = lock_user(msg, len, 1);
- target_to_host_sockaddr(addr, target_addr, addrlen);
- ret = get_errno(sendto(sockfd, host_msg, len, flags, addr, addrlen));
- unlock_user(host_msg, msg, 0);
- }
- break;
- case SOCKOP_recvfrom:
- {
- int sockfd = tgetl(vptr);
- target_ulong msg = tgetl(vptr + n);
- size_t len = tgetl(vptr + 2 * n);
- int flags = tgetl(vptr + 3 * n);
- target_ulong target_addr = tgetl(vptr + 4 * n);
- target_ulong target_addrlen = tgetl(vptr + 5 * n);
- socklen_t addrlen = tget32(target_addrlen);
- void *addr = alloca(addrlen);
- void *host_msg;
-
- host_msg = lock_user(msg, len, 0);
- ret = get_errno(recvfrom(sockfd, host_msg, len, flags, addr, &addrlen));
- if (!is_error(ret)) {
- host_to_target_sockaddr(target_addr, addr, addrlen);
- tput32(target_addrlen, addrlen);
- unlock_user(host_msg, msg, len);
- } else {
- unlock_user(host_msg, msg, 0);
- }
- }
- break;
- case SOCKOP_shutdown:
- {
- int sockfd = tgetl(vptr);
- int how = tgetl(vptr + n);
-
- ret = get_errno(shutdown(sockfd, how));
- }
- break;
- case SOCKOP_sendmsg:
- case SOCKOP_recvmsg:
- {
- int fd;
- target_ulong target_msg;
- int flags;
-
- fd = tgetl(vptr);
- target_msg = tgetl(vptr + n);
- flags = tgetl(vptr + 2 * n);
-
- ret = do_sendrecvmsg(fd, target_msg, flags,
- (num == SOCKOP_sendmsg));
- }
- break;
- case SOCKOP_setsockopt:
- {
- int sockfd = tgetl(vptr);
- int level = tgetl(vptr + n);
- int optname = tgetl(vptr + 2 * n);
- target_ulong optval = tgetl(vptr + 3 * n);
- socklen_t optlen = tgetl(vptr + 4 * n);
-
- ret = do_setsockopt(sockfd, level, optname, optval, optlen);
- }
- break;
- case SOCKOP_getsockopt:
- {
- int sockfd = tgetl(vptr);
- int level = tgetl(vptr + n);
- int optname = tgetl(vptr + 2 * n);
- target_ulong optval = tgetl(vptr + 3 * n);
- target_ulong poptlen = tgetl(vptr + 4 * n);
-
- ret = do_getsockopt(sockfd, level, optname, optval, poptlen);
- }
- break;
- default:
- gemu_log("Unsupported socketcall: %d\n", num);
- ret = -ENOSYS;
- break;
- }
- return ret;
-}
-
-/* XXX: suppress this function and call directly the related socket
- functions */
-static long do_socketcallwrapper(int num, long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6)
-{
- target_long args[6];
-
- tputl(args, arg1);
- tputl(args+1, arg2);
- tputl(args+2, arg3);
- tputl(args+3, arg4);
- tputl(args+4, arg5);
- tputl(args+5, arg6);
-
- return do_socketcall(num, (target_ulong) args);
-}
-
-#define N_SHM_REGIONS 32
-
-static struct shm_region {
- uint32_t start;
- uint32_t size;
-} shm_regions[N_SHM_REGIONS];
-
-/* ??? This only works with linear mappings. */
-static long do_ipc(long call, long first, long second, long third,
- long ptr, long fifth)
-{
- int version;
- long ret = 0;
- unsigned long raddr;
- struct shmid_ds shm_info;
- int i;
-
- version = call >> 16;
- call &= 0xffff;
-
- switch (call) {
- case IPCOP_shmat:
- /* SHM_* flags are the same on all linux platforms */
- ret = get_errno((long) shmat(first, (void *) ptr, second));
- if (is_error(ret))
- break;
- raddr = ret;
- /* find out the length of the shared memory segment */
-
- ret = get_errno(shmctl(first, IPC_STAT, &shm_info));
- if (is_error(ret)) {
- /* can't get length, bail out */
- shmdt((void *) raddr);
- break;
- }
- page_set_flags(raddr, raddr + shm_info.shm_segsz,
- PAGE_VALID | PAGE_READ |
- ((second & SHM_RDONLY)? 0: PAGE_WRITE));
- for (i = 0; i < N_SHM_REGIONS; ++i) {
- if (shm_regions[i].start == 0) {
- shm_regions[i].start = raddr;
- shm_regions[i].size = shm_info.shm_segsz;
- break;
- }
- }
- if (put_user(raddr, (uint32_t *)third))
- return -EFAULT;
- ret = 0;
- break;
- case IPCOP_shmdt:
- for (i = 0; i < N_SHM_REGIONS; ++i) {
- if (shm_regions[i].start == ptr) {
- shm_regions[i].start = 0;
- page_set_flags(ptr, shm_regions[i].size, 0);
- break;
- }
- }
- ret = get_errno(shmdt((void *) ptr));
- break;
-
- case IPCOP_shmget:
- /* IPC_* flag values are the same on all linux platforms */
- ret = get_errno(shmget(first, second, third));
- break;
-
- /* IPC_* and SHM_* command values are the same on all linux platforms */
- case IPCOP_shmctl:
- switch(second) {
- case IPC_RMID:
- case SHM_LOCK:
- case SHM_UNLOCK:
- ret = get_errno(shmctl(first, second, NULL));
- break;
- default:
- goto unimplemented;
- }
- break;
- default:
- unimplemented:
- gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version);
- ret = -ENOSYS;
- break;
- }
- return ret;
-}
-
-/* kernel structure types definitions */
-#define IFNAMSIZ 16
-
-#define STRUCT(name, list...) STRUCT_ ## name,
-#define STRUCT_SPECIAL(name) STRUCT_ ## name,
-enum {
-#include "syscall_types.h"
-};
-#undef STRUCT
-#undef STRUCT_SPECIAL
-
-#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL };
-#define STRUCT_SPECIAL(name)
-#include "syscall_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...) \
- { TARGET_ ## 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;
- long 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;
-}
-
-bitmask_transtbl iflag_tbl[] = {
- { TARGET_IGNBRK, TARGET_IGNBRK, IGNBRK, IGNBRK },
- { TARGET_BRKINT, TARGET_BRKINT, BRKINT, BRKINT },
- { TARGET_IGNPAR, TARGET_IGNPAR, IGNPAR, IGNPAR },
- { TARGET_PARMRK, TARGET_PARMRK, PARMRK, PARMRK },
- { TARGET_INPCK, TARGET_INPCK, INPCK, INPCK },
- { TARGET_ISTRIP, TARGET_ISTRIP, ISTRIP, ISTRIP },
- { TARGET_INLCR, TARGET_INLCR, INLCR, INLCR },
- { TARGET_IGNCR, TARGET_IGNCR, IGNCR, IGNCR },
- { TARGET_ICRNL, TARGET_ICRNL, ICRNL, ICRNL },
- { TARGET_IUCLC, TARGET_IUCLC, IUCLC, IUCLC },
- { TARGET_IXON, TARGET_IXON, IXON, IXON },
- { TARGET_IXANY, TARGET_IXANY, IXANY, IXANY },
- { TARGET_IXOFF, TARGET_IXOFF, IXOFF, IXOFF },
- { TARGET_IMAXBEL, TARGET_IMAXBEL, IMAXBEL, IMAXBEL },
- { 0, 0, 0, 0 }
-};
-
-bitmask_transtbl oflag_tbl[] = {
- { TARGET_OPOST, TARGET_OPOST, OPOST, OPOST },
- { TARGET_OLCUC, TARGET_OLCUC, OLCUC, OLCUC },
- { TARGET_ONLCR, TARGET_ONLCR, ONLCR, ONLCR },
- { TARGET_OCRNL, TARGET_OCRNL, OCRNL, OCRNL },
- { TARGET_ONOCR, TARGET_ONOCR, ONOCR, ONOCR },
- { TARGET_ONLRET, TARGET_ONLRET, ONLRET, ONLRET },
- { TARGET_OFILL, TARGET_OFILL, OFILL, OFILL },
- { TARGET_OFDEL, TARGET_OFDEL, OFDEL, OFDEL },
- { TARGET_NLDLY, TARGET_NL0, NLDLY, NL0 },
- { TARGET_NLDLY, TARGET_NL1, NLDLY, NL1 },
- { TARGET_CRDLY, TARGET_CR0, CRDLY, CR0 },
- { TARGET_CRDLY, TARGET_CR1, CRDLY, CR1 },
- { TARGET_CRDLY, TARGET_CR2, CRDLY, CR2 },
- { TARGET_CRDLY, TARGET_CR3, CRDLY, CR3 },
- { TARGET_TABDLY, TARGET_TAB0, TABDLY, TAB0 },
- { TARGET_TABDLY, TARGET_TAB1, TABDLY, TAB1 },
- { TARGET_TABDLY, TARGET_TAB2, TABDLY, TAB2 },
- { TARGET_TABDLY, TARGET_TAB3, TABDLY, TAB3 },
- { TARGET_BSDLY, TARGET_BS0, BSDLY, BS0 },
- { TARGET_BSDLY, TARGET_BS1, BSDLY, BS1 },
- { TARGET_VTDLY, TARGET_VT0, VTDLY, VT0 },
- { TARGET_VTDLY, TARGET_VT1, VTDLY, VT1 },
- { TARGET_FFDLY, TARGET_FF0, FFDLY, FF0 },
- { TARGET_FFDLY, TARGET_FF1, FFDLY, FF1 },
- { 0, 0, 0, 0 }
-};
-
-bitmask_transtbl cflag_tbl[] = {
- { TARGET_CBAUD, TARGET_B0, CBAUD, B0 },
- { TARGET_CBAUD, TARGET_B50, CBAUD, B50 },
- { TARGET_CBAUD, TARGET_B75, CBAUD, B75 },
- { TARGET_CBAUD, TARGET_B110, CBAUD, B110 },
- { TARGET_CBAUD, TARGET_B134, CBAUD, B134 },
- { TARGET_CBAUD, TARGET_B150, CBAUD, B150 },
- { TARGET_CBAUD, TARGET_B200, CBAUD, B200 },
- { TARGET_CBAUD, TARGET_B300, CBAUD, B300 },
- { TARGET_CBAUD, TARGET_B600, CBAUD, B600 },
- { TARGET_CBAUD, TARGET_B1200, CBAUD, B1200 },
- { TARGET_CBAUD, TARGET_B1800, CBAUD, B1800 },
- { TARGET_CBAUD, TARGET_B2400, CBAUD, B2400 },
- { TARGET_CBAUD, TARGET_B4800, CBAUD, B4800 },
- { TARGET_CBAUD, TARGET_B9600, CBAUD, B9600 },
- { TARGET_CBAUD, TARGET_B19200, CBAUD, B19200 },
- { TARGET_CBAUD, TARGET_B38400, CBAUD, B38400 },
- { TARGET_CBAUD, TARGET_B57600, CBAUD, B57600 },
- { TARGET_CBAUD, TARGET_B115200, CBAUD, B115200 },
- { TARGET_CBAUD, TARGET_B230400, CBAUD, B230400 },
- { TARGET_CBAUD, TARGET_B460800, CBAUD, B460800 },
- { TARGET_CSIZE, TARGET_CS5, CSIZE, CS5 },
- { TARGET_CSIZE, TARGET_CS6, CSIZE, CS6 },
- { TARGET_CSIZE, TARGET_CS7, CSIZE, CS7 },
- { TARGET_CSIZE, TARGET_CS8, CSIZE, CS8 },
- { TARGET_CSTOPB, TARGET_CSTOPB, CSTOPB, CSTOPB },
- { TARGET_CREAD, TARGET_CREAD, CREAD, CREAD },
- { TARGET_PARENB, TARGET_PARENB, PARENB, PARENB },
- { TARGET_PARODD, TARGET_PARODD, PARODD, PARODD },
- { TARGET_HUPCL, TARGET_HUPCL, HUPCL, HUPCL },
- { TARGET_CLOCAL, TARGET_CLOCAL, CLOCAL, CLOCAL },
- { TARGET_CRTSCTS, TARGET_CRTSCTS, CRTSCTS, CRTSCTS },
- { 0, 0, 0, 0 }
-};
-
-bitmask_transtbl lflag_tbl[] = {
- { TARGET_ISIG, TARGET_ISIG, ISIG, ISIG },
- { TARGET_ICANON, TARGET_ICANON, ICANON, ICANON },
- { TARGET_XCASE, TARGET_XCASE, XCASE, XCASE },
- { TARGET_ECHO, TARGET_ECHO, ECHO, ECHO },
- { TARGET_ECHOE, TARGET_ECHOE, ECHOE, ECHOE },
- { TARGET_ECHOK, TARGET_ECHOK, ECHOK, ECHOK },
- { TARGET_ECHONL, TARGET_ECHONL, ECHONL, ECHONL },
- { TARGET_NOFLSH, TARGET_NOFLSH, NOFLSH, NOFLSH },
- { TARGET_TOSTOP, TARGET_TOSTOP, TOSTOP, TOSTOP },
- { TARGET_ECHOCTL, TARGET_ECHOCTL, ECHOCTL, ECHOCTL },
- { TARGET_ECHOPRT, TARGET_ECHOPRT, ECHOPRT, ECHOPRT },
- { TARGET_ECHOKE, TARGET_ECHOKE, ECHOKE, ECHOKE },
- { TARGET_FLUSHO, TARGET_FLUSHO, FLUSHO, FLUSHO },
- { TARGET_PENDIN, TARGET_PENDIN, PENDIN, PENDIN },
- { TARGET_IEXTEN, TARGET_IEXTEN, IEXTEN, IEXTEN },
- { 0, 0, 0, 0 }
-};
-
-static void target_to_host_termios (void *dst, const void *src)
-{
- struct host_termios *host = dst;
- const struct target_termios *target = src;
-
- host->c_iflag =
- target_to_host_bitmask(tswap32(target->c_iflag), iflag_tbl);
- host->c_oflag =
- target_to_host_bitmask(tswap32(target->c_oflag), oflag_tbl);
- host->c_cflag =
- target_to_host_bitmask(tswap32(target->c_cflag), cflag_tbl);
- host->c_lflag =
- target_to_host_bitmask(tswap32(target->c_lflag), lflag_tbl);
- host->c_line = target->c_line;
-
- host->c_cc[VINTR] = target->c_cc[TARGET_VINTR];
- host->c_cc[VQUIT] = target->c_cc[TARGET_VQUIT];
- host->c_cc[VERASE] = target->c_cc[TARGET_VERASE];
- host->c_cc[VKILL] = target->c_cc[TARGET_VKILL];
- host->c_cc[VEOF] = target->c_cc[TARGET_VEOF];
- host->c_cc[VTIME] = target->c_cc[TARGET_VTIME];
- host->c_cc[VMIN] = target->c_cc[TARGET_VMIN];
- host->c_cc[VSWTC] = target->c_cc[TARGET_VSWTC];
- host->c_cc[VSTART] = target->c_cc[TARGET_VSTART];
- host->c_cc[VSTOP] = target->c_cc[TARGET_VSTOP];
- host->c_cc[VSUSP] = target->c_cc[TARGET_VSUSP];
- host->c_cc[VEOL] = target->c_cc[TARGET_VEOL];
- host->c_cc[VREPRINT] = target->c_cc[TARGET_VREPRINT];
- host->c_cc[VDISCARD] = target->c_cc[TARGET_VDISCARD];
- host->c_cc[VWERASE] = target->c_cc[TARGET_VWERASE];
- host->c_cc[VLNEXT] = target->c_cc[TARGET_VLNEXT];
- host->c_cc[VEOL2] = target->c_cc[TARGET_VEOL2];
-}
-
-static void host_to_target_termios (void *dst, const void *src)
-{
- struct target_termios *target = dst;
- const struct host_termios *host = src;
-
- target->c_iflag =
- tswap32(host_to_target_bitmask(host->c_iflag, iflag_tbl));
- target->c_oflag =
- tswap32(host_to_target_bitmask(host->c_oflag, oflag_tbl));
- target->c_cflag =
- tswap32(host_to_target_bitmask(host->c_cflag, cflag_tbl));
- target->c_lflag =
- tswap32(host_to_target_bitmask(host->c_lflag, lflag_tbl));
- target->c_line = host->c_line;
-
- target->c_cc[TARGET_VINTR] = host->c_cc[VINTR];
- target->c_cc[TARGET_VQUIT] = host->c_cc[VQUIT];
- target->c_cc[TARGET_VERASE] = host->c_cc[VERASE];
- target->c_cc[TARGET_VKILL] = host->c_cc[VKILL];
- target->c_cc[TARGET_VEOF] = host->c_cc[VEOF];
- target->c_cc[TARGET_VTIME] = host->c_cc[VTIME];
- target->c_cc[TARGET_VMIN] = host->c_cc[VMIN];
- target->c_cc[TARGET_VSWTC] = host->c_cc[VSWTC];
- target->c_cc[TARGET_VSTART] = host->c_cc[VSTART];
- target->c_cc[TARGET_VSTOP] = host->c_cc[VSTOP];
- target->c_cc[TARGET_VSUSP] = host->c_cc[VSUSP];
- target->c_cc[TARGET_VEOL] = host->c_cc[VEOL];
- target->c_cc[TARGET_VREPRINT] = host->c_cc[VREPRINT];
- target->c_cc[TARGET_VDISCARD] = host->c_cc[VDISCARD];
- target->c_cc[TARGET_VWERASE] = host->c_cc[VWERASE];
- target->c_cc[TARGET_VLNEXT] = host->c_cc[VLNEXT];
- target->c_cc[TARGET_VEOL2] = host->c_cc[VEOL2];
-}
-
-StructEntry struct_termios_def = {
- .convert = { host_to_target_termios, target_to_host_termios },
- .size = { sizeof(struct target_termios), sizeof(struct host_termios) },
- .align = { __alignof__(struct target_termios), __alignof__(struct host_termios) },
-};
-
-static bitmask_transtbl mmap_flags_tbl[] = {
- { TARGET_MAP_SHARED, TARGET_MAP_SHARED, MAP_SHARED, MAP_SHARED },
- { TARGET_MAP_PRIVATE, TARGET_MAP_PRIVATE, MAP_PRIVATE, MAP_PRIVATE },
- { TARGET_MAP_FIXED, TARGET_MAP_FIXED, MAP_FIXED, MAP_FIXED },
- { TARGET_MAP_ANONYMOUS, TARGET_MAP_ANONYMOUS, MAP_ANONYMOUS, MAP_ANONYMOUS },
- { TARGET_MAP_GROWSDOWN, TARGET_MAP_GROWSDOWN, MAP_GROWSDOWN, MAP_GROWSDOWN },
- { TARGET_MAP_DENYWRITE, TARGET_MAP_DENYWRITE, MAP_DENYWRITE, MAP_DENYWRITE },
- { TARGET_MAP_EXECUTABLE, TARGET_MAP_EXECUTABLE, MAP_EXECUTABLE, MAP_EXECUTABLE },
- { TARGET_MAP_LOCKED, TARGET_MAP_LOCKED, MAP_LOCKED, MAP_LOCKED },
- { 0, 0, 0, 0 }
-};
-
-static bitmask_transtbl fcntl_flags_tbl[] = {
- { TARGET_O_ACCMODE, TARGET_O_WRONLY, O_ACCMODE, O_WRONLY, },
- { TARGET_O_ACCMODE, TARGET_O_RDWR, O_ACCMODE, O_RDWR, },
- { TARGET_O_CREAT, TARGET_O_CREAT, O_CREAT, O_CREAT, },
- { TARGET_O_EXCL, TARGET_O_EXCL, O_EXCL, O_EXCL, },
- { TARGET_O_NOCTTY, TARGET_O_NOCTTY, O_NOCTTY, O_NOCTTY, },
- { TARGET_O_TRUNC, TARGET_O_TRUNC, O_TRUNC, O_TRUNC, },
- { TARGET_O_APPEND, TARGET_O_APPEND, O_APPEND, O_APPEND, },
- { TARGET_O_NONBLOCK, TARGET_O_NONBLOCK, O_NONBLOCK, O_NONBLOCK, },
- { TARGET_O_SYNC, TARGET_O_SYNC, O_SYNC, O_SYNC, },
- { TARGET_FASYNC, TARGET_FASYNC, FASYNC, FASYNC, },
- { TARGET_O_DIRECTORY, TARGET_O_DIRECTORY, O_DIRECTORY, O_DIRECTORY, },
- { TARGET_O_NOFOLLOW, TARGET_O_NOFOLLOW, O_NOFOLLOW, O_NOFOLLOW, },
- { TARGET_O_LARGEFILE, TARGET_O_LARGEFILE, O_LARGEFILE, O_LARGEFILE, },
-#if defined(O_DIRECT)
- { TARGET_O_DIRECT, TARGET_O_DIRECT, O_DIRECT, O_DIRECT, },
-#endif
- { 0, 0, 0, 0 }
-};
-
-#if defined(TARGET_I386)
-
-/* NOTE: there is really one LDT for all the threads */
-uint8_t *ldt_table;
-
-static int read_ldt(target_ulong ptr, unsigned long bytecount)
-{
- int size;
- void *p;
-
- if (!ldt_table)
- return 0;
- size = TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE;
- if (size > bytecount)
- size = bytecount;
- p = lock_user(ptr, size, 0);
- /* ??? Shoudl this by byteswapped? */
- memcpy(p, ldt_table, size);
- unlock_user(p, ptr, size);
- return size;
-}
-
-/* XXX: add locking support */
-static int write_ldt(CPUX86State *env,
- target_ulong ptr, unsigned long bytecount, int oldmode)
-{
- struct target_modify_ldt_ldt_s ldt_info;
- struct target_modify_ldt_ldt_s *target_ldt_info;
- int seg_32bit, contents, read_exec_only, limit_in_pages;
- int seg_not_present, useable;
- uint32_t *lp, entry_1, entry_2;
-
- if (bytecount != sizeof(ldt_info))
- return -EINVAL;
- lock_user_struct(target_ldt_info, ptr, 1);
- ldt_info.entry_number = tswap32(target_ldt_info->entry_number);
- ldt_info.base_addr = tswapl(target_ldt_info->base_addr);
- ldt_info.limit = tswap32(target_ldt_info->limit);
- ldt_info.flags = tswap32(target_ldt_info->flags);
- unlock_user_struct(target_ldt_info, ptr, 0);
-
- if (ldt_info.entry_number >= TARGET_LDT_ENTRIES)
- return -EINVAL;
- seg_32bit = ldt_info.flags & 1;
- contents = (ldt_info.flags >> 1) & 3;
- read_exec_only = (ldt_info.flags >> 3) & 1;
- limit_in_pages = (ldt_info.flags >> 4) & 1;
- seg_not_present = (ldt_info.flags >> 5) & 1;
- useable = (ldt_info.flags >> 6) & 1;
-
- if (contents == 3) {
- if (oldmode)
- return -EINVAL;
- if (seg_not_present == 0)
- return -EINVAL;
- }
- /* allocate the LDT */
- if (!ldt_table) {
- ldt_table = malloc(TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
- if (!ldt_table)
- return -ENOMEM;
- memset(ldt_table, 0, TARGET_LDT_ENTRIES * TARGET_LDT_ENTRY_SIZE);
- env->ldt.base = h2g(ldt_table);
- env->ldt.limit = 0xffff;
- }
-
- /* NOTE: same code as Linux kernel */
- /* Allow LDTs to be cleared by the user. */
- if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
- if (oldmode ||
- (contents == 0 &&
- read_exec_only == 1 &&
- seg_32bit == 0 &&
- limit_in_pages == 0 &&
- seg_not_present == 1 &&
- useable == 0 )) {
- entry_1 = 0;
- entry_2 = 0;
- goto install;
- }
- }
-
- entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
- (ldt_info.limit & 0x0ffff);
- entry_2 = (ldt_info.base_addr & 0xff000000) |
- ((ldt_info.base_addr & 0x00ff0000) >> 16) |
- (ldt_info.limit & 0xf0000) |
- ((read_exec_only ^ 1) << 9) |
- (contents << 10) |
- ((seg_not_present ^ 1) << 15) |
- (seg_32bit << 22) |
- (limit_in_pages << 23) |
- 0x7000;
- if (!oldmode)
- entry_2 |= (useable << 20);
-
- /* Install the new entry ... */
-install:
- lp = (uint32_t *)(ldt_table + (ldt_info.entry_number << 3));
- lp[0] = tswap32(entry_1);
- lp[1] = tswap32(entry_2);
- return 0;
-}
-
-/* specific and weird i386 syscalls */
-int do_modify_ldt(CPUX86State *env, int func, target_ulong ptr, unsigned long bytecount)
-{
- int ret = -ENOSYS;
-
- switch (func) {
- case 0:
- ret = read_ldt(ptr, bytecount);
- break;
- case 1:
- ret = write_ldt(env, ptr, bytecount, 1);
- break;
- case 0x11:
- ret = write_ldt(env, ptr, bytecount, 0);
- break;
- }
- return ret;
-}
-
-#endif /* defined(TARGET_I386) */
-
-/* this stack is the equivalent of the kernel stack associated with a
- thread/process */
-#define NEW_STACK_SIZE 8192
-
-static int clone_func(void *arg)
-{
- CPUState *env = arg;
- cpu_loop(env);
- /* never exits */
- return 0;
-}
-
-int do_fork(CPUState *env, unsigned int flags, unsigned long newsp)
-{
- int ret;
- TaskState *ts;
- uint8_t *new_stack;
- CPUState *new_env;
-
- if (flags & CLONE_VM) {
- ts = malloc(sizeof(TaskState) + NEW_STACK_SIZE);
- memset(ts, 0, sizeof(TaskState));
- new_stack = ts->stack;
- ts->used = 1;
- /* add in task state list */
- 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));
-#if defined(TARGET_I386)
- if (!newsp)
- newsp = env->regs[R_ESP];
- new_env->regs[R_ESP] = newsp;
- new_env->regs[R_EAX] = 0;
-#elif defined(TARGET_ARM)
- if (!newsp)
- newsp = env->regs[13];
- new_env->regs[13] = newsp;
- new_env->regs[0] = 0;
-#elif defined(TARGET_SPARC)
- if (!newsp)
- newsp = env->regwptr[22];
- new_env->regwptr[22] = newsp;
- new_env->regwptr[0] = 0;
- /* XXXXX */
- printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
-#elif defined(TARGET_MIPS)
- printf ("HELPME: %s:%d\n", __FILE__, __LINE__);
-#elif defined(TARGET_PPC)
- if (!newsp)
- newsp = env->gpr[1];
- new_env->gpr[1] = newsp;
- {
- int i;
- for (i = 7; i < 32; i++)
- new_env->gpr[i] = 0;
- }
-#elif defined(TARGET_SH4)
- if (!newsp)
- newsp = env->gregs[15];
- new_env->gregs[15] = newsp;
- /* XXXXX */
-#else
-#error unsupported target CPU
-#endif
- new_env->opaque = ts;
-#ifdef __ia64__
- ret = __clone2(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
-#else
- ret = clone(clone_func, new_stack + NEW_STACK_SIZE, flags, new_env);
-#endif
- } else {
- /* if no CLONE_VM, we consider it is a fork */
- if ((flags & ~CSIGNAL) != 0)
- return -EINVAL;
- ret = fork();
- }
- return ret;
-}
-
-static long do_fcntl(int fd, int cmd, target_ulong arg)
-{
- struct flock fl;
- struct target_flock *target_fl;
- long ret;
-
- switch(cmd) {
- case TARGET_F_GETLK:
- ret = fcntl(fd, cmd, &fl);
- if (ret == 0) {
- lock_user_struct(target_fl, arg, 0);
- target_fl->l_type = tswap16(fl.l_type);
- target_fl->l_whence = tswap16(fl.l_whence);
- target_fl->l_start = tswapl(fl.l_start);
- target_fl->l_len = tswapl(fl.l_len);
- target_fl->l_pid = tswapl(fl.l_pid);
- unlock_user_struct(target_fl, arg, 1);
- }
- break;
-
- case TARGET_F_SETLK:
- case TARGET_F_SETLKW:
- 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);
- break;
-
- case TARGET_F_GETLK64:
- case TARGET_F_SETLK64:
- case TARGET_F_SETLKW64:
- ret = -1;
- errno = EINVAL;
- break;
-
- case F_GETFL:
- ret = fcntl(fd, cmd, arg);
- ret = host_to_target_bitmask(ret, fcntl_flags_tbl);
- break;
-
- case F_SETFL:
- ret = fcntl(fd, cmd, target_to_host_bitmask(arg, fcntl_flags_tbl));
- break;
-
- default:
- ret = fcntl(fd, cmd, arg);
- break;
- }
- return ret;
-}
-
-#ifdef USE_UID16
-
-static inline int high2lowuid(int uid)
-{
- if (uid > 65535)
- return 65534;
- else
- return uid;
-}
-
-static inline int high2lowgid(int gid)
-{
- if (gid > 65535)
- return 65534;
- else
- return gid;
-}
-
-static inline int low2highuid(int uid)
-{
- if ((int16_t)uid == -1)
- return -1;
- else
- return uid;
-}
-
-static inline int low2highgid(int gid)
-{
- if ((int16_t)gid == -1)
- return -1;
- else
- return gid;
-}
-
-#endif /* USE_UID16 */
-
-void syscall_init(void)
-{
- IOCTLEntry *ie;
- const argtype *arg_type;
- int size;
-
-#define STRUCT(name, list...) thunk_register_struct(STRUCT_ ## name, #name, struct_ ## name ## _def);
-#define STRUCT_SPECIAL(name) thunk_register_struct_direct(STRUCT_ ## name, #name, &struct_ ## name ## _def);
-#include "syscall_types.h"
-#undef STRUCT
-#undef STRUCT_SPECIAL
-
- /* we patch the ioctl size if necessary. We rely on the fact that
- no ioctl has all the bits at '1' in the size field */
- ie = ioctl_entries;
- while (ie->target_cmd != 0) {
- if (((ie->target_cmd >> TARGET_IOC_SIZESHIFT) & TARGET_IOC_SIZEMASK) ==
- TARGET_IOC_SIZEMASK) {
- arg_type = ie->arg_type;
- if (arg_type[0] != TYPE_PTR) {
- fprintf(stderr, "cannot patch size for ioctl 0x%x\n",
- ie->target_cmd);
- exit(1);
- }
- arg_type++;
- size = thunk_type_size(arg_type, 0);
- ie->target_cmd = (ie->target_cmd &
- ~(TARGET_IOC_SIZEMASK << TARGET_IOC_SIZESHIFT)) |
- (size << TARGET_IOC_SIZESHIFT);
- }
- /* automatic consistency check if same arch */
-#if defined(__i386__) && defined(TARGET_I386)
- if (ie->target_cmd != ie->host_cmd) {
- fprintf(stderr, "ERROR: ioctl: target=0x%x host=0x%x\n",
- ie->target_cmd, ie->host_cmd);
- }
-#endif
- ie++;
- }
-}
-
-static inline uint64_t target_offset64(uint32_t word0, uint32_t word1)
-{
-#ifdef TARGET_WORDS_BIG_ENDIAN
- return ((uint64_t)word0 << 32) | word1;
-#else
- return ((uint64_t)word1 << 32) | word0;
-#endif
-}
-
-#ifdef TARGET_NR_truncate64
-static inline long target_truncate64(void *cpu_env, const char *arg1,
- long arg2, long arg3, long arg4)
-{
-#ifdef TARGET_ARM
- if (((CPUARMState *)cpu_env)->eabi)
- {
- arg2 = arg3;
- arg3 = arg4;
- }
-#endif
- return get_errno(truncate64(arg1, target_offset64(arg2, arg3)));
-}
-#endif
-
-#ifdef TARGET_NR_ftruncate64
-static inline long target_ftruncate64(void *cpu_env, long arg1, long arg2,
- long arg3, long arg4)
-{
-#ifdef TARGET_ARM
- if (((CPUARMState *)cpu_env)->eabi)
- {
- arg2 = arg3;
- arg3 = arg4;
- }
-#endif
- return get_errno(ftruncate64(arg1, target_offset64(arg2, arg3)));
-}
-#endif
-
-static inline void target_to_host_timespec(struct timespec *host_ts,
- target_ulong target_addr)
-{
- struct target_timespec *target_ts;
-
- lock_user_struct(target_ts, target_addr, 1);
- host_ts->tv_sec = tswapl(target_ts->tv_sec);
- host_ts->tv_nsec = tswapl(target_ts->tv_nsec);
- unlock_user_struct(target_ts, target_addr, 0);
-}
-
-static inline void host_to_target_timespec(target_ulong target_addr,
- struct timespec *host_ts)
-{
- struct target_timespec *target_ts;
-
- lock_user_struct(target_ts, target_addr, 0);
- target_ts->tv_sec = tswapl(host_ts->tv_sec);
- target_ts->tv_nsec = tswapl(host_ts->tv_nsec);
- unlock_user_struct(target_ts, target_addr, 1);
-}
-
-long do_syscall(void *cpu_env, int num, long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6)
-{
- long ret;
- struct stat st;
- struct statfs stfs;
- void *p;
-
-#ifdef DEBUG
- gemu_log("syscall %d", num);
-#endif
- switch(num) {
- case TARGET_NR_exit:
-#ifdef HAVE_GPROF
- _mcleanup();
-#endif
- gdb_exit(cpu_env, arg1);
- /* XXX: should free thread stack and CPU env */
- _exit(arg1);
- ret = 0; /* avoid warning */
- break;
- case TARGET_NR_read:
- page_unprotect_range(arg2, arg3);
- p = lock_user(arg2, arg3, 0);
- ret = get_errno(read(arg1, p, arg3));
- unlock_user(p, arg2, ret);
- break;
- case TARGET_NR_write:
- p = lock_user(arg2, arg3, 1);
- ret = get_errno(write(arg1, p, arg3));
- unlock_user(p, arg2, 0);
- break;
- case TARGET_NR_open:
- p = lock_user_string(arg1);
- ret = get_errno(open(path(p),
- target_to_host_bitmask(arg2, fcntl_flags_tbl),
- arg3));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_close:
- ret = get_errno(close(arg1));
- break;
- case TARGET_NR_brk:
- ret = do_brk(arg1);
- break;
- case TARGET_NR_fork:
- ret = get_errno(do_fork(cpu_env, SIGCHLD, 0));
- break;
- case TARGET_NR_waitpid:
- {
- int status;
- ret = get_errno(waitpid(arg1, &status, arg3));
- if (!is_error(ret) && arg2)
- tput32(arg2, status);
- }
- break;
- case TARGET_NR_creat:
- p = lock_user_string(arg1);
- ret = get_errno(creat(p, arg2));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_link:
- {
- void * p2;
- p = lock_user_string(arg1);
- p2 = lock_user_string(arg2);
- ret = get_errno(link(p, p2));
- unlock_user(p2, arg2, 0);
- unlock_user(p, arg1, 0);
- }
- break;
- case TARGET_NR_unlink:
- p = lock_user_string(arg1);
- ret = get_errno(unlink(p));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_execve:
- {
- char **argp, **envp;
- int argc, envc;
- target_ulong gp;
- target_ulong guest_argp;
- target_ulong guest_envp;
- target_ulong addr;
- char **q;
-
- argc = 0;
- guest_argp = arg2;
- for (gp = guest_argp; tgetl(gp); gp++)
- argc++;
- envc = 0;
- guest_envp = arg3;
- for (gp = guest_envp; tgetl(gp); gp++)
- envc++;
-
- argp = alloca((argc + 1) * sizeof(void *));
- envp = alloca((envc + 1) * sizeof(void *));
-
- for (gp = guest_argp, q = argp; ;
- gp += sizeof(target_ulong), q++) {
- addr = tgetl(gp);
- if (!addr)
- break;
- *q = lock_user_string(addr);
- }
- *q = NULL;
-
- for (gp = guest_envp, q = envp; ;
- gp += sizeof(target_ulong), q++) {
- addr = tgetl(gp);
- if (!addr)
- break;
- *q = lock_user_string(addr);
- }
- *q = NULL;
-
- p = lock_user_string(arg1);
- ret = get_errno(execve(p, argp, envp));
- unlock_user(p, arg1, 0);
-
- for (gp = guest_argp, q = argp; *q;
- gp += sizeof(target_ulong), q++) {
- addr = tgetl(gp);
- unlock_user(*q, addr, 0);
- }
- for (gp = guest_envp, q = envp; *q;
- gp += sizeof(target_ulong), q++) {
- addr = tgetl(gp);
- unlock_user(*q, addr, 0);
- }
- }
- break;
- case TARGET_NR_chdir:
- p = lock_user_string(arg1);
- ret = get_errno(chdir(p));
- unlock_user(p, arg1, 0);
- break;
-#ifdef TARGET_NR_time
- case TARGET_NR_time:
- {
- time_t host_time;
- ret = get_errno(time(&host_time));
- if (!is_error(ret) && arg1)
- tputl(arg1, host_time);
- }
- break;
-#endif
- case TARGET_NR_mknod:
- p = lock_user_string(arg1);
- ret = get_errno(mknod(p, arg2, arg3));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_chmod:
- p = lock_user_string(arg1);
- ret = get_errno(chmod(p, arg2));
- unlock_user(p, arg1, 0);
- break;
-#ifdef TARGET_NR_break
- case TARGET_NR_break:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_oldstat
- case TARGET_NR_oldstat:
- goto unimplemented;
-#endif
- case TARGET_NR_lseek:
- ret = get_errno(lseek(arg1, arg2, arg3));
- break;
- case TARGET_NR_getpid:
- ret = get_errno(getpid());
- break;
- case TARGET_NR_mount:
- /* need to look at the data field */
- goto unimplemented;
- case TARGET_NR_umount:
- p = lock_user_string(arg1);
- ret = get_errno(umount(p));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_stime:
- {
- time_t host_time;
- host_time = tgetl(arg1);
- ret = get_errno(stime(&host_time));
- }
- break;
- case TARGET_NR_ptrace:
- goto unimplemented;
- case TARGET_NR_alarm:
- ret = alarm(arg1);
- break;
-#ifdef TARGET_NR_oldfstat
- case TARGET_NR_oldfstat:
- goto unimplemented;
-#endif
- case TARGET_NR_pause:
- ret = get_errno(pause());
- break;
- case TARGET_NR_utime:
- {
- struct utimbuf tbuf, *host_tbuf;
- struct target_utimbuf *target_tbuf;
- if (arg2) {
- lock_user_struct(target_tbuf, arg2, 1);
- tbuf.actime = tswapl(target_tbuf->actime);
- tbuf.modtime = tswapl(target_tbuf->modtime);
- unlock_user_struct(target_tbuf, arg2, 0);
- host_tbuf = &tbuf;
- } else {
- host_tbuf = NULL;
- }
- p = lock_user_string(arg1);
- ret = get_errno(utime(p, host_tbuf));
- unlock_user(p, arg1, 0);
- }
- break;
- case TARGET_NR_utimes:
- {
- struct timeval *tvp, tv[2];
- if (arg2) {
- target_to_host_timeval(&tv[0], arg2);
- target_to_host_timeval(&tv[1],
- arg2 + sizeof (struct target_timeval));
- tvp = tv;
- } else {
- tvp = NULL;
- }
- p = lock_user_string(arg1);
- ret = get_errno(utimes(p, tvp));
- unlock_user(p, arg1, 0);
- }
- break;
-#ifdef TARGET_NR_stty
- case TARGET_NR_stty:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_gtty
- case TARGET_NR_gtty:
- goto unimplemented;
-#endif
- case TARGET_NR_access:
- p = lock_user_string(arg1);
- ret = get_errno(access(p, arg2));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_nice:
- ret = get_errno(nice(arg1));
- break;
-#ifdef TARGET_NR_ftime
- case TARGET_NR_ftime:
- goto unimplemented;
-#endif
- case TARGET_NR_sync:
- sync();
- ret = 0;
- break;
- case TARGET_NR_kill:
- ret = get_errno(kill(arg1, arg2));
- break;
- case TARGET_NR_rename:
- {
- void *p2;
- p = lock_user_string(arg1);
- p2 = lock_user_string(arg2);
- ret = get_errno(rename(p, p2));
- unlock_user(p2, arg2, 0);
- unlock_user(p, arg1, 0);
- }
- break;
- case TARGET_NR_mkdir:
- p = lock_user_string(arg1);
- ret = get_errno(mkdir(p, arg2));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_rmdir:
- p = lock_user_string(arg1);
- ret = get_errno(rmdir(p));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_dup:
- ret = get_errno(dup(arg1));
- break;
- case TARGET_NR_pipe:
- {
- int host_pipe[2];
- ret = get_errno(pipe(host_pipe));
- if (!is_error(ret)) {
- tput32(arg1, host_pipe[0]);
- tput32(arg1 + 4, host_pipe[1]);
- }
- }
- break;
- case TARGET_NR_times:
- {
- struct target_tms *tmsp;
- struct tms tms;
- ret = get_errno(times(&tms));
- if (arg1) {
- tmsp = lock_user(arg1, sizeof(struct target_tms), 0);
- tmsp->tms_utime = tswapl(host_to_target_clock_t(tms.tms_utime));
- tmsp->tms_stime = tswapl(host_to_target_clock_t(tms.tms_stime));
- tmsp->tms_cutime = tswapl(host_to_target_clock_t(tms.tms_cutime));
- tmsp->tms_cstime = tswapl(host_to_target_clock_t(tms.tms_cstime));
- }
- if (!is_error(ret))
- ret = host_to_target_clock_t(ret);
- }
- break;
-#ifdef TARGET_NR_prof
- case TARGET_NR_prof:
- goto unimplemented;
-#endif
- case TARGET_NR_signal:
- goto unimplemented;
-
- case TARGET_NR_acct:
- p = lock_user_string(arg1);
- ret = get_errno(acct(path(p)));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_umount2:
- p = lock_user_string(arg1);
- ret = get_errno(umount2(p, arg2));
- unlock_user(p, arg1, 0);
- break;
-#ifdef TARGET_NR_lock
- case TARGET_NR_lock:
- goto unimplemented;
-#endif
- case TARGET_NR_ioctl:
- ret = do_ioctl(arg1, arg2, arg3);
- break;
- case TARGET_NR_fcntl:
- ret = get_errno(do_fcntl(arg1, arg2, arg3));
- break;
-#ifdef TARGET_NR_mpx
- case TARGET_NR_mpx:
- goto unimplemented;
-#endif
- case TARGET_NR_setpgid:
- ret = get_errno(setpgid(arg1, arg2));
- break;
-#ifdef TARGET_NR_ulimit
- case TARGET_NR_ulimit:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_oldolduname
- case TARGET_NR_oldolduname:
- goto unimplemented;
-#endif
- case TARGET_NR_umask:
- ret = get_errno(umask(arg1));
- break;
- case TARGET_NR_chroot:
- p = lock_user_string(arg1);
- ret = get_errno(chroot(p));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_ustat:
- goto unimplemented;
- case TARGET_NR_dup2:
- ret = get_errno(dup2(arg1, arg2));
- break;
- case TARGET_NR_getppid:
- ret = get_errno(getppid());
- break;
- case TARGET_NR_getpgrp:
- ret = get_errno(getpgrp());
- break;
- case TARGET_NR_setsid:
- ret = get_errno(setsid());
- break;
- case TARGET_NR_sigaction:
- {
- #if !defined(TARGET_MIPS)
- struct target_old_sigaction *old_act;
- struct target_sigaction act, oact, *pact;
- if (arg2) {
- lock_user_struct(old_act, arg2, 1);
- act._sa_handler = old_act->_sa_handler;
- target_siginitset(&act.sa_mask, old_act->sa_mask);
- act.sa_flags = old_act->sa_flags;
- act.sa_restorer = old_act->sa_restorer;
- unlock_user_struct(old_act, arg2, 0);
- pact = &act;
- } else {
- pact = NULL;
- }
- ret = get_errno(do_sigaction(arg1, pact, &oact));
- if (!is_error(ret) && arg3) {
- lock_user_struct(old_act, arg3, 0);
- old_act->_sa_handler = oact._sa_handler;
- old_act->sa_mask = oact.sa_mask.sig[0];
- old_act->sa_flags = oact.sa_flags;
- old_act->sa_restorer = oact.sa_restorer;
- unlock_user_struct(old_act, arg3, 1);
- }
- #else
- struct target_sigaction act, oact, *pact, *old_act;
-
- if (arg2) {
- lock_user_struct(old_act, arg2, 1);
- act._sa_handler = old_act->_sa_handler;
- target_siginitset(&act.sa_mask, old_act->sa_mask.sig[0]);
- act.sa_flags = old_act->sa_flags;
- unlock_user_struct(old_act, arg2, 0);
- pact = &act;
- } else {
- pact = NULL;
- }
-
- ret = get_errno(do_sigaction(arg1, pact, &oact));
-
- if (!is_error(ret) && arg3) {
- lock_user_struct(old_act, arg3, 0);
- old_act->_sa_handler = oact._sa_handler;
- old_act->sa_flags = oact.sa_flags;
- old_act->sa_mask.sig[0] = oact.sa_mask.sig[0];
- old_act->sa_mask.sig[1] = 0;
- old_act->sa_mask.sig[2] = 0;
- old_act->sa_mask.sig[3] = 0;
- unlock_user_struct(old_act, arg3, 1);
- }
- #endif
- }
- break;
- case TARGET_NR_rt_sigaction:
- {
- struct target_sigaction *act;
- struct target_sigaction *oact;
-
- if (arg2)
- lock_user_struct(act, arg2, 1);
- else
- act = NULL;
- if (arg3)
- lock_user_struct(oact, arg3, 0);
- else
- oact = NULL;
- ret = get_errno(do_sigaction(arg1, act, oact));
- if (arg2)
- unlock_user_struct(act, arg2, 0);
- if (arg3)
- unlock_user_struct(oact, arg3, 1);
- }
- break;
- case TARGET_NR_sgetmask:
- {
- sigset_t cur_set;
- target_ulong target_set;
- sigprocmask(0, NULL, &cur_set);
- host_to_target_old_sigset(&target_set, &cur_set);
- ret = target_set;
- }
- break;
- case TARGET_NR_ssetmask:
- {
- sigset_t set, oset, cur_set;
- target_ulong target_set = arg1;
- sigprocmask(0, NULL, &cur_set);
- target_to_host_old_sigset(&set, &target_set);
- sigorset(&set, &set, &cur_set);
- sigprocmask(SIG_SETMASK, &set, &oset);
- host_to_target_old_sigset(&target_set, &oset);
- ret = target_set;
- }
- break;
- case TARGET_NR_sigprocmask:
- {
- int how = arg1;
- sigset_t set, oldset, *set_ptr;
-
- if (arg2) {
- switch(how) {
- case TARGET_SIG_BLOCK:
- how = SIG_BLOCK;
- break;
- case TARGET_SIG_UNBLOCK:
- how = SIG_UNBLOCK;
- break;
- case TARGET_SIG_SETMASK:
- how = SIG_SETMASK;
- break;
- default:
- ret = -EINVAL;
- goto fail;
- }
- p = lock_user(arg2, sizeof(target_sigset_t), 1);
- target_to_host_old_sigset(&set, p);
- unlock_user(p, arg2, 0);
- set_ptr = &set;
- } else {
- how = 0;
- set_ptr = NULL;
- }
- ret = get_errno(sigprocmask(arg1, set_ptr, &oldset));
- if (!is_error(ret) && arg3) {
- p = lock_user(arg3, sizeof(target_sigset_t), 0);
- host_to_target_old_sigset(p, &oldset);
- unlock_user(p, arg3, sizeof(target_sigset_t));
- }
- }
- break;
- case TARGET_NR_rt_sigprocmask:
- {
- int how = arg1;
- sigset_t set, oldset, *set_ptr;
-
- if (arg2) {
- switch(how) {
- case TARGET_SIG_BLOCK:
- how = SIG_BLOCK;
- break;
- case TARGET_SIG_UNBLOCK:
- how = SIG_UNBLOCK;
- break;
- case TARGET_SIG_SETMASK:
- how = SIG_SETMASK;
- break;
- default:
- ret = -EINVAL;
- goto fail;
- }
- p = lock_user(arg2, sizeof(target_sigset_t), 1);
- target_to_host_sigset(&set, p);
- unlock_user(p, arg2, 0);
- set_ptr = &set;
- } else {
- how = 0;
- set_ptr = NULL;
- }
- ret = get_errno(sigprocmask(how, set_ptr, &oldset));
- if (!is_error(ret) && arg3) {
- p = lock_user(arg3, sizeof(target_sigset_t), 0);
- host_to_target_sigset(p, &oldset);
- unlock_user(p, arg3, sizeof(target_sigset_t));
- }
- }
- break;
- case TARGET_NR_sigpending:
- {
- sigset_t set;
- ret = get_errno(sigpending(&set));
- if (!is_error(ret)) {
- p = lock_user(arg1, sizeof(target_sigset_t), 0);
- host_to_target_old_sigset(p, &set);
- unlock_user(p, arg1, sizeof(target_sigset_t));
- }
- }
- break;
- case TARGET_NR_rt_sigpending:
- {
- sigset_t set;
- ret = get_errno(sigpending(&set));
- if (!is_error(ret)) {
- p = lock_user(arg1, sizeof(target_sigset_t), 0);
- host_to_target_sigset(p, &set);
- unlock_user(p, arg1, sizeof(target_sigset_t));
- }
- }
- break;
- case TARGET_NR_sigsuspend:
- {
- sigset_t set;
- p = lock_user(arg1, sizeof(target_sigset_t), 1);
- target_to_host_old_sigset(&set, p);
- unlock_user(p, arg1, 0);
- ret = get_errno(sigsuspend(&set));
- }
- break;
- case TARGET_NR_rt_sigsuspend:
- {
- sigset_t set;
- p = lock_user(arg1, sizeof(target_sigset_t), 1);
- target_to_host_sigset(&set, p);
- unlock_user(p, arg1, 0);
- ret = get_errno(sigsuspend(&set));
- }
- break;
- case TARGET_NR_rt_sigtimedwait:
- {
- sigset_t set;
- struct timespec uts, *puts;
- siginfo_t uinfo;
-
- p = lock_user(arg1, sizeof(target_sigset_t), 1);
- target_to_host_sigset(&set, p);
- unlock_user(p, arg1, 0);
- if (arg3) {
- puts = &uts;
- target_to_host_timespec(puts, arg3);
- } else {
- puts = NULL;
- }
- ret = get_errno(sigtimedwait(&set, &uinfo, puts));
- if (!is_error(ret) && arg2) {
- p = lock_user(arg2, sizeof(target_sigset_t), 0);
- host_to_target_siginfo(p, &uinfo);
- unlock_user(p, arg2, sizeof(target_sigset_t));
- }
- }
- break;
- case TARGET_NR_rt_sigqueueinfo:
- {
- siginfo_t uinfo;
- p = lock_user(arg3, sizeof(target_sigset_t), 1);
- target_to_host_siginfo(&uinfo, p);
- unlock_user(p, arg1, 0);
- ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
- }
- break;
- case TARGET_NR_sigreturn:
- /* NOTE: ret is eax, so not transcoding must be done */
- ret = do_sigreturn(cpu_env);
- break;
- case TARGET_NR_rt_sigreturn:
- /* NOTE: ret is eax, so not transcoding must be done */
- ret = do_rt_sigreturn(cpu_env);
- break;
- case TARGET_NR_sethostname:
- p = lock_user_string(arg1);
- ret = get_errno(sethostname(p, arg2));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_setrlimit:
- {
- /* XXX: convert resource ? */
- int resource = arg1;
- struct target_rlimit *target_rlim;
- struct rlimit rlim;
- lock_user_struct(target_rlim, arg2, 1);
- rlim.rlim_cur = tswapl(target_rlim->rlim_cur);
- rlim.rlim_max = tswapl(target_rlim->rlim_max);
- unlock_user_struct(target_rlim, arg2, 0);
- ret = get_errno(setrlimit(resource, &rlim));
- }
- break;
- case TARGET_NR_getrlimit:
- {
- /* XXX: convert resource ? */
- int resource = arg1;
- struct target_rlimit *target_rlim;
- struct rlimit rlim;
-
- ret = get_errno(getrlimit(resource, &rlim));
- if (!is_error(ret)) {
- lock_user_struct(target_rlim, arg2, 0);
- rlim.rlim_cur = tswapl(target_rlim->rlim_cur);
- rlim.rlim_max = tswapl(target_rlim->rlim_max);
- unlock_user_struct(target_rlim, arg2, 1);
- }
- }
- break;
- case TARGET_NR_getrusage:
- {
- struct rusage rusage;
- ret = get_errno(getrusage(arg1, &rusage));
- if (!is_error(ret)) {
- host_to_target_rusage(arg2, &rusage);
- }
- }
- break;
- case TARGET_NR_gettimeofday:
- {
- struct timeval tv;
- ret = get_errno(gettimeofday(&tv, NULL));
- if (!is_error(ret)) {
- host_to_target_timeval(arg1, &tv);
- }
- }
- break;
- case TARGET_NR_settimeofday:
- {
- struct timeval tv;
- target_to_host_timeval(&tv, arg1);
- ret = get_errno(settimeofday(&tv, NULL));
- }
- break;
-#ifdef TARGET_NR_select
- case TARGET_NR_select:
- {
- struct target_sel_arg_struct *sel;
- target_ulong inp, outp, exp, tvp;
- long nsel;
-
- lock_user_struct(sel, arg1, 1);
- nsel = tswapl(sel->n);
- inp = tswapl(sel->inp);
- outp = tswapl(sel->outp);
- exp = tswapl(sel->exp);
- tvp = tswapl(sel->tvp);
- unlock_user_struct(sel, arg1, 0);
- ret = do_select(nsel, inp, outp, exp, tvp);
- }
- break;
-#endif
- case TARGET_NR_symlink:
- {
- void *p2;
- p = lock_user_string(arg1);
- p2 = lock_user_string(arg2);
- ret = get_errno(symlink(p, p2));
- unlock_user(p2, arg2, 0);
- unlock_user(p, arg1, 0);
- }
- break;
-#ifdef TARGET_NR_oldlstat
- case TARGET_NR_oldlstat:
- goto unimplemented;
-#endif
- case TARGET_NR_readlink:
- {
- void *p2;
- p = lock_user_string(arg1);
- p2 = lock_user(arg2, arg3, 0);
- ret = get_errno(readlink(path(p), p2, arg3));
- unlock_user(p2, arg2, ret);
- unlock_user(p, arg1, 0);
- }
- break;
- case TARGET_NR_uselib:
- goto unimplemented;
- case TARGET_NR_swapon:
- p = lock_user_string(arg1);
- ret = get_errno(swapon(p, arg2));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_reboot:
- goto unimplemented;
- case TARGET_NR_readdir:
- goto unimplemented;
- case TARGET_NR_mmap:
-#if defined(TARGET_I386) || defined(TARGET_ARM)
- {
- target_ulong *v;
- target_ulong v1, v2, v3, v4, v5, v6;
- v = lock_user(arg1, 6 * sizeof(target_ulong), 1);
- v1 = tswapl(v[0]);
- v2 = tswapl(v[1]);
- v3 = tswapl(v[2]);
- v4 = tswapl(v[3]);
- v5 = tswapl(v[4]);
- v6 = tswapl(v[5]);
- unlock_user(v, arg1, 0);
- ret = get_errno(target_mmap(v1, v2, v3,
- target_to_host_bitmask(v4, mmap_flags_tbl),
- v5, v6));
- }
-#else
- ret = get_errno(target_mmap(arg1, arg2, arg3,
- target_to_host_bitmask(arg4, mmap_flags_tbl),
- arg5,
- arg6));
-#endif
- break;
-#ifdef TARGET_NR_mmap2
- case TARGET_NR_mmap2:
-#if defined(TARGET_SPARC)
-#define MMAP_SHIFT 12
-#else
-#define MMAP_SHIFT TARGET_PAGE_BITS
-#endif
- ret = get_errno(target_mmap(arg1, arg2, arg3,
- target_to_host_bitmask(arg4, mmap_flags_tbl),
- arg5,
- arg6 << MMAP_SHIFT));
- break;
-#endif
- case TARGET_NR_munmap:
- ret = get_errno(target_munmap(arg1, arg2));
- break;
- case TARGET_NR_mprotect:
- ret = get_errno(target_mprotect(arg1, arg2, arg3));
- break;
- case TARGET_NR_mremap:
- ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
- break;
- /* ??? msync/mlock/munlock are broken for softmmu. */
- case TARGET_NR_msync:
- ret = get_errno(msync(g2h(arg1), arg2, arg3));
- break;
- case TARGET_NR_mlock:
- ret = get_errno(mlock(g2h(arg1), arg2));
- break;
- case TARGET_NR_munlock:
- ret = get_errno(munlock(g2h(arg1), arg2));
- break;
- case TARGET_NR_mlockall:
- ret = get_errno(mlockall(arg1));
- break;
- case TARGET_NR_munlockall:
- ret = get_errno(munlockall());
- break;
- case TARGET_NR_truncate:
- p = lock_user_string(arg1);
- ret = get_errno(truncate(p, arg2));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_ftruncate:
- ret = get_errno(ftruncate(arg1, arg2));
- break;
- case TARGET_NR_fchmod:
- ret = get_errno(fchmod(arg1, arg2));
- break;
- case TARGET_NR_getpriority:
- ret = get_errno(getpriority(arg1, arg2));
- break;
- case TARGET_NR_setpriority:
- ret = get_errno(setpriority(arg1, arg2, arg3));
- break;
-#ifdef TARGET_NR_profil
- case TARGET_NR_profil:
- goto unimplemented;
-#endif
- case TARGET_NR_statfs:
- p = lock_user_string(arg1);
- ret = get_errno(statfs(path(p), &stfs));
- unlock_user(p, arg1, 0);
- convert_statfs:
- if (!is_error(ret)) {
- struct target_statfs *target_stfs;
-
- lock_user_struct(target_stfs, arg2, 0);
- /* ??? put_user is probably wrong. */
- put_user(stfs.f_type, &target_stfs->f_type);
- put_user(stfs.f_bsize, &target_stfs->f_bsize);
- put_user(stfs.f_blocks, &target_stfs->f_blocks);
- put_user(stfs.f_bfree, &target_stfs->f_bfree);
- put_user(stfs.f_bavail, &target_stfs->f_bavail);
- put_user(stfs.f_files, &target_stfs->f_files);
- put_user(stfs.f_ffree, &target_stfs->f_ffree);
- put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid);
- put_user(stfs.f_namelen, &target_stfs->f_namelen);
- unlock_user_struct(target_stfs, arg2, 1);
- }
- break;
- case TARGET_NR_fstatfs:
- ret = get_errno(fstatfs(arg1, &stfs));
- goto convert_statfs;
-#ifdef TARGET_NR_statfs64
- case TARGET_NR_statfs64:
- p = lock_user_string(arg1);
- ret = get_errno(statfs(path(p), &stfs));
- unlock_user(p, arg1, 0);
- convert_statfs64:
- if (!is_error(ret)) {
- struct target_statfs64 *target_stfs;
-
- lock_user_struct(target_stfs, arg3, 0);
- /* ??? put_user is probably wrong. */
- put_user(stfs.f_type, &target_stfs->f_type);
- put_user(stfs.f_bsize, &target_stfs->f_bsize);
- put_user(stfs.f_blocks, &target_stfs->f_blocks);
- put_user(stfs.f_bfree, &target_stfs->f_bfree);
- put_user(stfs.f_bavail, &target_stfs->f_bavail);
- put_user(stfs.f_files, &target_stfs->f_files);
- put_user(stfs.f_ffree, &target_stfs->f_ffree);
- put_user(stfs.f_fsid.__val[0], &target_stfs->f_fsid);
- put_user(stfs.f_namelen, &target_stfs->f_namelen);
- unlock_user_struct(target_stfs, arg3, 0);
- }
- break;
- case TARGET_NR_fstatfs64:
- ret = get_errno(fstatfs(arg1, &stfs));
- goto convert_statfs64;
-#endif
-#ifdef TARGET_NR_ioperm
- case TARGET_NR_ioperm:
- goto unimplemented;
-#endif
- case TARGET_NR_socketcall:
- ret = do_socketcall(arg1, arg2);
- break;
-
-#ifdef TARGET_NR_accept
- case TARGET_NR_accept:
- ret = do_socketcallwrapper(SOCKOP_accept, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
-#endif
-#ifdef TARGET_NR_bind
- case TARGET_NR_bind:
- ret = do_bind(arg1, arg2, arg3);
- break;
-#endif
-#ifdef TARGET_NR_connect
- case TARGET_NR_connect:
- ret = do_connect(arg1, arg2, arg3);
- break;
-#endif
-#ifdef TARGET_NR_getpeername
- case TARGET_NR_getpeername:
- ret = do_socketcallwrapper(SOCKOP_getpeername, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
-#endif
-#ifdef TARGET_NR_getsockname
- case TARGET_NR_getsockname:
- ret = do_socketcallwrapper(SOCKOP_getsockname, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
-#endif
-#ifdef TARGET_NR_getsockopt
- case TARGET_NR_getsockopt:
- ret = do_getsockopt(arg1, arg2, arg3, arg4, arg5);
- break;
-#endif
-#ifdef TARGET_NR_listen
- case TARGET_NR_listen:
- ret = do_socketcallwrapper(SOCKOP_listen, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
-#endif
-#ifdef TARGET_NR_recv
- case TARGET_NR_recv:
- ret = do_socketcallwrapper(SOCKOP_recv, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
-#endif
-#ifdef TARGET_NR_recvfrom
- case TARGET_NR_recvfrom:
- ret = do_socketcallwrapper(SOCKOP_recvfrom, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
-#endif
-#ifdef TARGET_NR_recvmsg
- case TARGET_NR_recvmsg:
- ret = do_sendrecvmsg(arg1, arg2, arg3, 0);
- break;
-#endif
-#ifdef TARGET_NR_send
- case TARGET_NR_send:
- ret = do_socketcallwrapper(SOCKOP_send, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
-#endif
-#ifdef TARGET_NR_sendmsg
- case TARGET_NR_sendmsg:
- ret = do_sendrecvmsg(arg1, arg2, arg3, 1);
- break;
-#endif
-#ifdef TARGET_NR_sendto
- case TARGET_NR_sendto:
- ret = do_socketcallwrapper(SOCKOP_sendto, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
-#endif
-#ifdef TARGET_NR_shutdown
- case TARGET_NR_shutdown:
- ret = do_socketcallwrapper(SOCKOP_shutdown, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
-#endif
-#ifdef TARGET_NR_socket
- case TARGET_NR_socket:
- ret = do_socket(arg1, arg2, arg3);
- break;
-#endif
-#ifdef TARGET_NR_socketpair
- case TARGET_NR_socketpair:
- ret = do_socketcallwrapper(SOCKOP_socketpair, arg1, arg2, arg3, arg4, arg5, arg6);
- break;
-#endif
-#ifdef TARGET_NR_setsockopt
- case TARGET_NR_setsockopt:
- ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
- break;
-#endif
-
- case TARGET_NR_syslog:
- goto unimplemented;
- case TARGET_NR_setitimer:
- {
- struct itimerval value, ovalue, *pvalue;
-
- if (arg2) {
- pvalue = &value;
- target_to_host_timeval(&pvalue->it_interval,
- arg2);
- target_to_host_timeval(&pvalue->it_value,
- arg2 + sizeof(struct target_timeval));
- } else {
- pvalue = NULL;
- }
- ret = get_errno(setitimer(arg1, pvalue, &ovalue));
- if (!is_error(ret) && arg3) {
- host_to_target_timeval(arg3,
- &ovalue.it_interval);
- host_to_target_timeval(arg3 + sizeof(struct target_timeval),
- &ovalue.it_value);
- }
- }
- break;
- case TARGET_NR_getitimer:
- {
- struct itimerval value;
-
- ret = get_errno(getitimer(arg1, &value));
- if (!is_error(ret) && arg2) {
- host_to_target_timeval(arg2,
- &value.it_interval);
- host_to_target_timeval(arg2 + sizeof(struct target_timeval),
- &value.it_value);
- }
- }
- break;
- case TARGET_NR_stat:
- p = lock_user_string(arg1);
- ret = get_errno(stat(path(p), &st));
- unlock_user(p, arg1, 0);
- goto do_stat;
- case TARGET_NR_lstat:
- p = lock_user_string(arg1);
- ret = get_errno(lstat(path(p), &st));
- unlock_user(p, arg1, 0);
- goto do_stat;
- case TARGET_NR_fstat:
- {
- ret = get_errno(fstat(arg1, &st));
- do_stat:
- if (!is_error(ret)) {
- struct target_stat *target_st;
-
- lock_user_struct(target_st, arg2, 0);
- target_st->st_dev = tswap16(st.st_dev);
- target_st->st_ino = tswapl(st.st_ino);
-#if defined(TARGET_PPC)
- target_st->st_mode = tswapl(st.st_mode); /* XXX: check this */
- target_st->st_uid = tswap32(st.st_uid);
- target_st->st_gid = tswap32(st.st_gid);
-#else
- target_st->st_mode = tswap16(st.st_mode);
- target_st->st_uid = tswap16(st.st_uid);
- target_st->st_gid = tswap16(st.st_gid);
-#endif
- target_st->st_nlink = tswap16(st.st_nlink);
- target_st->st_rdev = tswap16(st.st_rdev);
- target_st->st_size = tswapl(st.st_size);
- target_st->st_blksize = tswapl(st.st_blksize);
- target_st->st_blocks = tswapl(st.st_blocks);
- target_st->target_st_atime = tswapl(st.st_atime);
- target_st->target_st_mtime = tswapl(st.st_mtime);
- target_st->target_st_ctime = tswapl(st.st_ctime);
- unlock_user_struct(target_st, arg2, 1);
- }
- }
- break;
-#ifdef TARGET_NR_olduname
- case TARGET_NR_olduname:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_iopl
- case TARGET_NR_iopl:
- goto unimplemented;
-#endif
- case TARGET_NR_vhangup:
- ret = get_errno(vhangup());
- break;
-#ifdef TARGET_NR_idle
- case TARGET_NR_idle:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_syscall
- case TARGET_NR_syscall:
- ret = do_syscall(cpu_env,arg1 & 0xffff,arg2,arg3,arg4,arg5,arg6,0);
- break;
-#endif
- case TARGET_NR_wait4:
- {
- int status;
- target_long status_ptr = arg2;
- struct rusage rusage, *rusage_ptr;
- target_ulong target_rusage = arg4;
- if (target_rusage)
- rusage_ptr = &rusage;
- else
- rusage_ptr = NULL;
- ret = get_errno(wait4(arg1, &status, arg3, rusage_ptr));
- if (!is_error(ret)) {
- if (status_ptr)
- tputl(status_ptr, status);
- if (target_rusage) {
- host_to_target_rusage(target_rusage, &rusage);
- }
- }
- }
- break;
- case TARGET_NR_swapoff:
- p = lock_user_string(arg1);
- ret = get_errno(swapoff(p));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_sysinfo:
- {
- struct target_sysinfo *target_value;
- struct sysinfo value;
- ret = get_errno(sysinfo(&value));
- if (!is_error(ret) && arg1)
- {
- /* ??? __put_user is probably wrong. */
- lock_user_struct(target_value, arg1, 0);
- __put_user(value.uptime, &target_value->uptime);
- __put_user(value.loads[0], &target_value->loads[0]);
- __put_user(value.loads[1], &target_value->loads[1]);
- __put_user(value.loads[2], &target_value->loads[2]);
- __put_user(value.totalram, &target_value->totalram);
- __put_user(value.freeram, &target_value->freeram);
- __put_user(value.sharedram, &target_value->sharedram);
- __put_user(value.bufferram, &target_value->bufferram);
- __put_user(value.totalswap, &target_value->totalswap);
- __put_user(value.freeswap, &target_value->freeswap);
- __put_user(value.procs, &target_value->procs);
- __put_user(value.totalhigh, &target_value->totalhigh);
- __put_user(value.freehigh, &target_value->freehigh);
- __put_user(value.mem_unit, &target_value->mem_unit);
- unlock_user_struct(target_value, arg1, 1);
- }
- }
- break;
- case TARGET_NR_ipc:
- ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
- break;
- case TARGET_NR_fsync:
- ret = get_errno(fsync(arg1));
- break;
- case TARGET_NR_clone:
- ret = get_errno(do_fork(cpu_env, arg1, arg2));
- break;
-#ifdef __NR_exit_group
- /* new thread calls */
- case TARGET_NR_exit_group:
- gdb_exit(cpu_env, arg1);
- ret = get_errno(exit_group(arg1));
- break;
-#endif
- case TARGET_NR_setdomainname:
- p = lock_user_string(arg1);
- ret = get_errno(setdomainname(p, arg2));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_uname:
- /* no need to transcode because we use the linux syscall */
- {
- struct new_utsname * buf;
-
- lock_user_struct(buf, arg1, 0);
- ret = get_errno(sys_uname(buf));
- if (!is_error(ret)) {
- /* Overrite the native machine name with whatever is being
- emulated. */
- strcpy (buf->machine, UNAME_MACHINE);
- /* Allow the user to override the reported release. */
- if (qemu_uname_release && *qemu_uname_release)
- strcpy (buf->release, qemu_uname_release);
- }
- unlock_user_struct(buf, arg1, 1);
- }
- break;
-#ifdef TARGET_I386
- case TARGET_NR_modify_ldt:
- ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3));
- break;
- case TARGET_NR_vm86old:
- goto unimplemented;
- case TARGET_NR_vm86:
- ret = do_vm86(cpu_env, arg1, arg2);
- break;
-#endif
- case TARGET_NR_adjtimex:
- goto unimplemented;
- case TARGET_NR_create_module:
- case TARGET_NR_init_module:
- case TARGET_NR_delete_module:
- case TARGET_NR_get_kernel_syms:
- goto unimplemented;
- case TARGET_NR_quotactl:
- goto unimplemented;
- case TARGET_NR_getpgid:
- ret = get_errno(getpgid(arg1));
- break;
- case TARGET_NR_fchdir:
- ret = get_errno(fchdir(arg1));
- break;
- case TARGET_NR_bdflush:
- goto unimplemented;
- case TARGET_NR_sysfs:
- goto unimplemented;
- case TARGET_NR_personality:
- ret = get_errno(personality(arg1));
- break;
- case TARGET_NR_afs_syscall:
- goto unimplemented;
- case TARGET_NR__llseek:
- {
-#if defined (__x86_64__)
- ret = get_errno(lseek(arg1, ((uint64_t )arg2 << 32) | arg3, arg5));
- tput64(arg4, ret);
-#else
- int64_t res;
- ret = get_errno(_llseek(arg1, arg2, arg3, &res, arg5));
- tput64(arg4, res);
-#endif
- }
- break;
- case TARGET_NR_getdents:
-#if TARGET_LONG_SIZE != 4
- goto unimplemented;
-#warning not supported
-#elif TARGET_LONG_SIZE == 4 && HOST_LONG_SIZE == 8
- {
- struct target_dirent *target_dirp;
- struct dirent *dirp;
- long count = arg3;
-
- dirp = malloc(count);
- if (!dirp)
- return -ENOMEM;
-
- ret = get_errno(sys_getdents(arg1, dirp, count));
- if (!is_error(ret)) {
- struct dirent *de;
- struct target_dirent *tde;
- int len = ret;
- int reclen, treclen;
- int count1, tnamelen;
-
- count1 = 0;
- de = dirp;
- target_dirp = lock_user(arg2, count, 0);
- tde = target_dirp;
- while (len > 0) {
- reclen = de->d_reclen;
- treclen = reclen - (2 * (sizeof(long) - sizeof(target_long)));
- tde->d_reclen = tswap16(treclen);
- tde->d_ino = tswapl(de->d_ino);
- tde->d_off = tswapl(de->d_off);
- tnamelen = treclen - (2 * sizeof(target_long) + 2);
- if (tnamelen > 256)
- tnamelen = 256;
- /* XXX: may not be correct */
- strncpy(tde->d_name, de->d_name, tnamelen);
- de = (struct dirent *)((char *)de + reclen);
- len -= reclen;
- tde = (struct dirent *)((char *)tde + treclen);
- count1 += treclen;
- }
- ret = count1;
- }
- unlock_user(target_dirp, arg2, ret);
- free(dirp);
- }
-#else
- {
- struct dirent *dirp;
- long count = arg3;
-
- dirp = lock_user(arg2, count, 0);
- ret = get_errno(sys_getdents(arg1, dirp, count));
- if (!is_error(ret)) {
- struct dirent *de;
- int len = ret;
- int reclen;
- de = dirp;
- while (len > 0) {
- reclen = de->d_reclen;
- if (reclen > len)
- break;
- de->d_reclen = tswap16(reclen);
- tswapls(&de->d_ino);
- tswapls(&de->d_off);
- de = (struct dirent *)((char *)de + reclen);
- len -= reclen;
- }
- }
- unlock_user(dirp, arg2, ret);
- }
-#endif
- break;
-#ifdef TARGET_NR_getdents64
- case TARGET_NR_getdents64:
- {
- struct dirent64 *dirp;
- long count = arg3;
- dirp = lock_user(arg2, count, 0);
- ret = get_errno(sys_getdents64(arg1, dirp, count));
- if (!is_error(ret)) {
- struct dirent64 *de;
- int len = ret;
- int reclen;
- de = dirp;
- while (len > 0) {
- reclen = de->d_reclen;
- if (reclen > len)
- break;
- de->d_reclen = tswap16(reclen);
- tswap64s(&de->d_ino);
- tswap64s(&de->d_off);
- de = (struct dirent64 *)((char *)de + reclen);
- len -= reclen;
- }
- }
- unlock_user(dirp, arg2, ret);
- }
- break;
-#endif /* TARGET_NR_getdents64 */
- case TARGET_NR__newselect:
- ret = do_select(arg1, arg2, arg3, arg4, arg5);
- break;
- case TARGET_NR_poll:
- {
- struct target_pollfd *target_pfd;
- unsigned int nfds = arg2;
- int timeout = arg3;
- struct pollfd *pfd;
- unsigned int i;
-
- target_pfd = lock_user(arg1, sizeof(struct target_pollfd) * nfds, 1);
- pfd = alloca(sizeof(struct pollfd) * nfds);
- for(i = 0; i < nfds; i++) {
- pfd[i].fd = tswap32(target_pfd[i].fd);
- pfd[i].events = tswap16(target_pfd[i].events);
- }
- ret = get_errno(poll(pfd, nfds, timeout));
- if (!is_error(ret)) {
- for(i = 0; i < nfds; i++) {
- target_pfd[i].revents = tswap16(pfd[i].revents);
- }
- ret += nfds * (sizeof(struct target_pollfd)
- - sizeof(struct pollfd));
- }
- unlock_user(target_pfd, arg1, ret);
- }
- break;
- case TARGET_NR_flock:
- /* NOTE: the flock constant seems to be the same for every
- Linux platform */
- ret = get_errno(flock(arg1, arg2));
- break;
- case TARGET_NR_readv:
- {
- int count = arg3;
- struct iovec *vec;
-
- vec = alloca(count * sizeof(struct iovec));
- lock_iovec(vec, arg2, count, 0);
- ret = get_errno(readv(arg1, vec, count));
- unlock_iovec(vec, arg2, count, 1);
- }
- break;
- case TARGET_NR_writev:
- {
- int count = arg3;
- struct iovec *vec;
-
- vec = alloca(count * sizeof(struct iovec));
- lock_iovec(vec, arg2, count, 1);
- ret = get_errno(writev(arg1, vec, count));
- unlock_iovec(vec, arg2, count, 0);
- }
- break;
- case TARGET_NR_getsid:
- ret = get_errno(getsid(arg1));
- break;
- case TARGET_NR_fdatasync:
- ret = get_errno(fdatasync(arg1));
- break;
- case TARGET_NR__sysctl:
- /* We don't implement this, but ENODIR is always a safe
- return value. */
- return -ENOTDIR;
- case TARGET_NR_sched_setparam:
- {
- struct sched_param *target_schp;
- struct sched_param schp;
-
- lock_user_struct(target_schp, arg2, 1);
- schp.sched_priority = tswap32(target_schp->sched_priority);
- unlock_user_struct(target_schp, arg2, 0);
- ret = get_errno(sched_setparam(arg1, &schp));
- }
- break;
- case TARGET_NR_sched_getparam:
- {
- struct sched_param *target_schp;
- struct sched_param schp;
- ret = get_errno(sched_getparam(arg1, &schp));
- if (!is_error(ret)) {
- lock_user_struct(target_schp, arg2, 0);
- target_schp->sched_priority = tswap32(schp.sched_priority);
- unlock_user_struct(target_schp, arg2, 1);
- }
- }
- break;
- case TARGET_NR_sched_setscheduler:
- {
- struct sched_param *target_schp;
- struct sched_param schp;
- lock_user_struct(target_schp, arg3, 1);
- schp.sched_priority = tswap32(target_schp->sched_priority);
- unlock_user_struct(target_schp, arg3, 0);
- ret = get_errno(sched_setscheduler(arg1, arg2, &schp));
- }
- break;
- case TARGET_NR_sched_getscheduler:
- ret = get_errno(sched_getscheduler(arg1));
- break;
- case TARGET_NR_sched_yield:
- ret = get_errno(sched_yield());
- break;
- case TARGET_NR_sched_get_priority_max:
- ret = get_errno(sched_get_priority_max(arg1));
- break;
- case TARGET_NR_sched_get_priority_min:
- ret = get_errno(sched_get_priority_min(arg1));
- break;
- case TARGET_NR_sched_rr_get_interval:
- {
- struct timespec ts;
- ret = get_errno(sched_rr_get_interval(arg1, &ts));
- if (!is_error(ret)) {
- host_to_target_timespec(arg2, &ts);
- }
- }
- break;
- case TARGET_NR_nanosleep:
- {
- struct timespec req, rem;
- target_to_host_timespec(&req, arg1);
- ret = get_errno(nanosleep(&req, &rem));
- if (is_error(ret) && arg2) {
- host_to_target_timespec(arg2, &rem);
- }
- }
- break;
- case TARGET_NR_query_module:
- goto unimplemented;
- case TARGET_NR_nfsservctl:
- goto unimplemented;
- case TARGET_NR_prctl:
- goto unimplemented;
-#ifdef TARGET_NR_pread
- case TARGET_NR_pread:
- page_unprotect_range(arg2, arg3);
- p = lock_user(arg2, arg3, 0);
- ret = get_errno(pread(arg1, p, arg3, arg4));
- unlock_user(p, arg2, ret);
- break;
- case TARGET_NR_pwrite:
- p = lock_user(arg2, arg3, 1);
- ret = get_errno(pwrite(arg1, p, arg3, arg4));
- unlock_user(p, arg2, 0);
- break;
-#endif
- case TARGET_NR_getcwd:
- p = lock_user(arg1, arg2, 0);
- ret = get_errno(sys_getcwd1(p, arg2));
- unlock_user(p, arg1, ret);
- break;
- case TARGET_NR_capget:
- goto unimplemented;
- case TARGET_NR_capset:
- goto unimplemented;
- case TARGET_NR_sigaltstack:
- goto unimplemented;
- case TARGET_NR_sendfile:
- goto unimplemented;
-#ifdef TARGET_NR_getpmsg
- case TARGET_NR_getpmsg:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_putpmsg
- case TARGET_NR_putpmsg:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_vfork
- case TARGET_NR_vfork:
- ret = get_errno(do_fork(cpu_env, CLONE_VFORK | CLONE_VM | SIGCHLD, 0));
- break;
-#endif
-#ifdef TARGET_NR_ugetrlimit
- case TARGET_NR_ugetrlimit:
- {
- struct rlimit rlim;
- ret = get_errno(getrlimit(arg1, &rlim));
- if (!is_error(ret)) {
- struct target_rlimit *target_rlim;
- lock_user_struct(target_rlim, arg2, 0);
- target_rlim->rlim_cur = tswapl(rlim.rlim_cur);
- target_rlim->rlim_max = tswapl(rlim.rlim_max);
- unlock_user_struct(target_rlim, arg2, 1);
- }
- break;
- }
-#endif
-#ifdef TARGET_NR_truncate64
- case TARGET_NR_truncate64:
- p = lock_user_string(arg1);
- ret = target_truncate64(cpu_env, p, arg2, arg3, arg4);
- unlock_user(p, arg1, 0);
- break;
-#endif
-#ifdef TARGET_NR_ftruncate64
- case TARGET_NR_ftruncate64:
- ret = target_ftruncate64(cpu_env, arg1, arg2, arg3, arg4);
- break;
-#endif
-#ifdef TARGET_NR_stat64
- case TARGET_NR_stat64:
- p = lock_user_string(arg1);
- ret = get_errno(stat(path(p), &st));
- unlock_user(p, arg1, 0);
- goto do_stat64;
-#endif
-#ifdef TARGET_NR_lstat64
- case TARGET_NR_lstat64:
- p = lock_user_string(arg1);
- ret = get_errno(lstat(path(p), &st));
- unlock_user(p, arg1, 0);
- goto do_stat64;
-#endif
-#ifdef TARGET_NR_fstat64
- case TARGET_NR_fstat64:
- {
- ret = get_errno(fstat(arg1, &st));
- do_stat64:
- if (!is_error(ret)) {
-#ifdef TARGET_ARM
- if (((CPUARMState *)cpu_env)->eabi) {
- struct target_eabi_stat64 *target_st;
- lock_user_struct(target_st, arg2, 1);
- memset(target_st, 0, sizeof(struct target_eabi_stat64));
- /* put_user is probably wrong. */
- put_user(st.st_dev, &target_st->st_dev);
- put_user(st.st_ino, &target_st->st_ino);
-#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
- put_user(st.st_ino, &target_st->__st_ino);
-#endif
- put_user(st.st_mode, &target_st->st_mode);
- put_user(st.st_nlink, &target_st->st_nlink);
- put_user(st.st_uid, &target_st->st_uid);
- put_user(st.st_gid, &target_st->st_gid);
- put_user(st.st_rdev, &target_st->st_rdev);
- /* XXX: better use of kernel struct */
- put_user(st.st_size, &target_st->st_size);
- put_user(st.st_blksize, &target_st->st_blksize);
- put_user(st.st_blocks, &target_st->st_blocks);
- put_user(st.st_atime, &target_st->target_st_atime);
- put_user(st.st_mtime, &target_st->target_st_mtime);
- put_user(st.st_ctime, &target_st->target_st_ctime);
- unlock_user_struct(target_st, arg2, 0);
- } else
-#endif
- {
- struct target_stat64 *target_st;
- lock_user_struct(target_st, arg2, 1);
- memset(target_st, 0, sizeof(struct target_stat64));
- /* ??? put_user is probably wrong. */
- put_user(st.st_dev, &target_st->st_dev);
- put_user(st.st_ino, &target_st->st_ino);
-#ifdef TARGET_STAT64_HAS_BROKEN_ST_INO
- put_user(st.st_ino, &target_st->__st_ino);
-#endif
- put_user(st.st_mode, &target_st->st_mode);
- put_user(st.st_nlink, &target_st->st_nlink);
- put_user(st.st_uid, &target_st->st_uid);
- put_user(st.st_gid, &target_st->st_gid);
- put_user(st.st_rdev, &target_st->st_rdev);
- /* XXX: better use of kernel struct */
- put_user(st.st_size, &target_st->st_size);
- put_user(st.st_blksize, &target_st->st_blksize);
- put_user(st.st_blocks, &target_st->st_blocks);
- put_user(st.st_atime, &target_st->target_st_atime);
- put_user(st.st_mtime, &target_st->target_st_mtime);
- put_user(st.st_ctime, &target_st->target_st_ctime);
- unlock_user_struct(target_st, arg2, 0);
- }
- }
- }
- break;
-#endif
-#ifdef USE_UID16
- case TARGET_NR_lchown:
- p = lock_user_string(arg1);
- ret = get_errno(lchown(p, low2highuid(arg2), low2highgid(arg3)));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_getuid:
- ret = get_errno(high2lowuid(getuid()));
- break;
- case TARGET_NR_getgid:
- ret = get_errno(high2lowgid(getgid()));
- break;
- case TARGET_NR_geteuid:
- ret = get_errno(high2lowuid(geteuid()));
- break;
- case TARGET_NR_getegid:
- ret = get_errno(high2lowgid(getegid()));
- break;
- case TARGET_NR_setreuid:
- ret = get_errno(setreuid(low2highuid(arg1), low2highuid(arg2)));
- break;
- case TARGET_NR_setregid:
- ret = get_errno(setregid(low2highgid(arg1), low2highgid(arg2)));
- break;
- case TARGET_NR_getgroups:
- {
- int gidsetsize = arg1;
- uint16_t *target_grouplist;
- gid_t *grouplist;
- int i;
-
- grouplist = alloca(gidsetsize * sizeof(gid_t));
- ret = get_errno(getgroups(gidsetsize, grouplist));
- if (!is_error(ret)) {
- target_grouplist = lock_user(arg2, gidsetsize * 2, 0);
- for(i = 0;i < gidsetsize; i++)
- target_grouplist[i] = tswap16(grouplist[i]);
- unlock_user(target_grouplist, arg2, gidsetsize * 2);
- }
- }
- break;
- case TARGET_NR_setgroups:
- {
- int gidsetsize = arg1;
- uint16_t *target_grouplist;
- gid_t *grouplist;
- int i;
-
- grouplist = alloca(gidsetsize * sizeof(gid_t));
- target_grouplist = lock_user(arg2, gidsetsize * 2, 1);
- for(i = 0;i < gidsetsize; i++)
- grouplist[i] = tswap16(target_grouplist[i]);
- unlock_user(target_grouplist, arg2, 0);
- ret = get_errno(setgroups(gidsetsize, grouplist));
- }
- break;
- case TARGET_NR_fchown:
- ret = get_errno(fchown(arg1, low2highuid(arg2), low2highgid(arg3)));
- break;
-#ifdef TARGET_NR_setresuid
- case TARGET_NR_setresuid:
- ret = get_errno(setresuid(low2highuid(arg1),
- low2highuid(arg2),
- low2highuid(arg3)));
- break;
-#endif
-#ifdef TARGET_NR_getresuid
- case TARGET_NR_getresuid:
- {
- uid_t ruid, euid, suid;
- ret = get_errno(getresuid(&ruid, &euid, &suid));
- if (!is_error(ret)) {
- tput16(arg1, tswap16(high2lowuid(ruid)));
- tput16(arg2, tswap16(high2lowuid(euid)));
- tput16(arg3, tswap16(high2lowuid(suid)));
- }
- }
- break;
-#endif
-#ifdef TARGET_NR_getresgid
- case TARGET_NR_setresgid:
- ret = get_errno(setresgid(low2highgid(arg1),
- low2highgid(arg2),
- low2highgid(arg3)));
- break;
-#endif
-#ifdef TARGET_NR_getresgid
- case TARGET_NR_getresgid:
- {
- gid_t rgid, egid, sgid;
- ret = get_errno(getresgid(&rgid, &egid, &sgid));
- if (!is_error(ret)) {
- tput16(arg1, tswap16(high2lowgid(rgid)));
- tput16(arg2, tswap16(high2lowgid(egid)));
- tput16(arg3, tswap16(high2lowgid(sgid)));
- }
- }
- break;
-#endif
- case TARGET_NR_chown:
- p = lock_user_string(arg1);
- ret = get_errno(chown(p, low2highuid(arg2), low2highgid(arg3)));
- unlock_user(p, arg1, 0);
- break;
- case TARGET_NR_setuid:
- ret = get_errno(setuid(low2highuid(arg1)));
- break;
- case TARGET_NR_setgid:
- ret = get_errno(setgid(low2highgid(arg1)));
- break;
- case TARGET_NR_setfsuid:
- ret = get_errno(setfsuid(arg1));
- break;
- case TARGET_NR_setfsgid:
- ret = get_errno(setfsgid(arg1));
- break;
-#endif /* USE_UID16 */
-
-#ifdef TARGET_NR_lchown32
- case TARGET_NR_lchown32:
- p = lock_user_string(arg1);
- ret = get_errno(lchown(p, arg2, arg3));
- unlock_user(p, arg1, 0);
- break;
-#endif
-#ifdef TARGET_NR_getuid32
- case TARGET_NR_getuid32:
- ret = get_errno(getuid());
- break;
-#endif
-#ifdef TARGET_NR_getgid32
- case TARGET_NR_getgid32:
- ret = get_errno(getgid());
- break;
-#endif
-#ifdef TARGET_NR_geteuid32
- case TARGET_NR_geteuid32:
- ret = get_errno(geteuid());
- break;
-#endif
-#ifdef TARGET_NR_getegid32
- case TARGET_NR_getegid32:
- ret = get_errno(getegid());
- break;
-#endif
-#ifdef TARGET_NR_setreuid32
- case TARGET_NR_setreuid32:
- ret = get_errno(setreuid(arg1, arg2));
- break;
-#endif
-#ifdef TARGET_NR_setregid32
- case TARGET_NR_setregid32:
- ret = get_errno(setregid(arg1, arg2));
- break;
-#endif
-#ifdef TARGET_NR_getgroups32
- case TARGET_NR_getgroups32:
- {
- int gidsetsize = arg1;
- uint32_t *target_grouplist;
- gid_t *grouplist;
- int i;
-
- grouplist = alloca(gidsetsize * sizeof(gid_t));
- ret = get_errno(getgroups(gidsetsize, grouplist));
- if (!is_error(ret)) {
- target_grouplist = lock_user(arg2, gidsetsize * 4, 0);
- for(i = 0;i < gidsetsize; i++)
- target_grouplist[i] = tswap32(grouplist[i]);
- unlock_user(target_grouplist, arg2, gidsetsize * 4);
- }
- }
- break;
-#endif
-#ifdef TARGET_NR_setgroups32
- case TARGET_NR_setgroups32:
- {
- int gidsetsize = arg1;
- uint32_t *target_grouplist;
- gid_t *grouplist;
- int i;
-
- grouplist = alloca(gidsetsize * sizeof(gid_t));
- target_grouplist = lock_user(arg2, gidsetsize * 4, 1);
- for(i = 0;i < gidsetsize; i++)
- grouplist[i] = tswap32(target_grouplist[i]);
- unlock_user(target_grouplist, arg2, 0);
- ret = get_errno(setgroups(gidsetsize, grouplist));
- }
- break;
-#endif
-#ifdef TARGET_NR_fchown32
- case TARGET_NR_fchown32:
- ret = get_errno(fchown(arg1, arg2, arg3));
- break;
-#endif
-#ifdef TARGET_NR_setresuid32
- case TARGET_NR_setresuid32:
- ret = get_errno(setresuid(arg1, arg2, arg3));
- break;
-#endif
-#ifdef TARGET_NR_getresuid32
- case TARGET_NR_getresuid32:
- {
- uid_t ruid, euid, suid;
- ret = get_errno(getresuid(&ruid, &euid, &suid));
- if (!is_error(ret)) {
- tput32(arg1, tswap32(ruid));
- tput32(arg2, tswap32(euid));
- tput32(arg3, tswap32(suid));
- }
- }
- break;
-#endif
-#ifdef TARGET_NR_setresgid32
- case TARGET_NR_setresgid32:
- ret = get_errno(setresgid(arg1, arg2, arg3));
- break;
-#endif
-#ifdef TARGET_NR_getresgid32
- case TARGET_NR_getresgid32:
- {
- gid_t rgid, egid, sgid;
- ret = get_errno(getresgid(&rgid, &egid, &sgid));
- if (!is_error(ret)) {
- tput32(arg1, tswap32(rgid));
- tput32(arg2, tswap32(egid));
- tput32(arg3, tswap32(sgid));
- }
- }
- break;
-#endif
-#ifdef TARGET_NR_chown32
- case TARGET_NR_chown32:
- p = lock_user_string(arg1);
- ret = get_errno(chown(p, arg2, arg3));
- unlock_user(p, arg1, 0);
- break;
-#endif
-#ifdef TARGET_NR_setuid32
- case TARGET_NR_setuid32:
- ret = get_errno(setuid(arg1));
- break;
-#endif
-#ifdef TARGET_NR_setgid32
- case TARGET_NR_setgid32:
- ret = get_errno(setgid(arg1));
- break;
-#endif
-#ifdef TARGET_NR_setfsuid32
- case TARGET_NR_setfsuid32:
- ret = get_errno(setfsuid(arg1));
- break;
-#endif
-#ifdef TARGET_NR_setfsgid32
- case TARGET_NR_setfsgid32:
- ret = get_errno(setfsgid(arg1));
- break;
-#endif
-
- case TARGET_NR_pivot_root:
- goto unimplemented;
-#ifdef TARGET_NR_mincore
- case TARGET_NR_mincore:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_madvise
- case TARGET_NR_madvise:
- /* A straight passthrough may not be safe because qemu sometimes
- turns private flie-backed mappings into anonymous mappings.
- This will break MADV_DONTNEED.
- This is a hint, so ignoring and returning success is ok. */
- ret = get_errno(0);
- break;
-#endif
-#if TARGET_LONG_BITS == 32
- case TARGET_NR_fcntl64:
- {
- struct flock64 fl;
- struct target_flock64 *target_fl;
-#ifdef TARGET_ARM
- struct target_eabi_flock64 *target_efl;
-#endif
-
- switch(arg2) {
- case F_GETLK64:
- ret = get_errno(fcntl(arg1, arg2, &fl));
- if (ret == 0) {
-#ifdef TARGET_ARM
- if (((CPUARMState *)cpu_env)->eabi) {
- lock_user_struct(target_efl, arg3, 0);
- target_efl->l_type = tswap16(fl.l_type);
- target_efl->l_whence = tswap16(fl.l_whence);
- target_efl->l_start = tswap64(fl.l_start);
- target_efl->l_len = tswap64(fl.l_len);
- target_efl->l_pid = tswapl(fl.l_pid);
- unlock_user_struct(target_efl, arg3, 1);
- } else
-#endif
- {
- lock_user_struct(target_fl, arg3, 0);
- target_fl->l_type = tswap16(fl.l_type);
- target_fl->l_whence = tswap16(fl.l_whence);
- target_fl->l_start = tswap64(fl.l_start);
- target_fl->l_len = tswap64(fl.l_len);
- target_fl->l_pid = tswapl(fl.l_pid);
- unlock_user_struct(target_fl, arg3, 1);
- }
- }
- break;
-
- case F_SETLK64:
- case F_SETLKW64:
-#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, arg2, &fl));
- break;
- default:
- ret = get_errno(do_fcntl(arg1, arg2, arg3));
- break;
- }
- break;
- }
-#endif
-#ifdef TARGET_NR_security
- case TARGET_NR_security:
- goto unimplemented;
-#endif
-#ifdef TARGET_NR_getpagesize
- case TARGET_NR_getpagesize:
- ret = TARGET_PAGE_SIZE;
- break;
-#endif
- case TARGET_NR_gettid:
- ret = get_errno(gettid());
- break;
- case TARGET_NR_readahead:
- goto unimplemented;
-#ifdef TARGET_NR_setxattr
- case TARGET_NR_setxattr:
- case TARGET_NR_lsetxattr:
- case TARGET_NR_fsetxattr:
- case TARGET_NR_getxattr:
- case TARGET_NR_lgetxattr:
- case TARGET_NR_fgetxattr:
- case TARGET_NR_listxattr:
- case TARGET_NR_llistxattr:
- case TARGET_NR_flistxattr:
- case TARGET_NR_removexattr:
- case TARGET_NR_lremovexattr:
- case TARGET_NR_fremovexattr:
- goto unimplemented_nowarn;
-#endif
-#ifdef TARGET_NR_set_thread_area
- case TARGET_NR_set_thread_area:
- case TARGET_NR_get_thread_area:
- goto unimplemented_nowarn;
-#endif
-#ifdef TARGET_NR_getdomainname
- case TARGET_NR_getdomainname:
- goto unimplemented_nowarn;
-#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)
- unimplemented_nowarn:
-#endif
- ret = -ENOSYS;
- break;
- }
- fail:
-#ifdef DEBUG
- gemu_log(" = %ld\n", ret);
-#endif
- return ret;
-}
-
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
deleted file mode 100644
index 73a5c42..0000000
--- a/linux-user/syscall_defs.h
+++ /dev/null
@@ -1,1516 +0,0 @@
-/* common syscall defines for all architectures */
-
-/* Note: although the syscall numbers change between architectures,
- most of them stay the same, so we handle it by puting ifdefs if
- necessary */
-
-#include "syscall_nr.h"
-
-#define SOCKOP_socket 1
-#define SOCKOP_bind 2
-#define SOCKOP_connect 3
-#define SOCKOP_listen 4
-#define SOCKOP_accept 5
-#define SOCKOP_getsockname 6
-#define SOCKOP_getpeername 7
-#define SOCKOP_socketpair 8
-#define SOCKOP_send 9
-#define SOCKOP_recv 10
-#define SOCKOP_sendto 11
-#define SOCKOP_recvfrom 12
-#define SOCKOP_shutdown 13
-#define SOCKOP_setsockopt 14
-#define SOCKOP_getsockopt 15
-#define SOCKOP_sendmsg 16
-#define SOCKOP_recvmsg 17
-
-#define IPCOP_semop 1
-#define IPCOP_semget 2
-#define IPCOP_semctl 3
-#define IPCOP_semtimedop 4
-#define IPCOP_msgsnd 11
-#define IPCOP_msgrcv 12
-#define IPCOP_msgget 13
-#define IPCOP_msgctl 14
-#define IPCOP_shmat 21
-#define IPCOP_shmdt 22
-#define IPCOP_shmget 23
-#define IPCOP_shmctl 24
-
-/*
- * The following is for compatibility across the various Linux
- * platforms. The i386 ioctl numbering scheme doesn't really enforce
- * a type field. De facto, however, the top 8 bits of the lower 16
- * bits are indeed used as a type field, so we might just as well make
- * this explicit here. Please be sure to use the decoding macros
- * below from now on.
- */
-#define TARGET_IOC_NRBITS 8
-#define TARGET_IOC_TYPEBITS 8
-
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4)
-
-#define TARGET_IOC_SIZEBITS 14
-#define TARGET_IOC_DIRBITS 2
-
-#define TARGET_IOC_NONE 0U
-#define TARGET_IOC_WRITE 1U
-#define TARGET_IOC_READ 2U
-
-#elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \
- defined(TARGET_SPARC) || defined(TARGET_MIPS)
-
-#define TARGET_IOC_SIZEBITS 13
-#define TARGET_IOC_DIRBITS 3
-
-#define TARGET_IOC_NONE 1U
-#define TARGET_IOC_READ 2U
-#define TARGET_IOC_WRITE 4U
-
-#else
-#error unsupported CPU
-#endif
-
-#define TARGET_IOC_NRMASK ((1 << TARGET_IOC_NRBITS)-1)
-#define TARGET_IOC_TYPEMASK ((1 << TARGET_IOC_TYPEBITS)-1)
-#define TARGET_IOC_SIZEMASK ((1 << TARGET_IOC_SIZEBITS)-1)
-#define TARGET_IOC_DIRMASK ((1 << TARGET_IOC_DIRBITS)-1)
-
-#define TARGET_IOC_NRSHIFT 0
-#define TARGET_IOC_TYPESHIFT (TARGET_IOC_NRSHIFT+TARGET_IOC_NRBITS)
-#define TARGET_IOC_SIZESHIFT (TARGET_IOC_TYPESHIFT+TARGET_IOC_TYPEBITS)
-#define TARGET_IOC_DIRSHIFT (TARGET_IOC_SIZESHIFT+TARGET_IOC_SIZEBITS)
-
-#define TARGET_IOC(dir,type,nr,size) \
- (((dir) << TARGET_IOC_DIRSHIFT) | \
- ((type) << TARGET_IOC_TYPESHIFT) | \
- ((nr) << TARGET_IOC_NRSHIFT) | \
- ((size) << TARGET_IOC_SIZESHIFT))
-
-/* used to create numbers */
-#define TARGET_IO(type,nr) TARGET_IOC(TARGET_IOC_NONE,(type),(nr),0)
-#define TARGET_IOR(type,nr,size) TARGET_IOC(TARGET_IOC_READ,(type),(nr),sizeof(size))
-#define TARGET_IOW(type,nr,size) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),sizeof(size))
-#define TARGET_IOWR(type,nr,size) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),sizeof(size))
-
-/* the size is automatically computed for these defines */
-#define TARGET_IORU(type,nr) TARGET_IOC(TARGET_IOC_READ,(type),(nr),TARGET_IOC_SIZEMASK)
-#define TARGET_IOWU(type,nr) TARGET_IOC(TARGET_IOC_WRITE,(type),(nr),TARGET_IOC_SIZEMASK)
-#define TARGET_IOWRU(type,nr) TARGET_IOC(TARGET_IOC_READ|TARGET_IOC_WRITE,(type),(nr),TARGET_IOC_SIZEMASK)
-
-struct target_sockaddr {
- uint16_t sa_family;
- uint8_t sa_data[14];
-};
-
-struct target_timeval {
- target_long tv_sec;
- target_long tv_usec;
-};
-
-struct target_timespec {
- target_long tv_sec;
- target_long tv_nsec;
-};
-
-struct target_itimerval {
- struct target_timeval it_interval;
- struct target_timeval it_value;
-};
-
-typedef target_long target_clock_t;
-
-#define TARGET_HZ 100
-
-struct target_tms {
- target_clock_t tms_utime;
- target_clock_t tms_stime;
- target_clock_t tms_cutime;
- target_clock_t tms_cstime;
-};
-
-struct target_utimbuf {
- target_long actime;
- target_long modtime;
-};
-
-struct target_sel_arg_struct {
- target_long n;
- target_long inp, outp, exp;
- target_long tvp;
-};
-
-struct target_iovec {
- target_long iov_base; /* Starting address */
- target_long iov_len; /* Number of bytes */
-};
-
-struct target_msghdr {
- target_long msg_name; /* Socket name */
- int msg_namelen; /* Length of name */
- target_long msg_iov; /* Data blocks */
- target_long msg_iovlen; /* Number of blocks */
- target_long msg_control; /* Per protocol magic (eg BSD file descriptor passing) */
- target_long msg_controllen; /* Length of cmsg list */
- unsigned int msg_flags;
-};
-
-struct target_cmsghdr {
- target_long cmsg_len;
- int cmsg_level;
- int cmsg_type;
-};
-
-#define TARGET_CMSG_DATA(cmsg) ((unsigned char *) ((struct target_cmsghdr *) (cmsg) + 1))
-#define TARGET_CMSG_NXTHDR(mhdr, cmsg) __target_cmsg_nxthdr (mhdr, cmsg)
-#define TARGET_CMSG_FIRSTHDR(mhdr) \
- ((size_t) tswapl((mhdr)->msg_controllen) >= sizeof (struct target_cmsghdr) \
- ? (struct target_cmsghdr *) tswapl((mhdr)->msg_control) : (struct target_cmsghdr *) NULL)
-#define TARGET_CMSG_ALIGN(len) (((len) + sizeof (target_long) - 1) \
- & (size_t) ~(sizeof (target_long) - 1))
-#define TARGET_CMSG_SPACE(len) (TARGET_CMSG_ALIGN (len) \
- + TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)))
-#define TARGET_CMSG_LEN(len) (TARGET_CMSG_ALIGN (sizeof (struct target_cmsghdr)) + (len))
-
-static __inline__ struct target_cmsghdr *
-__target_cmsg_nxthdr (struct target_msghdr *__mhdr, struct target_cmsghdr *__cmsg)
-{
- if (tswapl(__cmsg->cmsg_len) < sizeof (struct target_cmsghdr))
- /* The kernel header does this so there may be a reason. */
- return 0;
-
- __cmsg = (struct target_cmsghdr *) ((unsigned char *) __cmsg
- + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len)));
- if ((unsigned char *) (__cmsg + 1) > ((unsigned char *) tswapl(__mhdr->msg_control)
- + tswapl(__mhdr->msg_controllen))
- || ((unsigned char *) __cmsg + TARGET_CMSG_ALIGN (tswapl(__cmsg->cmsg_len))
- > ((unsigned char *) tswapl(__mhdr->msg_control)
- + tswapl(__mhdr->msg_controllen))))
- /* No more entries. */
- return 0;
- return __cmsg;
-}
-
-
-struct target_rusage {
- struct target_timeval ru_utime; /* user time used */
- struct target_timeval ru_stime; /* system time used */
- target_long ru_maxrss; /* maximum resident set size */
- target_long ru_ixrss; /* integral shared memory size */
- target_long ru_idrss; /* integral unshared data size */
- target_long ru_isrss; /* integral unshared stack size */
- target_long ru_minflt; /* page reclaims */
- target_long ru_majflt; /* page faults */
- target_long ru_nswap; /* swaps */
- target_long ru_inblock; /* block input operations */
- target_long ru_oublock; /* block output operations */
- target_long ru_msgsnd; /* messages sent */
- target_long ru_msgrcv; /* messages received */
- target_long ru_nsignals; /* signals received */
- target_long ru_nvcsw; /* voluntary context switches */
- target_long ru_nivcsw; /* involuntary " */
-};
-
-typedef struct {
- int val[2];
-} kernel_fsid_t;
-
-struct kernel_statfs {
- int f_type;
- int f_bsize;
- int f_blocks;
- int f_bfree;
- int f_bavail;
- int f_files;
- int f_ffree;
- kernel_fsid_t f_fsid;
- int f_namelen;
- int f_spare[6];
-};
-
-struct target_dirent {
- target_long d_ino;
- target_long d_off;
- unsigned short d_reclen;
- char d_name[256]; /* We must not include limits.h! */
-};
-
-struct target_dirent64 {
- uint64_t d_ino;
- int64_t d_off;
- unsigned short d_reclen;
- unsigned char d_type;
- char d_name[256];
-};
-
-
-/* mostly generic signal stuff */
-#define TARGET_SIG_DFL ((target_long)0) /* default signal handling */
-#define TARGET_SIG_IGN ((target_long)1) /* ignore signal */
-#define TARGET_SIG_ERR ((target_long)-1) /* error return from signal */
-
-#ifdef TARGET_MIPS
-#define TARGET_NSIG 128
-#else
-#define TARGET_NSIG 64
-#endif
-#define TARGET_NSIG_BPW TARGET_LONG_BITS
-#define TARGET_NSIG_WORDS (TARGET_NSIG / TARGET_NSIG_BPW)
-
-typedef struct {
- target_ulong sig[TARGET_NSIG_WORDS];
-} target_sigset_t;
-
-#ifdef BSWAP_NEEDED
-static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
-{
- int i;
- for(i = 0;i < TARGET_NSIG_WORDS; i++)
- d->sig[i] = tswapl(s->sig[i]);
-}
-#else
-static inline void tswap_sigset(target_sigset_t *d, const target_sigset_t *s)
-{
- *d = *s;
-}
-#endif
-
-static inline void target_siginitset(target_sigset_t *d, target_ulong set)
-{
- int i;
- d->sig[0] = set;
- for(i = 1;i < TARGET_NSIG_WORDS; i++)
- d->sig[i] = 0;
-}
-
-void host_to_target_sigset(target_sigset_t *d, const sigset_t *s);
-void target_to_host_sigset(sigset_t *d, const target_sigset_t *s);
-void host_to_target_old_sigset(target_ulong *old_sigset,
- const sigset_t *sigset);
-void target_to_host_old_sigset(sigset_t *sigset,
- const target_ulong *old_sigset);
-struct target_sigaction;
-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)
-
-#if defined(TARGET_SPARC)
-#define TARGET_SA_NOCLDSTOP 8u
-#define TARGET_SA_NOCLDWAIT 0x100u
-#define TARGET_SA_SIGINFO 0x200u
-#define TARGET_SA_ONSTACK 1u
-#define TARGET_SA_RESTART 2u
-#define TARGET_SA_NODEFER 0x20u
-#define TARGET_SA_RESETHAND 4u
-#elif defined(TARGET_MIPS)
-#define TARGET_SA_NOCLDSTOP 0x00000001
-#define TARGET_SA_NOCLDWAIT 0x00010000
-#define TARGET_SA_SIGINFO 0x00000008
-#define TARGET_SA_ONSTACK 0x08000000
-#define TARGET_SA_NODEFER 0x40000000
-#define TARGET_SA_RESTART 0x10000000
-#define TARGET_SA_RESETHAND 0x80000000
-#define TARGET_SA_RESTORER 0x04000000 /* Only for o32 */
-#else
-#define TARGET_SA_NOCLDSTOP 0x00000001
-#define TARGET_SA_NOCLDWAIT 0x00000002 /* not supported yet */
-#define TARGET_SA_SIGINFO 0x00000004
-#define TARGET_SA_ONSTACK 0x08000000
-#define TARGET_SA_RESTART 0x10000000
-#define TARGET_SA_NODEFER 0x40000000
-#define TARGET_SA_RESETHAND 0x80000000
-#define TARGET_SA_RESTORER 0x04000000
-#endif
-
-#if defined(TARGET_SPARC)
-
-#define TARGET_SIGHUP 1
-#define TARGET_SIGINT 2
-#define TARGET_SIGQUIT 3
-#define TARGET_SIGILL 4
-#define TARGET_SIGTRAP 5
-#define TARGET_SIGABRT 6
-#define TARGET_SIGIOT 6
-#define TARGET_SIGSTKFLT 7 /* actually EMT */
-#define TARGET_SIGFPE 8
-#define TARGET_SIGKILL 9
-#define TARGET_SIGBUS 10
-#define TARGET_SIGSEGV 11
-#define TARGET_SIGSYS 12
-#define TARGET_SIGPIPE 13
-#define TARGET_SIGALRM 14
-#define TARGET_SIGTERM 15
-#define TARGET_SIGURG 16
-#define TARGET_SIGSTOP 17
-#define TARGET_SIGTSTP 18
-#define TARGET_SIGCONT 19
-#define TARGET_SIGCHLD 20
-#define TARGET_SIGTTIN 21
-#define TARGET_SIGTTOU 22
-#define TARGET_SIGIO 23
-#define TARGET_SIGXCPU 24
-#define TARGET_SIGXFSZ 25
-#define TARGET_SIGVTALRM 26
-#define TARGET_SIGPROF 27
-#define TARGET_SIGWINCH 28
-#define TARGET_SIGPWR 29
-#define TARGET_SIGUSR1 30
-#define TARGET_SIGUSR2 31
-#define TARGET_SIGRTMIN 32
-
-#define TARGET_SIG_BLOCK 0x01 /* for blocking signals */
-#define TARGET_SIG_UNBLOCK 0x02 /* for unblocking signals */
-#define TARGET_SIG_SETMASK 0x04 /* for setting the signal mask */
-
-#elif defined(TARGET_MIPS)
-
-#define TARGET_SIGHUP 1 /* Hangup (POSIX). */
-#define TARGET_SIGINT 2 /* Interrupt (ANSI). */
-#define TARGET_SIGQUIT 3 /* Quit (POSIX). */
-#define TARGET_SIGILL 4 /* Illegal instruction (ANSI). */
-#define TARGET_SIGTRAP 5 /* Trace trap (POSIX). */
-#define TARGET_SIGIOT 6 /* IOT trap (4.2 BSD). */
-#define TARGET_SIGABRT TARGET_SIGIOT /* Abort (ANSI). */
-#define TARGET_SIGEMT 7
-#define TARGET_SIGSTKFLT 7 /* XXX: incorrect */
-#define TARGET_SIGFPE 8 /* Floating-point exception (ANSI). */
-#define TARGET_SIGKILL 9 /* Kill, unblockable (POSIX). */
-#define TARGET_SIGBUS 10 /* BUS error (4.2 BSD). */
-#define TARGET_SIGSEGV 11 /* Segmentation violation (ANSI). */
-#define TARGET_SIGSYS 12
-#define TARGET_SIGPIPE 13 /* Broken pipe (POSIX). */
-#define TARGET_SIGALRM 14 /* Alarm clock (POSIX). */
-#define TARGET_SIGTERM 15 /* Termination (ANSI). */
-#define TARGET_SIGUSR1 16 /* User-defined signal 1 (POSIX). */
-#define TARGET_SIGUSR2 17 /* User-defined signal 2 (POSIX). */
-#define TARGET_SIGCHLD 18 /* Child status has changed (POSIX). */
-#define TARGET_SIGCLD TARGET_SIGCHLD /* Same as TARGET_SIGCHLD (System V). */
-#define TARGET_SIGPWR 19 /* Power failure restart (System V). */
-#define TARGET_SIGWINCH 20 /* Window size change (4.3 BSD, Sun). */
-#define TARGET_SIGURG 21 /* Urgent condition on socket (4.2 BSD). */
-#define TARGET_SIGIO 22 /* I/O now possible (4.2 BSD). */
-#define TARGET_SIGPOLL TARGET_SIGIO /* Pollable event occurred (System V). */
-#define TARGET_SIGSTOP 23 /* Stop, unblockable (POSIX). */
-#define TARGET_SIGTSTP 24 /* Keyboard stop (POSIX). */
-#define TARGET_SIGCONT 25 /* Continue (POSIX). */
-#define TARGET_SIGTTIN 26 /* Background read from tty (POSIX). */
-#define TARGET_SIGTTOU 27 /* Background write to tty (POSIX). */
-#define TARGET_SIGVTALRM 28 /* Virtual alarm clock (4.2 BSD). */
-#define TARGET_SIGPROF 29 /* Profiling alarm clock (4.2 BSD). */
-#define TARGET_SIGXCPU 30 /* CPU limit exceeded (4.2 BSD). */
-#define TARGET_SIGXFSZ 31 /* File size limit exceeded (4.2 BSD). */
-#define TARGET_SIGRTMIN 32
-
-#define TARGET_SIG_BLOCK 1 /* for blocking signals */
-#define TARGET_SIG_UNBLOCK 2 /* for unblocking signals */
-#define TARGET_SIG_SETMASK 3 /* for setting the signal mask */
-
-#else
-
-#define TARGET_SIGHUP 1
-#define TARGET_SIGINT 2
-#define TARGET_SIGQUIT 3
-#define TARGET_SIGILL 4
-#define TARGET_SIGTRAP 5
-#define TARGET_SIGABRT 6
-#define TARGET_SIGIOT 6
-#define TARGET_SIGBUS 7
-#define TARGET_SIGFPE 8
-#define TARGET_SIGKILL 9
-#define TARGET_SIGUSR1 10
-#define TARGET_SIGSEGV 11
-#define TARGET_SIGUSR2 12
-#define TARGET_SIGPIPE 13
-#define TARGET_SIGALRM 14
-#define TARGET_SIGTERM 15
-#define TARGET_SIGSTKFLT 16
-#define TARGET_SIGCHLD 17
-#define TARGET_SIGCONT 18
-#define TARGET_SIGSTOP 19
-#define TARGET_SIGTSTP 20
-#define TARGET_SIGTTIN 21
-#define TARGET_SIGTTOU 22
-#define TARGET_SIGURG 23
-#define TARGET_SIGXCPU 24
-#define TARGET_SIGXFSZ 25
-#define TARGET_SIGVTALRM 26
-#define TARGET_SIGPROF 27
-#define TARGET_SIGWINCH 28
-#define TARGET_SIGIO 29
-#define TARGET_SIGPWR 30
-#define TARGET_SIGSYS 31
-#define TARGET_SIGRTMIN 32
-
-#define TARGET_SIG_BLOCK 0 /* for blocking signals */
-#define TARGET_SIG_UNBLOCK 1 /* for unblocking signals */
-#define TARGET_SIG_SETMASK 2 /* for setting the signal mask */
-
-#endif
-
-#if defined(TARGET_MIPS)
-
-struct target_sigaction {
- target_ulong sa_flags;
- target_ulong _sa_handler;
- target_sigset_t sa_mask;
-};
-
-#else
-struct target_old_sigaction {
- target_ulong _sa_handler;
- target_ulong sa_mask;
- target_ulong sa_flags;
- target_ulong sa_restorer;
-};
-
-struct target_sigaction {
- target_ulong _sa_handler;
- target_ulong sa_flags;
- target_ulong sa_restorer;
- target_sigset_t sa_mask;
-};
-#endif
-
-typedef union target_sigval {
- int sival_int;
- target_ulong sival_ptr;
-} target_sigval_t;
-#if 0
-#if defined (TARGET_SPARC)
-typedef struct {
- struct {
- target_ulong psr;
- target_ulong pc;
- target_ulong npc;
- target_ulong y;
- target_ulong u_regs[16]; /* globals and ins */
- } si_regs;
- int si_mask;
-} __siginfo_t;
-
-typedef struct {
- unsigned long si_float_regs [32];
- unsigned long si_fsr;
- unsigned long si_fpqdepth;
- struct {
- unsigned long *insn_addr;
- unsigned long insn;
- } si_fpqueue [16];
-} __siginfo_fpu_t;
-#endif
-#endif
-
-#define TARGET_SI_MAX_SIZE 128
-#define TARGET_SI_PAD_SIZE ((TARGET_SI_MAX_SIZE/sizeof(int)) - 3)
-
-typedef struct target_siginfo {
- int si_signo;
- int si_errno;
- int si_code;
-
- union {
- int _pad[TARGET_SI_PAD_SIZE];
-
- /* kill() */
- struct {
- pid_t _pid; /* sender's pid */
- uid_t _uid; /* sender's uid */
- } _kill;
-
- /* POSIX.1b timers */
- struct {
- unsigned int _timer1;
- unsigned int _timer2;
- } _timer;
-
- /* POSIX.1b signals */
- struct {
- pid_t _pid; /* sender's pid */
- uid_t _uid; /* sender's uid */
- target_sigval_t _sigval;
- } _rt;
-
- /* SIGCHLD */
- struct {
- pid_t _pid; /* which child */
- uid_t _uid; /* sender's uid */
- int _status; /* exit code */
- target_clock_t _utime;
- target_clock_t _stime;
- } _sigchld;
-
- /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
- struct {
- target_ulong _addr; /* faulting insn/memory ref. */
- } _sigfault;
-
- /* SIGPOLL */
- struct {
- int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
- int _fd;
- } _sigpoll;
- } _sifields;
-} target_siginfo_t;
-
-/*
- * si_code values
- * Digital reserves positive values for kernel-generated signals.
- */
-#define TARGET_SI_USER 0 /* sent by kill, sigsend, raise */
-#define TARGET_SI_KERNEL 0x80 /* sent by the kernel from somewhere */
-#define TARGET_SI_QUEUE -1 /* sent by sigqueue */
-#define TARGET_SI_TIMER -2 /* sent by timer expiration */
-#define TARGET_SI_MESGQ -3 /* sent by real time mesq state change */
-#define TARGET_SI_ASYNCIO -4 /* sent by AIO completion */
-#define TARGET_SI_SIGIO -5 /* sent by queued SIGIO */
-
-/*
- * SIGILL si_codes
- */
-#define TARGET_ILL_ILLOPC (1) /* illegal opcode */
-#define TARGET_ILL_ILLOPN (2) /* illegal operand */
-#define TARGET_ILL_ILLADR (3) /* illegal addressing mode */
-#define TARGET_ILL_ILLTRP (4) /* illegal trap */
-#define TARGET_ILL_PRVOPC (5) /* privileged opcode */
-#define TARGET_ILL_PRVREG (6) /* privileged register */
-#define TARGET_ILL_COPROC (7) /* coprocessor error */
-#define TARGET_ILL_BADSTK (8) /* internal stack error */
-
-/*
- * SIGFPE si_codes
- */
-#define TARGET_FPE_INTDIV (1) /* integer divide by zero */
-#define TARGET_FPE_INTOVF (2) /* integer overflow */
-#define TARGET_FPE_FLTDIV (3) /* floating point divide by zero */
-#define TARGET_FPE_FLTOVF (4) /* floating point overflow */
-#define TARGET_FPE_FLTUND (5) /* floating point underflow */
-#define TARGET_FPE_FLTRES (6) /* floating point inexact result */
-#define TARGET_FPE_FLTINV (7) /* floating point invalid operation */
-#define TARGET_FPE_FLTSUB (8) /* subscript out of range */
-#define TARGET_NSIGFPE 8
-
-/*
- * SIGSEGV si_codes
- */
-#define TARGET_SEGV_MAPERR (1) /* address not mapped to object */
-#define TARGET_SEGV_ACCERR (2) /* invalid permissions for mapped object */
-
-/*
- * SIGBUS si_codes
- */
-#define TARGET_BUS_ADRALN (1) /* invalid address alignment */
-#define TARGET_BUS_ADRERR (2) /* non-existant physical address */
-#define TARGET_BUS_OBJERR (3) /* object specific hardware error */
-
-/*
- * SIGTRAP si_codes
- */
-#define TARGET_TRAP_BRKPT (1) /* process breakpoint */
-#define TARGET_TRAP_TRACE (2) /* process trace trap */
-
-#endif /* defined(TARGET_I386) || defined(TARGET_ARM) */
-
-struct target_rlimit {
- target_ulong rlim_cur;
- target_ulong rlim_max;
-};
-
-struct target_pollfd {
- int fd; /* file descriptor */
- short events; /* requested events */
- short revents; /* returned events */
-};
-
-/* virtual terminal ioctls */
-#define TARGET_KIOCSOUND 0x4B2F /* start sound generation (0 for off) */
-#define TARGET_KDMKTONE 0x4B30 /* generate tone */
-#define TARGET_KDGKBTYPE 0x4b33
-#define TARGET_KDGKBENT 0x4B46 /* gets one entry in translation table */
-#define TARGET_KDGKBSENT 0x4B48 /* gets one function key string entry */
-
-#define TARGET_SIOCATMARK 0x8905
-
-/* Networking ioctls */
-#define TARGET_SIOCADDRT 0x890B /* add routing table entry */
-#define TARGET_SIOCDELRT 0x890C /* delete routing table entry */
-#define TARGET_SIOCGIFNAME 0x8910 /* get iface name */
-#define TARGET_SIOCSIFLINK 0x8911 /* set iface channel */
-#define TARGET_SIOCGIFCONF 0x8912 /* get iface list */
-#define TARGET_SIOCGIFFLAGS 0x8913 /* get flags */
-#define TARGET_SIOCSIFFLAGS 0x8914 /* set flags */
-#define TARGET_SIOCGIFADDR 0x8915 /* get PA address */
-#define TARGET_SIOCSIFADDR 0x8916 /* set PA address */
-#define TARGET_SIOCGIFDSTADDR 0x8917 /* get remote PA address */
-#define TARGET_SIOCSIFDSTADDR 0x8918 /* set remote PA address */
-#define TARGET_SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */
-#define TARGET_SIOCSIFBRDADDR 0x891a /* set broadcast PA address */
-#define TARGET_SIOCGIFNETMASK 0x891b /* get network PA mask */
-#define TARGET_SIOCSIFNETMASK 0x891c /* set network PA mask */
-#define TARGET_SIOCGIFMETRIC 0x891d /* get metric */
-#define TARGET_SIOCSIFMETRIC 0x891e /* set metric */
-#define TARGET_SIOCGIFMEM 0x891f /* get memory address (BSD) */
-#define TARGET_SIOCSIFMEM 0x8920 /* set memory address (BSD) */
-#define TARGET_SIOCGIFMTU 0x8921 /* get MTU size */
-#define TARGET_SIOCSIFMTU 0x8922 /* set MTU size */
-#define TARGET_SIOCSIFHWADDR 0x8924 /* set hardware address (NI) */
-#define TARGET_SIOCGIFENCAP 0x8925 /* get/set slip encapsulation */
-#define TARGET_SIOCSIFENCAP 0x8926
-#define TARGET_SIOCGIFHWADDR 0x8927 /* Get hardware address */
-#define TARGET_SIOCGIFSLAVE 0x8929 /* Driver slaving support */
-#define TARGET_SIOCSIFSLAVE 0x8930
-#define TARGET_SIOCADDMULTI 0x8931 /* Multicast address lists */
-#define TARGET_SIOCDELMULTI 0x8932
-
-/* Bridging control calls */
-#define TARGET_SIOCGIFBR 0x8940 /* Bridging support */
-#define TARGET_SIOCSIFBR 0x8941 /* Set bridging options */
-
-#define TARGET_SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */
-#define TARGET_SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */
-
-/* ARP cache control calls. */
-#define TARGET_OLD_SIOCDARP 0x8950 /* old delete ARP table entry */
-#define TARGET_OLD_SIOCGARP 0x8951 /* old get ARP table entry */
-#define TARGET_OLD_SIOCSARP 0x8952 /* old set ARP table entry */
-#define TARGET_SIOCDARP 0x8953 /* delete ARP table entry */
-#define TARGET_SIOCGARP 0x8954 /* get ARP table entry */
-#define TARGET_SIOCSARP 0x8955 /* set ARP table entry */
-
-/* RARP cache control calls. */
-#define TARGET_SIOCDRARP 0x8960 /* delete RARP table entry */
-#define TARGET_SIOCGRARP 0x8961 /* get RARP table entry */
-#define TARGET_SIOCSRARP 0x8962 /* set RARP table entry */
-
-/* Driver configuration calls */
-#define TARGET_SIOCGIFMAP 0x8970 /* Get device parameters */
-#define TARGET_SIOCSIFMAP 0x8971 /* Set device parameters */
-
-/* DLCI configuration calls */
-#define TARGET_SIOCADDDLCI 0x8980 /* Create new DLCI device */
-#define TARGET_SIOCDELDLCI 0x8981 /* Delete DLCI device */
-
-
-/* From <linux/fs.h> */
-
-#define TARGET_BLKROSET TARGET_IO(0x12,93) /* set device read-only (0 = read-write) */
-#define TARGET_BLKROGET TARGET_IO(0x12,94) /* get read-only status (0 = read_write) */
-#define TARGET_BLKRRPART TARGET_IO(0x12,95) /* re-read partition table */
-#define TARGET_BLKGETSIZE TARGET_IO(0x12,96) /* return device size /512 (long *arg) */
-#define TARGET_BLKFLSBUF TARGET_IO(0x12,97) /* flush buffer cache */
-#define TARGET_BLKRASET TARGET_IO(0x12,98) /* Set read ahead for block device */
-#define TARGET_BLKRAGET TARGET_IO(0x12,99) /* get current read ahead setting */
-#define TARGET_BLKFRASET TARGET_IO(0x12,100)/* set filesystem (mm/filemap.c) read-ahead */
-#define TARGET_BLKFRAGET TARGET_IO(0x12,101)/* get filesystem (mm/filemap.c) read-ahead */
-#define TARGET_BLKSECTSET TARGET_IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
-#define TARGET_BLKSECTGET TARGET_IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
-#define TARGET_BLKSSZGET TARGET_IO(0x12,104)/* get block device sector size */
-/* A jump here: 108-111 have been used for various private purposes. */
-#define TARGET_BLKBSZGET TARGET_IOR(0x12,112,sizeof(int))
-#define TARGET_BLKBSZSET TARGET_IOW(0x12,113,sizeof(int))
-#define TARGET_BLKGETSIZE64 TARGET_IOR(0x12,114,sizeof(uint64_t)) /* return device size in bytes (u64 *arg) */
-#define TARGET_FIBMAP TARGET_IO(0x00,1) /* bmap access */
-#define TARGET_FIGETBSZ TARGET_IO(0x00,2) /* get the block size used for bmap */
-
-/* cdrom commands */
-#define TARGET_CDROMPAUSE 0x5301 /* Pause Audio Operation */
-#define TARGET_CDROMRESUME 0x5302 /* Resume paused Audio Operation */
-#define TARGET_CDROMPLAYMSF 0x5303 /* Play Audio MSF (struct cdrom_msf) */
-#define TARGET_CDROMPLAYTRKIND 0x5304 /* Play Audio Track/index
- (struct cdrom_ti) */
-#define TARGET_CDROMREADTOCHDR 0x5305 /* Read TOC header
- (struct cdrom_tochdr) */
-#define TARGET_CDROMREADTOCENTRY 0x5306 /* Read TOC entry
- (struct cdrom_tocentry) */
-#define TARGET_CDROMSTOP 0x5307 /* Stop the cdrom drive */
-#define TARGET_CDROMSTART 0x5308 /* Start the cdrom drive */
-#define TARGET_CDROMEJECT 0x5309 /* Ejects the cdrom media */
-#define TARGET_CDROMVOLCTRL 0x530a /* Control output volume
- (struct cdrom_volctrl) */
-#define TARGET_CDROMSUBCHNL 0x530b /* Read subchannel data
- (struct cdrom_subchnl) */
-#define TARGET_CDROMREADMODE2 0x530c /* Read TARGET_CDROM mode 2 data (2336 Bytes)
- (struct cdrom_read) */
-#define TARGET_CDROMREADMODE1 0x530d /* Read TARGET_CDROM mode 1 data (2048 Bytes)
- (struct cdrom_read) */
-#define TARGET_CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */
-#define TARGET_CDROMEJECT_SW 0x530f /* enable(1)/disable(0) auto-ejecting */
-#define TARGET_CDROMMULTISESSION 0x5310 /* Obtain the start-of-last-session
- address of multi session disks
- (struct cdrom_multisession) */
-#define TARGET_CDROM_GET_MCN 0x5311 /* Obtain the "Universal Product Code"
- if available (struct cdrom_mcn) */
-#define TARGET_CDROM_GET_UPC TARGET_CDROM_GET_MCN /* This one is depricated,
- but here anyway for compatability */
-#define TARGET_CDROMRESET 0x5312 /* hard-reset the drive */
-#define TARGET_CDROMVOLREAD 0x5313 /* Get the drive's volume setting
- (struct cdrom_volctrl) */
-#define TARGET_CDROMREADRAW 0x5314 /* read data in raw mode (2352 Bytes)
- (struct cdrom_read) */
-/*
- * These ioctls are used only used in aztcd.c and optcd.c
- */
-#define TARGET_CDROMREADCOOKED 0x5315 /* read data in cooked mode */
-#define TARGET_CDROMSEEK 0x5316 /* seek msf address */
-
-/*
- * This ioctl is only used by the scsi-cd driver.
- It is for playing audio in logical block addressing mode.
- */
-#define TARGET_CDROMPLAYBLK 0x5317 /* (struct cdrom_blk) */
-
-/*
- * These ioctls are only used in optcd.c
- */
-#define TARGET_CDROMREADALL 0x5318 /* read all 2646 bytes */
-
-/*
- * These ioctls are (now) only in ide-cd.c for controlling
- * drive spindown time. They should be implemented in the
- * Uniform driver, via generic packet commands, GPCMD_MODE_SELECT_10,
- * GPCMD_MODE_SENSE_10 and the GPMODE_POWER_PAGE...
- * -Erik
- */
-#define TARGET_CDROMGETSPINDOWN 0x531d
-#define TARGET_CDROMSETSPINDOWN 0x531e
-
-/*
- * These ioctls are implemented through the uniform CD-ROM driver
- * They _will_ be adopted by all CD-ROM drivers, when all the CD-ROM
- * drivers are eventually ported to the uniform CD-ROM driver interface.
- */
-#define TARGET_CDROMCLOSETRAY 0x5319 /* pendant of CDROMEJECT */
-#define TARGET_CDROM_SET_OPTIONS 0x5320 /* Set behavior options */
-#define TARGET_CDROM_CLEAR_OPTIONS 0x5321 /* Clear behavior options */
-#define TARGET_CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */
-#define TARGET_CDROM_SELECT_DISC 0x5323 /* Select disc (for juke-boxes) */
-#define TARGET_CDROM_MEDIA_CHANGED 0x5325 /* Check is media changed */
-#define TARGET_CDROM_DRIVE_STATUS 0x5326 /* Get tray position, etc. */
-#define TARGET_CDROM_DISC_STATUS 0x5327 /* Get disc type, etc. */
-#define TARGET_CDROM_CHANGER_NSLOTS 0x5328 /* Get number of slots */
-#define TARGET_CDROM_LOCKDOOR 0x5329 /* lock or unlock door */
-#define TARGET_CDROM_DEBUG 0x5330 /* Turn debug messages on/off */
-#define TARGET_CDROM_GET_CAPABILITY 0x5331 /* get capabilities */
-
-/* Note that scsi/scsi_ioctl.h also uses 0x5382 - 0x5386.
- * Future CDROM ioctls should be kept below 0x537F
- */
-
-/* This ioctl is only used by sbpcd at the moment */
-#define TARGET_CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */
- /* conflict with SCSI_IOCTL_GET_IDLUN */
-
-/* DVD-ROM Specific ioctls */
-#define TARGET_DVD_READ_STRUCT 0x5390 /* Read structure */
-#define TARGET_DVD_WRITE_STRUCT 0x5391 /* Write structure */
-#define TARGET_DVD_AUTH 0x5392 /* Authentication */
-
-#define TARGET_CDROM_SEND_PACKET 0x5393 /* send a packet to the drive */
-#define TARGET_CDROM_NEXT_WRITABLE 0x5394 /* get next writable block */
-#define TARGET_CDROM_LAST_WRITTEN 0x5395 /* get last block written on disc */
-
-/* HD commands */
-
-/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */
-#define TARGET_HDIO_GETGEO 0x0301 /* get device geometry */
-#define TARGET_HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */
-#define TARGET_HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */
-#define TARGET_HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */
-#define TARGET_HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */
-#define TARGET_HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */
-#define TARGET_HDIO_GET_DMA 0x030b /* get use-dma flag */
-#define TARGET_HDIO_GET_IDENTITY 0x030d /* get IDE identification info */
-#define TARGET_HDIO_DRIVE_CMD 0x031f /* execute a special drive command */
-
-/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */
-#define TARGET_HDIO_SET_MULTCOUNT 0x0321 /* change IDE blockmode */
-#define TARGET_HDIO_SET_UNMASKINTR 0x0322 /* permit other irqs during I/O */
-#define TARGET_HDIO_SET_KEEPSETTINGS 0x0323 /* keep ioctl settings on reset */
-#define TARGET_HDIO_SET_32BIT 0x0324 /* change io_32bit flags */
-#define TARGET_HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */
-#define TARGET_HDIO_SET_DMA 0x0326 /* change use-dma flag */
-#define TARGET_HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */
-
-
-/* from asm/termbits.h */
-
-#define TARGET_NCC 8
-struct target_termio {
- unsigned short c_iflag; /* input mode flags */
- unsigned short c_oflag; /* output mode flags */
- unsigned short c_cflag; /* control mode flags */
- unsigned short c_lflag; /* local mode flags */
- unsigned char c_line; /* line discipline */
- unsigned char c_cc[TARGET_NCC]; /* control characters */
-};
-
-struct target_winsize {
- unsigned short ws_row;
- unsigned short ws_col;
- unsigned short ws_xpixel;
- unsigned short ws_ypixel;
-};
-
-#include "termbits.h"
-
-#define TARGET_MAP_SHARED 0x01 /* Share changes */
-#define TARGET_MAP_PRIVATE 0x02 /* Changes are private */
-#define TARGET_MAP_TYPE 0x0f /* Mask for type of mapping */
-#define TARGET_MAP_FIXED 0x10 /* Interpret addr exactly */
-#if defined(TARGET_MIPS)
-#define TARGET_MAP_ANONYMOUS 0x0800 /* don't use a file */
-#define TARGET_MAP_GROWSDOWN 0x1000 /* stack-like segment */
-#define TARGET_MAP_DENYWRITE 0x2000 /* ETXTBSY */
-#define TARGET_MAP_EXECUTABLE 0x4000 /* mark it as an executable */
-#define TARGET_MAP_LOCKED 0x8000 /* pages are locked */
-#define TARGET_MAP_NORESERVE 0x0400 /* don't check for reservations */
-#else
-#define TARGET_MAP_ANONYMOUS 0x20 /* don't use a file */
-#define TARGET_MAP_GROWSDOWN 0x0100 /* stack-like segment */
-#define TARGET_MAP_DENYWRITE 0x0800 /* ETXTBSY */
-#define TARGET_MAP_EXECUTABLE 0x1000 /* mark it as an executable */
-#define TARGET_MAP_LOCKED 0x2000 /* pages are locked */
-#define TARGET_MAP_NORESERVE 0x4000 /* don't check for reservations */
-#endif
-
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4)
-struct target_stat {
- unsigned short st_dev;
- unsigned short __pad1;
- target_ulong st_ino;
- unsigned short st_mode;
- unsigned short st_nlink;
- unsigned short st_uid;
- unsigned short st_gid;
- unsigned short st_rdev;
- unsigned short __pad2;
- target_ulong st_size;
- target_ulong st_blksize;
- target_ulong st_blocks;
- target_ulong target_st_atime;
- target_ulong __unused1;
- target_ulong target_st_mtime;
- target_ulong __unused2;
- target_ulong target_st_ctime;
- target_ulong __unused3;
- target_ulong __unused4;
- target_ulong __unused5;
-};
-
-/* This matches struct stat64 in glibc2.1, hence the absolutely
- * insane amounts of padding around dev_t's.
- */
-struct target_stat64 {
- unsigned short st_dev;
- unsigned char __pad0[10];
-
-#define TARGET_STAT64_HAS_BROKEN_ST_INO 1
- target_ulong __st_ino;
-
- unsigned int st_mode;
- unsigned int st_nlink;
-
- target_ulong st_uid;
- target_ulong st_gid;
-
- unsigned short st_rdev;
- unsigned char __pad3[10];
-
- long long st_size;
- target_ulong st_blksize;
-
- target_ulong st_blocks; /* Number 512-byte blocks allocated. */
- target_ulong __pad4; /* future possible st_blocks high bits */
-
- target_ulong target_st_atime;
- target_ulong __pad5;
-
- target_ulong target_st_mtime;
- target_ulong __pad6;
-
- target_ulong target_st_ctime;
- target_ulong __pad7; /* will be high 32 bits of ctime someday */
-
- unsigned long long st_ino;
-} __attribute__((packed));
-
-#ifdef TARGET_ARM
-struct target_eabi_stat64 {
- unsigned long long st_dev;
- unsigned int __pad1;
- unsigned long __st_ino;
- unsigned int st_mode;
- unsigned int st_nlink;
-
- unsigned long st_uid;
- unsigned long st_gid;
-
- unsigned long long st_rdev;
- unsigned int __pad2[2];
-
- long long st_size;
- unsigned long st_blksize;
- unsigned int __pad3;
- unsigned long long st_blocks;
-
- unsigned long target_st_atime;
- unsigned long target_st_atime_nsec;
-
- unsigned long target_st_mtime;
- unsigned long target_st_mtime_nsec;
-
- unsigned long target_st_ctime;
- unsigned long target_st_ctime_nsec;
-
- unsigned long long st_ino;
-} __attribute__ ((packed));
-#endif
-
-#elif defined(TARGET_SPARC)
-
-struct target_stat {
- unsigned short st_dev;
- target_ulong st_ino;
- unsigned short st_mode;
- short st_nlink;
- unsigned short st_uid;
- unsigned short st_gid;
- unsigned short st_rdev;
- target_long st_size;
- target_long target_st_atime;
- target_ulong __unused1;
- target_long target_st_mtime;
- target_ulong __unused2;
- target_long target_st_ctime;
- target_ulong __unused3;
- target_long st_blksize;
- target_long st_blocks;
- target_ulong __unused4[2];
-};
-
-struct target_stat64 {
- unsigned char __pad0[6];
- unsigned short st_dev;
-
- uint64_t st_ino;
-
- unsigned int st_mode;
- unsigned int st_nlink;
-
- unsigned int st_uid;
- unsigned int st_gid;
-
- unsigned char __pad2[6];
- unsigned short st_rdev;
-
- unsigned char __pad3[8];
-
- int64_t st_size;
- unsigned int st_blksize;
-
- unsigned char __pad4[8];
- unsigned int st_blocks;
-
- unsigned int target_st_atime;
- unsigned int __unused1;
-
- unsigned int target_st_mtime;
- unsigned int __unused2;
-
- unsigned int target_st_ctime;
- unsigned int __unused3;
-
- unsigned int __unused4;
- unsigned int __unused5;
-};
-
-#elif defined(TARGET_PPC)
-
-struct target_stat {
- unsigned short st_dev;
- target_ulong st_ino;
- unsigned int st_mode;
- unsigned short st_nlink;
- unsigned int st_uid;
- unsigned int st_gid;
- unsigned short st_rdev;
- target_ulong st_size;
- target_ulong st_blksize;
- target_ulong st_blocks;
- target_ulong target_st_atime;
- target_ulong __unused1;
- target_ulong target_st_mtime;
- target_ulong __unused2;
- target_ulong target_st_ctime;
- target_ulong __unused3;
- target_ulong __unused4;
- target_ulong __unused5;
-};
-
-struct target_stat64 {
- unsigned long long st_dev;
- unsigned long long st_ino;
- unsigned int st_mode;
- unsigned int st_nlink;
- unsigned int st_uid;
- unsigned int st_gid;
- unsigned long long st_rdev;
- long long pad0;
- long long st_size;
- target_ulong st_blksize;
- target_ulong pad1;
- long long st_blocks; /* Number 512-byte blocks allocated. */
- target_ulong target_st_atime;
- target_ulong target_st_atime_nsec;
- target_ulong target_st_mtime;
- target_ulong target_st_mtime_nsec;
- target_ulong target_st_ctime;
- target_ulong target_st_ctime_nsec;
- target_ulong __unused4;
- target_ulong __unused5;
-};
-
-#elif defined(TARGET_MIPS)
-
-struct target_stat {
- unsigned st_dev;
- target_long st_pad1[3]; /* Reserved for network id */
- target_ulong st_ino;
- unsigned int st_mode;
- unsigned int st_nlink;
- int st_uid;
- int st_gid;
- unsigned st_rdev;
- target_long st_pad2[2];
- target_long st_size;
- target_long st_pad3;
- /*
- * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
- * but we don't have it under Linux.
- */
- target_long target_st_atime;
- target_long target_st_atime_nsec;
- target_long target_st_mtime;
- target_long target_st_mtime_nsec;
- target_long target_st_ctime;
- target_long target_st_ctime_nsec;
- target_long st_blksize;
- target_long st_blocks;
- target_long st_pad4[14];
-};
-
-/*
- * This matches struct stat64 in glibc2.1, hence the absolutely insane
- * amounts of padding around dev_t's. The memory layout is the same as of
- * struct stat of the 64-bit kernel.
- */
-
-struct target_stat64 {
- target_ulong st_dev;
- target_ulong st_pad0[3]; /* Reserved for st_dev expansion */
-
- uint64_t st_ino;
-
- unsigned int st_mode;
- unsigned int st_nlink;
-
- int st_uid;
- int st_gid;
-
- target_ulong st_rdev;
- target_ulong st_pad1[3]; /* Reserved for st_rdev expansion */
-
- int64_t st_size;
-
- /*
- * Actually this should be timestruc_t st_atime, st_mtime and st_ctime
- * but we don't have it under Linux.
- */
- target_long target_st_atime;
- target_ulong target_st_atime_nsec; /* Reserved for st_atime expansion */
-
- target_long target_st_mtime;
- target_ulong target_st_mtime_nsec; /* Reserved for st_mtime expansion */
-
- target_long target_st_ctime;
- target_ulong target_st_ctime_nsec; /* Reserved for st_ctime expansion */
-
- target_ulong st_blksize;
- target_ulong st_pad2;
-
- int64_t st_blocks;
-};
-#else
-#error unsupported CPU
-#endif
-
-#ifdef TARGET_MIPS
-struct target_statfs {
- target_long f_type;
- target_long f_bsize;
- target_long f_frsize; /* Fragment size - unsupported */
- target_long f_blocks;
- target_long f_bfree;
- target_long f_files;
- target_long f_ffree;
- target_long f_bavail;
-
- /* Linux specials */
- int f_fsid;
- target_long f_namelen;
- target_long f_spare[6];
-};
-
-struct target_statfs64 {
- uint32_t f_type;
- uint32_t f_bsize;
- uint32_t f_frsize; /* Fragment size - unsupported */
- uint32_t __pad;
- uint64_t f_blocks;
- uint64_t f_bfree;
- uint64_t f_files;
- uint64_t f_ffree;
- uint64_t f_bavail;
- int f_fsid;
- uint32_t f_namelen;
- uint32_t f_spare[6];
-};
-#else
-struct target_statfs {
- uint32_t f_type;
- uint32_t f_bsize;
- uint32_t f_blocks;
- uint32_t f_bfree;
- uint32_t f_bavail;
- uint32_t f_files;
- uint32_t f_ffree;
- int f_fsid;
- uint32_t f_namelen;
- uint32_t f_frsize;
- uint32_t f_spare[5];
-};
-
-struct target_statfs64 {
- uint32_t f_type;
- uint32_t f_bsize;
- uint64_t f_blocks;
- uint64_t f_bfree;
- uint64_t f_bavail;
- uint64_t f_files;
- uint64_t f_ffree;
- int f_fsid;
- uint32_t f_namelen;
- uint32_t f_frsize;
- uint32_t f_spare[5];
-};
-#endif
-
-
-#define TARGET_F_DUPFD 0 /* dup */
-#define TARGET_F_GETFD 1 /* get close_on_exec */
-#define TARGET_F_SETFD 2 /* set/clear close_on_exec */
-#define TARGET_F_GETFL 3 /* get file->f_flags */
-#define TARGET_F_SETFL 4 /* set file->f_flags */
-
-#if defined(TARGET_ALPHA)
-#define TARGET_F_GETLK 7
-#define TARGET_F_SETLK 8
-#define TARGET_F_SETLKW 9
-#define TARGET_F_SETOWN 5 /* for sockets. */
-#define TARGET_F_GETOWN 6 /* for sockets. */
-#else
-#define TARGET_F_GETLK 5
-#define TARGET_F_SETLK 6
-#define TARGET_F_SETLKW 7
-#define TARGET_F_SETOWN 8 /* for sockets. */
-#define TARGET_F_GETOWN 9 /* for sockets. */
-#endif
-
-#define TARGET_F_SETSIG 10 /* for sockets. */
-#define TARGET_F_GETSIG 11 /* for sockets. */
-
-#define TARGET_F_GETLK64 12 /* using 'struct flock64' */
-#define TARGET_F_SETLK64 13
-#define TARGET_F_SETLKW64 14
-
-#if defined (TARGET_ARM)
-#define TARGET_O_ACCMODE 0003
-#define TARGET_O_RDONLY 00
-#define TARGET_O_WRONLY 01
-#define TARGET_O_RDWR 02
-#define TARGET_O_CREAT 0100 /* not fcntl */
-#define TARGET_O_EXCL 0200 /* not fcntl */
-#define TARGET_O_NOCTTY 0400 /* not fcntl */
-#define TARGET_O_TRUNC 01000 /* not fcntl */
-#define TARGET_O_APPEND 02000
-#define TARGET_O_NONBLOCK 04000
-#define TARGET_O_NDELAY TARGET_O_NONBLOCK
-#define TARGET_O_SYNC 010000
-#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
-#define TARGET_O_DIRECTORY 040000 /* must be a directory */
-#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
-#define TARGET_O_DIRECT 0200000 /* direct disk access hint */
-#define TARGET_O_LARGEFILE 0400000
-#elif defined (TARGET_PPC)
-#define TARGET_O_ACCMODE 0003
-#define TARGET_O_RDONLY 00
-#define TARGET_O_WRONLY 01
-#define TARGET_O_RDWR 02
-#define TARGET_O_CREAT 0100 /* not fcntl */
-#define TARGET_O_EXCL 0200 /* not fcntl */
-#define TARGET_O_NOCTTY 0400 /* not fcntl */
-#define TARGET_O_TRUNC 01000 /* not fcntl */
-#define TARGET_O_APPEND 02000
-#define TARGET_O_NONBLOCK 04000
-#define TARGET_O_NDELAY TARGET_O_NONBLOCK
-#define TARGET_O_SYNC 010000
-#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
-#define TARGET_O_DIRECTORY 040000 /* must be a directory */
-#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */
-#define TARGET_O_LARGEFILE 0200000
-#define TARGET_O_DIRECT 0400000 /* direct disk access hint */
-#elif defined (TARGET_SPARC)
-#define TARGET_O_RDONLY 0x0000
-#define TARGET_O_WRONLY 0x0001
-#define TARGET_O_RDWR 0x0002
-#define TARGET_O_ACCMODE 0x0003
-#define TARGET_O_APPEND 0x0008
-#define TARGET_FASYNC 0x0040 /* fcntl, for BSD compatibility */
-#define TARGET_O_CREAT 0x0200 /* not fcntl */
-#define TARGET_O_TRUNC 0x0400 /* not fcntl */
-#define TARGET_O_EXCL 0x0800 /* not fcntl */
-#define TARGET_O_SYNC 0x2000
-#define TARGET_O_NONBLOCK 0x4000
-#define TARGET_O_NDELAY (0x0004 | TARGET_O_NONBLOCK)
-#define TARGET_O_NOCTTY 0x8000 /* not fcntl */
-#define TARGET_O_DIRECTORY 0x10000 /* must be a directory */
-#define TARGET_O_NOFOLLOW 0x20000 /* don't follow links */
-#define TARGET_O_LARGEFILE 0x40000
-#define TARGET_O_DIRECT 0x100000 /* direct disk access hint */
-#elif defined(TARGET_MIPS)
-#define TARGET_O_ACCMODE 0x0003
-#define TARGET_O_RDONLY 0x0000
-#define TARGET_O_WRONLY 0x0001
-#define TARGET_O_RDWR 0x0002
-#define TARGET_O_APPEND 0x0008
-#define TARGET_O_SYNC 0x0010
-#define TARGET_O_NONBLOCK 0x0080
-#define TARGET_O_CREAT 0x0100 /* not fcntl */
-#define TARGET_O_TRUNC 0x0200 /* not fcntl */
-#define TARGET_O_EXCL 0x0400 /* not fcntl */
-#define TARGET_O_NOCTTY 0x0800 /* not fcntl */
-#define TARGET_FASYNC 0x1000 /* fcntl, for BSD compatibility */
-#define TARGET_O_LARGEFILE 0x2000 /* allow large file opens */
-#define TARGET_O_DIRECT 0x8000 /* direct disk access hint */
-#define TARGET_O_DIRECTORY 0x10000 /* must be a directory */
-#define TARGET_O_NOFOLLOW 0x20000 /* don't follow links */
-#define TARGET_O_NOATIME 0x40000
-#define TARGET_O_NDELAY TARGET_O_NONBLOCK
-#else
-#define TARGET_O_ACCMODE 0003
-#define TARGET_O_RDONLY 00
-#define TARGET_O_WRONLY 01
-#define TARGET_O_RDWR 02
-#define TARGET_O_CREAT 0100 /* not fcntl */
-#define TARGET_O_EXCL 0200 /* not fcntl */
-#define TARGET_O_NOCTTY 0400 /* not fcntl */
-#define TARGET_O_TRUNC 01000 /* not fcntl */
-#define TARGET_O_APPEND 02000
-#define TARGET_O_NONBLOCK 04000
-#define TARGET_O_NDELAY TARGET_O_NONBLOCK
-#define TARGET_O_SYNC 010000
-#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */
-#define TARGET_O_DIRECT 040000 /* direct disk access hint */
-#define TARGET_O_LARGEFILE 0100000
-#define TARGET_O_DIRECTORY 0200000 /* must be a directory */
-#define TARGET_O_NOFOLLOW 0400000 /* don't follow links */
-#endif
-
-struct target_flock {
- short l_type;
- short l_whence;
- target_ulong l_start;
- target_ulong l_len;
- int l_pid;
-};
-
-struct target_flock64 {
- short l_type;
- short l_whence;
- unsigned long long l_start;
- unsigned long long l_len;
- int l_pid;
-}__attribute__((packed));
-
-#ifdef TARGET_ARM
-struct target_eabi_flock64 {
- short l_type;
- short l_whence;
- int __pad;
- unsigned long long l_start;
- unsigned long long l_len;
- int l_pid;
-}__attribute__((packed));
-#endif
-
-/* soundcard defines */
-/* XXX: convert them all to arch indepedent entries */
-#define TARGET_SNDCTL_COPR_HALT TARGET_IOWR('C', 7, int);
-#define TARGET_SNDCTL_COPR_LOAD 0xcfb04301
-#define TARGET_SNDCTL_COPR_RCODE 0xc0144303
-#define TARGET_SNDCTL_COPR_RCVMSG 0x8fa44309
-#define TARGET_SNDCTL_COPR_RDATA 0xc0144302
-#define TARGET_SNDCTL_COPR_RESET 0x00004300
-#define TARGET_SNDCTL_COPR_RUN 0xc0144306
-#define TARGET_SNDCTL_COPR_SENDMSG 0xcfa44308
-#define TARGET_SNDCTL_COPR_WCODE 0x40144305
-#define TARGET_SNDCTL_COPR_WDATA 0x40144304
-#define TARGET_SNDCTL_DSP_RESET TARGET_IO('P', 0)
-#define TARGET_SNDCTL_DSP_SYNC TARGET_IO('P', 1)
-#define TARGET_SNDCTL_DSP_SPEED TARGET_IOWR('P', 2, int)
-#define TARGET_SNDCTL_DSP_STEREO TARGET_IOWR('P', 3, int)
-#define TARGET_SNDCTL_DSP_GETBLKSIZE TARGET_IOWR('P', 4, int)
-#define TARGET_SNDCTL_DSP_SETFMT TARGET_IOWR('P', 5, int)
-#define TARGET_SNDCTL_DSP_CHANNELS TARGET_IOWR('P', 6, int)
-#define TARGET_SOUND_PCM_WRITE_FILTER TARGET_IOWR('P', 7, int)
-#define TARGET_SNDCTL_DSP_POST TARGET_IO('P', 8)
-#define TARGET_SNDCTL_DSP_SUBDIVIDE TARGET_IOWR('P', 9, int)
-#define TARGET_SNDCTL_DSP_SETFRAGMENT TARGET_IOWR('P',10, int)
-#define TARGET_SNDCTL_DSP_GETFMTS TARGET_IOR('P', 11, int)
-#define TARGET_SNDCTL_DSP_GETOSPACE TARGET_IORU('P',12)
-#define TARGET_SNDCTL_DSP_GETISPACE TARGET_IORU('P',13)
-#define TARGET_SNDCTL_DSP_GETCAPS TARGET_IOR('P', 15, int)
-#define TARGET_SNDCTL_DSP_GETTRIGGER TARGET_IOR('P',16, int)
-#define TARGET_SNDCTL_DSP_GETIPTR TARGET_IORU('P',17)
-#define TARGET_SNDCTL_DSP_GETOPTR TARGET_IORU('P',18)
-#define TARGET_SNDCTL_DSP_MAPINBUF 0x80085013
-#define TARGET_SNDCTL_DSP_MAPOUTBUF 0x80085014
-#define TARGET_SNDCTL_DSP_NONBLOCK 0x0000500e
-#define TARGET_SNDCTL_DSP_SAMPLESIZE 0xc0045005
-#define TARGET_SNDCTL_DSP_SETDUPLEX 0x00005016
-#define TARGET_SNDCTL_DSP_SETSYNCRO 0x00005015
-#define TARGET_SNDCTL_DSP_SETTRIGGER 0x40045010
-#define TARGET_SNDCTL_FM_4OP_ENABLE 0x4004510f
-#define TARGET_SNDCTL_FM_LOAD_INSTR 0x40285107
-#define TARGET_SNDCTL_MIDI_INFO 0xc074510c
-#define TARGET_SNDCTL_MIDI_MPUCMD 0xc0216d02
-#define TARGET_SNDCTL_MIDI_MPUMODE 0xc0046d01
-#define TARGET_SNDCTL_MIDI_PRETIME 0xc0046d00
-#define TARGET_SNDCTL_PMGR_ACCESS 0xcfb85110
-#define TARGET_SNDCTL_PMGR_IFACE 0xcfb85001
-#define TARGET_SNDCTL_SEQ_CTRLRATE 0xc0045103
-#define TARGET_SNDCTL_SEQ_GETINCOUNT 0x80045105
-#define TARGET_SNDCTL_SEQ_GETOUTCOUNT 0x80045104
-#define TARGET_SNDCTL_SEQ_NRMIDIS 0x8004510b
-#define TARGET_SNDCTL_SEQ_NRSYNTHS 0x8004510a
-#define TARGET_SNDCTL_SEQ_OUTOFBAND 0x40085112
-#define TARGET_SNDCTL_SEQ_PANIC 0x00005111
-#define TARGET_SNDCTL_SEQ_PERCMODE 0x40045106
-#define TARGET_SNDCTL_SEQ_RESET 0x00005100
-#define TARGET_SNDCTL_SEQ_RESETSAMPLES 0x40045109
-#define TARGET_SNDCTL_SEQ_SYNC 0x00005101
-#define TARGET_SNDCTL_SEQ_TESTMIDI 0x40045108
-#define TARGET_SNDCTL_SEQ_THRESHOLD 0x4004510d
-#define TARGET_SNDCTL_SEQ_TRESHOLD 0x4004510d
-#define TARGET_SNDCTL_SYNTH_INFO 0xc08c5102
-#define TARGET_SNDCTL_SYNTH_MEMAVL 0xc004510e
-#define TARGET_SNDCTL_TMR_CONTINUE 0x00005404
-#define TARGET_SNDCTL_TMR_METRONOME 0x40045407
-#define TARGET_SNDCTL_TMR_SELECT 0x40045408
-#define TARGET_SNDCTL_TMR_SOURCE 0xc0045406
-#define TARGET_SNDCTL_TMR_START 0x00005402
-#define TARGET_SNDCTL_TMR_STOP 0x00005403
-#define TARGET_SNDCTL_TMR_TEMPO 0xc0045405
-#define TARGET_SNDCTL_TMR_TIMEBASE 0xc0045401
-#define TARGET_SOUND_PCM_READ_RATE 0x80045002
-#define TARGET_SOUND_PCM_READ_CHANNELS 0x80045006
-#define TARGET_SOUND_PCM_READ_BITS 0x80045005
-#define TARGET_SOUND_PCM_READ_FILTER 0x80045007
-#define TARGET_SOUND_MIXER_INFO TARGET_IOR ('M', 101, mixer_info)
-#define TARGET_SOUND_MIXER_ACCESS 0xc0804d66
-#define TARGET_SOUND_MIXER_PRIVATE1 TARGET_IOWR('M', 111, int)
-#define TARGET_SOUND_MIXER_PRIVATE2 TARGET_IOWR('M', 112, int)
-#define TARGET_SOUND_MIXER_PRIVATE3 TARGET_IOWR('M', 113, int)
-#define TARGET_SOUND_MIXER_PRIVATE4 TARGET_IOWR('M', 114, int)
-#define TARGET_SOUND_MIXER_PRIVATE5 TARGET_IOWR('M', 115, int)
-
-#define TARGET_MIXER_READ(dev) TARGET_IOR('M', dev, int)
-
-#define TARGET_SOUND_MIXER_READ_VOLUME TARGET_MIXER_READ(SOUND_MIXER_VOLUME)
-#define TARGET_SOUND_MIXER_READ_BASS TARGET_MIXER_READ(SOUND_MIXER_BASS)
-#define TARGET_SOUND_MIXER_READ_TREBLE TARGET_MIXER_READ(SOUND_MIXER_TREBLE)
-#define TARGET_SOUND_MIXER_READ_SYNTH TARGET_MIXER_READ(SOUND_MIXER_SYNTH)
-#define TARGET_SOUND_MIXER_READ_PCM TARGET_MIXER_READ(SOUND_MIXER_PCM)
-#define TARGET_SOUND_MIXER_READ_SPEAKER TARGET_MIXER_READ(SOUND_MIXER_SPEAKER)
-#define TARGET_SOUND_MIXER_READ_LINE TARGET_MIXER_READ(SOUND_MIXER_LINE)
-#define TARGET_SOUND_MIXER_READ_MIC TARGET_MIXER_READ(SOUND_MIXER_MIC)
-#define TARGET_SOUND_MIXER_READ_CD TARGET_MIXER_READ(SOUND_MIXER_CD)
-#define TARGET_SOUND_MIXER_READ_IMIX TARGET_MIXER_READ(SOUND_MIXER_IMIX)
-#define TARGET_SOUND_MIXER_READ_ALTPCM TARGET_MIXER_READ(SOUND_MIXER_ALTPCM)
-#define TARGET_SOUND_MIXER_READ_RECLEV TARGET_MIXER_READ(SOUND_MIXER_RECLEV)
-#define TARGET_SOUND_MIXER_READ_IGAIN TARGET_MIXER_READ(SOUND_MIXER_IGAIN)
-#define TARGET_SOUND_MIXER_READ_OGAIN TARGET_MIXER_READ(SOUND_MIXER_OGAIN)
-#define TARGET_SOUND_MIXER_READ_LINE1 TARGET_MIXER_READ(SOUND_MIXER_LINE1)
-#define TARGET_SOUND_MIXER_READ_LINE2 TARGET_MIXER_READ(SOUND_MIXER_LINE2)
-#define TARGET_SOUND_MIXER_READ_LINE3 TARGET_MIXER_READ(SOUND_MIXER_LINE3)
-
-/* Obsolete macros */
-#define TARGET_SOUND_MIXER_READ_MUTE TARGET_MIXER_READ(SOUND_MIXER_MUTE)
-#define TARGET_SOUND_MIXER_READ_ENHANCE TARGET_MIXER_READ(SOUND_MIXER_ENHANCE)
-#define TARGET_SOUND_MIXER_READ_LOUD TARGET_MIXER_READ(SOUND_MIXER_LOUD)
-
-#define TARGET_SOUND_MIXER_READ_RECSRC TARGET_MIXER_READ(SOUND_MIXER_RECSRC)
-#define TARGET_SOUND_MIXER_READ_DEVMASK TARGET_MIXER_READ(SOUND_MIXER_DEVMASK)
-#define TARGET_SOUND_MIXER_READ_RECMASK TARGET_MIXER_READ(SOUND_MIXER_RECMASK)
-#define TARGET_SOUND_MIXER_READ_STEREODEVS TARGET_MIXER_READ(SOUND_MIXER_STEREODEVS)
-#define TARGET_SOUND_MIXER_READ_CAPS TARGET_MIXER_READ(SOUND_MIXER_CAPS)
-
-#define TARGET_MIXER_WRITE(dev) TARGET_IOWR('M', dev, int)
-
-#define TARGET_SOUND_MIXER_WRITE_VOLUME TARGET_MIXER_WRITE(SOUND_MIXER_VOLUME)
-#define TARGET_SOUND_MIXER_WRITE_BASS TARGET_MIXER_WRITE(SOUND_MIXER_BASS)
-#define TARGET_SOUND_MIXER_WRITE_TREBLE TARGET_MIXER_WRITE(SOUND_MIXER_TREBLE)
-#define TARGET_SOUND_MIXER_WRITE_SYNTH TARGET_MIXER_WRITE(SOUND_MIXER_SYNTH)
-#define TARGET_SOUND_MIXER_WRITE_PCM TARGET_MIXER_WRITE(SOUND_MIXER_PCM)
-#define TARGET_SOUND_MIXER_WRITE_SPEAKER TARGET_MIXER_WRITE(SOUND_MIXER_SPEAKER)
-#define TARGET_SOUND_MIXER_WRITE_LINE TARGET_MIXER_WRITE(SOUND_MIXER_LINE)
-#define TARGET_SOUND_MIXER_WRITE_MIC TARGET_MIXER_WRITE(SOUND_MIXER_MIC)
-#define TARGET_SOUND_MIXER_WRITE_CD TARGET_MIXER_WRITE(SOUND_MIXER_CD)
-#define TARGET_SOUND_MIXER_WRITE_IMIX TARGET_MIXER_WRITE(SOUND_MIXER_IMIX)
-#define TARGET_SOUND_MIXER_WRITE_ALTPCM TARGET_MIXER_WRITE(SOUND_MIXER_ALTPCM)
-#define TARGET_SOUND_MIXER_WRITE_RECLEV TARGET_MIXER_WRITE(SOUND_MIXER_RECLEV)
-#define TARGET_SOUND_MIXER_WRITE_IGAIN TARGET_MIXER_WRITE(SOUND_MIXER_IGAIN)
-#define TARGET_SOUND_MIXER_WRITE_OGAIN TARGET_MIXER_WRITE(SOUND_MIXER_OGAIN)
-#define TARGET_SOUND_MIXER_WRITE_LINE1 TARGET_MIXER_WRITE(SOUND_MIXER_LINE1)
-#define TARGET_SOUND_MIXER_WRITE_LINE2 TARGET_MIXER_WRITE(SOUND_MIXER_LINE2)
-#define TARGET_SOUND_MIXER_WRITE_LINE3 TARGET_MIXER_WRITE(SOUND_MIXER_LINE3)
-
-/* Obsolete macros */
-#define TARGET_SOUND_MIXER_WRITE_MUTE TARGET_MIXER_WRITE(SOUND_MIXER_MUTE)
-#define TARGET_SOUND_MIXER_WRITE_ENHANCE TARGET_MIXER_WRITE(SOUND_MIXER_ENHANCE)
-#define TARGET_SOUND_MIXER_WRITE_LOUD TARGET_MIXER_WRITE(SOUND_MIXER_LOUD)
-
-#define TARGET_SOUND_MIXER_WRITE_RECSRC TARGET_MIXER_WRITE(SOUND_MIXER_RECSRC)
-
-/* vfat ioctls */
-#define TARGET_VFAT_IOCTL_READDIR_BOTH TARGET_IORU('r', 1)
-#define TARGET_VFAT_IOCTL_READDIR_SHORT TARGET_IORU('r', 2)
-
-struct target_sysinfo {
- target_long uptime; /* Seconds since boot */
- target_ulong loads[3]; /* 1, 5, and 15 minute load averages */
- target_ulong totalram; /* Total usable main memory size */
- target_ulong freeram; /* Available memory size */
- target_ulong sharedram; /* Amount of shared memory */
- target_ulong bufferram; /* Memory used by buffers */
- target_ulong totalswap; /* Total swap space size */
- target_ulong freeswap; /* swap space still available */
- unsigned short procs; /* Number of current processes */
- unsigned short pad; /* explicit padding for m68k */
- target_ulong totalhigh; /* Total high memory size */
- target_ulong freehigh; /* Available high memory size */
- unsigned int mem_unit; /* Memory unit size in bytes */
- char _f[20-2*sizeof(target_long)-sizeof(int)]; /* Padding: libc5 uses this.. */
-};
-
-#include "socket.h"
diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h
deleted file mode 100644
index 308da48..0000000
--- a/linux-user/syscall_types.h
+++ /dev/null
@@ -1,81 +0,0 @@
-STRUCT_SPECIAL(termios)
-
-STRUCT(winsize,
- TYPE_SHORT, TYPE_SHORT, TYPE_SHORT, TYPE_SHORT)
-
-STRUCT(serial_multiport_struct,
- TYPE_INT, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR,
- TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_CHAR, TYPE_CHAR, TYPE_INT,
- MK_ARRAY(TYPE_INT, 32))
-
-STRUCT(serial_icounter_struct,
- TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_INT, 16))
-
-STRUCT(sockaddr,
- TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 14))
-
-STRUCT(rtentry,
- TYPE_ULONG, MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr),
- TYPE_SHORT, TYPE_SHORT, TYPE_ULONG, TYPE_PTRVOID, TYPE_SHORT, TYPE_PTRVOID,
- TYPE_ULONG, TYPE_ULONG, TYPE_SHORT)
-
-STRUCT(ifmap,
- TYPE_ULONG, TYPE_ULONG, TYPE_SHORT, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR,
- /* Spare 3 bytes */
- TYPE_CHAR, TYPE_CHAR, TYPE_CHAR)
-
-/* The *_ifreq_list arrays deal with the fact that struct ifreq has unions */
-
-STRUCT(sockaddr_ifreq,
- MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_sockaddr))
-
-STRUCT(short_ifreq,
- MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_SHORT)
-
-STRUCT(int_ifreq,
- MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_INT)
-
-STRUCT(ifmap_ifreq,
- MK_ARRAY(TYPE_CHAR, IFNAMSIZ), MK_STRUCT(STRUCT_ifmap))
-
-STRUCT(char_ifreq,
- MK_ARRAY(TYPE_CHAR, IFNAMSIZ),
- MK_ARRAY(TYPE_CHAR, IFNAMSIZ))
-
-STRUCT(ptr_ifreq,
- MK_ARRAY(TYPE_CHAR, IFNAMSIZ), TYPE_PTRVOID)
-
-STRUCT(ifconf,
- TYPE_INT, TYPE_PTRVOID)
-
-STRUCT(arpreq,
- MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr),
- MK_ARRAY(TYPE_CHAR, 16))
-
-STRUCT(arpreq_old,
- MK_STRUCT(STRUCT_sockaddr), MK_STRUCT(STRUCT_sockaddr), TYPE_INT, MK_STRUCT(STRUCT_sockaddr))
-
-STRUCT(cdrom_read_audio,
- TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_CHAR, TYPE_INT, TYPE_PTRVOID,
- TYPE_NULL)
-
-STRUCT(hd_geometry,
- TYPE_CHAR, TYPE_CHAR, TYPE_SHORT, TYPE_ULONG)
-
-STRUCT(dirent,
- TYPE_LONG, TYPE_LONG, TYPE_SHORT, MK_ARRAY(TYPE_CHAR, 256))
-
-STRUCT(kbentry,
- TYPE_CHAR, TYPE_CHAR, TYPE_SHORT)
-
-STRUCT(kbsentry,
- TYPE_CHAR, MK_ARRAY(TYPE_CHAR, 512))
-
-STRUCT(audio_buf_info,
- TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT)
-
-STRUCT(count_info,
- TYPE_INT, TYPE_INT, TYPE_INT)
-
-STRUCT(mixer_info,
- MK_ARRAY(TYPE_CHAR, 16), MK_ARRAY(TYPE_CHAR, 32), TYPE_INT, MK_ARRAY(TYPE_INT, 10))
diff --git a/linux-user/vm86.c b/linux-user/vm86.c
deleted file mode 100644
index b28eea6..0000000
--- a/linux-user/vm86.c
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * vm86 linux syscall support
- *
- * 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 <errno.h>
-#include <unistd.h>
-
-#include "qemu.h"
-
-//#define DEBUG_VM86
-
-#define set_flags(X,new,mask) \
-((X) = ((X) & ~(mask)) | ((new) & (mask)))
-
-#define SAFE_MASK (0xDD5)
-#define RETURN_MASK (0xDFF)
-
-static inline int is_revectored(int nr, struct target_revectored_struct *bitmap)
-{
- return (((uint8_t *)bitmap)[nr >> 3] >> (nr & 7)) & 1;
-}
-
-static inline void vm_putw(uint8_t *segptr, unsigned int reg16, unsigned int val)
-{
- stw(segptr + (reg16 & 0xffff), val);
-}
-
-static inline void vm_putl(uint8_t *segptr, unsigned int reg16, unsigned int val)
-{
- stl(segptr + (reg16 & 0xffff), val);
-}
-
-static inline unsigned int vm_getw(uint8_t *segptr, unsigned int reg16)
-{
- return lduw(segptr + (reg16 & 0xffff));
-}
-
-static inline unsigned int vm_getl(uint8_t *segptr, unsigned int reg16)
-{
- return ldl(segptr + (reg16 & 0xffff));
-}
-
-void save_v86_state(CPUX86State *env)
-{
- TaskState *ts = env->opaque;
- struct target_vm86plus_struct * target_v86;
-
- lock_user_struct(target_v86, ts->target_v86, 0);
- /* put the VM86 registers in the userspace register structure */
- target_v86->regs.eax = tswap32(env->regs[R_EAX]);
- target_v86->regs.ebx = tswap32(env->regs[R_EBX]);
- target_v86->regs.ecx = tswap32(env->regs[R_ECX]);
- target_v86->regs.edx = tswap32(env->regs[R_EDX]);
- target_v86->regs.esi = tswap32(env->regs[R_ESI]);
- target_v86->regs.edi = tswap32(env->regs[R_EDI]);
- target_v86->regs.ebp = tswap32(env->regs[R_EBP]);
- target_v86->regs.esp = tswap32(env->regs[R_ESP]);
- target_v86->regs.eip = tswap32(env->eip);
- target_v86->regs.cs = tswap16(env->segs[R_CS].selector);
- target_v86->regs.ss = tswap16(env->segs[R_SS].selector);
- target_v86->regs.ds = tswap16(env->segs[R_DS].selector);
- target_v86->regs.es = tswap16(env->segs[R_ES].selector);
- target_v86->regs.fs = tswap16(env->segs[R_FS].selector);
- target_v86->regs.gs = tswap16(env->segs[R_GS].selector);
- set_flags(env->eflags, ts->v86flags, VIF_MASK | ts->v86mask);
- target_v86->regs.eflags = tswap32(env->eflags);
- unlock_user_struct(target_v86, ts->target_v86, 1);
-#ifdef DEBUG_VM86
- fprintf(logfile, "save_v86_state: eflags=%08x cs:ip=%04x:%04x\n",
- env->eflags, env->segs[R_CS].selector, env->eip);
-#endif
-
- /* restore 32 bit registers */
- env->regs[R_EAX] = ts->vm86_saved_regs.eax;
- env->regs[R_EBX] = ts->vm86_saved_regs.ebx;
- env->regs[R_ECX] = ts->vm86_saved_regs.ecx;
- env->regs[R_EDX] = ts->vm86_saved_regs.edx;
- env->regs[R_ESI] = ts->vm86_saved_regs.esi;
- env->regs[R_EDI] = ts->vm86_saved_regs.edi;
- env->regs[R_EBP] = ts->vm86_saved_regs.ebp;
- env->regs[R_ESP] = ts->vm86_saved_regs.esp;
- env->eflags = ts->vm86_saved_regs.eflags;
- env->eip = ts->vm86_saved_regs.eip;
-
- cpu_x86_load_seg(env, R_CS, ts->vm86_saved_regs.cs);
- cpu_x86_load_seg(env, R_SS, ts->vm86_saved_regs.ss);
- cpu_x86_load_seg(env, R_DS, ts->vm86_saved_regs.ds);
- cpu_x86_load_seg(env, R_ES, ts->vm86_saved_regs.es);
- cpu_x86_load_seg(env, R_FS, ts->vm86_saved_regs.fs);
- cpu_x86_load_seg(env, R_GS, ts->vm86_saved_regs.gs);
-}
-
-/* return from vm86 mode to 32 bit. The vm86() syscall will return
- 'retval' */
-static inline void return_to_32bit(CPUX86State *env, int retval)
-{
-#ifdef DEBUG_VM86
- fprintf(logfile, "return_to_32bit: ret=0x%x\n", retval);
-#endif
- save_v86_state(env);
- env->regs[R_EAX] = retval;
-}
-
-static inline int set_IF(CPUX86State *env)
-{
- TaskState *ts = env->opaque;
-
- ts->v86flags |= VIF_MASK;
- if (ts->v86flags & VIP_MASK) {
- return_to_32bit(env, TARGET_VM86_STI);
- return 1;
- }
- return 0;
-}
-
-static inline void clear_IF(CPUX86State *env)
-{
- TaskState *ts = env->opaque;
-
- ts->v86flags &= ~VIF_MASK;
-}
-
-static inline void clear_TF(CPUX86State *env)
-{
- env->eflags &= ~TF_MASK;
-}
-
-static inline void clear_AC(CPUX86State *env)
-{
- env->eflags &= ~AC_MASK;
-}
-
-static inline int set_vflags_long(unsigned long eflags, CPUX86State *env)
-{
- TaskState *ts = env->opaque;
-
- set_flags(ts->v86flags, eflags, ts->v86mask);
- set_flags(env->eflags, eflags, SAFE_MASK);
- if (eflags & IF_MASK)
- return set_IF(env);
- else
- clear_IF(env);
- return 0;
-}
-
-static inline int set_vflags_short(unsigned short flags, CPUX86State *env)
-{
- TaskState *ts = env->opaque;
-
- set_flags(ts->v86flags, flags, ts->v86mask & 0xffff);
- set_flags(env->eflags, flags, SAFE_MASK);
- if (flags & IF_MASK)
- return set_IF(env);
- else
- clear_IF(env);
- return 0;
-}
-
-static inline unsigned int get_vflags(CPUX86State *env)
-{
- TaskState *ts = env->opaque;
- unsigned int flags;
-
- flags = env->eflags & RETURN_MASK;
- if (ts->v86flags & VIF_MASK)
- flags |= IF_MASK;
- flags |= IOPL_MASK;
- return flags | (ts->v86flags & ts->v86mask);
-}
-
-#define ADD16(reg, val) reg = (reg & ~0xffff) | ((reg + (val)) & 0xffff)
-
-/* handle VM86 interrupt (NOTE: the CPU core currently does not
- support TSS interrupt revectoring, so this code is always executed) */
-static void do_int(CPUX86State *env, int intno)
-{
- TaskState *ts = env->opaque;
- uint32_t *int_ptr, segoffs;
- uint8_t *ssp;
- unsigned int sp;
-
- if (env->segs[R_CS].selector == TARGET_BIOSSEG)
- goto cannot_handle;
- if (is_revectored(intno, &ts->vm86plus.int_revectored))
- goto cannot_handle;
- if (intno == 0x21 && is_revectored((env->regs[R_EAX] >> 8) & 0xff,
- &ts->vm86plus.int21_revectored))
- goto cannot_handle;
- int_ptr = (uint32_t *)(intno << 2);
- segoffs = tswap32(*int_ptr);
- if ((segoffs >> 16) == TARGET_BIOSSEG)
- goto cannot_handle;
-#if defined(DEBUG_VM86)
- fprintf(logfile, "VM86: emulating int 0x%x. CS:IP=%04x:%04x\n",
- intno, segoffs >> 16, segoffs & 0xffff);
-#endif
- /* save old state */
- ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
- sp = env->regs[R_ESP] & 0xffff;
- vm_putw(ssp, sp - 2, get_vflags(env));
- vm_putw(ssp, sp - 4, env->segs[R_CS].selector);
- vm_putw(ssp, sp - 6, env->eip);
- ADD16(env->regs[R_ESP], -6);
- /* goto interrupt handler */
- env->eip = segoffs & 0xffff;
- cpu_x86_load_seg(env, R_CS, segoffs >> 16);
- clear_TF(env);
- clear_IF(env);
- clear_AC(env);
- return;
- cannot_handle:
-#if defined(DEBUG_VM86)
- fprintf(logfile, "VM86: return to 32 bits int 0x%x\n", intno);
-#endif
- return_to_32bit(env, TARGET_VM86_INTx | (intno << 8));
-}
-
-void handle_vm86_trap(CPUX86State *env, int trapno)
-{
- if (trapno == 1 || trapno == 3) {
- return_to_32bit(env, TARGET_VM86_TRAP + (trapno << 8));
- } else {
- do_int(env, trapno);
- }
-}
-
-#define CHECK_IF_IN_TRAP() \
- if ((ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) && \
- (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_TFpendig)) \
- newflags |= TF_MASK
-
-#define VM86_FAULT_RETURN \
- if ((ts->vm86plus.vm86plus.flags & TARGET_force_return_for_pic) && \
- (ts->v86flags & (IF_MASK | VIF_MASK))) \
- return_to_32bit(env, TARGET_VM86_PICRETURN); \
- return
-
-void handle_vm86_fault(CPUX86State *env)
-{
- TaskState *ts = env->opaque;
- uint8_t *csp, *pc, *ssp;
- unsigned int ip, sp, newflags, newip, newcs, opcode, intno;
- int data32, pref_done;
-
- csp = (uint8_t *)(env->segs[R_CS].selector << 4);
- ip = env->eip & 0xffff;
- pc = csp + ip;
-
- ssp = (uint8_t *)(env->segs[R_SS].selector << 4);
- sp = env->regs[R_ESP] & 0xffff;
-
-#if defined(DEBUG_VM86)
- fprintf(logfile, "VM86 exception %04x:%08x %02x %02x\n",
- env->segs[R_CS].selector, env->eip, pc[0], pc[1]);
-#endif
-
- data32 = 0;
- pref_done = 0;
- do {
- opcode = csp[ip];
- ADD16(ip, 1);
- switch (opcode) {
- case 0x66: /* 32-bit data */ data32=1; break;
- case 0x67: /* 32-bit address */ break;
- case 0x2e: /* CS */ break;
- case 0x3e: /* DS */ break;
- case 0x26: /* ES */ break;
- case 0x36: /* SS */ break;
- case 0x65: /* GS */ break;
- case 0x64: /* FS */ break;
- case 0xf2: /* repnz */ break;
- case 0xf3: /* rep */ break;
- default: pref_done = 1;
- }
- } while (!pref_done);
-
- /* VM86 mode */
- switch(opcode) {
- case 0x9c: /* pushf */
- if (data32) {
- vm_putl(ssp, sp - 4, get_vflags(env));
- ADD16(env->regs[R_ESP], -4);
- } else {
- vm_putw(ssp, sp - 2, get_vflags(env));
- ADD16(env->regs[R_ESP], -2);
- }
- env->eip = ip;
- VM86_FAULT_RETURN;
-
- case 0x9d: /* popf */
- if (data32) {
- newflags = vm_getl(ssp, sp);
- ADD16(env->regs[R_ESP], 4);
- } else {
- newflags = vm_getw(ssp, sp);
- ADD16(env->regs[R_ESP], 2);
- }
- env->eip = ip;
- CHECK_IF_IN_TRAP();
- if (data32) {
- if (set_vflags_long(newflags, env))
- return;
- } else {
- if (set_vflags_short(newflags, env))
- return;
- }
- VM86_FAULT_RETURN;
-
- case 0xcd: /* int */
- intno = csp[ip];
- ADD16(ip, 1);
- env->eip = ip;
- if (ts->vm86plus.vm86plus.flags & TARGET_vm86dbg_active) {
- if ( (ts->vm86plus.vm86plus.vm86dbg_intxxtab[intno >> 3] >>
- (intno &7)) & 1) {
- return_to_32bit(env, TARGET_VM86_INTx + (intno << 8));
- return;
- }
- }
- do_int(env, intno);
- break;
-
- case 0xcf: /* iret */
- if (data32) {
- newip = vm_getl(ssp, sp) & 0xffff;
- newcs = vm_getl(ssp, sp + 4) & 0xffff;
- newflags = vm_getl(ssp, sp + 8);
- ADD16(env->regs[R_ESP], 12);
- } else {
- newip = vm_getw(ssp, sp);
- newcs = vm_getw(ssp, sp + 2);
- newflags = vm_getw(ssp, sp + 4);
- ADD16(env->regs[R_ESP], 6);
- }
- env->eip = newip;
- cpu_x86_load_seg(env, R_CS, newcs);
- CHECK_IF_IN_TRAP();
- if (data32) {
- if (set_vflags_long(newflags, env))
- return;
- } else {
- if (set_vflags_short(newflags, env))
- return;
- }
- VM86_FAULT_RETURN;
-
- case 0xfa: /* cli */
- env->eip = ip;
- clear_IF(env);
- VM86_FAULT_RETURN;
-
- case 0xfb: /* sti */
- env->eip = ip;
- if (set_IF(env))
- return;
- VM86_FAULT_RETURN;
-
- default:
- /* real VM86 GPF exception */
- return_to_32bit(env, TARGET_VM86_UNKNOWN);
- break;
- }
-}
-
-int do_vm86(CPUX86State *env, long subfunction, target_ulong vm86_addr)
-{
- TaskState *ts = env->opaque;
- struct target_vm86plus_struct * target_v86;
- int ret;
-
- switch (subfunction) {
- case TARGET_VM86_REQUEST_IRQ:
- case TARGET_VM86_FREE_IRQ:
- case TARGET_VM86_GET_IRQ_BITS:
- case TARGET_VM86_GET_AND_RESET_IRQ:
- gemu_log("qemu: unsupported vm86 subfunction (%ld)\n", subfunction);
- ret = -EINVAL;
- goto out;
- case TARGET_VM86_PLUS_INSTALL_CHECK:
- /* NOTE: on old vm86 stuff this will return the error
- from verify_area(), because the subfunction is
- interpreted as (invalid) address to vm86_struct.
- So the installation check works.
- */
- ret = 0;
- goto out;
- }
-
- /* save current CPU regs */
- ts->vm86_saved_regs.eax = 0; /* default vm86 syscall return code */
- ts->vm86_saved_regs.ebx = env->regs[R_EBX];
- ts->vm86_saved_regs.ecx = env->regs[R_ECX];
- ts->vm86_saved_regs.edx = env->regs[R_EDX];
- ts->vm86_saved_regs.esi = env->regs[R_ESI];
- ts->vm86_saved_regs.edi = env->regs[R_EDI];
- ts->vm86_saved_regs.ebp = env->regs[R_EBP];
- ts->vm86_saved_regs.esp = env->regs[R_ESP];
- ts->vm86_saved_regs.eflags = env->eflags;
- ts->vm86_saved_regs.eip = env->eip;
- ts->vm86_saved_regs.cs = env->segs[R_CS].selector;
- ts->vm86_saved_regs.ss = env->segs[R_SS].selector;
- ts->vm86_saved_regs.ds = env->segs[R_DS].selector;
- ts->vm86_saved_regs.es = env->segs[R_ES].selector;
- ts->vm86_saved_regs.fs = env->segs[R_FS].selector;
- ts->vm86_saved_regs.gs = env->segs[R_GS].selector;
-
- ts->target_v86 = vm86_addr;
- lock_user_struct(target_v86, vm86_addr, 1);
- /* build vm86 CPU state */
- ts->v86flags = tswap32(target_v86->regs.eflags);
- env->eflags = (env->eflags & ~SAFE_MASK) |
- (tswap32(target_v86->regs.eflags) & SAFE_MASK) | VM_MASK;
-
- ts->vm86plus.cpu_type = tswapl(target_v86->cpu_type);
- switch (ts->vm86plus.cpu_type) {
- case TARGET_CPU_286:
- ts->v86mask = 0;
- break;
- case TARGET_CPU_386:
- ts->v86mask = NT_MASK | IOPL_MASK;
- break;
- case TARGET_CPU_486:
- ts->v86mask = AC_MASK | NT_MASK | IOPL_MASK;
- break;
- default:
- ts->v86mask = ID_MASK | AC_MASK | NT_MASK | IOPL_MASK;
- break;
- }
-
- env->regs[R_EBX] = tswap32(target_v86->regs.ebx);
- env->regs[R_ECX] = tswap32(target_v86->regs.ecx);
- env->regs[R_EDX] = tswap32(target_v86->regs.edx);
- env->regs[R_ESI] = tswap32(target_v86->regs.esi);
- env->regs[R_EDI] = tswap32(target_v86->regs.edi);
- env->regs[R_EBP] = tswap32(target_v86->regs.ebp);
- env->regs[R_ESP] = tswap32(target_v86->regs.esp);
- env->eip = tswap32(target_v86->regs.eip);
- cpu_x86_load_seg(env, R_CS, tswap16(target_v86->regs.cs));
- cpu_x86_load_seg(env, R_SS, tswap16(target_v86->regs.ss));
- cpu_x86_load_seg(env, R_DS, tswap16(target_v86->regs.ds));
- cpu_x86_load_seg(env, R_ES, tswap16(target_v86->regs.es));
- cpu_x86_load_seg(env, R_FS, tswap16(target_v86->regs.fs));
- cpu_x86_load_seg(env, R_GS, tswap16(target_v86->regs.gs));
- ret = tswap32(target_v86->regs.eax); /* eax will be restored at
- the end of the syscall */
- memcpy(&ts->vm86plus.int_revectored,
- &target_v86->int_revectored, 32);
- memcpy(&ts->vm86plus.int21_revectored,
- &target_v86->int21_revectored, 32);
- ts->vm86plus.vm86plus.flags = tswapl(target_v86->vm86plus.flags);
- memcpy(&ts->vm86plus.vm86plus.vm86dbg_intxxtab,
- target_v86->vm86plus.vm86dbg_intxxtab, 32);
- unlock_user_struct(target_v86, vm86_addr, 0);
-
-#ifdef DEBUG_VM86
- fprintf(logfile, "do_vm86: cs:ip=%04x:%04x\n",
- env->segs[R_CS].selector, env->eip);
-#endif
- /* now the virtual CPU is ready for vm86 execution ! */
- out:
- return ret;
-}
-
diff --git a/linux_keycodes.h b/linux_keycodes.h
new file mode 100644
index 0000000..3875028
--- /dev/null
+++ b/linux_keycodes.h
@@ -0,0 +1,452 @@
+#ifndef _INPUT_H
+#define _INPUT_H
+
+/*
+ * Copyright (c) 1999-2002 Vojtech Pavlik
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+/*
+ * Keys and buttons
+ */
+
+#define KEY_RESERVED 0
+#define KEY_ESC 1
+#define KEY_1 2
+#define KEY_2 3
+#define KEY_3 4
+#define KEY_4 5
+#define KEY_5 6
+#define KEY_6 7
+#define KEY_7 8
+#define KEY_8 9
+#define KEY_9 10
+#define KEY_0 11
+#define KEY_MINUS 12
+#define KEY_EQUAL 13
+#define KEY_BACKSPACE 14
+#define KEY_TAB 15
+#define KEY_Q 16
+#define KEY_W 17
+#define KEY_E 18
+#define KEY_R 19
+#define KEY_T 20
+#define KEY_Y 21
+#define KEY_U 22
+#define KEY_I 23
+#define KEY_O 24
+#define KEY_P 25
+#define KEY_LEFTBRACE 26
+#define KEY_RIGHTBRACE 27
+#define KEY_ENTER 28
+#define KEY_LEFTCTRL 29
+#define KEY_A 30
+#define KEY_S 31
+#define KEY_D 32
+#define KEY_F 33
+#define KEY_G 34
+#define KEY_H 35
+#define KEY_J 36
+#define KEY_K 37
+#define KEY_L 38
+#define KEY_SEMICOLON 39
+#define KEY_APOSTROPHE 40
+#define KEY_GRAVE 41
+#define KEY_LEFTSHIFT 42
+#define KEY_BACKSLASH 43
+#define KEY_Z 44
+#define KEY_X 45
+#define KEY_C 46
+#define KEY_V 47
+#define KEY_B 48
+#define KEY_N 49
+#define KEY_M 50
+#define KEY_COMMA 51
+#define KEY_DOT 52
+#define KEY_SLASH 53
+#define KEY_RIGHTSHIFT 54
+#define KEY_KPASTERISK 55
+#define KEY_LEFTALT 56
+#define KEY_SPACE 57
+#define KEY_CAPSLOCK 58
+#define KEY_F1 59
+#define KEY_F2 60
+#define KEY_F3 61
+#define KEY_F4 62
+#define KEY_F5 63
+#define KEY_F6 64
+#define KEY_F7 65
+#define KEY_F8 66
+#define KEY_F9 67
+#define KEY_F10 68
+#define KEY_NUMLOCK 69
+#define KEY_SCROLLLOCK 70
+#define KEY_KP7 71
+#define KEY_KP8 72
+#define KEY_KP9 73
+#define KEY_KPMINUS 74
+#define KEY_KP4 75
+#define KEY_KP5 76
+#define KEY_KP6 77
+#define KEY_KPPLUS 78
+#define KEY_KP1 79
+#define KEY_KP2 80
+#define KEY_KP3 81
+#define KEY_KP0 82
+#define KEY_KPDOT 83
+
+#define KEY_ZENKAKUHANKAKU 85
+#define KEY_102ND 86
+#define KEY_F11 87
+#define KEY_F12 88
+#define KEY_RO 89
+#define KEY_KATAKANA 90
+#define KEY_HIRAGANA 91
+#define KEY_HENKAN 92
+#define KEY_KATAKANAHIRAGANA 93
+#define KEY_MUHENKAN 94
+#define KEY_KPJPCOMMA 95
+#define KEY_KPENTER 96
+#define KEY_RIGHTCTRL 97
+#define KEY_KPSLASH 98
+#define KEY_SYSRQ 99
+#define KEY_RIGHTALT 100
+#define KEY_LINEFEED 101
+#define KEY_HOME 102
+#define KEY_UP 103
+#define KEY_PAGEUP 104
+#define KEY_LEFT 105
+#define KEY_RIGHT 106
+#define KEY_END 107
+#define KEY_DOWN 108
+#define KEY_PAGEDOWN 109
+#define KEY_INSERT 110
+#define KEY_DELETE 111
+#define KEY_MACRO 112
+#define KEY_MUTE 113
+#define KEY_VOLUMEDOWN 114
+#define KEY_VOLUMEUP 115
+#define KEY_POWER 116
+#define KEY_KPEQUAL 117
+#define KEY_KPPLUSMINUS 118
+#define KEY_PAUSE 119
+
+#define KEY_KPCOMMA 121
+#define KEY_HANGEUL 122
+#define KEY_HANGUEL KEY_HANGEUL
+#define KEY_HANJA 123
+#define KEY_YEN 124
+#define KEY_LEFTMETA 125
+#define KEY_RIGHTMETA 126
+#define KEY_COMPOSE 127
+
+#define KEY_STOP 128
+#define KEY_AGAIN 129
+#define KEY_PROPS 130
+#define KEY_UNDO 131
+#define KEY_FRONT 132
+#define KEY_COPY 133
+#define KEY_OPEN 134
+#define KEY_PASTE 135
+#define KEY_FIND 136
+#define KEY_CUT 137
+#define KEY_HELP 138
+#define KEY_MENU 139
+#define KEY_CALC 140
+#define KEY_SETUP 141
+#define KEY_SLEEP 142
+#define KEY_WAKEUP 143
+#define KEY_FILE 144
+#define KEY_SENDFILE 145
+#define KEY_DELETEFILE 146
+#define KEY_XFER 147
+#define KEY_PROG1 148
+#define KEY_PROG2 149
+#define KEY_WWW 150
+#define KEY_MSDOS 151
+#define KEY_COFFEE 152
+#define KEY_DIRECTION 153
+#define KEY_CYCLEWINDOWS 154
+#define KEY_MAIL 155
+#define KEY_BOOKMARKS 156
+#define KEY_COMPUTER 157
+#define KEY_BACK 158
+#define KEY_FORWARD 159
+#define KEY_CLOSECD 160
+#define KEY_EJECTCD 161
+#define KEY_EJECTCLOSECD 162
+#define KEY_NEXTSONG 163
+#define KEY_PLAYPAUSE 164
+#define KEY_PREVIOUSSONG 165
+#define KEY_STOPCD 166
+#define KEY_RECORD 167
+#define KEY_REWIND 168
+#define KEY_PHONE 169
+#define KEY_ISO 170
+#define KEY_CONFIG 171
+#define KEY_HOMEPAGE 172
+#define KEY_REFRESH 173
+#define KEY_EXIT 174
+#define KEY_MOVE 175
+#define KEY_EDIT 176
+#define KEY_SCROLLUP 177
+#define KEY_SCROLLDOWN 178
+#define KEY_KPLEFTPAREN 179
+#define KEY_KPRIGHTPAREN 180
+#define KEY_NEW 181
+#define KEY_REDO 182
+
+#define KEY_F13 183
+#define KEY_F14 184
+#define KEY_F15 185
+#define KEY_F16 186
+#define KEY_F17 187
+#define KEY_F18 188
+#define KEY_F19 189
+#define KEY_F20 190
+#define KEY_F21 191
+#define KEY_F22 192
+#define KEY_F23 193
+#define KEY_F24 194
+
+#define KEY_PLAYCD 200
+#define KEY_PAUSECD 201
+#define KEY_PROG3 202
+#define KEY_PROG4 203
+#define KEY_SUSPEND 205
+#define KEY_CLOSE 206
+#define KEY_PLAY 207
+#define KEY_FASTFORWARD 208
+#define KEY_BASSBOOST 209
+#define KEY_PRINT 210
+#define KEY_HP 211
+#define KEY_CAMERA 212
+#define KEY_SOUND 213
+#define KEY_QUESTION 214
+#define KEY_EMAIL 215
+#define KEY_CHAT 216
+#define KEY_SEARCH 217
+#define KEY_CONNECT 218
+#define KEY_FINANCE 219
+#define KEY_SPORT 220
+#define KEY_SHOP 221
+#define KEY_ALTERASE 222
+#define KEY_CANCEL 223
+#define KEY_BRIGHTNESSDOWN 224
+#define KEY_BRIGHTNESSUP 225
+#define KEY_MEDIA 226
+
+
+/*Zeus: these keys are defined for OMAP730 Perseus2*/
+#define KEY_STAR 227
+#define KEY_SHARP 228
+#define KEY_SOFT1 229
+#define KEY_SOFT2 230
+#define KEY_SEND 231
+#define KEY_CENTER 232
+#define KEY_HEADSETHOOK 233
+#define KEY_0_5 234
+#define KEY_2_5 235
+
+#define KEY_SWITCHVIDEOMODE 236
+#define KEY_KBDILLUMTOGGLE 237
+#define KEY_KBDILLUMDOWN 238
+#define KEY_KBDILLUMUP 239
+
+#define KEY_SEND 231
+#define KEY_REPLY 232
+#define KEY_FORWARDMAIL 233
+#define KEY_SAVE 234
+#define KEY_DOCUMENTS 235
+
+#define KEY_BATTERY 236
+
+#define KEY_UNKNOWN 240
+
+#define KEY_NUM 241
+#define KEY_FOCUS 242
+#define KEY_PLUS 243
+#define KEY_NOTIFICATION 244
+
+#define BTN_MISC 0x100
+#define BTN_0 0x100
+#define BTN_1 0x101
+#define BTN_2 0x102
+#define BTN_3 0x103
+#define BTN_4 0x104
+#define BTN_5 0x105
+#define BTN_6 0x106
+#define BTN_7 0x107
+#define BTN_8 0x108
+#define BTN_9 0x109
+
+#define BTN_MOUSE 0x110
+#define BTN_LEFT 0x110
+#define BTN_RIGHT 0x111
+#define BTN_MIDDLE 0x112
+#define BTN_SIDE 0x113
+#define BTN_EXTRA 0x114
+#define BTN_FORWARD 0x115
+#define BTN_BACK 0x116
+#define BTN_TASK 0x117
+
+#define BTN_JOYSTICK 0x120
+#define BTN_TRIGGER 0x120
+#define BTN_THUMB 0x121
+#define BTN_THUMB2 0x122
+#define BTN_TOP 0x123
+#define BTN_TOP2 0x124
+#define BTN_PINKIE 0x125
+#define BTN_BASE 0x126
+#define BTN_BASE2 0x127
+#define BTN_BASE3 0x128
+#define BTN_BASE4 0x129
+#define BTN_BASE5 0x12a
+#define BTN_BASE6 0x12b
+#define BTN_DEAD 0x12f
+
+#define BTN_GAMEPAD 0x130
+#define BTN_A 0x130
+#define BTN_B 0x131
+#define BTN_C 0x132
+#define BTN_X 0x133
+#define BTN_Y 0x134
+#define BTN_Z 0x135
+#define BTN_TL 0x136
+#define BTN_TR 0x137
+#define BTN_TL2 0x138
+#define BTN_TR2 0x139
+#define BTN_SELECT 0x13a
+#define BTN_START 0x13b
+#define BTN_MODE 0x13c
+#define BTN_THUMBL 0x13d
+#define BTN_THUMBR 0x13e
+
+#define BTN_DIGI 0x140
+#define BTN_TOOL_PEN 0x140
+#define BTN_TOOL_RUBBER 0x141
+#define BTN_TOOL_BRUSH 0x142
+#define BTN_TOOL_PENCIL 0x143
+#define BTN_TOOL_AIRBRUSH 0x144
+#define BTN_TOOL_FINGER 0x145
+#define BTN_TOOL_MOUSE 0x146
+#define BTN_TOOL_LENS 0x147
+#define BTN_TOUCH 0x14a
+#define BTN_STYLUS 0x14b
+#define BTN_STYLUS2 0x14c
+#define BTN_TOOL_DOUBLETAP 0x14d
+#define BTN_TOOL_TRIPLETAP 0x14e
+
+#define BTN_WHEEL 0x150
+#define BTN_GEAR_DOWN 0x150
+#define BTN_GEAR_UP 0x151
+
+#define KEY_OK 0x160
+#define KEY_SELECT 0x161
+#define KEY_GOTO 0x162
+#define KEY_CLEAR 0x163
+#define KEY_POWER2 0x164
+#define KEY_OPTION 0x165
+#define KEY_INFO 0x166
+#define KEY_TIME 0x167
+#define KEY_VENDOR 0x168
+#define KEY_ARCHIVE 0x169
+#define KEY_PROGRAM 0x16a
+#define KEY_CHANNEL 0x16b
+#define KEY_FAVORITES 0x16c
+#define KEY_EPG 0x16d
+#define KEY_PVR 0x16e
+#define KEY_MHP 0x16f
+#define KEY_LANGUAGE 0x170
+#define KEY_TITLE 0x171
+#define KEY_SUBTITLE 0x172
+#define KEY_ANGLE 0x173
+#define KEY_ZOOM 0x174
+#define KEY_MODE 0x175
+#define KEY_KEYBOARD 0x176
+#define KEY_SCREEN 0x177
+#define KEY_PC 0x178
+#define KEY_TV 0x179
+#define KEY_TV2 0x17a
+#define KEY_VCR 0x17b
+#define KEY_VCR2 0x17c
+#define KEY_SAT 0x17d
+#define KEY_SAT2 0x17e
+#define KEY_CD 0x17f
+#define KEY_TAPE 0x180
+#define KEY_RADIO 0x181
+#define KEY_TUNER 0x182
+#define KEY_PLAYER 0x183
+#define KEY_TEXT 0x184
+#define KEY_DVD 0x185
+#define KEY_AUX 0x186
+#define KEY_MP3 0x187
+#define KEY_AUDIO 0x188
+#define KEY_VIDEO 0x189
+#define KEY_DIRECTORY 0x18a
+#define KEY_LIST 0x18b
+#define KEY_MEMO 0x18c
+#define KEY_CALENDAR 0x18d
+#define KEY_RED 0x18e
+#define KEY_GREEN 0x18f
+#define KEY_YELLOW 0x190
+#define KEY_BLUE 0x191
+#define KEY_CHANNELUP 0x192
+#define KEY_CHANNELDOWN 0x193
+#define KEY_FIRST 0x194
+#define KEY_LAST 0x195
+#define KEY_AB 0x196
+#define KEY_NEXT 0x197
+#define KEY_RESTART 0x198
+#define KEY_SLOW 0x199
+#define KEY_SHUFFLE 0x19a
+#define KEY_BREAK 0x19b
+#define KEY_PREVIOUS 0x19c
+#define KEY_DIGITS 0x19d
+#define KEY_TEEN 0x19e
+#define KEY_TWEN 0x19f
+
+#define KEY_DEL_EOL 0x1c0
+#define KEY_DEL_EOS 0x1c1
+#define KEY_INS_LINE 0x1c2
+#define KEY_DEL_LINE 0x1c3
+
+#define KEY_FN 0x1d0
+#define KEY_FN_ESC 0x1d1
+#define KEY_FN_F1 0x1d2
+#define KEY_FN_F2 0x1d3
+#define KEY_FN_F3 0x1d4
+#define KEY_FN_F4 0x1d5
+#define KEY_FN_F5 0x1d6
+#define KEY_FN_F6 0x1d7
+#define KEY_FN_F7 0x1d8
+#define KEY_FN_F8 0x1d9
+#define KEY_FN_F9 0x1da
+#define KEY_FN_F10 0x1db
+#define KEY_FN_F11 0x1dc
+#define KEY_FN_F12 0x1dd
+#define KEY_FN_1 0x1de
+#define KEY_FN_2 0x1df
+#define KEY_FN_D 0x1e0
+#define KEY_FN_E 0x1e1
+#define KEY_FN_F 0x1e2
+#define KEY_FN_S 0x1e3
+#define KEY_FN_B 0x1e4
+
+#define KEY_BRL_DOT1 0x1f1
+#define KEY_BRL_DOT2 0x1f2
+#define KEY_BRL_DOT3 0x1f3
+#define KEY_BRL_DOT4 0x1f4
+#define KEY_BRL_DOT5 0x1f5
+#define KEY_BRL_DOT6 0x1f6
+#define KEY_BRL_DOT7 0x1f7
+#define KEY_BRL_DOT8 0x1f8
+
+/* We avoid low common keys in module aliases so they don't get huge. */
+#define KEY_MIN_INTERESTING KEY_MUTE
+#define KEY_MAX 0x1ff
+
+#endif
diff --git a/loader.c b/loader.c
index 3fa681d..606ca10 100644
--- a/loader.c
+++ b/loader.c
@@ -1,8 +1,8 @@
/*
* QEMU Executable loader
- *
+ *
* Copyright (c) 2006 Fabrice Bellard
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
@@ -28,7 +28,7 @@
int get_image_size(const char *filename)
{
int fd, size;
- fd = open(filename, O_RDONLY | O_BINARY);
+ fd = open(filename, O_BINARY | O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
size = lseek(fd, 0, SEEK_END);
@@ -218,7 +218,7 @@ int load_elf(const char *filename, int64_t virt_to_phys_addend,
data_order = ELFDATA2LSB;
#endif
must_swab = data_order != e_ident[EI_DATA];
-
+
lseek(fd, 0, SEEK_SET);
if (e_ident[EI_CLASS] == ELFCLASS64) {
ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry);
diff --git a/loadpng.c b/loadpng.c
new file mode 100644
index 0000000..b5c7a37
--- /dev/null
+++ b/loadpng.c
@@ -0,0 +1,275 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <png.h>
+
+#if 0
+#define LOG(x...) fprintf(stderr,"error: " x)
+#else
+#define LOG(x...) do {} while (0)
+#endif
+
+void *loadpng(const char *fn, unsigned *_width, unsigned *_height)
+{
+ FILE *fp = 0;
+ unsigned char header[8];
+ unsigned char *data = 0;
+ unsigned char **rowptrs = 0;
+ png_structp p = 0;
+ png_infop pi = 0;
+
+ png_uint_32 width, height;
+ int bitdepth, colortype, imethod, cmethod, fmethod, i;
+
+ p = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ if(p == 0) {
+ LOG("%s: failed to allocate png read struct\n", fn);
+ return 0;
+ }
+
+ pi = png_create_info_struct(p);
+ if(pi == 0) {
+ LOG("%s: failed to allocate png info struct\n", fn);
+ goto oops;
+ }
+
+ fp = fopen(fn, "rb");
+ if(fp == 0) {
+ LOG("%s: failed to open file\n", fn);
+ return 0;
+ }
+
+ if(fread(header, 8, 1, fp) != 1) {
+ LOG("%s: failed to read header\n", fn);
+ goto oops;
+ }
+
+ if(png_sig_cmp(header, 0, 8)) {
+ LOG("%s: header is not a PNG header\n", fn);
+ goto oops;
+ }
+
+ if(setjmp(png_jmpbuf(p))) {
+ LOG("%s: png library error\n", fn);
+ oops:
+ png_destroy_read_struct(&p, &pi, 0);
+ if(fp != 0) fclose(fp);
+ if(data != 0) free(data);
+ if(rowptrs != 0) free(rowptrs);
+ return 0;
+ }
+
+ png_init_io(p, fp);
+ png_set_sig_bytes(p, 8);
+
+ png_read_info(p, pi);
+
+ png_get_IHDR(p, pi, &width, &height, &bitdepth, &colortype,
+ &imethod, &cmethod, &fmethod);
+// printf("PNG: %d x %d (d=%d, c=%d)\n",
+// width, height, bitdepth, colortype);
+
+ switch(colortype){
+ case PNG_COLOR_TYPE_PALETTE:
+ png_set_palette_to_rgb(p);
+ break;
+
+ case PNG_COLOR_TYPE_RGB:
+ if(png_get_valid(p, pi, PNG_INFO_tRNS)) {
+ png_set_tRNS_to_alpha(p);
+ } else {
+ png_set_filler(p, 0xff, PNG_FILLER_AFTER);
+ }
+ break;
+
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ break;
+
+ case PNG_COLOR_TYPE_GRAY:
+ if(bitdepth < 8) {
+ png_set_gray_1_2_4_to_8(p);
+ }
+
+ default:
+ LOG("%s: unsupported (grayscale?) color type\n");
+ goto oops;
+ }
+
+ if(bitdepth == 16) {
+ png_set_strip_16(p);
+ }
+
+ data = (unsigned char*) malloc((width * 4) * height);
+ rowptrs = (unsigned char **) malloc(sizeof(unsigned char*) * height);
+
+ if((data == 0) || (rowptrs == 0)){
+ LOG("could not allocate data buffer\n");
+ goto oops;
+ }
+
+ for(i = 0; i < height; i++) {
+ rowptrs[i] = data + ((width * 4) * i);
+ }
+
+ png_read_image(p, rowptrs);
+
+ png_destroy_read_struct(&p, &pi, 0);
+ fclose(fp);
+ if(rowptrs != 0) free(rowptrs);
+
+ *_width = width;
+ *_height = height;
+
+ return (void*) data;
+}
+
+
+typedef struct
+{
+ const unsigned char* base;
+ const unsigned char* end;
+ const unsigned char* cursor;
+
+} PngReader;
+
+static void
+png_reader_read_data( png_structp png_ptr,
+ png_bytep data,
+ png_size_t length )
+{
+ PngReader* reader = png_get_io_ptr(png_ptr);
+ png_size_t avail = (png_size_t)(reader->end - reader->cursor);
+
+ if (avail > length)
+ avail = length;
+
+ memcpy( data, reader->cursor, avail );
+ reader->cursor += avail;
+}
+
+
+void *readpng(const unsigned char *base, size_t size, unsigned *_width, unsigned *_height)
+{
+ PngReader reader;
+ unsigned char *data = 0;
+ unsigned char **rowptrs = 0;
+ png_structp p = 0;
+ png_infop pi = 0;
+
+ png_uint_32 width, height;
+ int bitdepth, colortype, imethod, cmethod, fmethod, i;
+
+ p = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
+ if(p == 0) {
+ LOG("%s: failed to allocate png read struct\n", fn);
+ return 0;
+ }
+
+ pi = png_create_info_struct(p);
+ if(pi == 0) {
+ LOG("%s: failed to allocate png info struct\n", fn);
+ goto oops;
+ }
+
+ reader.base = base;
+ reader.end = base + size;
+ reader.cursor = base;
+
+ if(size < 8 || png_sig_cmp(base, 0, 8)) {
+ LOG("%s: header is not a PNG header\n", fn);
+ goto oops;
+ }
+
+ reader.cursor += 8;
+
+ if(setjmp(png_jmpbuf(p))) {
+ LOG("%s: png library error\n", fn);
+ oops:
+ png_destroy_read_struct(&p, &pi, 0);
+ if(data != 0) free(data);
+ if(rowptrs != 0) free(rowptrs);
+ return 0;
+ }
+
+ png_set_read_fn (p, &reader, png_reader_read_data);
+ png_set_sig_bytes(p, 8);
+
+ png_read_info(p, pi);
+
+ png_get_IHDR(p, pi, &width, &height, &bitdepth, &colortype,
+ &imethod, &cmethod, &fmethod);
+// printf("PNG: %d x %d (d=%d, c=%d)\n",
+// width, height, bitdepth, colortype);
+
+ switch(colortype){
+ case PNG_COLOR_TYPE_PALETTE:
+ png_set_palette_to_rgb(p);
+ break;
+
+ case PNG_COLOR_TYPE_RGB:
+ if(png_get_valid(p, pi, PNG_INFO_tRNS)) {
+ png_set_tRNS_to_alpha(p);
+ } else {
+ png_set_filler(p, 0xff, PNG_FILLER_AFTER);
+ }
+ break;
+
+ case PNG_COLOR_TYPE_RGB_ALPHA:
+ break;
+
+ case PNG_COLOR_TYPE_GRAY:
+ if(bitdepth < 8) {
+ png_set_gray_1_2_4_to_8(p);
+ }
+
+ default:
+ LOG("%s: unsupported (grayscale?) color type\n");
+ goto oops;
+ }
+
+ if(bitdepth == 16) {
+ png_set_strip_16(p);
+ }
+
+ data = (unsigned char*) malloc((width * 4) * height);
+ rowptrs = (unsigned char **) malloc(sizeof(unsigned char*) * height);
+
+ if((data == 0) || (rowptrs == 0)){
+ LOG("could not allocate data buffer\n");
+ goto oops;
+ }
+
+ for(i = 0; i < height; i++) {
+ rowptrs[i] = data + ((width * 4) * i);
+ }
+
+ png_read_image(p, rowptrs);
+
+ png_destroy_read_struct(&p, &pi, 0);
+ if(rowptrs != 0) free(rowptrs);
+
+ *_width = width;
+ *_height = height;
+
+ return (void*) data;
+}
+
+
+#if 0
+int main(int argc, char **argv)
+{
+ unsigned w,h;
+ unsigned char *data;
+
+ if(argc < 2) return 0;
+
+
+ data = loadpng(argv[1], &w, &h);
+
+ if(data != 0) {
+ printf("w: %d h: %d\n", w, h);
+ }
+
+ return 0;
+}
+#endif
diff --git a/m68k-dis.c b/m68k-dis.c
deleted file mode 100644
index dd19558..0000000
--- a/m68k-dis.c
+++ /dev/null
@@ -1,5051 +0,0 @@
-/* This file is composed of several different files from the upstream
- sourceware.org CVS. Original file boundaries marked with **** */
-
-#include <string.h>
-#include <math.h>
-#include <stdio.h>
-
-#include "dis-asm.h"
-
-/* **** foatformat.h from sourceware.org CVS 2005-08-14. */
-/* IEEE floating point support declarations, for GDB, the GNU Debugger.
- Copyright 1991, 1994, 1995, 1997, 2000, 2003 Free Software Foundation, Inc.
-
-This file is part of GDB.
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
-
-#if !defined (FLOATFORMAT_H)
-#define FLOATFORMAT_H 1
-
-/*#include "ansidecl.h" */
-
-/* A floatformat consists of a sign bit, an exponent and a mantissa. Once the
- bytes are concatenated according to the byteorder flag, then each of those
- fields is contiguous. We number the bits with 0 being the most significant
- (i.e. BITS_BIG_ENDIAN type numbering), and specify which bits each field
- contains with the *_start and *_len fields. */
-
-/* What is the order of the bytes. */
-
-enum floatformat_byteorders {
-
- /* Standard little endian byte order.
- EX: 1.2345678e10 => 00 00 80 c5 e0 fe 06 42 */
-
- floatformat_little,
-
- /* Standard big endian byte order.
- EX: 1.2345678e10 => 42 06 fe e0 c5 80 00 00 */
-
- floatformat_big,
-
- /* Little endian byte order but big endian word order.
- EX: 1.2345678e10 => e0 fe 06 42 00 00 80 c5 */
-
- floatformat_littlebyte_bigword
-
-};
-
-enum floatformat_intbit { floatformat_intbit_yes, floatformat_intbit_no };
-
-struct floatformat
-{
- enum floatformat_byteorders byteorder;
- unsigned int totalsize; /* Total size of number in bits */
-
- /* Sign bit is always one bit long. 1 means negative, 0 means positive. */
- unsigned int sign_start;
-
- unsigned int exp_start;
- unsigned int exp_len;
- /* Bias added to a "true" exponent to form the biased exponent. It
- is intentionally signed as, otherwize, -exp_bias can turn into a
- very large number (e.g., given the exp_bias of 0x3fff and a 64
- bit long, the equation (long)(1 - exp_bias) evaluates to
- 4294950914) instead of -16382). */
- int exp_bias;
- /* Exponent value which indicates NaN. This is the actual value stored in
- the float, not adjusted by the exp_bias. This usually consists of all
- one bits. */
- unsigned int exp_nan;
-
- unsigned int man_start;
- unsigned int man_len;
-
- /* Is the integer bit explicit or implicit? */
- enum floatformat_intbit intbit;
-
- /* Internal name for debugging. */
- const char *name;
-
- /* Validator method. */
- int (*is_valid) (const struct floatformat *fmt, const char *from);
-};
-
-/* floatformats for IEEE single and double, big and little endian. */
-
-extern const struct floatformat floatformat_ieee_single_big;
-extern const struct floatformat floatformat_ieee_single_little;
-extern const struct floatformat floatformat_ieee_double_big;
-extern const struct floatformat floatformat_ieee_double_little;
-
-/* floatformat for ARM IEEE double, little endian bytes and big endian words */
-
-extern const struct floatformat floatformat_ieee_double_littlebyte_bigword;
-
-/* floatformats for various extendeds. */
-
-extern const struct floatformat floatformat_i387_ext;
-extern const struct floatformat floatformat_m68881_ext;
-extern const struct floatformat floatformat_i960_ext;
-extern const struct floatformat floatformat_m88110_ext;
-extern const struct floatformat floatformat_m88110_harris_ext;
-extern const struct floatformat floatformat_arm_ext_big;
-extern const struct floatformat floatformat_arm_ext_littlebyte_bigword;
-/* IA-64 Floating Point register spilt into memory. */
-extern const struct floatformat floatformat_ia64_spill_big;
-extern const struct floatformat floatformat_ia64_spill_little;
-extern const struct floatformat floatformat_ia64_quad_big;
-extern const struct floatformat floatformat_ia64_quad_little;
-
-/* Convert from FMT to a double.
- FROM is the address of the extended float.
- Store the double in *TO. */
-
-extern void
-floatformat_to_double (const struct floatformat *, const char *, double *);
-
-/* The converse: convert the double *FROM to FMT
- and store where TO points. */
-
-extern void
-floatformat_from_double (const struct floatformat *, const double *, char *);
-
-/* Return non-zero iff the data at FROM is a valid number in format FMT. */
-
-extern int
-floatformat_is_valid (const struct floatformat *fmt, const char *from);
-
-#endif /* defined (FLOATFORMAT_H) */
-/* **** End of floatformat.h */
-/* **** m68k-dis.h from sourceware.org CVS 2005-08-14. */
-/* Opcode table header for m680[01234]0/m6888[12]/m68851.
- Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, 2001,
- 2003, 2004 Free Software Foundation, Inc.
-
- This file is part of GDB, GAS, and the GNU binutils.
-
- GDB, GAS, and the GNU binutils are free software; you can redistribute
- them and/or modify them under the terms of the GNU General Public
- License as published by the Free Software Foundation; either version
- 1, or (at your option) any later version.
-
- GDB, GAS, and the GNU binutils are distributed in the hope that they
- will be useful, but WITHOUT ANY WARRANTY; without even the implied
- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this file; see the file COPYING. If not, write to the Free
- Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
- 02110-1301, USA. */
-
-/* These are used as bit flags for the arch field in the m68k_opcode
- structure. */
-#define _m68k_undef 0
-#define m68000 0x001
-#define m68008 m68000 /* Synonym for -m68000. otherwise unused. */
-#define m68010 0x002
-#define m68020 0x004
-#define m68030 0x008
-#define m68ec030 m68030 /* Similar enough to -m68030 to ignore differences;
- gas will deal with the few differences. */
-#define m68040 0x010
-/* There is no 68050. */
-#define m68060 0x020
-#define m68881 0x040
-#define m68882 m68881 /* Synonym for -m68881. otherwise unused. */
-#define m68851 0x080
-#define cpu32 0x100 /* e.g., 68332 */
-
-#define mcfmac 0x200 /* ColdFire MAC. */
-#define mcfemac 0x400 /* ColdFire EMAC. */
-#define cfloat 0x800 /* ColdFire FPU. */
-#define mcfhwdiv 0x1000 /* ColdFire hardware divide. */
-
-#define mcfisa_a 0x2000 /* ColdFire ISA_A. */
-#define mcfisa_aa 0x4000 /* ColdFire ISA_A+. */
-#define mcfisa_b 0x8000 /* ColdFire ISA_B. */
-#define mcfusp 0x10000 /* ColdFire USP instructions. */
-
-#define mcf5200 0x20000
-#define mcf5206e 0x40000
-#define mcf521x 0x80000
-#define mcf5249 0x100000
-#define mcf528x 0x200000
-#define mcf5307 0x400000
-#define mcf5407 0x800000
-#define mcf5470 0x1000000
-#define mcf5480 0x2000000
-
- /* Handy aliases. */
-#define m68040up (m68040 | m68060)
-#define m68030up (m68030 | m68040up)
-#define m68020up (m68020 | m68030up)
-#define m68010up (m68010 | cpu32 | m68020up)
-#define m68000up (m68000 | m68010up)
-
-#define mfloat (m68881 | m68882 | m68040 | m68060)
-#define mmmu (m68851 | m68030 | m68040 | m68060)
-
-/* The structure used to hold information for an opcode. */
-
-struct m68k_opcode
-{
- /* The opcode name. */
- const char *name;
- /* The pseudo-size of the instruction(in bytes). Used to determine
- number of bytes necessary to disassemble the instruction. */
- unsigned int size;
- /* The opcode itself. */
- unsigned long opcode;
- /* The mask used by the disassembler. */
- unsigned long match;
- /* The arguments. */
- const char *args;
- /* The architectures which support this opcode. */
- unsigned int arch;
-};
-
-/* The structure used to hold information for an opcode alias. */
-
-struct m68k_opcode_alias
-{
- /* The alias name. */
- const char *alias;
- /* The instruction for which this is an alias. */
- const char *primary;
-};
-
-/* We store four bytes of opcode for all opcodes because that is the
- most any of them need. The actual length of an instruction is
- always at least 2 bytes, and is as much longer as necessary to hold
- the operands it has.
-
- The match field is a mask saying which bits must match particular
- opcode in order for an instruction to be an instance of that
- opcode.
-
- The args field is a string containing two characters for each
- operand of the instruction. The first specifies the kind of
- operand; the second, the place it is stored. */
-
-/* Kinds of operands:
- Characters used: AaBbCcDdEeFfGgHIiJkLlMmnOopQqRrSsTtU VvWwXxYyZz01234|*~%;@!&$?/<>#^+-
-
- D data register only. Stored as 3 bits.
- A address register only. Stored as 3 bits.
- a address register indirect only. Stored as 3 bits.
- R either kind of register. Stored as 4 bits.
- r either kind of register indirect only. Stored as 4 bits.
- At the moment, used only for cas2 instruction.
- F floating point coprocessor register only. Stored as 3 bits.
- O an offset (or width): immediate data 0-31 or data register.
- Stored as 6 bits in special format for BF... insns.
- + autoincrement only. Stored as 3 bits (number of the address register).
- - autodecrement only. Stored as 3 bits (number of the address register).
- Q quick immediate data. Stored as 3 bits.
- This matches an immediate operand only when value is in range 1 .. 8.
- M moveq immediate data. Stored as 8 bits.
- This matches an immediate operand only when value is in range -128..127
- T trap vector immediate data. Stored as 4 bits.
-
- k K-factor for fmove.p instruction. Stored as a 7-bit constant or
- a three bit register offset, depending on the field type.
-
- # immediate data. Stored in special places (b, w or l)
- which say how many bits to store.
- ^ immediate data for floating point instructions. Special places
- are offset by 2 bytes from '#'...
- B pc-relative address, converted to an offset
- that is treated as immediate data.
- d displacement and register. Stores the register as 3 bits
- and stores the displacement in the entire second word.
-
- C the CCR. No need to store it; this is just for filtering validity.
- S the SR. No need to store, just as with CCR.
- U the USP. No need to store, just as with CCR.
- E the MAC ACC. No need to store, just as with CCR.
- e the EMAC ACC[0123].
- G the MAC/EMAC MACSR. No need to store, just as with CCR.
- g the EMAC ACCEXT{01,23}.
- H the MASK. No need to store, just as with CCR.
- i the MAC/EMAC scale factor.
-
- I Coprocessor ID. Not printed if 1. The Coprocessor ID is always
- extracted from the 'd' field of word one, which means that an extended
- coprocessor opcode can be skipped using the 'i' place, if needed.
-
- s System Control register for the floating point coprocessor.
-
- J Misc register for movec instruction, stored in 'j' format.
- Possible values:
- 0x000 SFC Source Function Code reg [60, 40, 30, 20, 10]
- 0x001 DFC Data Function Code reg [60, 40, 30, 20, 10]
- 0x002 CACR Cache Control Register [60, 40, 30, 20, mcf]
- 0x003 TC MMU Translation Control [60, 40]
- 0x004 ITT0 Instruction Transparent
- Translation reg 0 [60, 40]
- 0x005 ITT1 Instruction Transparent
- Translation reg 1 [60, 40]
- 0x006 DTT0 Data Transparent
- Translation reg 0 [60, 40]
- 0x007 DTT1 Data Transparent
- Translation reg 1 [60, 40]
- 0x008 BUSCR Bus Control Register [60]
- 0x800 USP User Stack Pointer [60, 40, 30, 20, 10]
- 0x801 VBR Vector Base reg [60, 40, 30, 20, 10, mcf]
- 0x802 CAAR Cache Address Register [ 30, 20]
- 0x803 MSP Master Stack Pointer [ 40, 30, 20]
- 0x804 ISP Interrupt Stack Pointer [ 40, 30, 20]
- 0x805 MMUSR MMU Status reg [ 40]
- 0x806 URP User Root Pointer [60, 40]
- 0x807 SRP Supervisor Root Pointer [60, 40]
- 0x808 PCR Processor Configuration reg [60]
- 0xC00 ROMBAR ROM Base Address Register [520X]
- 0xC04 RAMBAR0 RAM Base Address Register 0 [520X]
- 0xC05 RAMBAR1 RAM Base Address Register 0 [520X]
- 0xC0F MBAR0 RAM Base Address Register 0 [520X]
- 0xC04 FLASHBAR FLASH Base Address Register [mcf528x]
- 0xC05 RAMBAR Static RAM Base Address Register [mcf528x]
-
- L Register list of the type d0-d7/a0-a7 etc.
- (New! Improved! Can also hold fp0-fp7, as well!)
- The assembler tries to see if the registers match the insn by
- looking at where the insn wants them stored.
-
- l Register list like L, but with all the bits reversed.
- Used for going the other way. . .
-
- c cache identifier which may be "nc" for no cache, "ic"
- for instruction cache, "dc" for data cache, or "bc"
- for both caches. Used in cinv and cpush. Always
- stored in position "d".
-
- u Any register, with ``upper'' or ``lower'' specification. Used
- in the mac instructions with size word.
-
- The remainder are all stored as 6 bits using an address mode and a
- register number; they differ in which addressing modes they match.
-
- * all (modes 0-6,7.0-4)
- ~ alterable memory (modes 2-6,7.0,7.1)
- (not 0,1,7.2-4)
- % alterable (modes 0-6,7.0,7.1)
- (not 7.2-4)
- ; data (modes 0,2-6,7.0-4)
- (not 1)
- @ data, but not immediate (modes 0,2-6,7.0-3)
- (not 1,7.4)
- ! control (modes 2,5,6,7.0-3)
- (not 0,1,3,4,7.4)
- & alterable control (modes 2,5,6,7.0,7.1)
- (not 0,1,3,4,7.2-4)
- $ alterable data (modes 0,2-6,7.0,7.1)
- (not 1,7.2-4)
- ? alterable control, or data register (modes 0,2,5,6,7.0,7.1)
- (not 1,3,4,7.2-4)
- / control, or data register (modes 0,2,5,6,7.0-3)
- (not 1,3,4,7.4)
- > *save operands (modes 2,4,5,6,7.0,7.1)
- (not 0,1,3,7.2-4)
- < *restore operands (modes 2,3,5,6,7.0-3)
- (not 0,1,4,7.4)
-
- coldfire move operands:
- m (modes 0-4)
- n (modes 5,7.2)
- o (modes 6,7.0,7.1,7.3,7.4)
- p (modes 0-5)
-
- coldfire bset/bclr/btst/mulsl/mulul operands:
- q (modes 0,2-5)
- v (modes 0,2-5,7.0,7.1)
- b (modes 0,2-5,7.2)
- w (modes 2-5,7.2)
- y (modes 2,5)
- z (modes 2,5,7.2)
- x mov3q immediate operand.
- 4 (modes 2,3,4,5)
- */
-
-/* For the 68851: */
-/* I didn't use much imagination in choosing the
- following codes, so many of them aren't very
- mnemonic. -rab
-
- 0 32 bit pmmu register
- Possible values:
- 000 TC Translation Control Register (68030, 68851)
-
- 1 16 bit pmmu register
- 111 AC Access Control (68851)
-
- 2 8 bit pmmu register
- 100 CAL Current Access Level (68851)
- 101 VAL Validate Access Level (68851)
- 110 SCC Stack Change Control (68851)
-
- 3 68030-only pmmu registers (32 bit)
- 010 TT0 Transparent Translation reg 0
- (aka Access Control reg 0 -- AC0 -- on 68ec030)
- 011 TT1 Transparent Translation reg 1
- (aka Access Control reg 1 -- AC1 -- on 68ec030)
-
- W wide pmmu registers
- Possible values:
- 001 DRP Dma Root Pointer (68851)
- 010 SRP Supervisor Root Pointer (68030, 68851)
- 011 CRP Cpu Root Pointer (68030, 68851)
-
- f function code register (68030, 68851)
- 0 SFC
- 1 DFC
-
- V VAL register only (68851)
-
- X BADx, BACx (16 bit)
- 100 BAD Breakpoint Acknowledge Data (68851)
- 101 BAC Breakpoint Acknowledge Control (68851)
-
- Y PSR (68851) (MMUSR on 68030) (ACUSR on 68ec030)
- Z PCSR (68851)
-
- | memory (modes 2-6, 7.*)
-
- t address test level (68030 only)
- Stored as 3 bits, range 0-7.
- Also used for breakpoint instruction now.
-
-*/
-
-/* Places to put an operand, for non-general operands:
- Characters used: BbCcDdFfGgHhIijkLlMmNnostWw123456789/
-
- s source, low bits of first word.
- d dest, shifted 9 in first word
- 1 second word, shifted 12
- 2 second word, shifted 6
- 3 second word, shifted 0
- 4 third word, shifted 12
- 5 third word, shifted 6
- 6 third word, shifted 0
- 7 second word, shifted 7
- 8 second word, shifted 10
- 9 second word, shifted 5
- D store in both place 1 and place 3; for divul and divsl.
- B first word, low byte, for branch displacements
- W second word (entire), for branch displacements
- L second and third words (entire), for branch displacements
- (also overloaded for move16)
- b second word, low byte
- w second word (entire) [variable word/long branch offset for dbra]
- W second word (entire) (must be signed 16 bit value)
- l second and third word (entire)
- g variable branch offset for bra and similar instructions.
- The place to store depends on the magnitude of offset.
- t store in both place 7 and place 8; for floating point operations
- c branch offset for cpBcc operations.
- The place to store is word two if bit six of word one is zero,
- and words two and three if bit six of word one is one.
- i Increment by two, to skip over coprocessor extended operands. Only
- works with the 'I' format.
- k Dynamic K-factor field. Bits 6-4 of word 2, used as a register number.
- Also used for dynamic fmovem instruction.
- C floating point coprocessor constant - 7 bits. Also used for static
- K-factors...
- j Movec register #, stored in 12 low bits of second word.
- m For M[S]ACx; 4 bits split with MSB shifted 6 bits in first word
- and remaining 3 bits of register shifted 9 bits in first word.
- Indicate upper/lower in 1 bit shifted 7 bits in second word.
- Use with `R' or `u' format.
- n `m' withouth upper/lower indication. (For M[S]ACx; 4 bits split
- with MSB shifted 6 bits in first word and remaining 3 bits of
- register shifted 9 bits in first word. No upper/lower
- indication is done.) Use with `R' or `u' format.
- o For M[S]ACw; 4 bits shifted 12 in second word (like `1').
- Indicate upper/lower in 1 bit shifted 7 bits in second word.
- Use with `R' or `u' format.
- M For M[S]ACw; 4 bits in low bits of first word. Indicate
- upper/lower in 1 bit shifted 6 bits in second word. Use with
- `R' or `u' format.
- N For M[S]ACw; 4 bits in low bits of second word. Indicate
- upper/lower in 1 bit shifted 6 bits in second word. Use with
- `R' or `u' format.
- h shift indicator (scale factor), 1 bit shifted 10 in second word
-
- Places to put operand, for general operands:
- d destination, shifted 6 bits in first word
- b source, at low bit of first word, and immediate uses one byte
- w source, at low bit of first word, and immediate uses two bytes
- l source, at low bit of first word, and immediate uses four bytes
- s source, at low bit of first word.
- Used sometimes in contexts where immediate is not allowed anyway.
- f single precision float, low bit of 1st word, immediate uses 4 bytes
- F double precision float, low bit of 1st word, immediate uses 8 bytes
- x extended precision float, low bit of 1st word, immediate uses 12 bytes
- p packed float, low bit of 1st word, immediate uses 12 bytes
- G EMAC accumulator, load (bit 4 2nd word, !bit8 first word)
- H EMAC accumulator, non load (bit 4 2nd word, bit 8 first word)
- F EMAC ACCx
- f EMAC ACCy
- I MAC/EMAC scale factor
- / Like 's', but set 2nd word, bit 5 if trailing_ampersand set
- ] first word, bit 10
-*/
-
-extern const struct m68k_opcode m68k_opcodes[];
-extern const struct m68k_opcode_alias m68k_opcode_aliases[];
-
-extern const int m68k_numopcodes, m68k_numaliases;
-
-/* **** End of m68k-opcode.h */
-/* **** m68k-dis.c from sourceware.org CVS 2005-08-14. */
-/* Print Motorola 68k instructions.
- Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
- Free Software Foundation, Inc.
-
- This file is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA. */
-
-/* Local function prototypes. */
-
-const char * const fpcr_names[] =
-{
- "", "%fpiar", "%fpsr", "%fpiar/%fpsr", "%fpcr",
- "%fpiar/%fpcr", "%fpsr/%fpcr", "%fpiar/%fpsr/%fpcr"
-};
-
-static char *const reg_names[] =
-{
- "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
- "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%fp", "%sp",
- "%ps", "%pc"
-};
-
-/* Name of register halves for MAC/EMAC.
- Seperate from reg_names since 'spu', 'fpl' look weird. */
-static char *const reg_half_names[] =
-{
- "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7",
- "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7",
- "%ps", "%pc"
-};
-
-/* Sign-extend an (unsigned char). */
-#if __STDC__ == 1
-#define COERCE_SIGNED_CHAR(ch) ((signed char) (ch))
-#else
-#define COERCE_SIGNED_CHAR(ch) ((int) (((ch) ^ 0x80) & 0xFF) - 128)
-#endif
-
-/* Get a 1 byte signed integer. */
-#define NEXTBYTE(p) (p += 2, FETCH_DATA (info, p), COERCE_SIGNED_CHAR(p[-1]))
-
-/* Get a 2 byte signed integer. */
-#define COERCE16(x) ((int) (((x) ^ 0x8000) - 0x8000))
-#define NEXTWORD(p) \
- (p += 2, FETCH_DATA (info, p), \
- COERCE16 ((p[-2] << 8) + p[-1]))
-
-/* Get a 4 byte signed integer. */
-#define COERCE32(x) ((bfd_signed_vma) ((x) ^ 0x80000000) - 0x80000000)
-#define NEXTLONG(p) \
- (p += 4, FETCH_DATA (info, p), \
- (COERCE32 ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1])))
-
-/* Get a 4 byte unsigned integer. */
-#define NEXTULONG(p) \
- (p += 4, FETCH_DATA (info, p), \
- (unsigned int) ((((((p[-4] << 8) + p[-3]) << 8) + p[-2]) << 8) + p[-1]))
-
-/* Get a single precision float. */
-#define NEXTSINGLE(val, p) \
- (p += 4, FETCH_DATA (info, p), \
- floatformat_to_double (&floatformat_ieee_single_big, (char *) p - 4, &val))
-
-/* Get a double precision float. */
-#define NEXTDOUBLE(val, p) \
- (p += 8, FETCH_DATA (info, p), \
- floatformat_to_double (&floatformat_ieee_double_big, (char *) p - 8, &val))
-
-/* Get an extended precision float. */
-#define NEXTEXTEND(val, p) \
- (p += 12, FETCH_DATA (info, p), \
- floatformat_to_double (&floatformat_m68881_ext, (char *) p - 12, &val))
-
-/* Need a function to convert from packed to double
- precision. Actually, it's easier to print a
- packed number than a double anyway, so maybe
- there should be a special case to handle this... */
-#define NEXTPACKED(p) \
- (p += 12, FETCH_DATA (info, p), 0.0)
-
-/* Maximum length of an instruction. */
-#define MAXLEN 22
-
-#include <setjmp.h>
-
-struct private
-{
- /* Points to first byte not fetched. */
- bfd_byte *max_fetched;
- bfd_byte the_buffer[MAXLEN];
- bfd_vma insn_start;
- jmp_buf bailout;
-};
-
-/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
- to ADDR (exclusive) are valid. Returns 1 for success, longjmps
- on error. */
-#define FETCH_DATA(info, addr) \
- ((addr) <= ((struct private *) (info->private_data))->max_fetched \
- ? 1 : fetch_data ((info), (addr)))
-
-static int
-fetch_data (struct disassemble_info *info, bfd_byte *addr)
-{
- int status;
- struct private *priv = (struct private *)info->private_data;
- bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
-
- status = (*info->read_memory_func) (start,
- priv->max_fetched,
- addr - priv->max_fetched,
- info);
- if (status != 0)
- {
- (*info->memory_error_func) (status, start, info);
- longjmp (priv->bailout, 1);
- }
- else
- priv->max_fetched = addr;
- return 1;
-}
-
-/* This function is used to print to the bit-bucket. */
-static int
-dummy_printer (FILE *file ATTRIBUTE_UNUSED,
- const char *format ATTRIBUTE_UNUSED,
- ...)
-{
- return 0;
-}
-
-static void
-dummy_print_address (bfd_vma vma ATTRIBUTE_UNUSED,
- struct disassemble_info *info ATTRIBUTE_UNUSED)
-{
-}
-
-/* Fetch BITS bits from a position in the instruction specified by CODE.
- CODE is a "place to put an argument", or 'x' for a destination
- that is a general address (mode and register).
- BUFFER contains the instruction. */
-
-static int
-fetch_arg (unsigned char *buffer,
- int code,
- int bits,
- disassemble_info *info)
-{
- int val = 0;
-
- switch (code)
- {
- case '/': /* MAC/EMAC mask bit. */
- val = buffer[3] >> 5;
- break;
-
- case 'G': /* EMAC ACC load. */
- val = ((buffer[3] >> 3) & 0x2) | ((~buffer[1] >> 7) & 0x1);
- break;
-
- case 'H': /* EMAC ACC !load. */
- val = ((buffer[3] >> 3) & 0x2) | ((buffer[1] >> 7) & 0x1);
- break;
-
- case ']': /* EMAC ACCEXT bit. */
- val = buffer[0] >> 2;
- break;
-
- case 'I': /* MAC/EMAC scale factor. */
- val = buffer[2] >> 1;
- break;
-
- case 'F': /* EMAC ACCx. */
- val = buffer[0] >> 1;
- break;
-
- case 'f':
- val = buffer[1];
- break;
-
- case 's':
- val = buffer[1];
- break;
-
- case 'd': /* Destination, for register or quick. */
- val = (buffer[0] << 8) + buffer[1];
- val >>= 9;
- break;
-
- case 'x': /* Destination, for general arg. */
- val = (buffer[0] << 8) + buffer[1];
- val >>= 6;
- break;
-
- case 'k':
- FETCH_DATA (info, buffer + 3);
- val = (buffer[3] >> 4);
- break;
-
- case 'C':
- FETCH_DATA (info, buffer + 3);
- val = buffer[3];
- break;
-
- case '1':
- FETCH_DATA (info, buffer + 3);
- val = (buffer[2] << 8) + buffer[3];
- val >>= 12;
- break;
-
- case '2':
- FETCH_DATA (info, buffer + 3);
- val = (buffer[2] << 8) + buffer[3];
- val >>= 6;
- break;
-
- case '3':
- case 'j':
- FETCH_DATA (info, buffer + 3);
- val = (buffer[2] << 8) + buffer[3];
- break;
-
- case '4':
- FETCH_DATA (info, buffer + 5);
- val = (buffer[4] << 8) + buffer[5];
- val >>= 12;
- break;
-
- case '5':
- FETCH_DATA (info, buffer + 5);
- val = (buffer[4] << 8) + buffer[5];
- val >>= 6;
- break;
-
- case '6':
- FETCH_DATA (info, buffer + 5);
- val = (buffer[4] << 8) + buffer[5];
- break;
-
- case '7':
- FETCH_DATA (info, buffer + 3);
- val = (buffer[2] << 8) + buffer[3];
- val >>= 7;
- break;
-
- case '8':
- FETCH_DATA (info, buffer + 3);
- val = (buffer[2] << 8) + buffer[3];
- val >>= 10;
- break;
-
- case '9':
- FETCH_DATA (info, buffer + 3);
- val = (buffer[2] << 8) + buffer[3];
- val >>= 5;
- break;
-
- case 'e':
- val = (buffer[1] >> 6);
- break;
-
- case 'm':
- val = (buffer[1] & 0x40 ? 0x8 : 0)
- | ((buffer[0] >> 1) & 0x7)
- | (buffer[3] & 0x80 ? 0x10 : 0);
- break;
-
- case 'n':
- val = (buffer[1] & 0x40 ? 0x8 : 0) | ((buffer[0] >> 1) & 0x7);
- break;
-
- case 'o':
- val = (buffer[2] >> 4) | (buffer[3] & 0x80 ? 0x10 : 0);
- break;
-
- case 'M':
- val = (buffer[1] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
- break;
-
- case 'N':
- val = (buffer[3] & 0xf) | (buffer[3] & 0x40 ? 0x10 : 0);
- break;
-
- case 'h':
- val = buffer[2] >> 2;
- break;
-
- default:
- abort ();
- }
-
- switch (bits)
- {
- case 1:
- return val & 1;
- case 2:
- return val & 3;
- case 3:
- return val & 7;
- case 4:
- return val & 017;
- case 5:
- return val & 037;
- case 6:
- return val & 077;
- case 7:
- return val & 0177;
- case 8:
- return val & 0377;
- case 12:
- return val & 07777;
- default:
- abort ();
- }
-}
-
-/* Check if an EA is valid for a particular code. This is required
- for the EMAC instructions since the type of source address determines
- if it is a EMAC-load instruciton if the EA is mode 2-5, otherwise it
- is a non-load EMAC instruction and the bits mean register Ry.
- A similar case exists for the movem instructions where the register
- mask is interpreted differently for different EAs. */
-
-static bfd_boolean
-m68k_valid_ea (char code, int val)
-{
- int mode, mask;
-#define M(n0,n1,n2,n3,n4,n5,n6,n70,n71,n72,n73,n74) \
- (n0 | n1 << 1 | n2 << 2 | n3 << 3 | n4 << 4 | n5 << 5 | n6 << 6 \
- | n70 << 7 | n71 << 8 | n72 << 9 | n73 << 10 | n74 << 11)
-
- switch (code)
- {
- case '*':
- mask = M (1,1,1,1,1,1,1,1,1,1,1,1);
- break;
- case '~':
- mask = M (0,0,1,1,1,1,1,1,1,0,0,0);
- break;
- case '%':
- mask = M (1,1,1,1,1,1,1,1,1,0,0,0);
- break;
- case ';':
- mask = M (1,0,1,1,1,1,1,1,1,1,1,1);
- break;
- case '@':
- mask = M (1,0,1,1,1,1,1,1,1,1,1,0);
- break;
- case '!':
- mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
- break;
- case '&':
- mask = M (0,0,1,0,0,1,1,1,1,0,0,0);
- break;
- case '$':
- mask = M (1,0,1,1,1,1,1,1,1,0,0,0);
- break;
- case '?':
- mask = M (1,0,1,0,0,1,1,1,1,0,0,0);
- break;
- case '/':
- mask = M (1,0,1,0,0,1,1,1,1,1,1,0);
- break;
- case '|':
- mask = M (0,0,1,0,0,1,1,1,1,1,1,0);
- break;
- case '>':
- mask = M (0,0,1,0,1,1,1,1,1,0,0,0);
- break;
- case '<':
- mask = M (0,0,1,1,0,1,1,1,1,1,1,0);
- break;
- case 'm':
- mask = M (1,1,1,1,1,0,0,0,0,0,0,0);
- break;
- case 'n':
- mask = M (0,0,0,0,0,1,0,0,0,1,0,0);
- break;
- case 'o':
- mask = M (0,0,0,0,0,0,1,1,1,0,1,1);
- break;
- case 'p':
- mask = M (1,1,1,1,1,1,0,0,0,0,0,0);
- break;
- case 'q':
- mask = M (1,0,1,1,1,1,0,0,0,0,0,0);
- break;
- case 'v':
- mask = M (1,0,1,1,1,1,0,1,1,0,0,0);
- break;
- case 'b':
- mask = M (1,0,1,1,1,1,0,0,0,1,0,0);
- break;
- case 'w':
- mask = M (0,0,1,1,1,1,0,0,0,1,0,0);
- break;
- case 'y':
- mask = M (0,0,1,0,0,1,0,0,0,0,0,0);
- break;
- case 'z':
- mask = M (0,0,1,0,0,1,0,0,0,1,0,0);
- break;
- case '4':
- mask = M (0,0,1,1,1,1,0,0,0,0,0,0);
- break;
- default:
- abort ();
- }
-#undef M
-
- mode = (val >> 3) & 7;
- if (mode == 7)
- mode += val & 7;
- return (mask & (1 << mode)) != 0;
-}
-
-/* Print a base register REGNO and displacement DISP, on INFO->STREAM.
- REGNO = -1 for pc, -2 for none (suppressed). */
-
-static void
-print_base (int regno, bfd_vma disp, disassemble_info *info)
-{
- if (regno == -1)
- {
- (*info->fprintf_func) (info->stream, "%%pc@(");
- (*info->print_address_func) (disp, info);
- }
- else
- {
- char buf[50];
-
- if (regno == -2)
- (*info->fprintf_func) (info->stream, "@(");
- else if (regno == -3)
- (*info->fprintf_func) (info->stream, "%%zpc@(");
- else
- (*info->fprintf_func) (info->stream, "%s@(", reg_names[regno]);
-
- sprintf_vma (buf, disp);
- (*info->fprintf_func) (info->stream, "%s", buf);
- }
-}
-
-/* Print an indexed argument. The base register is BASEREG (-1 for pc).
- P points to extension word, in buffer.
- ADDR is the nominal core address of that extension word. */
-
-static unsigned char *
-print_indexed (int basereg,
- unsigned char *p,
- bfd_vma addr,
- disassemble_info *info)
-{
- int word;
- static char *const scales[] = { "", ":2", ":4", ":8" };
- bfd_vma base_disp;
- bfd_vma outer_disp;
- char buf[40];
- char vmabuf[50];
-
- word = NEXTWORD (p);
-
- /* Generate the text for the index register.
- Where this will be output is not yet determined. */
- sprintf (buf, "%s:%c%s",
- reg_names[(word >> 12) & 0xf],
- (word & 0x800) ? 'l' : 'w',
- scales[(word >> 9) & 3]);
-
- /* Handle the 68000 style of indexing. */
-
- if ((word & 0x100) == 0)
- {
- base_disp = word & 0xff;
- if ((base_disp & 0x80) != 0)
- base_disp -= 0x100;
- if (basereg == -1)
- base_disp += addr;
- print_base (basereg, base_disp, info);
- (*info->fprintf_func) (info->stream, ",%s)", buf);
- return p;
- }
-
- /* Handle the generalized kind. */
- /* First, compute the displacement to add to the base register. */
- if (word & 0200)
- {
- if (basereg == -1)
- basereg = -3;
- else
- basereg = -2;
- }
- if (word & 0100)
- buf[0] = '\0';
- base_disp = 0;
- switch ((word >> 4) & 3)
- {
- case 2:
- base_disp = NEXTWORD (p);
- break;
- case 3:
- base_disp = NEXTLONG (p);
- }
- if (basereg == -1)
- base_disp += addr;
-
- /* Handle single-level case (not indirect). */
- if ((word & 7) == 0)
- {
- print_base (basereg, base_disp, info);
- if (buf[0] != '\0')
- (*info->fprintf_func) (info->stream, ",%s", buf);
- (*info->fprintf_func) (info->stream, ")");
- return p;
- }
-
- /* Two level. Compute displacement to add after indirection. */
- outer_disp = 0;
- switch (word & 3)
- {
- case 2:
- outer_disp = NEXTWORD (p);
- break;
- case 3:
- outer_disp = NEXTLONG (p);
- }
-
- print_base (basereg, base_disp, info);
- if ((word & 4) == 0 && buf[0] != '\0')
- {
- (*info->fprintf_func) (info->stream, ",%s", buf);
- buf[0] = '\0';
- }
- sprintf_vma (vmabuf, outer_disp);
- (*info->fprintf_func) (info->stream, ")@(%s", vmabuf);
- if (buf[0] != '\0')
- (*info->fprintf_func) (info->stream, ",%s", buf);
- (*info->fprintf_func) (info->stream, ")");
-
- return p;
-}
-
-/* Returns number of bytes "eaten" by the operand, or
- return -1 if an invalid operand was found, or -2 if
- an opcode tabe error was found.
- ADDR is the pc for this arg to be relative to. */
-
-static int
-print_insn_arg (const char *d,
- unsigned char *buffer,
- unsigned char *p0,
- bfd_vma addr,
- disassemble_info *info)
-{
- int val = 0;
- int place = d[1];
- unsigned char *p = p0;
- int regno;
- const char *regname;
- unsigned char *p1;
- double flval;
- int flt_p;
- bfd_signed_vma disp;
- unsigned int uval;
-
- switch (*d)
- {
- case 'c': /* Cache identifier. */
- {
- static char *const cacheFieldName[] = { "nc", "dc", "ic", "bc" };
- val = fetch_arg (buffer, place, 2, info);
- (*info->fprintf_func) (info->stream, cacheFieldName[val]);
- break;
- }
-
- case 'a': /* Address register indirect only. Cf. case '+'. */
- {
- (*info->fprintf_func)
- (info->stream,
- "%s@",
- reg_names[fetch_arg (buffer, place, 3, info) + 8]);
- break;
- }
-
- case '_': /* 32-bit absolute address for move16. */
- {
- uval = NEXTULONG (p);
- (*info->print_address_func) (uval, info);
- break;
- }
-
- case 'C':
- (*info->fprintf_func) (info->stream, "%%ccr");
- break;
-
- case 'S':
- (*info->fprintf_func) (info->stream, "%%sr");
- break;
-
- case 'U':
- (*info->fprintf_func) (info->stream, "%%usp");
- break;
-
- case 'E':
- (*info->fprintf_func) (info->stream, "%%acc");
- break;
-
- case 'G':
- (*info->fprintf_func) (info->stream, "%%macsr");
- break;
-
- case 'H':
- (*info->fprintf_func) (info->stream, "%%mask");
- break;
-
- case 'J':
- {
- /* FIXME: There's a problem here, different m68k processors call the
- same address different names. This table can't get it right
- because it doesn't know which processor it's disassembling for. */
- static const struct { char *name; int value; } names[]
- = {{"%sfc", 0x000}, {"%dfc", 0x001}, {"%cacr", 0x002},
- {"%tc", 0x003}, {"%itt0",0x004}, {"%itt1", 0x005},
- {"%dtt0",0x006}, {"%dtt1",0x007}, {"%buscr",0x008},
- {"%usp", 0x800}, {"%vbr", 0x801}, {"%caar", 0x802},
- {"%msp", 0x803}, {"%isp", 0x804},
- {"%flashbar", 0xc04}, {"%rambar", 0xc05}, /* mcf528x added these. */
-
- /* Should we be calling this psr like we do in case 'Y'? */
- {"%mmusr",0x805},
-
- {"%urp", 0x806}, {"%srp", 0x807}, {"%pcr", 0x808}};
-
- val = fetch_arg (buffer, place, 12, info);
- for (regno = sizeof names / sizeof names[0] - 1; regno >= 0; regno--)
- if (names[regno].value == val)
- {
- (*info->fprintf_func) (info->stream, "%s", names[regno].name);
- break;
- }
- if (regno < 0)
- (*info->fprintf_func) (info->stream, "%d", val);
- }
- break;
-
- case 'Q':
- val = fetch_arg (buffer, place, 3, info);
- /* 0 means 8, except for the bkpt instruction... */
- if (val == 0 && d[1] != 's')
- val = 8;
- (*info->fprintf_func) (info->stream, "#%d", val);
- break;
-
- case 'x':
- val = fetch_arg (buffer, place, 3, info);
- /* 0 means -1. */
- if (val == 0)
- val = -1;
- (*info->fprintf_func) (info->stream, "#%d", val);
- break;
-
- case 'M':
- if (place == 'h')
- {
- static char *const scalefactor_name[] = { "<<", ">>" };
- val = fetch_arg (buffer, place, 1, info);
- (*info->fprintf_func) (info->stream, scalefactor_name[val]);
- }
- else
- {
- val = fetch_arg (buffer, place, 8, info);
- if (val & 0x80)
- val = val - 0x100;
- (*info->fprintf_func) (info->stream, "#%d", val);
- }
- break;
-
- case 'T':
- val = fetch_arg (buffer, place, 4, info);
- (*info->fprintf_func) (info->stream, "#%d", val);
- break;
-
- case 'D':
- (*info->fprintf_func) (info->stream, "%s",
- reg_names[fetch_arg (buffer, place, 3, info)]);
- break;
-
- case 'A':
- (*info->fprintf_func)
- (info->stream, "%s",
- reg_names[fetch_arg (buffer, place, 3, info) + 010]);
- break;
-
- case 'R':
- (*info->fprintf_func)
- (info->stream, "%s",
- reg_names[fetch_arg (buffer, place, 4, info)]);
- break;
-
- case 'r':
- regno = fetch_arg (buffer, place, 4, info);
- if (regno > 7)
- (*info->fprintf_func) (info->stream, "%s@", reg_names[regno]);
- else
- (*info->fprintf_func) (info->stream, "@(%s)", reg_names[regno]);
- break;
-
- case 'F':
- (*info->fprintf_func)
- (info->stream, "%%fp%d",
- fetch_arg (buffer, place, 3, info));
- break;
-
- case 'O':
- val = fetch_arg (buffer, place, 6, info);
- if (val & 0x20)
- (*info->fprintf_func) (info->stream, "%s", reg_names[val & 7]);
- else
- (*info->fprintf_func) (info->stream, "%d", val);
- break;
-
- case '+':
- (*info->fprintf_func)
- (info->stream, "%s@+",
- reg_names[fetch_arg (buffer, place, 3, info) + 8]);
- break;
-
- case '-':
- (*info->fprintf_func)
- (info->stream, "%s@-",
- reg_names[fetch_arg (buffer, place, 3, info) + 8]);
- break;
-
- case 'k':
- if (place == 'k')
- (*info->fprintf_func)
- (info->stream, "{%s}",
- reg_names[fetch_arg (buffer, place, 3, info)]);
- else if (place == 'C')
- {
- val = fetch_arg (buffer, place, 7, info);
- if (val > 63) /* This is a signed constant. */
- val -= 128;
- (*info->fprintf_func) (info->stream, "{#%d}", val);
- }
- else
- return -2;
- break;
-
- case '#':
- case '^':
- p1 = buffer + (*d == '#' ? 2 : 4);
- if (place == 's')
- val = fetch_arg (buffer, place, 4, info);
- else if (place == 'C')
- val = fetch_arg (buffer, place, 7, info);
- else if (place == '8')
- val = fetch_arg (buffer, place, 3, info);
- else if (place == '3')
- val = fetch_arg (buffer, place, 8, info);
- else if (place == 'b')
- val = NEXTBYTE (p1);
- else if (place == 'w' || place == 'W')
- val = NEXTWORD (p1);
- else if (place == 'l')
- val = NEXTLONG (p1);
- else
- return -2;
- (*info->fprintf_func) (info->stream, "#%d", val);
- break;
-
- case 'B':
- if (place == 'b')
- disp = NEXTBYTE (p);
- else if (place == 'B')
- disp = COERCE_SIGNED_CHAR (buffer[1]);
- else if (place == 'w' || place == 'W')
- disp = NEXTWORD (p);
- else if (place == 'l' || place == 'L' || place == 'C')
- disp = NEXTLONG (p);
- else if (place == 'g')
- {
- disp = NEXTBYTE (buffer);
- if (disp == 0)
- disp = NEXTWORD (p);
- else if (disp == -1)
- disp = NEXTLONG (p);
- }
- else if (place == 'c')
- {
- if (buffer[1] & 0x40) /* If bit six is one, long offset. */
- disp = NEXTLONG (p);
- else
- disp = NEXTWORD (p);
- }
- else
- return -2;
-
- (*info->print_address_func) (addr + disp, info);
- break;
-
- case 'd':
- val = NEXTWORD (p);
- (*info->fprintf_func)
- (info->stream, "%s@(%d)",
- reg_names[fetch_arg (buffer, place, 3, info) + 8], val);
- break;
-
- case 's':
- (*info->fprintf_func) (info->stream, "%s",
- fpcr_names[fetch_arg (buffer, place, 3, info)]);
- break;
-
- case 'e':
- val = fetch_arg(buffer, place, 2, info);
- (*info->fprintf_func) (info->stream, "%%acc%d", val);
- break;
-
- case 'g':
- val = fetch_arg(buffer, place, 1, info);
- (*info->fprintf_func) (info->stream, "%%accext%s", val==0 ? "01" : "23");
- break;
-
- case 'i':
- val = fetch_arg(buffer, place, 2, info);
- if (val == 1)
- (*info->fprintf_func) (info->stream, "<<");
- else if (val == 3)
- (*info->fprintf_func) (info->stream, ">>");
- else
- return -1;
- break;
-
- case 'I':
- /* Get coprocessor ID... */
- val = fetch_arg (buffer, 'd', 3, info);
-
- if (val != 1) /* Unusual coprocessor ID? */
- (*info->fprintf_func) (info->stream, "(cpid=%d) ", val);
- break;
-
- case '4':
- case '*':
- case '~':
- case '%':
- case ';':
- case '@':
- case '!':
- case '$':
- case '?':
- case '/':
- case '&':
- case '|':
- case '<':
- case '>':
- case 'm':
- case 'n':
- case 'o':
- case 'p':
- case 'q':
- case 'v':
- case 'b':
- case 'w':
- case 'y':
- case 'z':
- if (place == 'd')
- {
- val = fetch_arg (buffer, 'x', 6, info);
- val = ((val & 7) << 3) + ((val >> 3) & 7);
- }
- else
- val = fetch_arg (buffer, 's', 6, info);
-
- /* If the <ea> is invalid for *d, then reject this match. */
- if (!m68k_valid_ea (*d, val))
- return -1;
-
- /* Get register number assuming address register. */
- regno = (val & 7) + 8;
- regname = reg_names[regno];
- switch (val >> 3)
- {
- case 0:
- (*info->fprintf_func) (info->stream, "%s", reg_names[val]);
- break;
-
- case 1:
- (*info->fprintf_func) (info->stream, "%s", regname);
- break;
-
- case 2:
- (*info->fprintf_func) (info->stream, "%s@", regname);
- break;
-
- case 3:
- (*info->fprintf_func) (info->stream, "%s@+", regname);
- break;
-
- case 4:
- (*info->fprintf_func) (info->stream, "%s@-", regname);
- break;
-
- case 5:
- val = NEXTWORD (p);
- (*info->fprintf_func) (info->stream, "%s@(%d)", regname, val);
- break;
-
- case 6:
- p = print_indexed (regno, p, addr, info);
- break;
-
- case 7:
- switch (val & 7)
- {
- case 0:
- val = NEXTWORD (p);
- (*info->print_address_func) (val, info);
- break;
-
- case 1:
- uval = NEXTULONG (p);
- (*info->print_address_func) (uval, info);
- break;
-
- case 2:
- val = NEXTWORD (p);
- (*info->fprintf_func) (info->stream, "%%pc@(");
- (*info->print_address_func) (addr + val, info);
- (*info->fprintf_func) (info->stream, ")");
- break;
-
- case 3:
- p = print_indexed (-1, p, addr, info);
- break;
-
- case 4:
- flt_p = 1; /* Assume it's a float... */
- switch (place)
- {
- case 'b':
- val = NEXTBYTE (p);
- flt_p = 0;
- break;
-
- case 'w':
- val = NEXTWORD (p);
- flt_p = 0;
- break;
-
- case 'l':
- val = NEXTLONG (p);
- flt_p = 0;
- break;
-
- case 'f':
- NEXTSINGLE (flval, p);
- break;
-
- case 'F':
- NEXTDOUBLE (flval, p);
- break;
-
- case 'x':
- NEXTEXTEND (flval, p);
- break;
-
- case 'p':
- flval = NEXTPACKED (p);
- break;
-
- default:
- return -1;
- }
- if (flt_p) /* Print a float? */
- (*info->fprintf_func) (info->stream, "#%g", flval);
- else
- (*info->fprintf_func) (info->stream, "#%d", val);
- break;
-
- default:
- return -1;
- }
- }
-
- /* If place is '/', then this is the case of the mask bit for
- mac/emac loads. Now that the arg has been printed, grab the
- mask bit and if set, add a '&' to the arg. */
- if (place == '/')
- {
- val = fetch_arg (buffer, place, 1, info);
- if (val)
- info->fprintf_func (info->stream, "&");
- }
- break;
-
- case 'L':
- case 'l':
- if (place == 'w')
- {
- char doneany;
- p1 = buffer + 2;
- val = NEXTWORD (p1);
- /* Move the pointer ahead if this point is farther ahead
- than the last. */
- p = p1 > p ? p1 : p;
- if (val == 0)
- {
- (*info->fprintf_func) (info->stream, "#0");
- break;
- }
- if (*d == 'l')
- {
- int newval = 0;
-
- for (regno = 0; regno < 16; ++regno)
- if (val & (0x8000 >> regno))
- newval |= 1 << regno;
- val = newval;
- }
- val &= 0xffff;
- doneany = 0;
- for (regno = 0; regno < 16; ++regno)
- if (val & (1 << regno))
- {
- int first_regno;
-
- if (doneany)
- (*info->fprintf_func) (info->stream, "/");
- doneany = 1;
- (*info->fprintf_func) (info->stream, "%s", reg_names[regno]);
- first_regno = regno;
- while (val & (1 << (regno + 1)))
- ++regno;
- if (regno > first_regno)
- (*info->fprintf_func) (info->stream, "-%s",
- reg_names[regno]);
- }
- }
- else if (place == '3')
- {
- /* `fmovem' insn. */
- char doneany;
- val = fetch_arg (buffer, place, 8, info);
- if (val == 0)
- {
- (*info->fprintf_func) (info->stream, "#0");
- break;
- }
- if (*d == 'l')
- {
- int newval = 0;
-
- for (regno = 0; regno < 8; ++regno)
- if (val & (0x80 >> regno))
- newval |= 1 << regno;
- val = newval;
- }
- val &= 0xff;
- doneany = 0;
- for (regno = 0; regno < 8; ++regno)
- if (val & (1 << regno))
- {
- int first_regno;
- if (doneany)
- (*info->fprintf_func) (info->stream, "/");
- doneany = 1;
- (*info->fprintf_func) (info->stream, "%%fp%d", regno);
- first_regno = regno;
- while (val & (1 << (regno + 1)))
- ++regno;
- if (regno > first_regno)
- (*info->fprintf_func) (info->stream, "-%%fp%d", regno);
- }
- }
- else if (place == '8')
- {
- /* fmoveml for FP status registers. */
- (*info->fprintf_func) (info->stream, "%s",
- fpcr_names[fetch_arg (buffer, place, 3,
- info)]);
- }
- else
- return -2;
- break;
-
- case 'X':
- place = '8';
- case 'Y':
- case 'Z':
- case 'W':
- case '0':
- case '1':
- case '2':
- case '3':
- {
- int val = fetch_arg (buffer, place, 5, info);
- char *name = 0;
-
- switch (val)
- {
- case 2: name = "%tt0"; break;
- case 3: name = "%tt1"; break;
- case 0x10: name = "%tc"; break;
- case 0x11: name = "%drp"; break;
- case 0x12: name = "%srp"; break;
- case 0x13: name = "%crp"; break;
- case 0x14: name = "%cal"; break;
- case 0x15: name = "%val"; break;
- case 0x16: name = "%scc"; break;
- case 0x17: name = "%ac"; break;
- case 0x18: name = "%psr"; break;
- case 0x19: name = "%pcsr"; break;
- case 0x1c:
- case 0x1d:
- {
- int break_reg = ((buffer[3] >> 2) & 7);
-
- (*info->fprintf_func)
- (info->stream, val == 0x1c ? "%%bad%d" : "%%bac%d",
- break_reg);
- }
- break;
- default:
- (*info->fprintf_func) (info->stream, "<mmu register %d>", val);
- }
- if (name)
- (*info->fprintf_func) (info->stream, "%s", name);
- }
- break;
-
- case 'f':
- {
- int fc = fetch_arg (buffer, place, 5, info);
-
- if (fc == 1)
- (*info->fprintf_func) (info->stream, "%%dfc");
- else if (fc == 0)
- (*info->fprintf_func) (info->stream, "%%sfc");
- else
- /* xgettext:c-format */
- (*info->fprintf_func) (info->stream, _("<function code %d>"), fc);
- }
- break;
-
- case 'V':
- (*info->fprintf_func) (info->stream, "%%val");
- break;
-
- case 't':
- {
- int level = fetch_arg (buffer, place, 3, info);
-
- (*info->fprintf_func) (info->stream, "%d", level);
- }
- break;
-
- case 'u':
- {
- short is_upper = 0;
- int reg = fetch_arg (buffer, place, 5, info);
-
- if (reg & 0x10)
- {
- is_upper = 1;
- reg &= 0xf;
- }
- (*info->fprintf_func) (info->stream, "%s%s",
- reg_half_names[reg],
- is_upper ? "u" : "l");
- }
- break;
-
- default:
- return -2;
- }
-
- return p - p0;
-}
-
-/* Try to match the current instruction to best and if so, return the
- number of bytes consumed from the instruction stream, else zero. */
-
-static int
-match_insn_m68k (bfd_vma memaddr,
- disassemble_info * info,
- const struct m68k_opcode * best,
- struct private * priv)
-{
- unsigned char *save_p;
- unsigned char *p;
- const char *d;
-
- bfd_byte *buffer = priv->the_buffer;
- fprintf_ftype save_printer = info->fprintf_func;
- void (* save_print_address) (bfd_vma, struct disassemble_info *)
- = info->print_address_func;
-
- /* Point at first word of argument data,
- and at descriptor for first argument. */
- p = buffer + 2;
-
- /* Figure out how long the fixed-size portion of the instruction is.
- The only place this is stored in the opcode table is
- in the arguments--look for arguments which specify fields in the 2nd
- or 3rd words of the instruction. */
- for (d = best->args; *d; d += 2)
- {
- /* I don't think it is necessary to be checking d[0] here;
- I suspect all this could be moved to the case statement below. */
- if (d[0] == '#')
- {
- if (d[1] == 'l' && p - buffer < 6)
- p = buffer + 6;
- else if (p - buffer < 4 && d[1] != 'C' && d[1] != '8')
- p = buffer + 4;
- }
-
- if ((d[0] == 'L' || d[0] == 'l') && d[1] == 'w' && p - buffer < 4)
- p = buffer + 4;
-
- switch (d[1])
- {
- case '1':
- case '2':
- case '3':
- case '7':
- case '8':
- case '9':
- case 'i':
- if (p - buffer < 4)
- p = buffer + 4;
- break;
- case '4':
- case '5':
- case '6':
- if (p - buffer < 6)
- p = buffer + 6;
- break;
- default:
- break;
- }
- }
-
- /* pflusha is an exceptions. It takes no arguments but is two words
- long. Recognize it by looking at the lower 16 bits of the mask. */
- if (p - buffer < 4 && (best->match & 0xFFFF) != 0)
- p = buffer + 4;
-
- /* lpstop is another exception. It takes a one word argument but is
- three words long. */
- if (p - buffer < 6
- && (best->match & 0xffff) == 0xffff
- && best->args[0] == '#'
- && best->args[1] == 'w')
- {
- /* Copy the one word argument into the usual location for a one
- word argument, to simplify printing it. We can get away with
- this because we know exactly what the second word is, and we
- aren't going to print anything based on it. */
- p = buffer + 6;
- FETCH_DATA (info, p);
- buffer[2] = buffer[4];
- buffer[3] = buffer[5];
- }
-
- FETCH_DATA (info, p);
-
- d = best->args;
-
- save_p = p;
- info->print_address_func = dummy_print_address;
- info->fprintf_func = (fprintf_ftype) dummy_printer;
-
- /* We scan the operands twice. The first time we don't print anything,
- but look for errors. */
- for (; *d; d += 2)
- {
- int eaten = print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
-
- if (eaten >= 0)
- p += eaten;
- else if (eaten == -1)
- {
- info->fprintf_func = save_printer;
- info->print_address_func = save_print_address;
- return 0;
- }
- else
- {
- info->fprintf_func (info->stream,
- /* xgettext:c-format */
- _("<internal error in opcode table: %s %s>\n"),
- best->name, best->args);
- info->fprintf_func = save_printer;
- info->print_address_func = save_print_address;
- return 2;
- }
- }
-
- p = save_p;
- info->fprintf_func = save_printer;
- info->print_address_func = save_print_address;
-
- d = best->args;
-
- info->fprintf_func (info->stream, "%s", best->name);
-
- if (*d)
- info->fprintf_func (info->stream, " ");
-
- while (*d)
- {
- p += print_insn_arg (d, buffer, p, memaddr + (p - buffer), info);
- d += 2;
-
- if (*d && *(d - 2) != 'I' && *d != 'k')
- info->fprintf_func (info->stream, ",");
- }
-
- return p - buffer;
-}
-
-/* Print the m68k instruction at address MEMADDR in debugged memory,
- on INFO->STREAM. Returns length of the instruction, in bytes. */
-
-int
-print_insn_m68k (bfd_vma memaddr, disassemble_info *info)
-{
- int i;
- const char *d;
- unsigned int arch_mask;
- struct private priv;
- bfd_byte *buffer = priv.the_buffer;
- int major_opcode;
- static int numopcodes[16];
- static const struct m68k_opcode **opcodes[16];
- int val;
-
- if (!opcodes[0])
- {
- /* Speed up the matching by sorting the opcode
- table on the upper four bits of the opcode. */
- const struct m68k_opcode **opc_pointer[16];
-
- /* First count how many opcodes are in each of the sixteen buckets. */
- for (i = 0; i < m68k_numopcodes; i++)
- numopcodes[(m68k_opcodes[i].opcode >> 28) & 15]++;
-
- /* Then create a sorted table of pointers
- that point into the unsorted table. */
- opc_pointer[0] = malloc (sizeof (struct m68k_opcode *)
- * m68k_numopcodes);
- opcodes[0] = opc_pointer[0];
-
- for (i = 1; i < 16; i++)
- {
- opc_pointer[i] = opc_pointer[i - 1] + numopcodes[i - 1];
- opcodes[i] = opc_pointer[i];
- }
-
- for (i = 0; i < m68k_numopcodes; i++)
- *opc_pointer[(m68k_opcodes[i].opcode >> 28) & 15]++ = &m68k_opcodes[i];
- }
-
- info->private_data = (PTR) &priv;
- /* Tell objdump to use two bytes per chunk
- and six bytes per line for displaying raw data. */
- info->bytes_per_chunk = 2;
- info->bytes_per_line = 6;
- info->display_endian = BFD_ENDIAN_BIG;
- priv.max_fetched = priv.the_buffer;
- priv.insn_start = memaddr;
-
- if (setjmp (priv.bailout) != 0)
- /* Error return. */
- return -1;
-
- switch (info->mach)
- {
- default:
- case 0:
- arch_mask = (unsigned int) -1;
- break;
- case bfd_mach_m68000:
- arch_mask = m68000|m68881|m68851;
- break;
- case bfd_mach_m68008:
- arch_mask = m68008|m68881|m68851;
- break;
- case bfd_mach_m68010:
- arch_mask = m68010|m68881|m68851;
- break;
- case bfd_mach_m68020:
- arch_mask = m68020|m68881|m68851;
- break;
- case bfd_mach_m68030:
- arch_mask = m68030|m68881|m68851;
- break;
- case bfd_mach_m68040:
- arch_mask = m68040|m68881|m68851;
- break;
- case bfd_mach_m68060:
- arch_mask = m68060|m68881|m68851;
- break;
- case bfd_mach_mcf5200:
- arch_mask = mcfisa_a;
- break;
- case bfd_mach_mcf521x:
- case bfd_mach_mcf528x:
- arch_mask = mcfisa_a|mcfhwdiv|mcfisa_aa|mcfusp|mcfemac;
- break;
- case bfd_mach_mcf5206e:
- arch_mask = mcfisa_a|mcfhwdiv|mcfmac;
- break;
- case bfd_mach_mcf5249:
- arch_mask = mcfisa_a|mcfhwdiv|mcfemac;
- break;
- case bfd_mach_mcf5307:
- arch_mask = mcfisa_a|mcfhwdiv|mcfmac;
- break;
- case bfd_mach_mcf5407:
- arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfmac;
- break;
- case bfd_mach_mcf547x:
- case bfd_mach_mcf548x:
- case bfd_mach_mcfv4e:
- arch_mask = mcfisa_a|mcfhwdiv|mcfisa_b|mcfusp|cfloat|mcfemac;
- break;
- }
-
- FETCH_DATA (info, buffer + 2);
- major_opcode = (buffer[0] >> 4) & 15;
-
- for (i = 0; i < numopcodes[major_opcode]; i++)
- {
- const struct m68k_opcode *opc = opcodes[major_opcode][i];
- unsigned long opcode = opc->opcode;
- unsigned long match = opc->match;
-
- if (((0xff & buffer[0] & (match >> 24)) == (0xff & (opcode >> 24)))
- && ((0xff & buffer[1] & (match >> 16)) == (0xff & (opcode >> 16)))
- /* Only fetch the next two bytes if we need to. */
- && (((0xffff & match) == 0)
- ||
- (FETCH_DATA (info, buffer + 4)
- && ((0xff & buffer[2] & (match >> 8)) == (0xff & (opcode >> 8)))
- && ((0xff & buffer[3] & match) == (0xff & opcode)))
- )
- && (opc->arch & arch_mask) != 0)
- {
- /* Don't use for printout the variants of divul and divsl
- that have the same register number in two places.
- The more general variants will match instead. */
- for (d = opc->args; *d; d += 2)
- if (d[1] == 'D')
- break;
-
- /* Don't use for printout the variants of most floating
- point coprocessor instructions which use the same
- register number in two places, as above. */
- if (*d == '\0')
- for (d = opc->args; *d; d += 2)
- if (d[1] == 't')
- break;
-
- /* Don't match fmovel with more than one register;
- wait for fmoveml. */
- if (*d == '\0')
- {
- for (d = opc->args; *d; d += 2)
- {
- if (d[0] == 's' && d[1] == '8')
- {
- val = fetch_arg (buffer, d[1], 3, info);
- if ((val & (val - 1)) != 0)
- break;
- }
- }
- }
-
- if (*d == '\0')
- if ((val = match_insn_m68k (memaddr, info, opc, & priv)))
- return val;
- }
- }
-
- /* Handle undefined instructions. */
- info->fprintf_func (info->stream, "0%o", (buffer[0] << 8) + buffer[1]);
- return 2;
-}
-/* **** End of m68k-dis.c */
-/* **** m68k-opc.h from sourceware.org CVS 2005-08-14. */
-/* Opcode table for m680[012346]0/m6888[12]/m68851/mcf5200.
- Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2003, 2004, 2005
- Free Software Foundation, Inc.
-
- This file is part of GDB, GAS, and the GNU binutils.
-
- GDB, GAS, and the GNU binutils are free software; you can redistribute
- them and/or modify them under the terms of the GNU General Public
- License as published by the Free Software Foundation; either version
- 1, or (at your option) any later version.
-
- GDB, GAS, and the GNU binutils are distributed in the hope that they
- will be useful, but WITHOUT ANY WARRANTY; without even the implied
- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
- the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this file; see the file COPYING. If not, write to the Free
- Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
- 02110-1301, USA. */
-
-#define one(x) ((unsigned int) (x) << 16)
-#define two(x, y) (((unsigned int) (x) << 16) + (y))
-
-/* The assembler requires that all instances of the same mnemonic must
- be consecutive. If they aren't, the assembler will bomb at
- runtime. */
-
-const struct m68k_opcode m68k_opcodes[] =
-{
-{"abcd", 2, one(0140400), one(0170770), "DsDd", m68000up },
-{"abcd", 2, one(0140410), one(0170770), "-s-d", m68000up },
-
-{"addaw", 2, one(0150300), one(0170700), "*wAd", m68000up },
-{"addal", 2, one(0150700), one(0170700), "*lAd", m68000up | mcfisa_a },
-
-{"addib", 4, one(0003000), one(0177700), "#b$s", m68000up },
-{"addiw", 4, one(0003100), one(0177700), "#w$s", m68000up },
-{"addil", 6, one(0003200), one(0177700), "#l$s", m68000up },
-{"addil", 6, one(0003200), one(0177700), "#lDs", mcfisa_a },
-
-{"addqb", 2, one(0050000), one(0170700), "Qd$b", m68000up },
-{"addqw", 2, one(0050100), one(0170700), "Qd%w", m68000up },
-{"addql", 2, one(0050200), one(0170700), "Qd%l", m68000up | mcfisa_a },
-
-/* The add opcode can generate the adda, addi, and addq instructions. */
-{"addb", 2, one(0050000), one(0170700), "Qd$b", m68000up },
-{"addb", 4, one(0003000), one(0177700), "#b$s", m68000up },
-{"addb", 2, one(0150000), one(0170700), ";bDd", m68000up },
-{"addb", 2, one(0150400), one(0170700), "Dd~b", m68000up },
-{"addw", 2, one(0050100), one(0170700), "Qd%w", m68000up },
-{"addw", 2, one(0150300), one(0170700), "*wAd", m68000up },
-{"addw", 4, one(0003100), one(0177700), "#w$s", m68000up },
-{"addw", 2, one(0150100), one(0170700), "*wDd", m68000up },
-{"addw", 2, one(0150500), one(0170700), "Dd~w", m68000up },
-{"addl", 2, one(0050200), one(0170700), "Qd%l", m68000up | mcfisa_a },
-{"addl", 6, one(0003200), one(0177700), "#l$s", m68000up },
-{"addl", 6, one(0003200), one(0177700), "#lDs", mcfisa_a },
-{"addl", 2, one(0150700), one(0170700), "*lAd", m68000up | mcfisa_a },
-{"addl", 2, one(0150200), one(0170700), "*lDd", m68000up | mcfisa_a },
-{"addl", 2, one(0150600), one(0170700), "Dd~l", m68000up | mcfisa_a },
-
-{"addxb", 2, one(0150400), one(0170770), "DsDd", m68000up },
-{"addxb", 2, one(0150410), one(0170770), "-s-d", m68000up },
-{"addxw", 2, one(0150500), one(0170770), "DsDd", m68000up },
-{"addxw", 2, one(0150510), one(0170770), "-s-d", m68000up },
-{"addxl", 2, one(0150600), one(0170770), "DsDd", m68000up | mcfisa_a },
-{"addxl", 2, one(0150610), one(0170770), "-s-d", m68000up },
-
-{"andib", 4, one(0001000), one(0177700), "#b$s", m68000up },
-{"andib", 4, one(0001074), one(0177777), "#bCs", m68000up },
-{"andiw", 4, one(0001100), one(0177700), "#w$s", m68000up },
-{"andiw", 4, one(0001174), one(0177777), "#wSs", m68000up },
-{"andil", 6, one(0001200), one(0177700), "#l$s", m68000up },
-{"andil", 6, one(0001200), one(0177700), "#lDs", mcfisa_a },
-{"andi", 4, one(0001100), one(0177700), "#w$s", m68000up },
-{"andi", 4, one(0001074), one(0177777), "#bCs", m68000up },
-{"andi", 4, one(0001174), one(0177777), "#wSs", m68000up },
-
-/* The and opcode can generate the andi instruction. */
-{"andb", 4, one(0001000), one(0177700), "#b$s", m68000up },
-{"andb", 4, one(0001074), one(0177777), "#bCs", m68000up },
-{"andb", 2, one(0140000), one(0170700), ";bDd", m68000up },
-{"andb", 2, one(0140400), one(0170700), "Dd~b", m68000up },
-{"andw", 4, one(0001100), one(0177700), "#w$s", m68000up },
-{"andw", 4, one(0001174), one(0177777), "#wSs", m68000up },
-{"andw", 2, one(0140100), one(0170700), ";wDd", m68000up },
-{"andw", 2, one(0140500), one(0170700), "Dd~w", m68000up },
-{"andl", 6, one(0001200), one(0177700), "#l$s", m68000up },
-{"andl", 6, one(0001200), one(0177700), "#lDs", mcfisa_a },
-{"andl", 2, one(0140200), one(0170700), ";lDd", m68000up | mcfisa_a },
-{"andl", 2, one(0140600), one(0170700), "Dd~l", m68000up | mcfisa_a },
-{"and", 4, one(0001100), one(0177700), "#w$w", m68000up },
-{"and", 4, one(0001074), one(0177777), "#bCs", m68000up },
-{"and", 4, one(0001174), one(0177777), "#wSs", m68000up },
-{"and", 2, one(0140100), one(0170700), ";wDd", m68000up },
-{"and", 2, one(0140500), one(0170700), "Dd~w", m68000up },
-
-{"aslb", 2, one(0160400), one(0170770), "QdDs", m68000up },
-{"aslb", 2, one(0160440), one(0170770), "DdDs", m68000up },
-{"aslw", 2, one(0160500), one(0170770), "QdDs", m68000up },
-{"aslw", 2, one(0160540), one(0170770), "DdDs", m68000up },
-{"aslw", 2, one(0160700), one(0177700), "~s", m68000up },
-{"asll", 2, one(0160600), one(0170770), "QdDs", m68000up | mcfisa_a },
-{"asll", 2, one(0160640), one(0170770), "DdDs", m68000up | mcfisa_a },
-
-{"asrb", 2, one(0160000), one(0170770), "QdDs", m68000up },
-{"asrb", 2, one(0160040), one(0170770), "DdDs", m68000up },
-{"asrw", 2, one(0160100), one(0170770), "QdDs", m68000up },
-{"asrw", 2, one(0160140), one(0170770), "DdDs", m68000up },
-{"asrw", 2, one(0160300), one(0177700), "~s", m68000up },
-{"asrl", 2, one(0160200), one(0170770), "QdDs", m68000up | mcfisa_a },
-{"asrl", 2, one(0160240), one(0170770), "DdDs", m68000up | mcfisa_a },
-
-{"bhiw", 2, one(0061000), one(0177777), "BW", m68000up | mcfisa_a },
-{"blsw", 2, one(0061400), one(0177777), "BW", m68000up | mcfisa_a },
-{"bccw", 2, one(0062000), one(0177777), "BW", m68000up | mcfisa_a },
-{"bcsw", 2, one(0062400), one(0177777), "BW", m68000up | mcfisa_a },
-{"bnew", 2, one(0063000), one(0177777), "BW", m68000up | mcfisa_a },
-{"beqw", 2, one(0063400), one(0177777), "BW", m68000up | mcfisa_a },
-{"bvcw", 2, one(0064000), one(0177777), "BW", m68000up | mcfisa_a },
-{"bvsw", 2, one(0064400), one(0177777), "BW", m68000up | mcfisa_a },
-{"bplw", 2, one(0065000), one(0177777), "BW", m68000up | mcfisa_a },
-{"bmiw", 2, one(0065400), one(0177777), "BW", m68000up | mcfisa_a },
-{"bgew", 2, one(0066000), one(0177777), "BW", m68000up | mcfisa_a },
-{"bltw", 2, one(0066400), one(0177777), "BW", m68000up | mcfisa_a },
-{"bgtw", 2, one(0067000), one(0177777), "BW", m68000up | mcfisa_a },
-{"blew", 2, one(0067400), one(0177777), "BW", m68000up | mcfisa_a },
-
-{"bhil", 2, one(0061377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"blsl", 2, one(0061777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bccl", 2, one(0062377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bcsl", 2, one(0062777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bnel", 2, one(0063377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"beql", 2, one(0063777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bvcl", 2, one(0064377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bvsl", 2, one(0064777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bpll", 2, one(0065377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bmil", 2, one(0065777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bgel", 2, one(0066377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bltl", 2, one(0066777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bgtl", 2, one(0067377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"blel", 2, one(0067777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-
-{"bhis", 2, one(0061000), one(0177400), "BB", m68000up | mcfisa_a },
-{"blss", 2, one(0061400), one(0177400), "BB", m68000up | mcfisa_a },
-{"bccs", 2, one(0062000), one(0177400), "BB", m68000up | mcfisa_a },
-{"bcss", 2, one(0062400), one(0177400), "BB", m68000up | mcfisa_a },
-{"bnes", 2, one(0063000), one(0177400), "BB", m68000up | mcfisa_a },
-{"beqs", 2, one(0063400), one(0177400), "BB", m68000up | mcfisa_a },
-{"bvcs", 2, one(0064000), one(0177400), "BB", m68000up | mcfisa_a },
-{"bvss", 2, one(0064400), one(0177400), "BB", m68000up | mcfisa_a },
-{"bpls", 2, one(0065000), one(0177400), "BB", m68000up | mcfisa_a },
-{"bmis", 2, one(0065400), one(0177400), "BB", m68000up | mcfisa_a },
-{"bges", 2, one(0066000), one(0177400), "BB", m68000up | mcfisa_a },
-{"blts", 2, one(0066400), one(0177400), "BB", m68000up | mcfisa_a },
-{"bgts", 2, one(0067000), one(0177400), "BB", m68000up | mcfisa_a },
-{"bles", 2, one(0067400), one(0177400), "BB", m68000up | mcfisa_a },
-
-{"jhi", 2, one(0061000), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jls", 2, one(0061400), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jcc", 2, one(0062000), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jcs", 2, one(0062400), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jne", 2, one(0063000), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jeq", 2, one(0063400), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jvc", 2, one(0064000), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jvs", 2, one(0064400), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jpl", 2, one(0065000), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jmi", 2, one(0065400), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jge", 2, one(0066000), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jlt", 2, one(0066400), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jgt", 2, one(0067000), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jle", 2, one(0067400), one(0177400), "Bg", m68000up | mcfisa_a },
-
-{"bchg", 2, one(0000500), one(0170700), "Dd$s", m68000up | mcfisa_a },
-{"bchg", 4, one(0004100), one(0177700), "#b$s", m68000up },
-{"bchg", 4, one(0004100), one(0177700), "#bqs", mcfisa_a },
-
-{"bclr", 2, one(0000600), one(0170700), "Dd$s", m68000up | mcfisa_a },
-{"bclr", 4, one(0004200), one(0177700), "#b$s", m68000up },
-{"bclr", 4, one(0004200), one(0177700), "#bqs", mcfisa_a },
-
-{"bfchg", 4, two(0165300, 0), two(0177700, 0170000), "?sO2O3", m68020up },
-{"bfclr", 4, two(0166300, 0), two(0177700, 0170000), "?sO2O3", m68020up },
-{"bfexts", 4, two(0165700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up },
-{"bfextu", 4, two(0164700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up },
-{"bfffo", 4, two(0166700, 0), two(0177700, 0100000), "/sO2O3D1", m68020up },
-{"bfins", 4, two(0167700, 0), two(0177700, 0100000), "D1?sO2O3", m68020up },
-{"bfset", 4, two(0167300, 0), two(0177700, 0170000), "?sO2O3", m68020up },
-{"bftst", 4, two(0164300, 0), two(0177700, 0170000), "/sO2O3", m68020up },
-
-{"bgnd", 2, one(0045372), one(0177777), "", cpu32 },
-
-{"bitrev", 2, one(0000300), one(0177770), "Ds", mcfisa_aa},
-
-{"bkpt", 2, one(0044110), one(0177770), "ts", m68010up },
-
-{"braw", 2, one(0060000), one(0177777), "BW", m68000up | mcfisa_a },
-{"bral", 2, one(0060377), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bras", 2, one(0060000), one(0177400), "BB", m68000up | mcfisa_a },
-
-{"bset", 2, one(0000700), one(0170700), "Dd$s", m68000up | mcfisa_a },
-{"bset", 2, one(0000700), one(0170700), "Ddvs", mcfisa_a },
-{"bset", 4, one(0004300), one(0177700), "#b$s", m68000up },
-{"bset", 4, one(0004300), one(0177700), "#bqs", mcfisa_a },
-
-{"bsrw", 2, one(0060400), one(0177777), "BW", m68000up | mcfisa_a },
-{"bsrl", 2, one(0060777), one(0177777), "BL", m68020up | cpu32 | mcfisa_b},
-{"bsrs", 2, one(0060400), one(0177400), "BB", m68000up | mcfisa_a },
-
-{"btst", 2, one(0000400), one(0170700), "Dd;b", m68000up | mcfisa_a },
-{"btst", 4, one(0004000), one(0177700), "#b@s", m68000up },
-{"btst", 4, one(0004000), one(0177700), "#bqs", mcfisa_a },
-
-{"byterev", 2, one(0001300), one(0177770), "Ds", mcfisa_aa},
-
-{"callm", 4, one(0003300), one(0177700), "#b!s", m68020 },
-
-{"cas2w", 6, two(0006374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up },
-{"cas2w", 6, two(0006374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up },
-{"cas2l", 6, two(0007374,0), two(0177777,0007070), "D3D6D2D5r1r4", m68020up },
-{"cas2l", 6, two(0007374,0), two(0177777,0007070), "D3D6D2D5R1R4", m68020up },
-
-{"casb", 4, two(0005300, 0), two(0177700, 0177070), "D3D2~s", m68020up },
-{"casw", 4, two(0006300, 0), two(0177700, 0177070), "D3D2~s", m68020up },
-{"casl", 4, two(0007300, 0), two(0177700, 0177070), "D3D2~s", m68020up },
-
-{"chk2b", 4, two(0000300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 },
-{"chk2w", 4, two(0001300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 },
-{"chk2l", 4, two(0002300,0004000), two(0177700,07777), "!sR1", m68020up | cpu32 },
-
-{"chkl", 2, one(0040400), one(0170700), ";lDd", m68000up },
-{"chkw", 2, one(0040600), one(0170700), ";wDd", m68000up },
-
-#define SCOPE_LINE (0x1 << 3)
-#define SCOPE_PAGE (0x2 << 3)
-#define SCOPE_ALL (0x3 << 3)
-
-{"cinva", 2, one(0xf400|SCOPE_ALL), one(0xff38), "ce", m68040up },
-{"cinvl", 2, one(0xf400|SCOPE_LINE), one(0xff38), "ceas", m68040up },
-{"cinvp", 2, one(0xf400|SCOPE_PAGE), one(0xff38), "ceas", m68040up },
-
-{"cpusha", 2, one(0xf420|SCOPE_ALL), one(0xff38), "ce", m68040up },
-{"cpushl", 2, one(0xf420|SCOPE_LINE), one(0xff38), "ceas", m68040up | mcfisa_a },
-{"cpushp", 2, one(0xf420|SCOPE_PAGE), one(0xff38), "ceas", m68040up },
-
-#undef SCOPE_LINE
-#undef SCOPE_PAGE
-#undef SCOPE_ALL
-
-{"clrb", 2, one(0041000), one(0177700), "$s", m68000up | mcfisa_a },
-{"clrw", 2, one(0041100), one(0177700), "$s", m68000up | mcfisa_a },
-{"clrl", 2, one(0041200), one(0177700), "$s", m68000up | mcfisa_a },
-
-{"cmp2b", 4, two(0000300,0), two(0177700,07777), "!sR1", m68020up | cpu32 },
-{"cmp2w", 4, two(0001300,0), two(0177700,07777), "!sR1", m68020up | cpu32 },
-{"cmp2l", 4, two(0002300,0), two(0177700,07777), "!sR1", m68020up | cpu32 },
-
-{"cmpaw", 2, one(0130300), one(0170700), "*wAd", m68000up },
-{"cmpal", 2, one(0130700), one(0170700), "*lAd", m68000up | mcfisa_a },
-
-{"cmpib", 4, one(0006000), one(0177700), "#b@s", m68000up },
-{"cmpib", 4, one(0006000), one(0177700), "#bDs", mcfisa_b },
-{"cmpiw", 4, one(0006100), one(0177700), "#w@s", m68000up },
-{"cmpiw", 4, one(0006100), one(0177700), "#wDs", mcfisa_b },
-{"cmpil", 6, one(0006200), one(0177700), "#l@s", m68000up },
-{"cmpil", 6, one(0006200), one(0177700), "#lDs", mcfisa_a },
-
-{"cmpmb", 2, one(0130410), one(0170770), "+s+d", m68000up },
-{"cmpmw", 2, one(0130510), one(0170770), "+s+d", m68000up },
-{"cmpml", 2, one(0130610), one(0170770), "+s+d", m68000up },
-
-/* The cmp opcode can generate the cmpa, cmpm, and cmpi instructions. */
-{"cmpb", 4, one(0006000), one(0177700), "#b@s", m68000up },
-{"cmpb", 4, one(0006000), one(0177700), "#bDs", mcfisa_b },
-{"cmpb", 2, one(0130410), one(0170770), "+s+d", m68000up },
-{"cmpb", 2, one(0130000), one(0170700), ";bDd", m68000up },
-{"cmpb", 2, one(0130000), one(0170700), "*bDd", mcfisa_b },
-{"cmpw", 2, one(0130300), one(0170700), "*wAd", m68000up },
-{"cmpw", 4, one(0006100), one(0177700), "#w@s", m68000up },
-{"cmpw", 4, one(0006100), one(0177700), "#wDs", mcfisa_b },
-{"cmpw", 2, one(0130510), one(0170770), "+s+d", m68000up },
-{"cmpw", 2, one(0130100), one(0170700), "*wDd", m68000up | mcfisa_b },
-{"cmpl", 2, one(0130700), one(0170700), "*lAd", m68000up | mcfisa_a },
-{"cmpl", 6, one(0006200), one(0177700), "#l@s", m68000up },
-{"cmpl", 6, one(0006200), one(0177700), "#lDs", mcfisa_a },
-{"cmpl", 2, one(0130610), one(0170770), "+s+d", m68000up },
-{"cmpl", 2, one(0130200), one(0170700), "*lDd", m68000up | mcfisa_a },
-
-{"dbcc", 2, one(0052310), one(0177770), "DsBw", m68000up },
-{"dbcs", 2, one(0052710), one(0177770), "DsBw", m68000up },
-{"dbeq", 2, one(0053710), one(0177770), "DsBw", m68000up },
-{"dbf", 2, one(0050710), one(0177770), "DsBw", m68000up },
-{"dbge", 2, one(0056310), one(0177770), "DsBw", m68000up },
-{"dbgt", 2, one(0057310), one(0177770), "DsBw", m68000up },
-{"dbhi", 2, one(0051310), one(0177770), "DsBw", m68000up },
-{"dble", 2, one(0057710), one(0177770), "DsBw", m68000up },
-{"dbls", 2, one(0051710), one(0177770), "DsBw", m68000up },
-{"dblt", 2, one(0056710), one(0177770), "DsBw", m68000up },
-{"dbmi", 2, one(0055710), one(0177770), "DsBw", m68000up },
-{"dbne", 2, one(0053310), one(0177770), "DsBw", m68000up },
-{"dbpl", 2, one(0055310), one(0177770), "DsBw", m68000up },
-{"dbt", 2, one(0050310), one(0177770), "DsBw", m68000up },
-{"dbvc", 2, one(0054310), one(0177770), "DsBw", m68000up },
-{"dbvs", 2, one(0054710), one(0177770), "DsBw", m68000up },
-
-{"divsw", 2, one(0100700), one(0170700), ";wDd", m68000up | mcfhwdiv },
-
-{"divsl", 4, two(0046100,0006000),two(0177700,0107770),";lD3D1", m68020up|cpu32 },
-{"divsl", 4, two(0046100,0004000),two(0177700,0107770),";lDD", m68020up|cpu32 },
-{"divsl", 4, two(0046100,0004000),two(0177700,0107770),"qsDD", mcfhwdiv },
-
-{"divsll", 4, two(0046100,0004000),two(0177700,0107770),";lD3D1",m68020up|cpu32 },
-{"divsll", 4, two(0046100,0004000),two(0177700,0107770),";lDD", m68020up|cpu32 },
-
-{"divuw", 2, one(0100300), one(0170700), ";wDd", m68000up | mcfhwdiv },
-
-{"divul", 4, two(0046100,0002000),two(0177700,0107770),";lD3D1", m68020up|cpu32 },
-{"divul", 4, two(0046100,0000000),two(0177700,0107770),";lDD", m68020up|cpu32 },
-{"divul", 4, two(0046100,0000000),two(0177700,0107770),"qsDD", mcfhwdiv },
-
-{"divull", 4, two(0046100,0000000),two(0177700,0107770),";lD3D1",m68020up|cpu32 },
-{"divull", 4, two(0046100,0000000),two(0177700,0107770),";lDD", m68020up|cpu32 },
-
-{"eorib", 4, one(0005000), one(0177700), "#b$s", m68000up },
-{"eorib", 4, one(0005074), one(0177777), "#bCs", m68000up },
-{"eoriw", 4, one(0005100), one(0177700), "#w$s", m68000up },
-{"eoriw", 4, one(0005174), one(0177777), "#wSs", m68000up },
-{"eoril", 6, one(0005200), one(0177700), "#l$s", m68000up },
-{"eoril", 6, one(0005200), one(0177700), "#lDs", mcfisa_a },
-{"eori", 4, one(0005074), one(0177777), "#bCs", m68000up },
-{"eori", 4, one(0005174), one(0177777), "#wSs", m68000up },
-{"eori", 4, one(0005100), one(0177700), "#w$s", m68000up },
-
-/* The eor opcode can generate the eori instruction. */
-{"eorb", 4, one(0005000), one(0177700), "#b$s", m68000up },
-{"eorb", 4, one(0005074), one(0177777), "#bCs", m68000up },
-{"eorb", 2, one(0130400), one(0170700), "Dd$s", m68000up },
-{"eorw", 4, one(0005100), one(0177700), "#w$s", m68000up },
-{"eorw", 4, one(0005174), one(0177777), "#wSs", m68000up },
-{"eorw", 2, one(0130500), one(0170700), "Dd$s", m68000up },
-{"eorl", 6, one(0005200), one(0177700), "#l$s", m68000up },
-{"eorl", 6, one(0005200), one(0177700), "#lDs", mcfisa_a },
-{"eorl", 2, one(0130600), one(0170700), "Dd$s", m68000up | mcfisa_a },
-{"eor", 4, one(0005074), one(0177777), "#bCs", m68000up },
-{"eor", 4, one(0005174), one(0177777), "#wSs", m68000up },
-{"eor", 4, one(0005100), one(0177700), "#w$s", m68000up },
-{"eor", 2, one(0130500), one(0170700), "Dd$s", m68000up },
-
-{"exg", 2, one(0140500), one(0170770), "DdDs", m68000up },
-{"exg", 2, one(0140510), one(0170770), "AdAs", m68000up },
-{"exg", 2, one(0140610), one(0170770), "DdAs", m68000up },
-{"exg", 2, one(0140610), one(0170770), "AsDd", m68000up },
-
-{"extw", 2, one(0044200), one(0177770), "Ds", m68000up|mcfisa_a },
-{"extl", 2, one(0044300), one(0177770), "Ds", m68000up|mcfisa_a },
-{"extbl", 2, one(0044700), one(0177770), "Ds", m68020up|cpu32|mcfisa_a },
-
-{"ff1", 2, one(0002300), one(0177770), "Ds", mcfisa_aa},
-
-/* float stuff starts here */
-
-{"fabsb", 4, two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fabsb", 4, two(0xF000, 0x5818), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fabsd", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fabsd", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fabsd", 4, two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fabsd", 4, two(0xF000, 0x5418), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fabsl", 4, two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fabsl", 4, two(0xF000, 0x4018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fabsp", 4, two(0xF000, 0x4C18), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fabss", 4, two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", cfloat },
-{"fabss", 4, two(0xF000, 0x4418), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fabsw", 4, two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fabsw", 4, two(0xF000, 0x5018), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fabsx", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fabsx", 4, two(0xF000, 0x4818), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fabsx", 4, two(0xF000, 0x0018), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fsabsb", 4, two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fsabsb", 4, two(0xF000, 0x5858), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsabsd", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fsabsd", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fsabsd", 4, two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fsabsd", 4, two(0xF000, 0x5458), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fsabsl", 4, two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fsabsl", 4, two(0xF000, 0x4058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsabsp", 4, two(0xF000, 0x4C58), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fsabss", 4, two(0xF000, 0x4258), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsabss", 4, two(0xF000, 0x4458), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fsabsw", 4, two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fsabsw", 4, two(0xF000, 0x5058), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsabsx", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fsabsx", 4, two(0xF000, 0x4858), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-{"fsabsx", 4, two(0xF000, 0x0058), two(0xF1C0, 0xE07F), "IiFt", m68040up },
-
-{"fdabsb", 4, two(0xF000, 0x585C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdabsb", 4, two(0xF000, 0x585c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up},
-{"fdabsd", 4, two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fdabsd", 4, two(0xF000, 0x005C), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fdabsd", 4, two(0xF000, 0x545C), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fdabsd", 4, two(0xF000, 0x545c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up},
-{"fdabsl", 4, two(0xF000, 0x405C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdabsl", 4, two(0xF000, 0x405c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up},
-{"fdabsp", 4, two(0xF000, 0x4C5c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up},
-{"fdabss", 4, two(0xF000, 0x425C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdabss", 4, two(0xF000, 0x445c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up},
-{"fdabsw", 4, two(0xF000, 0x505C), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdabsw", 4, two(0xF000, 0x505c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up},
-{"fdabsx", 4, two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up},
-{"fdabsx", 4, two(0xF000, 0x485c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up},
-{"fdabsx", 4, two(0xF000, 0x005c), two(0xF1C0, 0xE07F), "IiFt", m68040up},
-
-{"facosb", 4, two(0xF000, 0x581C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"facosd", 4, two(0xF000, 0x541C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"facosl", 4, two(0xF000, 0x401C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"facosp", 4, two(0xF000, 0x4C1C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"facoss", 4, two(0xF000, 0x441C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"facosw", 4, two(0xF000, 0x501C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"facosx", 4, two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"facosx", 4, two(0xF000, 0x481C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"facosx", 4, two(0xF000, 0x001C), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"faddb", 4, two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"faddb", 4, two(0xF000, 0x5822), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"faddd", 4, two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"faddd", 4, two(0xF000, 0x5422), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"faddl", 4, two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"faddl", 4, two(0xF000, 0x4022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"faddp", 4, two(0xF000, 0x4C22), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fadds", 4, two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fadds", 4, two(0xF000, 0x4422), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"faddw", 4, two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"faddw", 4, two(0xF000, 0x5022), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"faddx", 4, two(0xF000, 0x0022), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"faddx", 4, two(0xF000, 0x4822), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-
-{"fsaddb", 4, two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fsaddb", 4, two(0xF000, 0x5862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsaddd", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fsaddd", 4, two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fsaddd", 4, two(0xF000, 0x5462), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fsaddl", 4, two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fsaddl", 4, two(0xF000, 0x4062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsaddp", 4, two(0xF000, 0x4C62), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fsadds", 4, two(0xF000, 0x4462), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fsadds", 4, two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsaddw", 4, two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fsaddw", 4, two(0xF000, 0x5062), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsaddx", 4, two(0xF000, 0x0062), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fsaddx", 4, two(0xF000, 0x4862), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-
-{"fdaddb", 4, two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdaddb", 4, two(0xF000, 0x5866), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fdaddd", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fdaddd", 4, two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdaddd", 4, two(0xF000, 0x5466), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fdaddl", 4, two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fdaddl", 4, two(0xF000, 0x4066), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fdaddp", 4, two(0xF000, 0x4C66), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fdadds", 4, two(0xF000, 0x4466), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fdadds", 4, two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdaddw", 4, two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdaddw", 4, two(0xF000, 0x5066), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fdaddx", 4, two(0xF000, 0x0066), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fdaddx", 4, two(0xF000, 0x4866), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-
-{"fasinb", 4, two(0xF000, 0x580C), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fasind", 4, two(0xF000, 0x540C), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fasinl", 4, two(0xF000, 0x400C), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fasinp", 4, two(0xF000, 0x4C0C), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fasins", 4, two(0xF000, 0x440C), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fasinw", 4, two(0xF000, 0x500C), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fasinx", 4, two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fasinx", 4, two(0xF000, 0x480C), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fasinx", 4, two(0xF000, 0x000C), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fatanb", 4, two(0xF000, 0x580A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fatand", 4, two(0xF000, 0x540A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fatanl", 4, two(0xF000, 0x400A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fatanp", 4, two(0xF000, 0x4C0A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fatans", 4, two(0xF000, 0x440A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fatanw", 4, two(0xF000, 0x500A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fatanx", 4, two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fatanx", 4, two(0xF000, 0x480A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fatanx", 4, two(0xF000, 0x000A), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fatanhb", 4, two(0xF000, 0x580D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fatanhd", 4, two(0xF000, 0x540D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fatanhl", 4, two(0xF000, 0x400D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fatanhp", 4, two(0xF000, 0x4C0D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fatanhs", 4, two(0xF000, 0x440D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fatanhw", 4, two(0xF000, 0x500D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fatanhx", 4, two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fatanhx", 4, two(0xF000, 0x480D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fatanhx", 4, two(0xF000, 0x000D), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fbeq", 2, one(0xF081), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbf", 2, one(0xF080), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbge", 2, one(0xF093), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbgl", 2, one(0xF096), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbgle", 2, one(0xF097), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbgt", 2, one(0xF092), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fble", 2, one(0xF095), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fblt", 2, one(0xF094), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbne", 2, one(0xF08E), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbnge", 2, one(0xF09C), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbngl", 2, one(0xF099), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbngle", 2, one(0xF098), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbngt", 2, one(0xF09D), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbnle", 2, one(0xF09A), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbnlt", 2, one(0xF09B), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fboge", 2, one(0xF083), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbogl", 2, one(0xF086), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbogt", 2, one(0xF082), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbole", 2, one(0xF085), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbolt", 2, one(0xF084), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbor", 2, one(0xF087), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbseq", 2, one(0xF091), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbsf", 2, one(0xF090), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbsne", 2, one(0xF09E), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbst", 2, one(0xF09F), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbt", 2, one(0xF08F), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbueq", 2, one(0xF089), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbuge", 2, one(0xF08B), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbugt", 2, one(0xF08A), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbule", 2, one(0xF08D), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbult", 2, one(0xF08C), one(0xF1FF), "IdBW", mfloat | cfloat },
-{"fbun", 2, one(0xF088), one(0xF1FF), "IdBW", mfloat | cfloat },
-
-{"fbeql", 2, one(0xF0C1), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbfl", 2, one(0xF0C0), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbgel", 2, one(0xF0D3), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbgll", 2, one(0xF0D6), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbglel", 2, one(0xF0D7), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbgtl", 2, one(0xF0D2), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fblel", 2, one(0xF0D5), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbltl", 2, one(0xF0D4), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbnel", 2, one(0xF0CE), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbngel", 2, one(0xF0DC), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbngll", 2, one(0xF0D9), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbnglel", 2, one(0xF0D8), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbngtl", 2, one(0xF0DD), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbnlel", 2, one(0xF0DA), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbnltl", 2, one(0xF0DB), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbogel", 2, one(0xF0C3), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbogll", 2, one(0xF0C6), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbogtl", 2, one(0xF0C2), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbolel", 2, one(0xF0C5), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fboltl", 2, one(0xF0C4), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fborl", 2, one(0xF0C7), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbseql", 2, one(0xF0D1), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbsfl", 2, one(0xF0D0), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbsnel", 2, one(0xF0DE), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbstl", 2, one(0xF0DF), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbtl", 2, one(0xF0CF), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbueql", 2, one(0xF0C9), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbugel", 2, one(0xF0CB), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbugtl", 2, one(0xF0CA), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbulel", 2, one(0xF0CD), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbultl", 2, one(0xF0CC), one(0xF1FF), "IdBC", mfloat | cfloat },
-{"fbunl", 2, one(0xF0C8), one(0xF1FF), "IdBC", mfloat | cfloat },
-
-{"fjeq", 2, one(0xF081), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjf", 2, one(0xF080), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjge", 2, one(0xF093), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjgl", 2, one(0xF096), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjgle", 2, one(0xF097), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjgt", 2, one(0xF092), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjle", 2, one(0xF095), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjlt", 2, one(0xF094), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjne", 2, one(0xF08E), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjnge", 2, one(0xF09C), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjngl", 2, one(0xF099), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjngle", 2, one(0xF098), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjngt", 2, one(0xF09D), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjnle", 2, one(0xF09A), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjnlt", 2, one(0xF09B), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjoge", 2, one(0xF083), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjogl", 2, one(0xF086), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjogt", 2, one(0xF082), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjole", 2, one(0xF085), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjolt", 2, one(0xF084), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjor", 2, one(0xF087), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjseq", 2, one(0xF091), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjsf", 2, one(0xF090), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjsne", 2, one(0xF09E), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjst", 2, one(0xF09F), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjt", 2, one(0xF08F), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjueq", 2, one(0xF089), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjuge", 2, one(0xF08B), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjugt", 2, one(0xF08A), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjule", 2, one(0xF08D), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjult", 2, one(0xF08C), one(0xF1BF), "IdBc", mfloat | cfloat },
-{"fjun", 2, one(0xF088), one(0xF1BF), "IdBc", mfloat | cfloat },
-
-{"fcmpb", 4, two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fcmpb", 4, two(0xF000, 0x5838), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fcmpd", 4, two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fcmpd", 4, two(0xF000, 0x5438), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fcmpd", 4, two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fcmpl", 4, two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fcmpl", 4, two(0xF000, 0x4038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fcmpp", 4, two(0xF000, 0x4C38), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fcmps", 4, two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fcmps", 4, two(0xF000, 0x4438), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fcmpw", 4, two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fcmpw", 4, two(0xF000, 0x5038), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fcmpx", 4, two(0xF000, 0x0038), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fcmpx", 4, two(0xF000, 0x4838), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-
-{"fcosb", 4, two(0xF000, 0x581D), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fcosd", 4, two(0xF000, 0x541D), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fcosl", 4, two(0xF000, 0x401D), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fcosp", 4, two(0xF000, 0x4C1D), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fcoss", 4, two(0xF000, 0x441D), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fcosw", 4, two(0xF000, 0x501D), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fcosx", 4, two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fcosx", 4, two(0xF000, 0x481D), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fcosx", 4, two(0xF000, 0x001D), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fcoshb", 4, two(0xF000, 0x5819), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fcoshd", 4, two(0xF000, 0x5419), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fcoshl", 4, two(0xF000, 0x4019), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fcoshp", 4, two(0xF000, 0x4C19), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fcoshs", 4, two(0xF000, 0x4419), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fcoshw", 4, two(0xF000, 0x5019), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fcoshx", 4, two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fcoshx", 4, two(0xF000, 0x4819), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fcoshx", 4, two(0xF000, 0x0019), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fdbeq", 4, two(0xF048, 0x0001), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbf", 4, two(0xF048, 0x0000), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbge", 4, two(0xF048, 0x0013), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbgl", 4, two(0xF048, 0x0016), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbgle", 4, two(0xF048, 0x0017), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbgt", 4, two(0xF048, 0x0012), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdble", 4, two(0xF048, 0x0015), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdblt", 4, two(0xF048, 0x0014), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbne", 4, two(0xF048, 0x000E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbnge", 4, two(0xF048, 0x001C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbngl", 4, two(0xF048, 0x0019), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbngle", 4, two(0xF048, 0x0018), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbngt", 4, two(0xF048, 0x001D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbnle", 4, two(0xF048, 0x001A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbnlt", 4, two(0xF048, 0x001B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdboge", 4, two(0xF048, 0x0003), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbogl", 4, two(0xF048, 0x0006), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbogt", 4, two(0xF048, 0x0002), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbole", 4, two(0xF048, 0x0005), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbolt", 4, two(0xF048, 0x0004), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbor", 4, two(0xF048, 0x0007), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbseq", 4, two(0xF048, 0x0011), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbsf", 4, two(0xF048, 0x0010), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbsne", 4, two(0xF048, 0x001E), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbst", 4, two(0xF048, 0x001F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbt", 4, two(0xF048, 0x000F), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbueq", 4, two(0xF048, 0x0009), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbuge", 4, two(0xF048, 0x000B), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbugt", 4, two(0xF048, 0x000A), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbule", 4, two(0xF048, 0x000D), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbult", 4, two(0xF048, 0x000C), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-{"fdbun", 4, two(0xF048, 0x0008), two(0xF1F8, 0xFFFF), "IiDsBw", mfloat },
-
-{"fdivb", 4, two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fdivb", 4, two(0xF000, 0x5820), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdivd", 4, two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fdivd", 4, two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fdivd", 4, two(0xF000, 0x5420), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fdivl", 4, two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fdivl", 4, two(0xF000, 0x4020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdivp", 4, two(0xF000, 0x4C20), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fdivs", 4, two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fdivs", 4, two(0xF000, 0x4420), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdivw", 4, two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fdivw", 4, two(0xF000, 0x5020), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdivx", 4, two(0xF000, 0x0020), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fdivx", 4, two(0xF000, 0x4820), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-
-{"fsdivb", 4, two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fsdivb", 4, two(0xF000, 0x5860), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsdivd", 4, two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fsdivd", 4, two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fsdivd", 4, two(0xF000, 0x5460), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fsdivl", 4, two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fsdivl", 4, two(0xF000, 0x4060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsdivp", 4, two(0xF000, 0x4C60), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fsdivs", 4, two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fsdivs", 4, two(0xF000, 0x4460), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsdivw", 4, two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fsdivw", 4, two(0xF000, 0x5060), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsdivx", 4, two(0xF000, 0x0060), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fsdivx", 4, two(0xF000, 0x4860), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-
-{"fddivb", 4, two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fddivb", 4, two(0xF000, 0x5864), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fddivd", 4, two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fddivd", 4, two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fddivd", 4, two(0xF000, 0x5464), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fddivl", 4, two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fddivl", 4, two(0xF000, 0x4064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fddivp", 4, two(0xF000, 0x4C64), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fddivs", 4, two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fddivs", 4, two(0xF000, 0x4464), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fddivw", 4, two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fddivw", 4, two(0xF000, 0x5064), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fddivx", 4, two(0xF000, 0x0064), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fddivx", 4, two(0xF000, 0x4864), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-
-{"fetoxb", 4, two(0xF000, 0x5810), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fetoxd", 4, two(0xF000, 0x5410), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fetoxl", 4, two(0xF000, 0x4010), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fetoxp", 4, two(0xF000, 0x4C10), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fetoxs", 4, two(0xF000, 0x4410), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fetoxw", 4, two(0xF000, 0x5010), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fetoxx", 4, two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fetoxx", 4, two(0xF000, 0x4810), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fetoxx", 4, two(0xF000, 0x0010), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fetoxm1b", 4, two(0xF000, 0x5808), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fetoxm1d", 4, two(0xF000, 0x5408), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fetoxm1l", 4, two(0xF000, 0x4008), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fetoxm1p", 4, two(0xF000, 0x4C08), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fetoxm1s", 4, two(0xF000, 0x4408), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fetoxm1w", 4, two(0xF000, 0x5008), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fetoxm1x", 4, two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fetoxm1x", 4, two(0xF000, 0x4808), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fetoxm1x", 4, two(0xF000, 0x0008), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fgetexpb", 4, two(0xF000, 0x581E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fgetexpd", 4, two(0xF000, 0x541E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fgetexpl", 4, two(0xF000, 0x401E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fgetexpp", 4, two(0xF000, 0x4C1E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fgetexps", 4, two(0xF000, 0x441E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fgetexpw", 4, two(0xF000, 0x501E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fgetexpx", 4, two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fgetexpx", 4, two(0xF000, 0x481E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fgetexpx", 4, two(0xF000, 0x001E), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fgetmanb", 4, two(0xF000, 0x581F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fgetmand", 4, two(0xF000, 0x541F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fgetmanl", 4, two(0xF000, 0x401F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fgetmanp", 4, two(0xF000, 0x4C1F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fgetmans", 4, two(0xF000, 0x441F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fgetmanw", 4, two(0xF000, 0x501F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fgetmanx", 4, two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fgetmanx", 4, two(0xF000, 0x481F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fgetmanx", 4, two(0xF000, 0x001F), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fintb", 4, two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fintb", 4, two(0xF000, 0x5801), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fintd", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fintd", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fintd", 4, two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fintd", 4, two(0xF000, 0x5401), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fintl", 4, two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fintl", 4, two(0xF000, 0x4001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fintp", 4, two(0xF000, 0x4C01), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fints", 4, two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fints", 4, two(0xF000, 0x4401), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fintw", 4, two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fintw", 4, two(0xF000, 0x5001), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fintx", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fintx", 4, two(0xF000, 0x4801), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fintx", 4, two(0xF000, 0x0001), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fintrzb", 4, two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fintrzb", 4, two(0xF000, 0x5803), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fintrzd", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fintrzd", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fintrzd", 4, two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fintrzd", 4, two(0xF000, 0x5403), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fintrzl", 4, two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fintrzl", 4, two(0xF000, 0x4003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fintrzp", 4, two(0xF000, 0x4C03), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fintrzs", 4, two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fintrzs", 4, two(0xF000, 0x4403), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fintrzw", 4, two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fintrzw", 4, two(0xF000, 0x5003), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fintrzx", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fintrzx", 4, two(0xF000, 0x4803), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fintrzx", 4, two(0xF000, 0x0003), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"flog10b", 4, two(0xF000, 0x5815), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"flog10d", 4, two(0xF000, 0x5415), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"flog10l", 4, two(0xF000, 0x4015), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"flog10p", 4, two(0xF000, 0x4C15), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"flog10s", 4, two(0xF000, 0x4415), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"flog10w", 4, two(0xF000, 0x5015), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"flog10x", 4, two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"flog10x", 4, two(0xF000, 0x4815), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"flog10x", 4, two(0xF000, 0x0015), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"flog2b", 4, two(0xF000, 0x5816), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"flog2d", 4, two(0xF000, 0x5416), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"flog2l", 4, two(0xF000, 0x4016), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"flog2p", 4, two(0xF000, 0x4C16), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"flog2s", 4, two(0xF000, 0x4416), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"flog2w", 4, two(0xF000, 0x5016), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"flog2x", 4, two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"flog2x", 4, two(0xF000, 0x4816), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"flog2x", 4, two(0xF000, 0x0016), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"flognb", 4, two(0xF000, 0x5814), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"flognd", 4, two(0xF000, 0x5414), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"flognl", 4, two(0xF000, 0x4014), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"flognp", 4, two(0xF000, 0x4C14), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"flogns", 4, two(0xF000, 0x4414), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"flognw", 4, two(0xF000, 0x5014), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"flognx", 4, two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"flognx", 4, two(0xF000, 0x4814), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"flognx", 4, two(0xF000, 0x0014), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"flognp1b", 4, two(0xF000, 0x5806), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"flognp1d", 4, two(0xF000, 0x5406), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"flognp1l", 4, two(0xF000, 0x4006), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"flognp1p", 4, two(0xF000, 0x4C06), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"flognp1s", 4, two(0xF000, 0x4406), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"flognp1w", 4, two(0xF000, 0x5006), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"flognp1x", 4, two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"flognp1x", 4, two(0xF000, 0x4806), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"flognp1x", 4, two(0xF000, 0x0006), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fmodb", 4, two(0xF000, 0x5821), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fmodd", 4, two(0xF000, 0x5421), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fmodl", 4, two(0xF000, 0x4021), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fmodp", 4, two(0xF000, 0x4C21), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fmods", 4, two(0xF000, 0x4421), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fmodw", 4, two(0xF000, 0x5021), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fmodx", 4, two(0xF000, 0x0021), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fmodx", 4, two(0xF000, 0x4821), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-
-{"fmoveb", 4, two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fmoveb", 4, two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat },
-{"fmoveb", 4, two(0xF000, 0x5800), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fmoveb", 4, two(0xF000, 0x7800), two(0xF1C0, 0xFC7F), "IiF7$b", mfloat },
-{"fmoved", 4, two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fmoved", 4, two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7~F", mfloat },
-{"fmoved", 4, two(0xF000, 0x0000), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fmoved", 4, two(0xF000, 0x5400), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fmoved", 4, two(0xF000, 0x7400), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat },
-{"fmovel", 4, two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fmovel", 4, two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7$l", mfloat },
-/* FIXME: the next two variants should not permit moving an address
- register to anything but the floating point instruction register. */
-{"fmovel", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat },
-{"fmovel", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ls8", mfloat },
-{"fmovel", 4, two(0xF000, 0x4000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fmovel", 4, two(0xF000, 0x6000), two(0xF1C0, 0xFC7F), "IiF7bs", cfloat },
- /* Move the FP control registers. */
-{"fmovel", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8ps", cfloat },
-{"fmovel", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Iibss8", cfloat },
-{"fmovep", 4, two(0xF000, 0x4C00), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fmovep", 4, two(0xF000, 0x6C00), two(0xF1C0, 0xFC00), "IiF7~pkC", mfloat },
-{"fmovep", 4, two(0xF000, 0x7C00), two(0xF1C0, 0xFC0F), "IiF7~pDk", mfloat },
-{"fmoves", 4, two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fmoves", 4, two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7$f", mfloat },
-{"fmoves", 4, two(0xF000, 0x4400), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fmoves", 4, two(0xF000, 0x6400), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fmovew", 4, two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fmovew", 4, two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7$w", mfloat },
-{"fmovew", 4, two(0xF000, 0x5000), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fmovew", 4, two(0xF000, 0x7000), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fmovex", 4, two(0xF000, 0x0000), two(0xF1FF, 0xE07F), "IiF8F7", mfloat },
-{"fmovex", 4, two(0xF000, 0x4800), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fmovex", 4, two(0xF000, 0x6800), two(0xF1C0, 0xFC7F), "IiF7~x", mfloat },
-
-{"fsmoveb", 4, two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fsmoveb", 4, two(0xF000, 0x5840), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsmoveb", 4, two(0xF000, 0x7840), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fsmoved", 4, two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fsmoved", 4, two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fsmoved", 4, two(0xF000, 0x5440), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fsmoved", 4, two(0xF000, 0x7440), two(0xF1C0, 0xFC7F), "IiF7ws", cfloat },
-{"fsmovel", 4, two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fsmovel", 4, two(0xF000, 0x4040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsmovel", 4, two(0xF000, 0x6040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fsmoves", 4, two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fsmoves", 4, two(0xF000, 0x4440), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsmoves", 4, two(0xF000, 0x6440), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fsmovew", 4, two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fsmovew", 4, two(0xF000, 0x5040), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsmovew", 4, two(0xF000, 0x7040), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fsmovex", 4, two(0xF000, 0x0040), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fsmovex", 4, two(0xF000, 0x4840), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-{"fsmovep", 4, two(0xF000, 0x4C40), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-
-{"fdmoveb", 4, two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fdmoveb", 4, two(0xF000, 0x5844), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdmoveb", 4, two(0xF000, 0x7844), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fdmoved", 4, two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fdmoved", 4, two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fdmoved", 4, two(0xF000, 0x5444), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fdmoved", 4, two(0xF000, 0x7444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fdmovel", 4, two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fdmovel", 4, two(0xF000, 0x4044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdmovel", 4, two(0xF000, 0x6044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fdmoves", 4, two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fdmoves", 4, two(0xF000, 0x4444), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdmoves", 4, two(0xF000, 0x6444), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fdmovew", 4, two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fdmovew", 4, two(0xF000, 0x5044), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdmovew", 4, two(0xF000, 0x7044), two(0xF1C0, 0xFC7F), "IiF7qs", cfloat },
-{"fdmovex", 4, two(0xF000, 0x0044), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fdmovex", 4, two(0xF000, 0x4844), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-{"fdmovep", 4, two(0xF000, 0x4C44), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-
-{"fmovecrx", 4, two(0xF000, 0x5C00), two(0xF1FF, 0xFC00), "Ii#CF7", mfloat },
-
-{"fmovemd", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizsl3", cfloat },
-{"fmovemd", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat },
-{"fmovemd", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat },
-{"fmovemd", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Iil3ys", cfloat },
-
-{"fmovemx", 4, two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat },
-{"fmovemx", 4, two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat },
-{"fmovemx", 4, two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat },
-{"fmovemx", 4, two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat },
-{"fmovemx", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat },
-{"fmovemx", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat },
-{"fmovemx", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat },
-{"fmovemx", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat },
-{"fmovemx", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat },
-{"fmovemx", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat },
-{"fmovemx", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat },
-{"fmovemx", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat },
-
-{"fmoveml", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat },
-{"fmoveml", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat },
-/* FIXME: In the next instruction, we should only permit %dn if the
- target is a single register. We should only permit %an if the
- target is a single %fpiar. */
-{"fmoveml", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*lL8", mfloat },
-
-{"fmovem", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "IizsL3", cfloat },
-{"fmovem", 4, two(0xF000, 0xD000), two(0xFFC0, 0xFF00), "Iizs#3", cfloat },
-{"fmovem", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "Ii#3ys", cfloat },
-{"fmovem", 4, two(0xF000, 0xF000), two(0xFFC0, 0xFF00), "IiL3ys", cfloat },
-
-{"fmovem", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "IdL3-s", mfloat },
-{"fmovem", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Idl3&s", mfloat },
-{"fmovem", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+sl3", mfloat },
-{"fmovem", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&sl3", mfloat },
-{"fmovem", 4, two(0xF020, 0xE000), two(0xF1F8, 0xFF00), "Id#3-s", mfloat },
-{"fmovem", 4, two(0xF020, 0xE800), two(0xF1F8, 0xFF8F), "IiDk-s", mfloat },
-{"fmovem", 4, two(0xF000, 0xF000), two(0xF1C0, 0xFF00), "Id#3&s", mfloat },
-{"fmovem", 4, two(0xF000, 0xF800), two(0xF1C0, 0xFF8F), "IiDk&s", mfloat },
-{"fmovem", 4, two(0xF018, 0xD000), two(0xF1F8, 0xFF00), "Id+s#3", mfloat },
-{"fmovem", 4, two(0xF018, 0xD800), two(0xF1F8, 0xFF8F), "Ii+sDk", mfloat },
-{"fmovem", 4, two(0xF000, 0xD000), two(0xF1C0, 0xFF00), "Id&s#3", mfloat },
-{"fmovem", 4, two(0xF000, 0xD800), two(0xF1C0, 0xFF8F), "Ii&sDk", mfloat },
-{"fmovem", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "Iis8%s", mfloat },
-{"fmovem", 4, two(0xF000, 0x8000), two(0xF1C0, 0xE3FF), "Ii*ss8", mfloat },
-{"fmovem", 4, two(0xF000, 0xA000), two(0xF1C0, 0xE3FF), "IiL8~s", mfloat },
-{"fmovem", 4, two(0xF000, 0x8000), two(0xF2C0, 0xE3FF), "Ii*sL8", mfloat },
-
-{"fmulb", 4, two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fmulb", 4, two(0xF000, 0x5823), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fmuld", 4, two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fmuld", 4, two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fmuld", 4, two(0xF000, 0x5423), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fmull", 4, two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fmull", 4, two(0xF000, 0x4023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fmulp", 4, two(0xF000, 0x4C23), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fmuls", 4, two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fmuls", 4, two(0xF000, 0x4423), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fmulw", 4, two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fmulw", 4, two(0xF000, 0x5023), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fmulx", 4, two(0xF000, 0x0023), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fmulx", 4, two(0xF000, 0x4823), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-
-{"fsmulb", 4, two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fsmulb", 4, two(0xF000, 0x5863), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsmuld", 4, two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fsmuld", 4, two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fsmuld", 4, two(0xF000, 0x5463), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fsmull", 4, two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fsmull", 4, two(0xF000, 0x4063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsmulp", 4, two(0xF000, 0x4C63), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fsmuls", 4, two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fsmuls", 4, two(0xF000, 0x4463), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsmulw", 4, two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fsmulw", 4, two(0xF000, 0x5063), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsmulx", 4, two(0xF000, 0x0063), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fsmulx", 4, two(0xF000, 0x4863), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-
-{"fdmulb", 4, two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fdmulb", 4, two(0xF000, 0x5867), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdmuld", 4, two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fdmuld", 4, two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fdmuld", 4, two(0xF000, 0x5467), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fdmull", 4, two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fdmull", 4, two(0xF000, 0x4067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdmulp", 4, two(0xF000, 0x4C67), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fdmuls", 4, two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fdmuls", 4, two(0xF000, 0x4467), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdmulw", 4, two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fdmulw", 4, two(0xF000, 0x5067), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdmulx", 4, two(0xF000, 0x0067), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fdmulx", 4, two(0xF000, 0x4867), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-
-{"fnegb", 4, two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fnegb", 4, two(0xF000, 0x581A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fnegd", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fnegd", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fnegd", 4, two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fnegd", 4, two(0xF000, 0x541A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fnegl", 4, two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fnegl", 4, two(0xF000, 0x401A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fnegp", 4, two(0xF000, 0x4C1A), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fnegs", 4, two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fnegs", 4, two(0xF000, 0x441A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fnegw", 4, two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fnegw", 4, two(0xF000, 0x501A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fnegx", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fnegx", 4, two(0xF000, 0x481A), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fnegx", 4, two(0xF000, 0x001A), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fsnegb", 4, two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fsnegb", 4, two(0xF000, 0x585A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsnegd", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fsnegd", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fsnegd", 4, two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fsnegd", 4, two(0xF000, 0x545A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fsnegl", 4, two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fsnegl", 4, two(0xF000, 0x405A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsnegp", 4, two(0xF000, 0x4C5A), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fsnegs", 4, two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fsnegs", 4, two(0xF000, 0x445A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsnegw", 4, two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fsnegw", 4, two(0xF000, 0x505A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsnegx", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fsnegx", 4, two(0xF000, 0x485A), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-{"fsnegx", 4, two(0xF000, 0x005A), two(0xF1C0, 0xE07F), "IiFt", m68040up },
-
-{"fdnegb", 4, two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fdnegb", 4, two(0xF000, 0x585E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdnegd", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fdnegd", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fdnegd", 4, two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fdnegd", 4, two(0xF000, 0x545E), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fdnegl", 4, two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fdnegl", 4, two(0xF000, 0x405E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdnegp", 4, two(0xF000, 0x4C5E), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fdnegs", 4, two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fdnegs", 4, two(0xF000, 0x445E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdnegw", 4, two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fdnegw", 4, two(0xF000, 0x505E), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdnegx", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fdnegx", 4, two(0xF000, 0x485E), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-{"fdnegx", 4, two(0xF000, 0x005E), two(0xF1C0, 0xE07F), "IiFt", m68040up },
-
-{"fnop", 4, two(0xF280, 0x0000), two(0xFFFF, 0xFFFF), "Ii", mfloat | cfloat },
-
-{"fremb", 4, two(0xF000, 0x5825), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fremd", 4, two(0xF000, 0x5425), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"freml", 4, two(0xF000, 0x4025), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fremp", 4, two(0xF000, 0x4C25), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"frems", 4, two(0xF000, 0x4425), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fremw", 4, two(0xF000, 0x5025), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fremx", 4, two(0xF000, 0x0025), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fremx", 4, two(0xF000, 0x4825), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-
-{"frestore", 2, one(0xF140), one(0xF1C0), "Id<s", mfloat },
-{"frestore", 2, one(0xF140), one(0xF1C0), "Idys", cfloat },
-
-{"fsave", 2, one(0xF100), one(0xF1C0), "Id>s", mfloat },
-{"fsave", 2, one(0xF100), one(0xF1C0), "Idzs", cfloat },
-
-{"fscaleb", 4, two(0xF000, 0x5826), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fscaled", 4, two(0xF000, 0x5426), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fscalel", 4, two(0xF000, 0x4026), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fscalep", 4, two(0xF000, 0x4C26), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fscales", 4, two(0xF000, 0x4426), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fscalew", 4, two(0xF000, 0x5026), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fscalex", 4, two(0xF000, 0x0026), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fscalex", 4, two(0xF000, 0x4826), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-
-/* $ is necessary to prevent the assembler from using PC-relative.
- If @ were used, "label: fseq label" could produce "ftrapeq", 2,
- because "label" became "pc@label". */
-{"fseq", 4, two(0xF040, 0x0001), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsf", 4, two(0xF040, 0x0000), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsge", 4, two(0xF040, 0x0013), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsgl", 4, two(0xF040, 0x0016), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsgle", 4, two(0xF040, 0x0017), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsgt", 4, two(0xF040, 0x0012), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsle", 4, two(0xF040, 0x0015), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fslt", 4, two(0xF040, 0x0014), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsne", 4, two(0xF040, 0x000E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsnge", 4, two(0xF040, 0x001C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsngl", 4, two(0xF040, 0x0019), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsngle", 4, two(0xF040, 0x0018), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsngt", 4, two(0xF040, 0x001D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsnle", 4, two(0xF040, 0x001A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsnlt", 4, two(0xF040, 0x001B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsoge", 4, two(0xF040, 0x0003), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsogl", 4, two(0xF040, 0x0006), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsogt", 4, two(0xF040, 0x0002), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsole", 4, two(0xF040, 0x0005), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsolt", 4, two(0xF040, 0x0004), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsor", 4, two(0xF040, 0x0007), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsseq", 4, two(0xF040, 0x0011), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fssf", 4, two(0xF040, 0x0010), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fssne", 4, two(0xF040, 0x001E), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsst", 4, two(0xF040, 0x001F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fst", 4, two(0xF040, 0x000F), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsueq", 4, two(0xF040, 0x0009), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsuge", 4, two(0xF040, 0x000B), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsugt", 4, two(0xF040, 0x000A), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsule", 4, two(0xF040, 0x000D), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsult", 4, two(0xF040, 0x000C), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-{"fsun", 4, two(0xF040, 0x0008), two(0xF1C0, 0xFFFF), "Ii$s", mfloat },
-
-{"fsgldivb", 4, two(0xF000, 0x5824), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fsgldivd", 4, two(0xF000, 0x5424), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fsgldivl", 4, two(0xF000, 0x4024), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fsgldivp", 4, two(0xF000, 0x4C24), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fsgldivs", 4, two(0xF000, 0x4424), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fsgldivw", 4, two(0xF000, 0x5024), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fsgldivx", 4, two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fsgldivx", 4, two(0xF000, 0x4824), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fsgldivx", 4, two(0xF000, 0x0024), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fsglmulb", 4, two(0xF000, 0x5827), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fsglmuld", 4, two(0xF000, 0x5427), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fsglmull", 4, two(0xF000, 0x4027), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fsglmulp", 4, two(0xF000, 0x4C27), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fsglmuls", 4, two(0xF000, 0x4427), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fsglmulw", 4, two(0xF000, 0x5027), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fsglmulx", 4, two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fsglmulx", 4, two(0xF000, 0x4827), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fsglmulx", 4, two(0xF000, 0x0027), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fsinb", 4, two(0xF000, 0x580E), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fsind", 4, two(0xF000, 0x540E), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fsinl", 4, two(0xF000, 0x400E), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fsinp", 4, two(0xF000, 0x4C0E), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fsins", 4, two(0xF000, 0x440E), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fsinw", 4, two(0xF000, 0x500E), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fsinx", 4, two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fsinx", 4, two(0xF000, 0x480E), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fsinx", 4, two(0xF000, 0x000E), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fsincosb", 4, two(0xF000, 0x5830), two(0xF1C0, 0xFC78), "Ii;bF3F7", mfloat },
-{"fsincosd", 4, two(0xF000, 0x5430), two(0xF1C0, 0xFC78), "Ii;FF3F7", mfloat },
-{"fsincosl", 4, two(0xF000, 0x4030), two(0xF1C0, 0xFC78), "Ii;lF3F7", mfloat },
-{"fsincosp", 4, two(0xF000, 0x4C30), two(0xF1C0, 0xFC78), "Ii;pF3F7", mfloat },
-{"fsincoss", 4, two(0xF000, 0x4430), two(0xF1C0, 0xFC78), "Ii;fF3F7", mfloat },
-{"fsincosw", 4, two(0xF000, 0x5030), two(0xF1C0, 0xFC78), "Ii;wF3F7", mfloat },
-{"fsincosx", 4, two(0xF000, 0x0030), two(0xF1C0, 0xE078), "IiF8F3F7", mfloat },
-{"fsincosx", 4, two(0xF000, 0x4830), two(0xF1C0, 0xFC78), "Ii;xF3F7", mfloat },
-
-{"fsinhb", 4, two(0xF000, 0x5802), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fsinhd", 4, two(0xF000, 0x5402), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fsinhl", 4, two(0xF000, 0x4002), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fsinhp", 4, two(0xF000, 0x4C02), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fsinhs", 4, two(0xF000, 0x4402), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fsinhw", 4, two(0xF000, 0x5002), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fsinhx", 4, two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fsinhx", 4, two(0xF000, 0x4802), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fsinhx", 4, two(0xF000, 0x0002), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fsqrtb", 4, two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fsqrtb", 4, two(0xF000, 0x5804), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsqrtd", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fsqrtd", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fsqrtd", 4, two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fsqrtd", 4, two(0xF000, 0x5404), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fsqrtl", 4, two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fsqrtl", 4, two(0xF000, 0x4004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsqrtp", 4, two(0xF000, 0x4C04), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fsqrts", 4, two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fsqrts", 4, two(0xF000, 0x4404), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsqrtw", 4, two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fsqrtw", 4, two(0xF000, 0x5004), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsqrtx", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fsqrtx", 4, two(0xF000, 0x4804), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fsqrtx", 4, two(0xF000, 0x0004), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fssqrtb", 4, two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fssqrtb", 4, two(0xF000, 0x5841), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fssqrtd", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fssqrtd", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fssqrtd", 4, two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fssqrtd", 4, two(0xF000, 0x5441), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fssqrtl", 4, two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fssqrtl", 4, two(0xF000, 0x4041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fssqrtp", 4, two(0xF000, 0x4C41), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fssqrts", 4, two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fssqrts", 4, two(0xF000, 0x4441), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fssqrtw", 4, two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fssqrtw", 4, two(0xF000, 0x5041), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fssqrtx", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fssqrtx", 4, two(0xF000, 0x4841), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-{"fssqrtx", 4, two(0xF000, 0x0041), two(0xF1C0, 0xE07F), "IiFt", m68040up },
-
-{"fdsqrtb", 4, two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fdsqrtb", 4, two(0xF000, 0x5845), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdsqrtd", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fdsqrtd", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt", cfloat },
-{"fdsqrtd", 4, two(0xF000, 0x5445), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fdsqrtl", 4, two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fdsqrtl", 4, two(0xF000, 0x4045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdsqrtp", 4, two(0xF000, 0x4C45), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fdsqrts", 4, two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fdsqrts", 4, two(0xF000, 0x4445), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdsqrtw", 4, two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fdsqrtw", 4, two(0xF000, 0x5045), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdsqrtx", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fdsqrtx", 4, two(0xF000, 0x4845), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-{"fdsqrtx", 4, two(0xF000, 0x0045), two(0xF1C0, 0xE07F), "IiFt", m68040up },
-
-{"fsubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"fsubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsubd", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fsubd", 4, two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"fsubd", 4, two(0xF000, 0x5428), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fsubl", 4, two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"fsubl", 4, two(0xF000, 0x4028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsubp", 4, two(0xF000, 0x4C28), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"fsubs", 4, two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"fsubs", 4, two(0xF000, 0x4428), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsubw", 4, two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"fsubw", 4, two(0xF000, 0x5028), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fsubx", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"fsubx", 4, two(0xF000, 0x4828), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"fsubx", 4, two(0xF000, 0x0028), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"fssubb", 4, two(0xF000, 0x5828), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fssubb", 4, two(0xF000, 0x5868), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fssubd", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fssubd", 4, two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fssubd", 4, two(0xF000, 0x5468), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fssubl", 4, two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fssubl", 4, two(0xF000, 0x4068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fssubp", 4, two(0xF000, 0x4C68), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fssubs", 4, two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fssubs", 4, two(0xF000, 0x4468), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fssubw", 4, two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fssubw", 4, two(0xF000, 0x5068), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fssubx", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fssubx", 4, two(0xF000, 0x4868), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-{"fssubx", 4, two(0xF000, 0x0068), two(0xF1C0, 0xE07F), "IiFt", m68040up },
-
-{"fdsubb", 4, two(0xF000, 0x586A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdsubb", 4, two(0xF000, 0x586c), two(0xF1C0, 0xFC7F), "Ii;bF7", m68040up },
-{"fdsubd", 4, two(0xF000, 0x006A), two(0xF1C0, 0xE07F), "IiF8F7", cfloat },
-{"fdsubd", 4, two(0xF000, 0x546A), two(0xF1C0, 0xFC7F), "IiwsF7", cfloat },
-{"fdsubd", 4, two(0xF000, 0x546c), two(0xF1C0, 0xFC7F), "Ii;FF7", m68040up },
-{"fdsubl", 4, two(0xF000, 0x406A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdsubl", 4, two(0xF000, 0x406c), two(0xF1C0, 0xFC7F), "Ii;lF7", m68040up },
-{"fdsubp", 4, two(0xF000, 0x4C6c), two(0xF1C0, 0xFC7F), "Ii;pF7", m68040up },
-{"fdsubs", 4, two(0xF000, 0x446A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdsubs", 4, two(0xF000, 0x446c), two(0xF1C0, 0xFC7F), "Ii;fF7", m68040up },
-{"fdsubw", 4, two(0xF000, 0x506A), two(0xF1C0, 0xFC7F), "IibsF7", cfloat },
-{"fdsubw", 4, two(0xF000, 0x506c), two(0xF1C0, 0xFC7F), "Ii;wF7", m68040up },
-{"fdsubx", 4, two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiF8F7", m68040up },
-{"fdsubx", 4, two(0xF000, 0x486c), two(0xF1C0, 0xFC7F), "Ii;xF7", m68040up },
-{"fdsubx", 4, two(0xF000, 0x006c), two(0xF1C0, 0xE07F), "IiFt", m68040up },
-
-{"ftanb", 4, two(0xF000, 0x580F), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"ftand", 4, two(0xF000, 0x540F), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"ftanl", 4, two(0xF000, 0x400F), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"ftanp", 4, two(0xF000, 0x4C0F), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"ftans", 4, two(0xF000, 0x440F), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"ftanw", 4, two(0xF000, 0x500F), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"ftanx", 4, two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"ftanx", 4, two(0xF000, 0x480F), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"ftanx", 4, two(0xF000, 0x000F), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"ftanhb", 4, two(0xF000, 0x5809), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"ftanhd", 4, two(0xF000, 0x5409), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"ftanhl", 4, two(0xF000, 0x4009), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"ftanhp", 4, two(0xF000, 0x4C09), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"ftanhs", 4, two(0xF000, 0x4409), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"ftanhw", 4, two(0xF000, 0x5009), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"ftanhx", 4, two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"ftanhx", 4, two(0xF000, 0x4809), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"ftanhx", 4, two(0xF000, 0x0009), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"ftentoxb", 4, two(0xF000, 0x5812), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"ftentoxd", 4, two(0xF000, 0x5412), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"ftentoxl", 4, two(0xF000, 0x4012), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"ftentoxp", 4, two(0xF000, 0x4C12), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"ftentoxs", 4, two(0xF000, 0x4412), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"ftentoxw", 4, two(0xF000, 0x5012), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"ftentoxx", 4, two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"ftentoxx", 4, two(0xF000, 0x4812), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"ftentoxx", 4, two(0xF000, 0x0012), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"ftrapeq", 4, two(0xF07C, 0x0001), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapf", 4, two(0xF07C, 0x0000), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapge", 4, two(0xF07C, 0x0013), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapgl", 4, two(0xF07C, 0x0016), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapgle", 4, two(0xF07C, 0x0017), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapgt", 4, two(0xF07C, 0x0012), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftraple", 4, two(0xF07C, 0x0015), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftraplt", 4, two(0xF07C, 0x0014), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapne", 4, two(0xF07C, 0x000E), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapnge", 4, two(0xF07C, 0x001C), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapngl", 4, two(0xF07C, 0x0019), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapngle", 4,two(0xF07C, 0x0018), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapngt", 4, two(0xF07C, 0x001D), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapnle", 4, two(0xF07C, 0x001A), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapnlt", 4, two(0xF07C, 0x001B), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapoge", 4, two(0xF07C, 0x0003), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapogl", 4, two(0xF07C, 0x0006), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapogt", 4, two(0xF07C, 0x0002), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapole", 4, two(0xF07C, 0x0005), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapolt", 4, two(0xF07C, 0x0004), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapor", 4, two(0xF07C, 0x0007), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapseq", 4, two(0xF07C, 0x0011), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapsf", 4, two(0xF07C, 0x0010), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapsne", 4, two(0xF07C, 0x001E), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapst", 4, two(0xF07C, 0x001F), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapt", 4, two(0xF07C, 0x000F), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapueq", 4, two(0xF07C, 0x0009), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapuge", 4, two(0xF07C, 0x000B), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapugt", 4, two(0xF07C, 0x000A), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapule", 4, two(0xF07C, 0x000D), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapult", 4, two(0xF07C, 0x000C), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-{"ftrapun", 4, two(0xF07C, 0x0008), two(0xF1FF, 0xFFFF), "Ii", mfloat },
-
-{"ftrapeqw", 4, two(0xF07A, 0x0001), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapfw", 4, two(0xF07A, 0x0000), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapgew", 4, two(0xF07A, 0x0013), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapglw", 4, two(0xF07A, 0x0016), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapglew", 4,two(0xF07A, 0x0017), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapgtw", 4, two(0xF07A, 0x0012), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftraplew", 4, two(0xF07A, 0x0015), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapltw", 4, two(0xF07A, 0x0014), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapnew", 4, two(0xF07A, 0x000E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapngew", 4,two(0xF07A, 0x001C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapnglw", 4,two(0xF07A, 0x0019), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapnglew", 4,two(0xF07A, 0x0018), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapngtw", 4,two(0xF07A, 0x001D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapnlew", 4,two(0xF07A, 0x001A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapnltw", 4,two(0xF07A, 0x001B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapogew", 4,two(0xF07A, 0x0003), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapoglw", 4,two(0xF07A, 0x0006), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapogtw", 4,two(0xF07A, 0x0002), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapolew", 4,two(0xF07A, 0x0005), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapoltw", 4,two(0xF07A, 0x0004), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftraporw", 4, two(0xF07A, 0x0007), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapseqw", 4,two(0xF07A, 0x0011), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapsfw", 4, two(0xF07A, 0x0010), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapsnew", 4,two(0xF07A, 0x001E), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapstw", 4, two(0xF07A, 0x001F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftraptw", 4, two(0xF07A, 0x000F), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapueqw", 4,two(0xF07A, 0x0009), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapugew", 4,two(0xF07A, 0x000B), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapugtw", 4,two(0xF07A, 0x000A), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapulew", 4,two(0xF07A, 0x000D), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapultw", 4,two(0xF07A, 0x000C), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-{"ftrapunw", 4, two(0xF07A, 0x0008), two(0xF1FF, 0xFFFF), "Ii^w", mfloat },
-
-{"ftrapeql", 4, two(0xF07B, 0x0001), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapfl", 4, two(0xF07B, 0x0000), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapgel", 4, two(0xF07B, 0x0013), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapgll", 4, two(0xF07B, 0x0016), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapglel", 4,two(0xF07B, 0x0017), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapgtl", 4, two(0xF07B, 0x0012), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftraplel", 4, two(0xF07B, 0x0015), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapltl", 4, two(0xF07B, 0x0014), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapnel", 4, two(0xF07B, 0x000E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapngel", 4,two(0xF07B, 0x001C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapngll", 4,two(0xF07B, 0x0019), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapnglel", 4,two(0xF07B, 0x0018), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapngtl", 4,two(0xF07B, 0x001D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapnlel", 4,two(0xF07B, 0x001A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapnltl", 4,two(0xF07B, 0x001B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapogel", 4,two(0xF07B, 0x0003), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapogll", 4,two(0xF07B, 0x0006), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapogtl", 4,two(0xF07B, 0x0002), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapolel", 4,two(0xF07B, 0x0005), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapoltl", 4,two(0xF07B, 0x0004), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftraporl", 4, two(0xF07B, 0x0007), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapseql", 4,two(0xF07B, 0x0011), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapsfl", 4, two(0xF07B, 0x0010), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapsnel", 4,two(0xF07B, 0x001E), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapstl", 4, two(0xF07B, 0x001F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftraptl", 4, two(0xF07B, 0x000F), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapueql", 4,two(0xF07B, 0x0009), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapugel", 4,two(0xF07B, 0x000B), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapugtl", 4,two(0xF07B, 0x000A), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapulel", 4,two(0xF07B, 0x000D), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapultl", 4,two(0xF07B, 0x000C), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-{"ftrapunl", 4, two(0xF07B, 0x0008), two(0xF1FF, 0xFFFF), "Ii^l", mfloat },
-
-{"ftstb", 4, two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Ii;b", mfloat },
-{"ftstb", 4, two(0xF000, 0x583A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
-{"ftstd", 4, two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", cfloat },
-{"ftstd", 4, two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Ii;F", mfloat },
-{"ftstd", 4, two(0xF000, 0x543A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
-{"ftstl", 4, two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Ii;l", mfloat },
-{"ftstl", 4, two(0xF000, 0x403A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
-{"ftstp", 4, two(0xF000, 0x4C3A), two(0xF1C0, 0xFC7F), "Ii;p", mfloat },
-{"ftsts", 4, two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Ii;f", mfloat },
-{"ftsts", 4, two(0xF000, 0x443A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
-{"ftstw", 4, two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Ii;w", mfloat },
-{"ftstw", 4, two(0xF000, 0x503A), two(0xF1C0, 0xFC7F), "Iibs", cfloat },
-{"ftstx", 4, two(0xF000, 0x003A), two(0xF1C0, 0xE07F), "IiF8", mfloat },
-{"ftstx", 4, two(0xF000, 0x483A), two(0xF1C0, 0xFC7F), "Ii;x", mfloat },
-
-{"ftwotoxb", 4, two(0xF000, 0x5811), two(0xF1C0, 0xFC7F), "Ii;bF7", mfloat },
-{"ftwotoxd", 4, two(0xF000, 0x5411), two(0xF1C0, 0xFC7F), "Ii;FF7", mfloat },
-{"ftwotoxl", 4, two(0xF000, 0x4011), two(0xF1C0, 0xFC7F), "Ii;lF7", mfloat },
-{"ftwotoxp", 4, two(0xF000, 0x4C11), two(0xF1C0, 0xFC7F), "Ii;pF7", mfloat },
-{"ftwotoxs", 4, two(0xF000, 0x4411), two(0xF1C0, 0xFC7F), "Ii;fF7", mfloat },
-{"ftwotoxw", 4, two(0xF000, 0x5011), two(0xF1C0, 0xFC7F), "Ii;wF7", mfloat },
-{"ftwotoxx", 4, two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiF8F7", mfloat },
-{"ftwotoxx", 4, two(0xF000, 0x4811), two(0xF1C0, 0xFC7F), "Ii;xF7", mfloat },
-{"ftwotoxx", 4, two(0xF000, 0x0011), two(0xF1C0, 0xE07F), "IiFt", mfloat },
-
-{"halt", 2, one(0045310), one(0177777), "", m68060 | mcfisa_a },
-
-{"illegal", 2, one(0045374), one(0177777), "", m68000up | mcfisa_a },
-{"intouch", 2, one(0xf428), one(0xfff8), "As", mcfisa_b },
-
-{"jmp", 2, one(0047300), one(0177700), "!s", m68000up | mcfisa_a },
-
-{"jra", 2, one(0060000), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jra", 2, one(0047300), one(0177700), "!s", m68000up | mcfisa_a },
-
-{"jsr", 2, one(0047200), one(0177700), "!s", m68000up | mcfisa_a },
-
-{"jbsr", 2, one(0060400), one(0177400), "Bg", m68000up | mcfisa_a },
-{"jbsr", 2, one(0047200), one(0177700), "!s", m68000up | mcfisa_a },
-
-{"lea", 2, one(0040700), one(0170700), "!sAd", m68000up | mcfisa_a },
-
-{"lpstop", 6, two(0174000,0000700),two(0177777,0177777),"#w", cpu32|m68060 },
-
-{"linkw", 4, one(0047120), one(0177770), "As#w", m68000up | mcfisa_a },
-{"linkl", 6, one(0044010), one(0177770), "As#l", m68020up | cpu32 },
-{"link", 4, one(0047120), one(0177770), "As#W", m68000up | mcfisa_a },
-{"link", 6, one(0044010), one(0177770), "As#l", m68020up | cpu32 },
-
-{"lslb", 2, one(0160410), one(0170770), "QdDs", m68000up },
-{"lslb", 2, one(0160450), one(0170770), "DdDs", m68000up },
-{"lslw", 2, one(0160510), one(0170770), "QdDs", m68000up },
-{"lslw", 2, one(0160550), one(0170770), "DdDs", m68000up },
-{"lslw", 2, one(0161700), one(0177700), "~s", m68000up },
-{"lsll", 2, one(0160610), one(0170770), "QdDs", m68000up | mcfisa_a },
-{"lsll", 2, one(0160650), one(0170770), "DdDs", m68000up | mcfisa_a },
-
-{"lsrb", 2, one(0160010), one(0170770), "QdDs", m68000up },
-{"lsrb", 2, one(0160050), one(0170770), "DdDs", m68000up },
-{"lsrw", 2, one(0160110), one(0170770), "QdDs", m68000up },
-{"lsrw", 2, one(0160150), one(0170770), "DdDs", m68000up },
-{"lsrw", 2, one(0161300), one(0177700), "~s", m68000up },
-{"lsrl", 2, one(0160210), one(0170770), "QdDs", m68000up | mcfisa_a },
-{"lsrl", 2, one(0160250), one(0170770), "DdDs", m68000up | mcfisa_a },
-
-{"macw", 4, two(0xa080, 0x0000), two(0xf180, 0x0910), "uNuoiI4/Rn", mcfmac },
-{"macw", 4, two(0xa080, 0x0200), two(0xf180, 0x0910), "uNuoMh4/Rn", mcfmac },
-{"macw", 4, two(0xa080, 0x0000), two(0xf180, 0x0f10), "uNuo4/Rn", mcfmac },
-{"macw", 4, two(0xa000, 0x0000), two(0xf1b0, 0x0900), "uMumiI", mcfmac },
-{"macw", 4, two(0xa000, 0x0200), two(0xf1b0, 0x0900), "uMumMh", mcfmac },
-{"macw", 4, two(0xa000, 0x0000), two(0xf1b0, 0x0f00), "uMum", mcfmac },
-
-{"macw", 4, two(0xa000, 0x0000), two(0xf100, 0x0900), "uNuoiI4/RneG", mcfemac },/* Ry,Rx,SF,<ea>,accX. */
-{"macw", 4, two(0xa000, 0x0200), two(0xf100, 0x0900), "uNuoMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,<ea>,accX. */
-{"macw", 4, two(0xa000, 0x0000), two(0xf100, 0x0f00), "uNuo4/RneG", mcfemac },/* Ry,Rx,<ea>,accX. */
-{"macw", 4, two(0xa000, 0x0000), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX. */
-{"macw", 4, two(0xa000, 0x0200), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX. */
-{"macw", 4, two(0xa000, 0x0000), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX. */
-
-{"macl", 4, two(0xa080, 0x0800), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac },
-{"macl", 4, two(0xa080, 0x0a00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac },
-{"macl", 4, two(0xa080, 0x0800), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac },
-{"macl", 4, two(0xa000, 0x0800), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac },
-{"macl", 4, two(0xa000, 0x0a00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac },
-{"macl", 4, two(0xa000, 0x0800), two(0xf1b0, 0x0800), "RMRm", mcfmac },
-
-{"macl", 4, two(0xa000, 0x0800), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac },
-{"macl", 4, two(0xa000, 0x0a00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac },
-{"macl", 4, two(0xa000, 0x0800), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac },
-{"macl", 4, two(0xa000, 0x0800), two(0xf130, 0x0900), "RMRmiIeH", mcfemac },
-{"macl", 4, two(0xa000, 0x0a00), two(0xf130, 0x0900), "RMRmMheH", mcfemac },
-{"macl", 4, two(0xa000, 0x0800), two(0xf130, 0x0f00), "RMRmeH", mcfemac },
-
-/* NOTE: The mcf5200 family programmer's reference manual does not
- indicate the byte form of the movea instruction is invalid (as it
- is on 68000 family cpus). However, experiments on the 5202 yeild
- unexpected results. The value is copied, but it is not sign extended
- (as is done with movea.w) and the top three bytes in the address
- register are not disturbed. I don't know if this is the intended
- behavior --- it could be a hole in instruction decoding (Motorola
- decided not to trap all invalid instructions for performance reasons)
- --- but I suspect that it is not.
-
- I reported this to Motorola ISD Technical Communications Support,
- which replied that other coldfire assemblers reject movea.b. For
- this reason I've decided to not allow moveab.
-
- jtc@cygnus.com - 97/01/24. */
-
-{"moveal", 2, one(0020100), one(0170700), "*lAd", m68000up | mcfisa_a },
-{"moveaw", 2, one(0030100), one(0170700), "*wAd", m68000up | mcfisa_a },
-
-{"movclrl", 2, one(0xA1C0), one(0xf9f0), "eFRs", mcfemac },
-
-{"movec", 4, one(0047173), one(0177777), "R1Jj", m68010up | mcfisa_a },
-{"movec", 4, one(0047173), one(0177777), "R1#j", m68010up | mcfisa_a },
-{"movec", 4, one(0047172), one(0177777), "JjR1", m68010up },
-{"movec", 4, one(0047172), one(0177777), "#jR1", m68010up },
-
-{"movemw", 4, one(0044200), one(0177700), "Lw&s", m68000up },
-{"movemw", 4, one(0044240), one(0177770), "lw-s", m68000up },
-{"movemw", 4, one(0044200), one(0177700), "#w>s", m68000up },
-{"movemw", 4, one(0046200), one(0177700), "<sLw", m68000up },
-{"movemw", 4, one(0046200), one(0177700), "<s#w", m68000up },
-{"moveml", 4, one(0044300), one(0177700), "Lw&s", m68000up },
-{"moveml", 4, one(0044340), one(0177770), "lw-s", m68000up },
-{"moveml", 4, one(0044300), one(0177700), "#w>s", m68000up },
-{"moveml", 4, one(0046300), one(0177700), "<sLw", m68000up },
-{"moveml", 4, one(0046300), one(0177700), "<s#w", m68000up },
-/* FIXME: need specifier for mode 2 and 5 to simplify below insn patterns. */
-{"moveml", 4, one(0044320), one(0177770), "Lwas", mcfisa_a },
-{"moveml", 4, one(0044320), one(0177770), "#was", mcfisa_a },
-{"moveml", 4, one(0044350), one(0177770), "Lwds", mcfisa_a },
-{"moveml", 4, one(0044350), one(0177770), "#wds", mcfisa_a },
-{"moveml", 4, one(0046320), one(0177770), "asLw", mcfisa_a },
-{"moveml", 4, one(0046320), one(0177770), "as#w", mcfisa_a },
-{"moveml", 4, one(0046350), one(0177770), "dsLw", mcfisa_a },
-{"moveml", 4, one(0046350), one(0177770), "ds#w", mcfisa_a },
-
-{"movepw", 2, one(0000410), one(0170770), "dsDd", m68000up },
-{"movepw", 2, one(0000610), one(0170770), "Ddds", m68000up },
-{"movepl", 2, one(0000510), one(0170770), "dsDd", m68000up },
-{"movepl", 2, one(0000710), one(0170770), "Ddds", m68000up },
-
-{"moveq", 2, one(0070000), one(0170400), "MsDd", m68000up | mcfisa_a },
-{"moveq", 2, one(0070000), one(0170400), "#BDd", m68000up | mcfisa_a },
-
-/* The move opcode can generate the movea and moveq instructions. */
-{"moveb", 2, one(0010000), one(0170000), ";b$d", m68000up },
-{"moveb", 2, one(0010000), one(0170070), "Ds$d", mcfisa_a },
-{"moveb", 2, one(0010020), one(0170070), "as$d", mcfisa_a },
-{"moveb", 2, one(0010030), one(0170070), "+s$d", mcfisa_a },
-{"moveb", 2, one(0010040), one(0170070), "-s$d", mcfisa_a },
-{"moveb", 2, one(0010000), one(0170000), "nsqd", mcfisa_a },
-{"moveb", 2, one(0010000), one(0170700), "obDd", mcfisa_a },
-{"moveb", 2, one(0010200), one(0170700), "obad", mcfisa_a },
-{"moveb", 2, one(0010300), one(0170700), "ob+d", mcfisa_a },
-{"moveb", 2, one(0010400), one(0170700), "ob-d", mcfisa_a },
-{"moveb", 2, one(0010000), one(0170000), "obnd", mcfisa_b },
-
-{"movew", 2, one(0030000), one(0170000), "*w%d", m68000up },
-{"movew", 2, one(0030000), one(0170000), "ms%d", mcfisa_a },
-{"movew", 2, one(0030000), one(0170000), "nspd", mcfisa_a },
-{"movew", 2, one(0030000), one(0170000), "owmd", mcfisa_a },
-{"movew", 2, one(0030000), one(0170000), "ownd", mcfisa_b },
-{"movew", 2, one(0040300), one(0177700), "Ss$s", m68000up },
-{"movew", 2, one(0040300), one(0177770), "SsDs", mcfisa_a },
-{"movew", 2, one(0041300), one(0177700), "Cs$s", m68010up },
-{"movew", 2, one(0041300), one(0177770), "CsDs", mcfisa_a },
-{"movew", 2, one(0042300), one(0177700), ";wCd", m68000up },
-{"movew", 2, one(0042300), one(0177700), "DsCd", mcfisa_a },
-{"movew", 4, one(0042374), one(0177777), "#wCd", mcfisa_a },
-{"movew", 2, one(0043300), one(0177700), ";wSd", m68000up },
-{"movew", 2, one(0043300), one(0177700), "DsSd", mcfisa_a },
-{"movew", 4, one(0043374), one(0177777), "#wSd", mcfisa_a },
-
-{"movel", 2, one(0070000), one(0170400), "MsDd", m68000up | mcfisa_a },
-{"movel", 2, one(0020000), one(0170000), "*l%d", m68000up },
-{"movel", 2, one(0020000), one(0170000), "ms%d", mcfisa_a },
-{"movel", 2, one(0020000), one(0170000), "nspd", mcfisa_a },
-{"movel", 2, one(0020000), one(0170000), "olmd", mcfisa_a },
-{"movel", 2, one(0020000), one(0170000), "olnd", mcfisa_b },
-{"movel", 2, one(0047140), one(0177770), "AsUd", m68000up | mcfusp },
-{"movel", 2, one(0047150), one(0177770), "UdAs", m68000up | mcfusp },
-{"movel", 2, one(0120600), one(0177760), "EsRs", mcfmac },
-{"movel", 2, one(0120400), one(0177760), "RsEs", mcfmac },
-{"movel", 6, one(0120474), one(0177777), "#lEs", mcfmac },
-{"movel", 2, one(0124600), one(0177760), "GsRs", mcfmac },
-{"movel", 2, one(0124400), one(0177760), "RsGs", mcfmac },
-{"movel", 6, one(0124474), one(0177777), "#lGs", mcfmac },
-{"movel", 2, one(0126600), one(0177760), "HsRs", mcfmac },
-{"movel", 2, one(0126400), one(0177760), "RsHs", mcfmac },
-{"movel", 6, one(0126474), one(0177777), "#lHs", mcfmac },
-{"movel", 2, one(0124700), one(0177777), "GsCs", mcfmac },
-
-{"movel", 2, one(0xa180), one(0xf9f0), "eFRs", mcfemac }, /* ACCx,Rx. */
-{"movel", 2, one(0xab80), one(0xfbf0), "g]Rs", mcfemac }, /* ACCEXTx,Rx. */
-{"movel", 2, one(0xa980), one(0xfff0), "G-Rs", mcfemac }, /* macsr,Rx. */
-{"movel", 2, one(0xad80), one(0xfff0), "H-Rs", mcfemac }, /* mask,Rx. */
-{"movel", 2, one(0xa110), one(0xf9fc), "efeF", mcfemac }, /* ACCy,ACCx. */
-{"movel", 2, one(0xa9c0), one(0xffff), "G-C-", mcfemac }, /* macsr,ccr. */
-{"movel", 2, one(0xa100), one(0xf9f0), "RseF", mcfemac }, /* Rx,ACCx. */
-{"movel", 6, one(0xa13c), one(0xf9ff), "#leF", mcfemac }, /* #,ACCx. */
-{"movel", 2, one(0xab00), one(0xfbc0), "Rsg]", mcfemac }, /* Rx,ACCEXTx. */
-{"movel", 6, one(0xab3c), one(0xfbff), "#lg]", mcfemac }, /* #,ACCEXTx. */
-{"movel", 2, one(0xa900), one(0xffc0), "RsG-", mcfemac }, /* Rx,macsr. */
-{"movel", 6, one(0xa93c), one(0xffff), "#lG-", mcfemac }, /* #,macsr. */
-{"movel", 2, one(0xad00), one(0xffc0), "RsH-", mcfemac }, /* Rx,mask. */
-{"movel", 6, one(0xad3c), one(0xffff), "#lH-", mcfemac }, /* #,mask. */
-
-{"move", 2, one(0030000), one(0170000), "*w%d", m68000up },
-{"move", 2, one(0030000), one(0170000), "ms%d", mcfisa_a },
-{"move", 2, one(0030000), one(0170000), "nspd", mcfisa_a },
-{"move", 2, one(0030000), one(0170000), "owmd", mcfisa_a },
-{"move", 2, one(0030000), one(0170000), "ownd", mcfisa_b },
-{"move", 2, one(0040300), one(0177700), "Ss$s", m68000up },
-{"move", 2, one(0040300), one(0177770), "SsDs", mcfisa_a },
-{"move", 2, one(0041300), one(0177700), "Cs$s", m68010up },
-{"move", 2, one(0041300), one(0177770), "CsDs", mcfisa_a },
-{"move", 2, one(0042300), one(0177700), ";wCd", m68000up },
-{"move", 2, one(0042300), one(0177700), "DsCd", mcfisa_a },
-{"move", 4, one(0042374), one(0177777), "#wCd", mcfisa_a },
-{"move", 2, one(0043300), one(0177700), ";wSd", m68000up },
-{"move", 2, one(0043300), one(0177700), "DsSd", mcfisa_a },
-{"move", 4, one(0043374), one(0177777), "#wSd", mcfisa_a },
-
-{"move", 2, one(0047140), one(0177770), "AsUd", m68000up },
-{"move", 2, one(0047150), one(0177770), "UdAs", m68000up },
-
-{"mov3ql", 2, one(0120500), one(0170700), "xd%s", mcfisa_b },
-{"mvsb", 2, one(0070400), one(0170700), "*bDd", mcfisa_b },
-{"mvsw", 2, one(0070500), one(0170700), "*wDd", mcfisa_b },
-{"mvzb", 2, one(0070600), one(0170700), "*bDd", mcfisa_b },
-{"mvzw", 2, one(0070700), one(0170700), "*wDd", mcfisa_b },
-
-{"movesb", 4, two(0007000, 0), two(0177700, 07777), "~sR1", m68010up },
-{"movesb", 4, two(0007000, 04000), two(0177700, 07777), "R1~s", m68010up },
-{"movesw", 4, two(0007100, 0), two(0177700, 07777), "~sR1", m68010up },
-{"movesw", 4, two(0007100, 04000), two(0177700, 07777), "R1~s", m68010up },
-{"movesl", 4, two(0007200, 0), two(0177700, 07777), "~sR1", m68010up },
-{"movesl", 4, two(0007200, 04000), two(0177700, 07777), "R1~s", m68010up },
-
-{"move16", 4, two(0xf620, 0x8000), two(0xfff8, 0x8fff), "+s+1", m68040up },
-{"move16", 2, one(0xf600), one(0xfff8), "+s_L", m68040up },
-{"move16", 2, one(0xf608), one(0xfff8), "_L+s", m68040up },
-{"move16", 2, one(0xf610), one(0xfff8), "as_L", m68040up },
-{"move16", 2, one(0xf618), one(0xfff8), "_Las", m68040up },
-
-{"msacw", 4, two(0xa080, 0x0100), two(0xf180, 0x0910), "uNuoiI4/Rn", mcfmac },
-{"msacw", 4, two(0xa080, 0x0300), two(0xf180, 0x0910), "uNuoMh4/Rn", mcfmac },
-{"msacw", 4, two(0xa080, 0x0100), two(0xf180, 0x0f10), "uNuo4/Rn", mcfmac },
-{"msacw", 4, two(0xa000, 0x0100), two(0xf1b0, 0x0900), "uMumiI", mcfmac },
-{"msacw", 4, two(0xa000, 0x0300), two(0xf1b0, 0x0900), "uMumMh", mcfmac },
-{"msacw", 4, two(0xa000, 0x0100), two(0xf1b0, 0x0f00), "uMum", mcfmac },
-
-{"msacw", 4, two(0xa000, 0x0100), two(0xf100, 0x0900), "uMumiI4/RneG", mcfemac },/* Ry,Rx,SF,<ea>,accX. */
-{"msacw", 4, two(0xa000, 0x0300), two(0xf100, 0x0900), "uMumMh4/RneG", mcfemac },/* Ry,Rx,+1/-1,<ea>,accX. */
-{"msacw", 4, two(0xa000, 0x0100), two(0xf100, 0x0f00), "uMum4/RneG", mcfemac },/* Ry,Rx,<ea>,accX. */
-{"msacw", 4, two(0xa000, 0x0100), two(0xf130, 0x0900), "uMumiIeH", mcfemac },/* Ry,Rx,SF,accX. */
-{"msacw", 4, two(0xa000, 0x0300), two(0xf130, 0x0900), "uMumMheH", mcfemac },/* Ry,Rx,+1/-1,accX. */
-{"msacw", 4, two(0xa000, 0x0100), two(0xf130, 0x0f00), "uMumeH", mcfemac }, /* Ry,Rx,accX. */
-
-{"msacl", 4, two(0xa080, 0x0900), two(0xf180, 0x0910), "RNRoiI4/Rn", mcfmac },
-{"msacl", 4, two(0xa080, 0x0b00), two(0xf180, 0x0910), "RNRoMh4/Rn", mcfmac },
-{"msacl", 4, two(0xa080, 0x0900), two(0xf180, 0x0f10), "RNRo4/Rn", mcfmac },
-{"msacl", 4, two(0xa000, 0x0900), two(0xf1b0, 0x0b00), "RMRmiI", mcfmac },
-{"msacl", 4, two(0xa000, 0x0b00), two(0xf1b0, 0x0b00), "RMRmMh", mcfmac },
-{"msacl", 4, two(0xa000, 0x0900), two(0xf1b0, 0x0800), "RMRm", mcfmac },
-
-{"msacl", 4, two(0xa000, 0x0900), two(0xf100, 0x0900), "R3R1iI4/RneG", mcfemac },
-{"msacl", 4, two(0xa000, 0x0b00), two(0xf100, 0x0900), "R3R1Mh4/RneG", mcfemac },
-{"msacl", 4, two(0xa000, 0x0900), two(0xf100, 0x0f00), "R3R14/RneG", mcfemac },
-{"msacl", 4, two(0xa000, 0x0900), two(0xf130, 0x0900), "RMRmiIeH", mcfemac },
-{"msacl", 4, two(0xa000, 0x0b00), two(0xf130, 0x0900), "RMRmMheH", mcfemac },
-{"msacl", 4, two(0xa000, 0x0900), two(0xf130, 0x0f00), "RMRmeH", mcfemac },
-
-{"mulsw", 2, one(0140700), one(0170700), ";wDd", m68000up|mcfisa_a },
-{"mulsl", 4, two(0046000,004000), two(0177700,0107770), ";lD1", m68020up|cpu32 },
-{"mulsl", 4, two(0046000,004000), two(0177700,0107770), "qsD1", mcfisa_a },
-{"mulsl", 4, two(0046000,006000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 },
-
-{"muluw", 2, one(0140300), one(0170700), ";wDd", m68000up|mcfisa_a },
-{"mulul", 4, two(0046000,000000), two(0177700,0107770), ";lD1", m68020up|cpu32 },
-{"mulul", 4, two(0046000,000000), two(0177700,0107770), "qsD1", mcfisa_a },
-{"mulul", 4, two(0046000,002000), two(0177700,0107770), ";lD3D1",m68020up|cpu32 },
-
-{"nbcd", 2, one(0044000), one(0177700), "$s", m68000up },
-
-{"negb", 2, one(0042000), one(0177700), "$s", m68000up },
-{"negw", 2, one(0042100), one(0177700), "$s", m68000up },
-{"negl", 2, one(0042200), one(0177700), "$s", m68000up },
-{"negl", 2, one(0042200), one(0177700), "Ds", mcfisa_a},
-
-{"negxb", 2, one(0040000), one(0177700), "$s", m68000up },
-{"negxw", 2, one(0040100), one(0177700), "$s", m68000up },
-{"negxl", 2, one(0040200), one(0177700), "$s", m68000up },
-{"negxl", 2, one(0040200), one(0177700), "Ds", mcfisa_a},
-
-{"nop", 2, one(0047161), one(0177777), "", m68000up | mcfisa_a},
-
-{"notb", 2, one(0043000), one(0177700), "$s", m68000up },
-{"notw", 2, one(0043100), one(0177700), "$s", m68000up },
-{"notl", 2, one(0043200), one(0177700), "$s", m68000up },
-{"notl", 2, one(0043200), one(0177700), "Ds", mcfisa_a},
-
-{"orib", 4, one(0000000), one(0177700), "#b$s", m68000up },
-{"orib", 4, one(0000074), one(0177777), "#bCs", m68000up },
-{"oriw", 4, one(0000100), one(0177700), "#w$s", m68000up },
-{"oriw", 4, one(0000174), one(0177777), "#wSs", m68000up },
-{"oril", 6, one(0000200), one(0177700), "#l$s", m68000up },
-{"oril", 6, one(0000200), one(0177700), "#lDs", mcfisa_a },
-{"ori", 4, one(0000074), one(0177777), "#bCs", m68000up },
-{"ori", 4, one(0000100), one(0177700), "#w$s", m68000up },
-{"ori", 4, one(0000174), one(0177777), "#wSs", m68000up },
-
-/* The or opcode can generate the ori instruction. */
-{"orb", 4, one(0000000), one(0177700), "#b$s", m68000up },
-{"orb", 4, one(0000074), one(0177777), "#bCs", m68000up },
-{"orb", 2, one(0100000), one(0170700), ";bDd", m68000up },
-{"orb", 2, one(0100400), one(0170700), "Dd~s", m68000up },
-{"orw", 4, one(0000100), one(0177700), "#w$s", m68000up },
-{"orw", 4, one(0000174), one(0177777), "#wSs", m68000up },
-{"orw", 2, one(0100100), one(0170700), ";wDd", m68000up },
-{"orw", 2, one(0100500), one(0170700), "Dd~s", m68000up },
-{"orl", 6, one(0000200), one(0177700), "#l$s", m68000up },
-{"orl", 6, one(0000200), one(0177700), "#lDs", mcfisa_a },
-{"orl", 2, one(0100200), one(0170700), ";lDd", m68000up | mcfisa_a },
-{"orl", 2, one(0100600), one(0170700), "Dd~s", m68000up | mcfisa_a },
-{"or", 4, one(0000074), one(0177777), "#bCs", m68000up },
-{"or", 4, one(0000100), one(0177700), "#w$s", m68000up },
-{"or", 4, one(0000174), one(0177777), "#wSs", m68000up },
-{"or", 2, one(0100100), one(0170700), ";wDd", m68000up },
-{"or", 2, one(0100500), one(0170700), "Dd~s", m68000up },
-
-{"pack", 4, one(0100500), one(0170770), "DsDd#w", m68020up },
-{"pack", 4, one(0100510), one(0170770), "-s-d#w", m68020up },
-
-{"pbac", 2, one(0xf087), one(0xffbf), "Bc", m68851 },
-{"pbacw", 2, one(0xf087), one(0xffff), "BW", m68851 },
-{"pbas", 2, one(0xf086), one(0xffbf), "Bc", m68851 },
-{"pbasw", 2, one(0xf086), one(0xffff), "BW", m68851 },
-{"pbbc", 2, one(0xf081), one(0xffbf), "Bc", m68851 },
-{"pbbcw", 2, one(0xf081), one(0xffff), "BW", m68851 },
-{"pbbs", 2, one(0xf080), one(0xffbf), "Bc", m68851 },
-{"pbbsw", 2, one(0xf080), one(0xffff), "BW", m68851 },
-{"pbcc", 2, one(0xf08f), one(0xffbf), "Bc", m68851 },
-{"pbccw", 2, one(0xf08f), one(0xffff), "BW", m68851 },
-{"pbcs", 2, one(0xf08e), one(0xffbf), "Bc", m68851 },
-{"pbcsw", 2, one(0xf08e), one(0xffff), "BW", m68851 },
-{"pbgc", 2, one(0xf08d), one(0xffbf), "Bc", m68851 },
-{"pbgcw", 2, one(0xf08d), one(0xffff), "BW", m68851 },
-{"pbgs", 2, one(0xf08c), one(0xffbf), "Bc", m68851 },
-{"pbgsw", 2, one(0xf08c), one(0xffff), "BW", m68851 },
-{"pbic", 2, one(0xf08b), one(0xffbf), "Bc", m68851 },
-{"pbicw", 2, one(0xf08b), one(0xffff), "BW", m68851 },
-{"pbis", 2, one(0xf08a), one(0xffbf), "Bc", m68851 },
-{"pbisw", 2, one(0xf08a), one(0xffff), "BW", m68851 },
-{"pblc", 2, one(0xf083), one(0xffbf), "Bc", m68851 },
-{"pblcw", 2, one(0xf083), one(0xffff), "BW", m68851 },
-{"pbls", 2, one(0xf082), one(0xffbf), "Bc", m68851 },
-{"pblsw", 2, one(0xf082), one(0xffff), "BW", m68851 },
-{"pbsc", 2, one(0xf085), one(0xffbf), "Bc", m68851 },
-{"pbscw", 2, one(0xf085), one(0xffff), "BW", m68851 },
-{"pbss", 2, one(0xf084), one(0xffbf), "Bc", m68851 },
-{"pbssw", 2, one(0xf084), one(0xffff), "BW", m68851 },
-{"pbwc", 2, one(0xf089), one(0xffbf), "Bc", m68851 },
-{"pbwcw", 2, one(0xf089), one(0xffff), "BW", m68851 },
-{"pbws", 2, one(0xf088), one(0xffbf), "Bc", m68851 },
-{"pbwsw", 2, one(0xf088), one(0xffff), "BW", m68851 },
-
-{"pdbac", 4, two(0xf048, 0x0007), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbas", 4, two(0xf048, 0x0006), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbbc", 4, two(0xf048, 0x0001), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbbs", 4, two(0xf048, 0x0000), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbcc", 4, two(0xf048, 0x000f), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbcs", 4, two(0xf048, 0x000e), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbgc", 4, two(0xf048, 0x000d), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbgs", 4, two(0xf048, 0x000c), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbic", 4, two(0xf048, 0x000b), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbis", 4, two(0xf048, 0x000a), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdblc", 4, two(0xf048, 0x0003), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbls", 4, two(0xf048, 0x0002), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbsc", 4, two(0xf048, 0x0005), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbss", 4, two(0xf048, 0x0004), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbwc", 4, two(0xf048, 0x0009), two(0xfff8, 0xffff), "DsBw", m68851 },
-{"pdbws", 4, two(0xf048, 0x0008), two(0xfff8, 0xffff), "DsBw", m68851 },
-
-{"pea", 2, one(0044100), one(0177700), "!s", m68000up|mcfisa_a },
-
-{"pflusha", 2, one(0xf518), one(0xfff8), "", m68040up },
-{"pflusha", 4, two(0xf000,0x2400), two(0xffff,0xffff), "", m68030 | m68851 },
-
-{"pflush", 4, two(0xf000,0x3010), two(0xffc0,0xfe10), "T3T9", m68030|m68851 },
-{"pflush", 4, two(0xf000,0x3810), two(0xffc0,0xfe10), "T3T9&s", m68030|m68851 },
-{"pflush", 4, two(0xf000,0x3008), two(0xffc0,0xfe18), "D3T9", m68030|m68851 },
-{"pflush", 4, two(0xf000,0x3808), two(0xffc0,0xfe18), "D3T9&s", m68030|m68851 },
-{"pflush", 4, two(0xf000,0x3000), two(0xffc0,0xfe1e), "f3T9", m68030|m68851 },
-{"pflush", 4, two(0xf000,0x3800), two(0xffc0,0xfe1e), "f3T9&s", m68030|m68851 },
-{"pflush", 2, one(0xf508), one(0xfff8), "as", m68040up },
-{"pflush", 2, one(0xf508), one(0xfff8), "As", m68040up },
-
-{"pflushan", 2, one(0xf510), one(0xfff8), "", m68040up },
-{"pflushn", 2, one(0xf500), one(0xfff8), "as", m68040up },
-{"pflushn", 2, one(0xf500), one(0xfff8), "As", m68040up },
-
-{"pflushr", 4, two(0xf000, 0xa000), two(0xffc0, 0xffff), "|s", m68851 },
-
-{"pflushs", 4, two(0xf000, 0x3410), two(0xfff8, 0xfe10), "T3T9", m68851 },
-{"pflushs", 4, two(0xf000, 0x3c10), two(0xfff8, 0xfe10), "T3T9&s", m68851 },
-{"pflushs", 4, two(0xf000, 0x3408), two(0xfff8, 0xfe18), "D3T9", m68851 },
-{"pflushs", 4, two(0xf000, 0x3c08), two(0xfff8, 0xfe18), "D3T9&s", m68851 },
-{"pflushs", 4, two(0xf000, 0x3400), two(0xfff8, 0xfe1e), "f3T9", m68851 },
-{"pflushs", 4, two(0xf000, 0x3c00), two(0xfff8, 0xfe1e), "f3T9&s", m68851 },
-
-{"ploadr", 4, two(0xf000,0x2210), two(0xffc0,0xfff0), "T3&s", m68030|m68851 },
-{"ploadr", 4, two(0xf000,0x2208), two(0xffc0,0xfff8), "D3&s", m68030|m68851 },
-{"ploadr", 4, two(0xf000,0x2200), two(0xffc0,0xfffe), "f3&s", m68030|m68851 },
-{"ploadw", 4, two(0xf000,0x2010), two(0xffc0,0xfff0), "T3&s", m68030|m68851 },
-{"ploadw", 4, two(0xf000,0x2008), two(0xffc0,0xfff8), "D3&s", m68030|m68851 },
-{"ploadw", 4, two(0xf000,0x2000), two(0xffc0,0xfffe), "f3&s", m68030|m68851 },
-
-{"plpar", 2, one(0xf5c8), one(0xfff8), "as", m68060 },
-{"plpaw", 2, one(0xf588), one(0xfff8), "as", m68060 },
-
-{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xffff), "*l08", m68030|m68851 },
-{"pmove", 4, two(0xf000,0x5c00), two(0xffc0,0xffff), "*w18", m68851 },
-{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xe3ff), "*b28", m68851 },
-{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xffff), "08%s", m68030|m68851 },
-{"pmove", 4, two(0xf000,0x5e00), two(0xffc0,0xffff), "18%s", m68851 },
-{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xe3ff), "28%s", m68851 },
-{"pmove", 4, two(0xf000,0x4000), two(0xffc0,0xe3ff), "|sW8", m68030|m68851 },
-{"pmove", 4, two(0xf000,0x4200), two(0xffc0,0xe3ff), "W8~s", m68030|m68851 },
-{"pmove", 4, two(0xf000,0x6200), two(0xffc0,0xe3e3), "*wX3", m68851 },
-{"pmove", 4, two(0xf000,0x6000), two(0xffc0,0xe3e3), "X3%s", m68851 },
-{"pmove", 4, two(0xf000,0x6000), two(0xffc0,0xffff), "*wY8", m68030|m68851 },
-{"pmove", 4, two(0xf000,0x6200), two(0xffc0,0xffff), "Y8%s", m68030|m68851 },
-{"pmove", 4, two(0xf000,0x6600), two(0xffc0,0xffff), "Z8%s", m68851 },
-{"pmove", 4, two(0xf000,0x0800), two(0xffc0,0xfbff), "*l38", m68030 },
-{"pmove", 4, two(0xf000,0x0a00), two(0xffc0,0xfbff), "38%s", m68030 },
-
-{"pmovefd", 4, two(0xf000, 0x4100), two(0xffc0, 0xe3ff), "*l08", m68030 },
-{"pmovefd", 4, two(0xf000, 0x4100), two(0xffc0, 0xe3ff), "|sW8", m68030 },
-{"pmovefd", 4, two(0xf000, 0x0900), two(0xffc0, 0xfbff), "*l38", m68030 },
-
-{"prestore", 2, one(0xf140), one(0xffc0), "<s", m68851 },
-
-{"psave", 2, one(0xf100), one(0xffc0), ">s", m68851 },
-
-{"psac", 4, two(0xf040, 0x0007), two(0xffc0, 0xffff), "$s", m68851 },
-{"psas", 4, two(0xf040, 0x0006), two(0xffc0, 0xffff), "$s", m68851 },
-{"psbc", 4, two(0xf040, 0x0001), two(0xffc0, 0xffff), "$s", m68851 },
-{"psbs", 4, two(0xf040, 0x0000), two(0xffc0, 0xffff), "$s", m68851 },
-{"pscc", 4, two(0xf040, 0x000f), two(0xffc0, 0xffff), "$s", m68851 },
-{"pscs", 4, two(0xf040, 0x000e), two(0xffc0, 0xffff), "$s", m68851 },
-{"psgc", 4, two(0xf040, 0x000d), two(0xffc0, 0xffff), "$s", m68851 },
-{"psgs", 4, two(0xf040, 0x000c), two(0xffc0, 0xffff), "$s", m68851 },
-{"psic", 4, two(0xf040, 0x000b), two(0xffc0, 0xffff), "$s", m68851 },
-{"psis", 4, two(0xf040, 0x000a), two(0xffc0, 0xffff), "$s", m68851 },
-{"pslc", 4, two(0xf040, 0x0003), two(0xffc0, 0xffff), "$s", m68851 },
-{"psls", 4, two(0xf040, 0x0002), two(0xffc0, 0xffff), "$s", m68851 },
-{"pssc", 4, two(0xf040, 0x0005), two(0xffc0, 0xffff), "$s", m68851 },
-{"psss", 4, two(0xf040, 0x0004), two(0xffc0, 0xffff), "$s", m68851 },
-{"pswc", 4, two(0xf040, 0x0009), two(0xffc0, 0xffff), "$s", m68851 },
-{"psws", 4, two(0xf040, 0x0008), two(0xffc0, 0xffff), "$s", m68851 },
-
-{"ptestr", 4, two(0xf000,0x8210), two(0xffc0, 0xe3f0), "T3&st8", m68030|m68851 },
-{"ptestr", 4, two(0xf000,0x8310), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 },
-{"ptestr", 4, two(0xf000,0x8208), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 },
-{"ptestr", 4, two(0xf000,0x8308), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 },
-{"ptestr", 4, two(0xf000,0x8200), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 },
-{"ptestr", 4, two(0xf000,0x8300), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 },
-{"ptestr", 2, one(0xf568), one(0xfff8), "as", m68040 },
-
-{"ptestw", 4, two(0xf000,0x8010), two(0xffc0,0xe3f0), "T3&st8", m68030|m68851 },
-{"ptestw", 4, two(0xf000,0x8110), two(0xffc0,0xe310), "T3&st8A9", m68030|m68851 },
-{"ptestw", 4, two(0xf000,0x8008), two(0xffc0,0xe3f8), "D3&st8", m68030|m68851 },
-{"ptestw", 4, two(0xf000,0x8108), two(0xffc0,0xe318), "D3&st8A9", m68030|m68851 },
-{"ptestw", 4, two(0xf000,0x8000), two(0xffc0,0xe3fe), "f3&st8", m68030|m68851 },
-{"ptestw", 4, two(0xf000,0x8100), two(0xffc0,0xe31e), "f3&st8A9", m68030|m68851 },
-{"ptestw", 2, one(0xf548), one(0xfff8), "as", m68040 },
-
-{"ptrapacw", 6, two(0xf07a, 0x0007), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapacl", 6, two(0xf07b, 0x0007), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapac", 4, two(0xf07c, 0x0007), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapasw", 6, two(0xf07a, 0x0006), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapasl", 6, two(0xf07b, 0x0006), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapas", 4, two(0xf07c, 0x0006), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapbcw", 6, two(0xf07a, 0x0001), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapbcl", 6, two(0xf07b, 0x0001), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapbc", 4, two(0xf07c, 0x0001), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapbsw", 6, two(0xf07a, 0x0000), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapbsl", 6, two(0xf07b, 0x0000), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapbs", 4, two(0xf07c, 0x0000), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapccw", 6, two(0xf07a, 0x000f), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapccl", 6, two(0xf07b, 0x000f), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapcc", 4, two(0xf07c, 0x000f), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapcsw", 6, two(0xf07a, 0x000e), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapcsl", 6, two(0xf07b, 0x000e), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapcs", 4, two(0xf07c, 0x000e), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapgcw", 6, two(0xf07a, 0x000d), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapgcl", 6, two(0xf07b, 0x000d), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapgc", 4, two(0xf07c, 0x000d), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapgsw", 6, two(0xf07a, 0x000c), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapgsl", 6, two(0xf07b, 0x000c), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapgs", 4, two(0xf07c, 0x000c), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapicw", 6, two(0xf07a, 0x000b), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapicl", 6, two(0xf07b, 0x000b), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapic", 4, two(0xf07c, 0x000b), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapisw", 6, two(0xf07a, 0x000a), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapisl", 6, two(0xf07b, 0x000a), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapis", 4, two(0xf07c, 0x000a), two(0xffff, 0xffff), "", m68851 },
-
-{"ptraplcw", 6, two(0xf07a, 0x0003), two(0xffff, 0xffff), "#w", m68851 },
-{"ptraplcl", 6, two(0xf07b, 0x0003), two(0xffff, 0xffff), "#l", m68851 },
-{"ptraplc", 4, two(0xf07c, 0x0003), two(0xffff, 0xffff), "", m68851 },
-
-{"ptraplsw", 6, two(0xf07a, 0x0002), two(0xffff, 0xffff), "#w", m68851 },
-{"ptraplsl", 6, two(0xf07b, 0x0002), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapls", 4, two(0xf07c, 0x0002), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapscw", 6, two(0xf07a, 0x0005), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapscl", 6, two(0xf07b, 0x0005), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapsc", 4, two(0xf07c, 0x0005), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapssw", 6, two(0xf07a, 0x0004), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapssl", 6, two(0xf07b, 0x0004), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapss", 4, two(0xf07c, 0x0004), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapwcw", 6, two(0xf07a, 0x0009), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapwcl", 6, two(0xf07b, 0x0009), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapwc", 4, two(0xf07c, 0x0009), two(0xffff, 0xffff), "", m68851 },
-
-{"ptrapwsw", 6, two(0xf07a, 0x0008), two(0xffff, 0xffff), "#w", m68851 },
-{"ptrapwsl", 6, two(0xf07b, 0x0008), two(0xffff, 0xffff), "#l", m68851 },
-{"ptrapws", 4, two(0xf07c, 0x0008), two(0xffff, 0xffff), "", m68851 },
-
-{"pulse", 2, one(0045314), one(0177777), "", m68060 | mcfisa_a },
-
-{"pvalid", 4, two(0xf000, 0x2800), two(0xffc0, 0xffff), "Vs&s", m68851 },
-{"pvalid", 4, two(0xf000, 0x2c00), two(0xffc0, 0xfff8), "A3&s", m68851 },
-
- /* FIXME: don't allow Dw==Dx. */
-{"remsl", 4, two(0x4c40, 0x0800), two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv },
-{"remul", 4, two(0x4c40, 0x0000), two(0xffc0, 0x8ff8), "qsD3D1", mcfhwdiv },
-
-{"reset", 2, one(0047160), one(0177777), "", m68000up },
-
-{"rolb", 2, one(0160430), one(0170770), "QdDs", m68000up },
-{"rolb", 2, one(0160470), one(0170770), "DdDs", m68000up },
-{"rolw", 2, one(0160530), one(0170770), "QdDs", m68000up },
-{"rolw", 2, one(0160570), one(0170770), "DdDs", m68000up },
-{"rolw", 2, one(0163700), one(0177700), "~s", m68000up },
-{"roll", 2, one(0160630), one(0170770), "QdDs", m68000up },
-{"roll", 2, one(0160670), one(0170770), "DdDs", m68000up },
-
-{"rorb", 2, one(0160030), one(0170770), "QdDs", m68000up },
-{"rorb", 2, one(0160070), one(0170770), "DdDs", m68000up },
-{"rorw", 2, one(0160130), one(0170770), "QdDs", m68000up },
-{"rorw", 2, one(0160170), one(0170770), "DdDs", m68000up },
-{"rorw", 2, one(0163300), one(0177700), "~s", m68000up },
-{"rorl", 2, one(0160230), one(0170770), "QdDs", m68000up },
-{"rorl", 2, one(0160270), one(0170770), "DdDs", m68000up },
-
-{"roxlb", 2, one(0160420), one(0170770), "QdDs", m68000up },
-{"roxlb", 2, one(0160460), one(0170770), "DdDs", m68000up },
-{"roxlw", 2, one(0160520), one(0170770), "QdDs", m68000up },
-{"roxlw", 2, one(0160560), one(0170770), "DdDs", m68000up },
-{"roxlw", 2, one(0162700), one(0177700), "~s", m68000up },
-{"roxll", 2, one(0160620), one(0170770), "QdDs", m68000up },
-{"roxll", 2, one(0160660), one(0170770), "DdDs", m68000up },
-
-{"roxrb", 2, one(0160020), one(0170770), "QdDs", m68000up },
-{"roxrb", 2, one(0160060), one(0170770), "DdDs", m68000up },
-{"roxrw", 2, one(0160120), one(0170770), "QdDs", m68000up },
-{"roxrw", 2, one(0160160), one(0170770), "DdDs", m68000up },
-{"roxrw", 2, one(0162300), one(0177700), "~s", m68000up },
-{"roxrl", 2, one(0160220), one(0170770), "QdDs", m68000up },
-{"roxrl", 2, one(0160260), one(0170770), "DdDs", m68000up },
-
-{"rtd", 4, one(0047164), one(0177777), "#w", m68010up },
-
-{"rte", 2, one(0047163), one(0177777), "", m68000up | mcfisa_a },
-
-{"rtm", 2, one(0003300), one(0177760), "Rs", m68020 },
-
-{"rtr", 2, one(0047167), one(0177777), "", m68000up },
-
-{"rts", 2, one(0047165), one(0177777), "", m68000up | mcfisa_a },
-
-{"satsl", 2, one(0046200), one(0177770), "Ds", mcfisa_b },
-
-{"sbcd", 2, one(0100400), one(0170770), "DsDd", m68000up },
-{"sbcd", 2, one(0100410), one(0170770), "-s-d", m68000up },
-
-{"scc", 2, one(0052300), one(0177700), "$s", m68000up },
-{"scc", 2, one(0052300), one(0177700), "Ds", mcfisa_a },
-{"scs", 2, one(0052700), one(0177700), "$s", m68000up },
-{"scs", 2, one(0052700), one(0177700), "Ds", mcfisa_a },
-{"seq", 2, one(0053700), one(0177700), "$s", m68000up },
-{"seq", 2, one(0053700), one(0177700), "Ds", mcfisa_a },
-{"sf", 2, one(0050700), one(0177700), "$s", m68000up },
-{"sf", 2, one(0050700), one(0177700), "Ds", mcfisa_a },
-{"sge", 2, one(0056300), one(0177700), "$s", m68000up },
-{"sge", 2, one(0056300), one(0177700), "Ds", mcfisa_a },
-{"sgt", 2, one(0057300), one(0177700), "$s", m68000up },
-{"sgt", 2, one(0057300), one(0177700), "Ds", mcfisa_a },
-{"shi", 2, one(0051300), one(0177700), "$s", m68000up },
-{"shi", 2, one(0051300), one(0177700), "Ds", mcfisa_a },
-{"sle", 2, one(0057700), one(0177700), "$s", m68000up },
-{"sle", 2, one(0057700), one(0177700), "Ds", mcfisa_a },
-{"sls", 2, one(0051700), one(0177700), "$s", m68000up },
-{"sls", 2, one(0051700), one(0177700), "Ds", mcfisa_a },
-{"slt", 2, one(0056700), one(0177700), "$s", m68000up },
-{"slt", 2, one(0056700), one(0177700), "Ds", mcfisa_a },
-{"smi", 2, one(0055700), one(0177700), "$s", m68000up },
-{"smi", 2, one(0055700), one(0177700), "Ds", mcfisa_a },
-{"sne", 2, one(0053300), one(0177700), "$s", m68000up },
-{"sne", 2, one(0053300), one(0177700), "Ds", mcfisa_a },
-{"spl", 2, one(0055300), one(0177700), "$s", m68000up },
-{"spl", 2, one(0055300), one(0177700), "Ds", mcfisa_a },
-{"st", 2, one(0050300), one(0177700), "$s", m68000up },
-{"st", 2, one(0050300), one(0177700), "Ds", mcfisa_a },
-{"svc", 2, one(0054300), one(0177700), "$s", m68000up },
-{"svc", 2, one(0054300), one(0177700), "Ds", mcfisa_a },
-{"svs", 2, one(0054700), one(0177700), "$s", m68000up },
-{"svs", 2, one(0054700), one(0177700), "Ds", mcfisa_a },
-
-{"stop", 4, one(0047162), one(0177777), "#w", m68000up | mcfisa_a },
-
-{"strldsr", 4, two(0040347,0043374), two(0177777,0177777), "#w", mcfisa_aa},
-
-{"subal", 2, one(0110700), one(0170700), "*lAd", m68000up | mcfisa_a },
-{"subaw", 2, one(0110300), one(0170700), "*wAd", m68000up },
-
-{"subib", 4, one(0002000), one(0177700), "#b$s", m68000up },
-{"subiw", 4, one(0002100), one(0177700), "#w$s", m68000up },
-{"subil", 6, one(0002200), one(0177700), "#l$s", m68000up },
-{"subil", 6, one(0002200), one(0177700), "#lDs", mcfisa_a },
-
-{"subqb", 2, one(0050400), one(0170700), "Qd%s", m68000up },
-{"subqw", 2, one(0050500), one(0170700), "Qd%s", m68000up },
-{"subql", 2, one(0050600), one(0170700), "Qd%s", m68000up | mcfisa_a },
-
-/* The sub opcode can generate the suba, subi, and subq instructions. */
-{"subb", 2, one(0050400), one(0170700), "Qd%s", m68000up },
-{"subb", 4, one(0002000), one(0177700), "#b$s", m68000up },
-{"subb", 2, one(0110000), one(0170700), ";bDd", m68000up },
-{"subb", 2, one(0110400), one(0170700), "Dd~s", m68000up },
-{"subw", 2, one(0050500), one(0170700), "Qd%s", m68000up },
-{"subw", 4, one(0002100), one(0177700), "#w$s", m68000up },
-{"subw", 2, one(0110300), one(0170700), "*wAd", m68000up },
-{"subw", 2, one(0110100), one(0170700), "*wDd", m68000up },
-{"subw", 2, one(0110500), one(0170700), "Dd~s", m68000up },
-{"subl", 2, one(0050600), one(0170700), "Qd%s", m68000up | mcfisa_a },
-{"subl", 6, one(0002200), one(0177700), "#l$s", m68000up },
-{"subl", 6, one(0002200), one(0177700), "#lDs", mcfisa_a },
-{"subl", 2, one(0110700), one(0170700), "*lAd", m68000up | mcfisa_a },
-{"subl", 2, one(0110200), one(0170700), "*lDd", m68000up | mcfisa_a },
-{"subl", 2, one(0110600), one(0170700), "Dd~s", m68000up | mcfisa_a },
-
-{"subxb", 2, one(0110400), one(0170770), "DsDd", m68000up },
-{"subxb", 2, one(0110410), one(0170770), "-s-d", m68000up },
-{"subxw", 2, one(0110500), one(0170770), "DsDd", m68000up },
-{"subxw", 2, one(0110510), one(0170770), "-s-d", m68000up },
-{"subxl", 2, one(0110600), one(0170770), "DsDd", m68000up | mcfisa_a },
-{"subxl", 2, one(0110610), one(0170770), "-s-d", m68000up },
-
-{"swap", 2, one(0044100), one(0177770), "Ds", m68000up | mcfisa_a },
-
-/* swbeg and swbegl are magic constants used on sysV68. The compiler
- generates them before a switch table. They tell the debugger and
- disassembler that a switch table follows. The parameter is the
- number of elements in the table. swbeg means that the entries in
- the table are word (2 byte) sized, and swbegl means that the
- entries in the table are longword (4 byte) sized. */
-{"swbeg", 4, one(0045374), one(0177777), "#w", m68000up | mcfisa_a },
-{"swbegl", 6, one(0045375), one(0177777), "#l", m68000up | mcfisa_a },
-
-{"tas", 2, one(0045300), one(0177700), "$s", m68000up | mcfisa_b},
-
-#define TBL1(name,insn_size,signed,round,size) \
- {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)|0000400), \
- two(0177700,0107777), "!sD1", cpu32 }, \
- {name, insn_size, two(0174000, (signed<<11)|(!round<<10)|(size<<6)), \
- two(0177770,0107770), "DsD3D1", cpu32 }
-#define TBL(name1, name2, name3, s, r) \
- TBL1(name1, 4, s, r, 0), TBL1(name2, 4, s, r, 1), TBL1(name3, 4, s, r, 2)
-TBL("tblsb", "tblsw", "tblsl", 2, 1),
-TBL("tblsnb", "tblsnw", "tblsnl", 2, 0),
-TBL("tblub", "tbluw", "tblul", 0, 1),
-TBL("tblunb", "tblunw", "tblunl", 0, 0),
-
-{"trap", 2, one(0047100), one(0177760), "Ts", m68000up | mcfisa_a },
-
-{"trapcc", 2, one(0052374), one(0177777), "", m68020up | cpu32 },
-{"trapcs", 2, one(0052774), one(0177777), "", m68020up | cpu32 },
-{"trapeq", 2, one(0053774), one(0177777), "", m68020up | cpu32 },
-{"trapf", 2, one(0050774), one(0177777), "", m68020up | cpu32 | mcfisa_a },
-{"trapge", 2, one(0056374), one(0177777), "", m68020up | cpu32 },
-{"trapgt", 2, one(0057374), one(0177777), "", m68020up | cpu32 },
-{"traphi", 2, one(0051374), one(0177777), "", m68020up | cpu32 },
-{"traple", 2, one(0057774), one(0177777), "", m68020up | cpu32 },
-{"trapls", 2, one(0051774), one(0177777), "", m68020up | cpu32 },
-{"traplt", 2, one(0056774), one(0177777), "", m68020up | cpu32 },
-{"trapmi", 2, one(0055774), one(0177777), "", m68020up | cpu32 },
-{"trapne", 2, one(0053374), one(0177777), "", m68020up | cpu32 },
-{"trappl", 2, one(0055374), one(0177777), "", m68020up | cpu32 },
-{"trapt", 2, one(0050374), one(0177777), "", m68020up | cpu32 },
-{"trapvc", 2, one(0054374), one(0177777), "", m68020up | cpu32 },
-{"trapvs", 2, one(0054774), one(0177777), "", m68020up | cpu32 },
-
-{"trapccw", 4, one(0052372), one(0177777), "#w", m68020up|cpu32 },
-{"trapcsw", 4, one(0052772), one(0177777), "#w", m68020up|cpu32 },
-{"trapeqw", 4, one(0053772), one(0177777), "#w", m68020up|cpu32 },
-{"trapfw", 4, one(0050772), one(0177777), "#w", m68020up|cpu32|mcfisa_a},
-{"trapgew", 4, one(0056372), one(0177777), "#w", m68020up|cpu32 },
-{"trapgtw", 4, one(0057372), one(0177777), "#w", m68020up|cpu32 },
-{"traphiw", 4, one(0051372), one(0177777), "#w", m68020up|cpu32 },
-{"traplew", 4, one(0057772), one(0177777), "#w", m68020up|cpu32 },
-{"traplsw", 4, one(0051772), one(0177777), "#w", m68020up|cpu32 },
-{"trapltw", 4, one(0056772), one(0177777), "#w", m68020up|cpu32 },
-{"trapmiw", 4, one(0055772), one(0177777), "#w", m68020up|cpu32 },
-{"trapnew", 4, one(0053372), one(0177777), "#w", m68020up|cpu32 },
-{"trapplw", 4, one(0055372), one(0177777), "#w", m68020up|cpu32 },
-{"traptw", 4, one(0050372), one(0177777), "#w", m68020up|cpu32 },
-{"trapvcw", 4, one(0054372), one(0177777), "#w", m68020up|cpu32 },
-{"trapvsw", 4, one(0054772), one(0177777), "#w", m68020up|cpu32 },
-
-{"trapccl", 6, one(0052373), one(0177777), "#l", m68020up|cpu32 },
-{"trapcsl", 6, one(0052773), one(0177777), "#l", m68020up|cpu32 },
-{"trapeql", 6, one(0053773), one(0177777), "#l", m68020up|cpu32 },
-{"trapfl", 6, one(0050773), one(0177777), "#l", m68020up|cpu32|mcfisa_a},
-{"trapgel", 6, one(0056373), one(0177777), "#l", m68020up|cpu32 },
-{"trapgtl", 6, one(0057373), one(0177777), "#l", m68020up|cpu32 },
-{"traphil", 6, one(0051373), one(0177777), "#l", m68020up|cpu32 },
-{"traplel", 6, one(0057773), one(0177777), "#l", m68020up|cpu32 },
-{"traplsl", 6, one(0051773), one(0177777), "#l", m68020up|cpu32 },
-{"trapltl", 6, one(0056773), one(0177777), "#l", m68020up|cpu32 },
-{"trapmil", 6, one(0055773), one(0177777), "#l", m68020up|cpu32 },
-{"trapnel", 6, one(0053373), one(0177777), "#l", m68020up|cpu32 },
-{"trappll", 6, one(0055373), one(0177777), "#l", m68020up|cpu32 },
-{"traptl", 6, one(0050373), one(0177777), "#l", m68020up|cpu32 },
-{"trapvcl", 6, one(0054373), one(0177777), "#l", m68020up|cpu32 },
-{"trapvsl", 6, one(0054773), one(0177777), "#l", m68020up|cpu32 },
-
-{"trapv", 2, one(0047166), one(0177777), "", m68000up },
-
-{"tstb", 2, one(0045000), one(0177700), ";b", m68020up|cpu32|mcfisa_a },
-{"tstb", 2, one(0045000), one(0177700), "$b", m68000up },
-{"tstw", 2, one(0045100), one(0177700), "*w", m68020up|cpu32|mcfisa_a },
-{"tstw", 2, one(0045100), one(0177700), "$w", m68000up },
-{"tstl", 2, one(0045200), one(0177700), "*l", m68020up|cpu32|mcfisa_a },
-{"tstl", 2, one(0045200), one(0177700), "$l", m68000up },
-
-{"unlk", 2, one(0047130), one(0177770), "As", m68000up | mcfisa_a },
-
-{"unpk", 4, one(0100600), one(0170770), "DsDd#w", m68020up },
-{"unpk", 4, one(0100610), one(0170770), "-s-d#w", m68020up },
-
-{"wddatab", 2, one(0175400), one(0177700), "~s", mcfisa_a },
-{"wddataw", 2, one(0175500), one(0177700), "~s", mcfisa_a },
-{"wddatal", 2, one(0175600), one(0177700), "~s", mcfisa_a },
-
-{"wdebug", 4, two(0175720, 03), two(0177770, 0xffff), "as", mcfisa_a },
-{"wdebug", 4, two(0175750, 03), two(0177770, 0xffff), "ds", mcfisa_a },
-};
-
-const int m68k_numopcodes = sizeof m68k_opcodes / sizeof m68k_opcodes[0];
-
-/* These aliases used to be in the above table, each one duplicating
- all of the entries for its primary exactly. This table was
- constructed by mechanical processing of the opcode table, with a
- small number of tweaks done by hand. There are probably a lot more
- aliases above that could be moved down here, except for very minor
- differences. */
-
-const struct m68k_opcode_alias m68k_opcode_aliases[] =
-{
- { "add", "addw", },
- { "adda", "addaw", },
- { "addi", "addiw", },
- { "addq", "addqw", },
- { "addx", "addxw", },
- { "asl", "aslw", },
- { "asr", "asrw", },
- { "bhi", "bhiw", },
- { "bls", "blsw", },
- { "bcc", "bccw", },
- { "bcs", "bcsw", },
- { "bne", "bnew", },
- { "beq", "beqw", },
- { "bvc", "bvcw", },
- { "bvs", "bvsw", },
- { "bpl", "bplw", },
- { "bmi", "bmiw", },
- { "bge", "bgew", },
- { "blt", "bltw", },
- { "bgt", "bgtw", },
- { "ble", "blew", },
- { "bra", "braw", },
- { "bsr", "bsrw", },
- { "bhib", "bhis", },
- { "blsb", "blss", },
- { "bccb", "bccs", },
- { "bcsb", "bcss", },
- { "bneb", "bnes", },
- { "beqb", "beqs", },
- { "bvcb", "bvcs", },
- { "bvsb", "bvss", },
- { "bplb", "bpls", },
- { "bmib", "bmis", },
- { "bgeb", "bges", },
- { "bltb", "blts", },
- { "bgtb", "bgts", },
- { "bleb", "bles", },
- { "brab", "bras", },
- { "bsrb", "bsrs", },
- { "bhs", "bccw" },
- { "bhss", "bccs" },
- { "bhsb", "bccs" },
- { "bhsw", "bccw" },
- { "bhsl", "bccl" },
- { "blo", "bcsw" },
- { "blos", "bcss" },
- { "blob", "bcss" },
- { "blow", "bcsw" },
- { "blol", "bcsl" },
- { "br", "braw", },
- { "brs", "bras", },
- { "brb", "bras", },
- { "brw", "braw", },
- { "brl", "bral", },
- { "jfnlt", "bcc", }, /* Apparently a sun alias. */
- { "jfngt", "ble", }, /* Apparently a sun alias. */
- { "jfeq", "beqs", }, /* Apparently a sun alias. */
- { "bchgb", "bchg", },
- { "bchgl", "bchg", },
- { "bclrb", "bclr", },
- { "bclrl", "bclr", },
- { "bsetb", "bset", },
- { "bsetl", "bset", },
- { "btstb", "btst", },
- { "btstl", "btst", },
- { "cas2", "cas2w", },
- { "cas", "casw", },
- { "chk2", "chk2w", },
- { "chk", "chkw", },
- { "clr", "clrw", },
- { "cmp2", "cmp2w", },
- { "cmpa", "cmpaw", },
- { "cmpi", "cmpiw", },
- { "cmpm", "cmpmw", },
- { "cmp", "cmpw", },
- { "dbccw", "dbcc", },
- { "dbcsw", "dbcs", },
- { "dbeqw", "dbeq", },
- { "dbfw", "dbf", },
- { "dbgew", "dbge", },
- { "dbgtw", "dbgt", },
- { "dbhiw", "dbhi", },
- { "dblew", "dble", },
- { "dblsw", "dbls", },
- { "dbltw", "dblt", },
- { "dbmiw", "dbmi", },
- { "dbnew", "dbne", },
- { "dbplw", "dbpl", },
- { "dbtw", "dbt", },
- { "dbvcw", "dbvc", },
- { "dbvsw", "dbvs", },
- { "dbhs", "dbcc", },
- { "dbhsw", "dbcc", },
- { "dbra", "dbf", },
- { "dbraw", "dbf", },
- { "tdivsl", "divsl", },
- { "divs", "divsw", },
- { "divu", "divuw", },
- { "ext", "extw", },
- { "extbw", "extw", },
- { "extwl", "extl", },
- { "fbneq", "fbne", },
- { "fbsneq", "fbsne", },
- { "fdbneq", "fdbne", },
- { "fdbsneq", "fdbsne", },
- { "fmovecr", "fmovecrx", },
- { "fmovm", "fmovem", },
- { "fsneq", "fsne", },
- { "fssneq", "fssne", },
- { "ftrapneq", "ftrapne", },
- { "ftrapsneq", "ftrapsne", },
- { "fjneq", "fjne", },
- { "fjsneq", "fjsne", },
- { "jmpl", "jmp", },
- { "jmps", "jmp", },
- { "jsrl", "jsr", },
- { "jsrs", "jsr", },
- { "leal", "lea", },
- { "lsl", "lslw", },
- { "lsr", "lsrw", },
- { "mac", "macw" },
- { "movea", "moveaw", },
- { "movem", "movemw", },
- { "movml", "moveml", },
- { "movmw", "movemw", },
- { "movm", "movemw", },
- { "movep", "movepw", },
- { "movpw", "movepw", },
- { "moves", "movesw" },
- { "muls", "mulsw", },
- { "mulu", "muluw", },
- { "msac", "msacw" },
- { "nbcdb", "nbcd" },
- { "neg", "negw", },
- { "negx", "negxw", },
- { "not", "notw", },
- { "peal", "pea", },
- { "rol", "rolw", },
- { "ror", "rorw", },
- { "roxl", "roxlw", },
- { "roxr", "roxrw", },
- { "sats", "satsl", },
- { "sbcdb", "sbcd", },
- { "sccb", "scc", },
- { "scsb", "scs", },
- { "seqb", "seq", },
- { "sfb", "sf", },
- { "sgeb", "sge", },
- { "sgtb", "sgt", },
- { "shib", "shi", },
- { "sleb", "sle", },
- { "slsb", "sls", },
- { "sltb", "slt", },
- { "smib", "smi", },
- { "sneb", "sne", },
- { "splb", "spl", },
- { "stb", "st", },
- { "svcb", "svc", },
- { "svsb", "svs", },
- { "sfge", "sge", },
- { "sfgt", "sgt", },
- { "sfle", "sle", },
- { "sflt", "slt", },
- { "sfneq", "sne", },
- { "suba", "subaw", },
- { "subi", "subiw", },
- { "subq", "subqw", },
- { "sub", "subw", },
- { "subx", "subxw", },
- { "swapw", "swap", },
- { "tasb", "tas", },
- { "tpcc", "trapcc", },
- { "tcc", "trapcc", },
- { "tst", "tstw", },
- { "jbra", "jra", },
- { "jbhi", "jhi", },
- { "jbls", "jls", },
- { "jbcc", "jcc", },
- { "jbcs", "jcs", },
- { "jbne", "jne", },
- { "jbeq", "jeq", },
- { "jbvc", "jvc", },
- { "jbvs", "jvs", },
- { "jbpl", "jpl", },
- { "jbmi", "jmi", },
- { "jbge", "jge", },
- { "jblt", "jlt", },
- { "jbgt", "jgt", },
- { "jble", "jle", },
- { "movql", "moveq", },
- { "moveql", "moveq", },
- { "movl", "movel", },
- { "movq", "moveq", },
- { "moval", "moveal", },
- { "movaw", "moveaw", },
- { "movb", "moveb", },
- { "movc", "movec", },
- { "movecl", "movec", },
- { "movpl", "movepl", },
- { "movw", "movew", },
- { "movsb", "movesb", },
- { "movsl", "movesl", },
- { "movsw", "movesw", },
- { "mov3q", "mov3ql", },
-
- { "tdivul", "divul", }, /* For m68k-svr4. */
- { "fmovb", "fmoveb", },
- { "fsmovb", "fsmoveb", },
- { "fdmovb", "fdmoveb", },
- { "fmovd", "fmoved", },
- { "fsmovd", "fsmoved", },
- { "fmovl", "fmovel", },
- { "fsmovl", "fsmovel", },
- { "fdmovl", "fdmovel", },
- { "fmovp", "fmovep", },
- { "fsmovp", "fsmovep", },
- { "fdmovp", "fdmovep", },
- { "fmovs", "fmoves", },
- { "fsmovs", "fsmoves", },
- { "fdmovs", "fdmoves", },
- { "fmovw", "fmovew", },
- { "fsmovw", "fsmovew", },
- { "fdmovw", "fdmovew", },
- { "fmovx", "fmovex", },
- { "fsmovx", "fsmovex", },
- { "fdmovx", "fdmovex", },
- { "fmovcr", "fmovecr", },
- { "fmovcrx", "fmovecrx", },
- { "ftestb", "ftstb", },
- { "ftestd", "ftstd", },
- { "ftestl", "ftstl", },
- { "ftestp", "ftstp", },
- { "ftests", "ftsts", },
- { "ftestw", "ftstw", },
- { "ftestx", "ftstx", },
-
- { "bitrevl", "bitrev", },
- { "byterevl", "byterev", },
- { "ff1l", "ff1", },
-
-};
-
-const int m68k_numaliases =
- sizeof m68k_opcode_aliases / sizeof m68k_opcode_aliases[0];
-/* **** End of m68k-opc.c */
-/* **** floatformat.c from sourceware.org CVS 2005-08-14. */
-/* IEEE floating point support routines, for GDB, the GNU Debugger.
- Copyright (C) 1991, 1994, 1999, 2000, 2003 Free Software Foundation, Inc.
-
-This file is part of GDB.
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
-
-/* This is needed to pick up the NAN macro on some systems. */
-//#define _GNU_SOURCE
-
-#ifndef INFINITY
-#ifdef HUGE_VAL
-#define INFINITY HUGE_VAL
-#else
-#define INFINITY (1.0 / 0.0)
-#endif
-#endif
-
-#ifndef NAN
-#define NAN (0.0 / 0.0)
-#endif
-
-static unsigned long get_field (const unsigned char *,
- enum floatformat_byteorders,
- unsigned int,
- unsigned int,
- unsigned int);
-static int floatformat_always_valid (const struct floatformat *fmt,
- const char *from);
-
-static int
-floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED,
- const char *from ATTRIBUTE_UNUSED)
-{
- return 1;
-}
-
-/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not
- going to bother with trying to muck around with whether it is defined in
- a system header, what we do if not, etc. */
-#define FLOATFORMAT_CHAR_BIT 8
-
-/* floatformats for IEEE single and double, big and little endian. */
-const struct floatformat floatformat_ieee_single_big =
-{
- floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23,
- floatformat_intbit_no,
- "floatformat_ieee_single_big",
- floatformat_always_valid
-};
-const struct floatformat floatformat_ieee_single_little =
-{
- floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23,
- floatformat_intbit_no,
- "floatformat_ieee_single_little",
- floatformat_always_valid
-};
-const struct floatformat floatformat_ieee_double_big =
-{
- floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52,
- floatformat_intbit_no,
- "floatformat_ieee_double_big",
- floatformat_always_valid
-};
-const struct floatformat floatformat_ieee_double_little =
-{
- floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52,
- floatformat_intbit_no,
- "floatformat_ieee_double_little",
- floatformat_always_valid
-};
-
-/* floatformat for IEEE double, little endian byte order, with big endian word
- ordering, as on the ARM. */
-
-const struct floatformat floatformat_ieee_double_littlebyte_bigword =
-{
- floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52,
- floatformat_intbit_no,
- "floatformat_ieee_double_littlebyte_bigword",
- floatformat_always_valid
-};
-
-static int floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from);
-
-static int
-floatformat_i387_ext_is_valid (const struct floatformat *fmt, const char *from)
-{
- /* In the i387 double-extended format, if the exponent is all ones,
- then the integer bit must be set. If the exponent is neither 0
- nor ~0, the intbit must also be set. Only if the exponent is
- zero can it be zero, and then it must be zero. */
- unsigned long exponent, int_bit;
- const unsigned char *ufrom = (const unsigned char *) from;
-
- exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
- fmt->exp_start, fmt->exp_len);
- int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize,
- fmt->man_start, 1);
-
- if ((exponent == 0) != (int_bit == 0))
- return 0;
- else
- return 1;
-}
-
-const struct floatformat floatformat_i387_ext =
-{
- floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
- floatformat_intbit_yes,
- "floatformat_i387_ext",
- floatformat_i387_ext_is_valid
-};
-const struct floatformat floatformat_m68881_ext =
-{
- /* Note that the bits from 16 to 31 are unused. */
- floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64,
- floatformat_intbit_yes,
- "floatformat_m68881_ext",
- floatformat_always_valid
-};
-const struct floatformat floatformat_i960_ext =
-{
- /* Note that the bits from 0 to 15 are unused. */
- floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64,
- floatformat_intbit_yes,
- "floatformat_i960_ext",
- floatformat_always_valid
-};
-const struct floatformat floatformat_m88110_ext =
-{
- floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64,
- floatformat_intbit_yes,
- "floatformat_m88110_ext",
- floatformat_always_valid
-};
-const struct floatformat floatformat_m88110_harris_ext =
-{
- /* Harris uses raw format 128 bytes long, but the number is just an ieee
- double, and the last 64 bits are wasted. */
- floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52,
- floatformat_intbit_no,
- "floatformat_m88110_ext_harris",
- floatformat_always_valid
-};
-const struct floatformat floatformat_arm_ext_big =
-{
- /* Bits 1 to 16 are unused. */
- floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
- floatformat_intbit_yes,
- "floatformat_arm_ext_big",
- floatformat_always_valid
-};
-const struct floatformat floatformat_arm_ext_littlebyte_bigword =
-{
- /* Bits 1 to 16 are unused. */
- floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64,
- floatformat_intbit_yes,
- "floatformat_arm_ext_littlebyte_bigword",
- floatformat_always_valid
-};
-const struct floatformat floatformat_ia64_spill_big =
-{
- floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
- floatformat_intbit_yes,
- "floatformat_ia64_spill_big",
- floatformat_always_valid
-};
-const struct floatformat floatformat_ia64_spill_little =
-{
- floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64,
- floatformat_intbit_yes,
- "floatformat_ia64_spill_little",
- floatformat_always_valid
-};
-const struct floatformat floatformat_ia64_quad_big =
-{
- floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
- floatformat_intbit_no,
- "floatformat_ia64_quad_big",
- floatformat_always_valid
-};
-const struct floatformat floatformat_ia64_quad_little =
-{
- floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112,
- floatformat_intbit_no,
- "floatformat_ia64_quad_little",
- floatformat_always_valid
-};
-
-/* Extract a field which starts at START and is LEN bits long. DATA and
- TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
-static unsigned long
-get_field (const unsigned char *data, enum floatformat_byteorders order,
- unsigned int total_len, unsigned int start, unsigned int len)
-{
- unsigned long result;
- unsigned int cur_byte;
- int cur_bitshift;
-
- /* Start at the least significant part of the field. */
- cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little)
- cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
- cur_bitshift =
- ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
- result = *(data + cur_byte) >> (-cur_bitshift);
- cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little)
- ++cur_byte;
- else
- --cur_byte;
-
- /* Move towards the most significant part of the field. */
- while ((unsigned int) cur_bitshift < len)
- {
- if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
- /* This is the last byte; zero out the bits which are not part of
- this field. */
- result |=
- (*(data + cur_byte) & ((1 << (len - cur_bitshift)) - 1))
- << cur_bitshift;
- else
- result |= *(data + cur_byte) << cur_bitshift;
- cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little)
- ++cur_byte;
- else
- --cur_byte;
- }
- return result;
-}
-
-#ifndef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#endif
-
-/* Convert from FMT to a double.
- FROM is the address of the extended float.
- Store the double in *TO. */
-
-void
-floatformat_to_double (const struct floatformat *fmt,
- const char *from, double *to)
-{
- const unsigned char *ufrom = (const unsigned char *)from;
- double dto;
- long exponent;
- unsigned long mant;
- unsigned int mant_bits, mant_off;
- int mant_bits_left;
- int special_exponent; /* It's a NaN, denorm or zero */
-
- exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
- fmt->exp_start, fmt->exp_len);
-
- /* If the exponent indicates a NaN, we don't have information to
- decide what to do. So we handle it like IEEE, except that we
- don't try to preserve the type of NaN. FIXME. */
- if ((unsigned long) exponent == fmt->exp_nan)
- {
- int nan;
-
- mant_off = fmt->man_start;
- mant_bits_left = fmt->man_len;
- nan = 0;
- while (mant_bits_left > 0)
- {
- mant_bits = min (mant_bits_left, 32);
-
- if (get_field (ufrom, fmt->byteorder, fmt->totalsize,
- mant_off, mant_bits) != 0)
- {
- /* This is a NaN. */
- nan = 1;
- break;
- }
-
- mant_off += mant_bits;
- mant_bits_left -= mant_bits;
- }
-
- /* On certain systems (such as GNU/Linux), the use of the
- INFINITY macro below may generate a warning that can not be
- silenced due to a bug in GCC (PR preprocessor/11931). The
- preprocessor fails to recognise the __extension__ keyword in
- conjunction with the GNU/C99 extension for hexadecimal
- floating point constants and will issue a warning when
- compiling with -pedantic. */
- if (nan)
- dto = NAN;
- else
- dto = INFINITY;
-
- if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
- dto = -dto;
-
- *to = dto;
-
- return;
- }
-
- mant_bits_left = fmt->man_len;
- mant_off = fmt->man_start;
- dto = 0.0;
-
- special_exponent = exponent == 0 || (unsigned long) exponent == fmt->exp_nan;
-
- /* Don't bias zero's, denorms or NaNs. */
- if (!special_exponent)
- exponent -= fmt->exp_bias;
-
- /* Build the result algebraically. Might go infinite, underflow, etc;
- who cares. */
-
- /* If this format uses a hidden bit, explicitly add it in now. Otherwise,
- increment the exponent by one to account for the integer bit. */
-
- if (!special_exponent)
- {
- if (fmt->intbit == floatformat_intbit_no)
- dto = ldexp (1.0, exponent);
- else
- exponent++;
- }
-
- while (mant_bits_left > 0)
- {
- mant_bits = min (mant_bits_left, 32);
-
- mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
- mant_off, mant_bits);
-
- /* Handle denormalized numbers. FIXME: What should we do for
- non-IEEE formats? */
- if (exponent == 0 && mant != 0)
- dto += ldexp ((double)mant,
- (- fmt->exp_bias
- - mant_bits
- - (mant_off - fmt->man_start)
- + 1));
- else
- dto += ldexp ((double)mant, exponent - mant_bits);
- if (exponent != 0)
- exponent -= mant_bits;
- mant_off += mant_bits;
- mant_bits_left -= mant_bits;
- }
-
- /* Negate it if negative. */
- if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
- dto = -dto;
- *to = dto;
-}
-
-static void put_field (unsigned char *, enum floatformat_byteorders,
- unsigned int,
- unsigned int,
- unsigned int,
- unsigned long);
-
-/* Set a field which starts at START and is LEN bits long. DATA and
- TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */
-static void
-put_field (unsigned char *data, enum floatformat_byteorders order,
- unsigned int total_len, unsigned int start, unsigned int len,
- unsigned long stuff_to_put)
-{
- unsigned int cur_byte;
- int cur_bitshift;
-
- /* Start at the least significant part of the field. */
- cur_byte = (start + len) / FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little)
- cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) - cur_byte - 1;
- cur_bitshift =
- ((start + len) % FLOATFORMAT_CHAR_BIT) - FLOATFORMAT_CHAR_BIT;
- *(data + cur_byte) &=
- ~(((1 << ((start + len) % FLOATFORMAT_CHAR_BIT)) - 1) << (-cur_bitshift));
- *(data + cur_byte) |=
- (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
- cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little)
- ++cur_byte;
- else
- --cur_byte;
-
- /* Move towards the most significant part of the field. */
- while ((unsigned int) cur_bitshift < len)
- {
- if (len - cur_bitshift < FLOATFORMAT_CHAR_BIT)
- {
- /* This is the last byte. */
- *(data + cur_byte) &=
- ~((1 << (len - cur_bitshift)) - 1);
- *(data + cur_byte) |= (stuff_to_put >> cur_bitshift);
- }
- else
- *(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
- & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
- cur_bitshift += FLOATFORMAT_CHAR_BIT;
- if (order == floatformat_little)
- ++cur_byte;
- else
- --cur_byte;
- }
-}
-
-/* The converse: convert the double *FROM to an extended float
- and store where TO points. Neither FROM nor TO have any alignment
- restrictions. */
-
-void
-floatformat_from_double (const struct floatformat *fmt,
- const double *from, char *to)
-{
- double dfrom;
- int exponent;
- double mant;
- unsigned int mant_bits, mant_off;
- int mant_bits_left;
- unsigned char *uto = (unsigned char *)to;
-
- dfrom = *from;
- memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT);
-
- /* If negative, set the sign bit. */
- if (dfrom < 0)
- {
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
- dfrom = -dfrom;
- }
-
- if (dfrom == 0)
- {
- /* 0.0. */
- return;
- }
-
- if (dfrom != dfrom)
- {
- /* NaN. */
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
- fmt->exp_len, fmt->exp_nan);
- /* Be sure it's not infinity, but NaN value is irrelevant. */
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
- 32, 1);
- return;
- }
-
- if (dfrom + dfrom == dfrom)
- {
- /* This can only happen for an infinite value (or zero, which we
- already handled above). */
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
- fmt->exp_len, fmt->exp_nan);
- return;
- }
-
- mant = frexp (dfrom, &exponent);
- if (exponent + fmt->exp_bias - 1 > 0)
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
- fmt->exp_len, exponent + fmt->exp_bias - 1);
- else
- {
- /* Handle a denormalized number. FIXME: What should we do for
- non-IEEE formats? */
- put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
- fmt->exp_len, 0);
- mant = ldexp (mant, exponent + fmt->exp_bias - 1);
- }
-
- mant_bits_left = fmt->man_len;
- mant_off = fmt->man_start;
- while (mant_bits_left > 0)
- {
- unsigned long mant_long;
- mant_bits = mant_bits_left < 32 ? mant_bits_left : 32;
-
- mant *= 4294967296.0;
- mant_long = (unsigned long)mant;
- mant -= mant_long;
-
- /* If the integer bit is implicit, and we are not creating a
- denormalized number, then we need to discard it. */
- if ((unsigned int) mant_bits_left == fmt->man_len
- && fmt->intbit == floatformat_intbit_no
- && exponent + fmt->exp_bias - 1 > 0)
- {
- mant_long &= 0x7fffffff;
- mant_bits -= 1;
- }
- else if (mant_bits < 32)
- {
- /* The bits we want are in the most significant MANT_BITS bits of
- mant_long. Move them to the least significant. */
- mant_long >>= 32 - mant_bits;
- }
-
- put_field (uto, fmt->byteorder, fmt->totalsize,
- mant_off, mant_bits, mant_long);
- mant_off += mant_bits;
- mant_bits_left -= mant_bits;
- }
-}
-
-/* Return non-zero iff the data at FROM is a valid number in format FMT. */
-
-int
-floatformat_is_valid (const struct floatformat *fmt, const char *from)
-{
- return fmt->is_valid (fmt, from);
-}
-
-
-#ifdef IEEE_DEBUG
-
-/* This is to be run on a host which uses IEEE floating point. */
-
-void
-ieee_test (double n)
-{
- double result;
-
- floatformat_to_double (&floatformat_ieee_double_little, (char *) &n,
- &result);
- if ((n != result && (! isnan (n) || ! isnan (result)))
- || (n < 0 && result >= 0)
- || (n >= 0 && result < 0))
- printf ("Differ(to): %.20g -> %.20g\n", n, result);
-
- floatformat_from_double (&floatformat_ieee_double_little, &n,
- (char *) &result);
- if ((n != result && (! isnan (n) || ! isnan (result)))
- || (n < 0 && result >= 0)
- || (n >= 0 && result < 0))
- printf ("Differ(from): %.20g -> %.20g\n", n, result);
-
-#if 0
- {
- char exten[16];
-
- floatformat_from_double (&floatformat_m68881_ext, &n, exten);
- floatformat_to_double (&floatformat_m68881_ext, exten, &result);
- if (n != result)
- printf ("Differ(to+from): %.20g -> %.20g\n", n, result);
- }
-#endif
-
-#if IEEE_DEBUG > 1
- /* This is to be run on a host which uses 68881 format. */
- {
- long double ex = *(long double *)exten;
- if (ex != n)
- printf ("Differ(from vs. extended): %.20g\n", n);
- }
-#endif
-}
-
-int
-main (void)
-{
- ieee_test (0.0);
- ieee_test (0.5);
- ieee_test (256.0);
- ieee_test (0.12345);
- ieee_test (234235.78907234);
- ieee_test (-512.0);
- ieee_test (-0.004321);
- ieee_test (1.2E-70);
- ieee_test (1.2E-316);
- ieee_test (4.9406564584124654E-324);
- ieee_test (- 4.9406564584124654E-324);
- ieee_test (- 0.0);
- ieee_test (- INFINITY);
- ieee_test (- NAN);
- ieee_test (INFINITY);
- ieee_test (NAN);
- return 0;
-}
-#endif
-/* **** End of floatformat.c */
diff --git a/mips-dis.c b/mips-dis.c
deleted file mode 100644
index 2e7dc85..0000000
--- a/mips-dis.c
+++ /dev/null
@@ -1,3999 +0,0 @@
-/* Print mips instructions for GDB, the GNU debugger, or for objdump.
- Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003
- Free Software Foundation, Inc.
- Contributed by Nobuyuki Hikichi(hikichi@sra.co.jp).
-
-This file is part of GDB, GAS, and the GNU binutils.
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "dis-asm.h"
-
-/* mips.h. Mips opcode list for GDB, the GNU debugger.
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- Free Software Foundation, Inc.
- Contributed by Ralph Campbell and OSF
- Commented and modified by Ian Lance Taylor, Cygnus Support
-
-This file is part of GDB, GAS, and the GNU binutils.
-
-GDB, GAS, and the GNU binutils are free software; you can redistribute
-them and/or modify them under the terms of the GNU General Public
-License as published by the Free Software Foundation; either version
-1, or (at your option) any later version.
-
-GDB, GAS, and the GNU binutils are distributed in the hope that they
-will be useful, but WITHOUT ANY WARRANTY; without even the implied
-warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
-the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this file; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* mips.h. Mips opcode list for GDB, the GNU debugger.
- Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- Free Software Foundation, Inc.
- Contributed by Ralph Campbell and OSF
- Commented and modified by Ian Lance Taylor, Cygnus Support
-
-This file is part of GDB, GAS, and the GNU binutils.
-
-GDB, GAS, and the GNU binutils are free software; you can redistribute
-them and/or modify them under the terms of the GNU General Public
-License as published by the Free Software Foundation; either version
-1, or (at your option) any later version.
-
-GDB, GAS, and the GNU binutils are distributed in the hope that they
-will be useful, but WITHOUT ANY WARRANTY; without even the implied
-warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
-the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this file; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* These are bit masks and shift counts to use to access the various
- fields of an instruction. To retrieve the X field of an
- instruction, use the expression
- (i >> OP_SH_X) & OP_MASK_X
- To set the same field (to j), use
- i = (i &~ (OP_MASK_X << OP_SH_X)) | (j << OP_SH_X)
-
- Make sure you use fields that are appropriate for the instruction,
- of course.
-
- The 'i' format uses OP, RS, RT and IMMEDIATE.
-
- The 'j' format uses OP and TARGET.
-
- The 'r' format uses OP, RS, RT, RD, SHAMT and FUNCT.
-
- The 'b' format uses OP, RS, RT and DELTA.
-
- The floating point 'i' format uses OP, RS, RT and IMMEDIATE.
-
- The floating point 'r' format uses OP, FMT, FT, FS, FD and FUNCT.
-
- A breakpoint instruction uses OP, CODE and SPEC (10 bits of the
- breakpoint instruction are not defined; Kane says the breakpoint
- code field in BREAK is 20 bits; yet MIPS assemblers and debuggers
- only use ten bits). An optional two-operand form of break/sdbbp
- allows the lower ten bits to be set too, and MIPS32 and later
- architectures allow 20 bits to be set with a signal operand
- (using CODE20).
-
- The syscall instruction uses CODE20.
-
- The general coprocessor instructions use COPZ. */
-
-#define OP_MASK_OP 0x3f
-#define OP_SH_OP 26
-#define OP_MASK_RS 0x1f
-#define OP_SH_RS 21
-#define OP_MASK_FR 0x1f
-#define OP_SH_FR 21
-#define OP_MASK_FMT 0x1f
-#define OP_SH_FMT 21
-#define OP_MASK_BCC 0x7
-#define OP_SH_BCC 18
-#define OP_MASK_CODE 0x3ff
-#define OP_SH_CODE 16
-#define OP_MASK_CODE2 0x3ff
-#define OP_SH_CODE2 6
-#define OP_MASK_RT 0x1f
-#define OP_SH_RT 16
-#define OP_MASK_FT 0x1f
-#define OP_SH_FT 16
-#define OP_MASK_CACHE 0x1f
-#define OP_SH_CACHE 16
-#define OP_MASK_RD 0x1f
-#define OP_SH_RD 11
-#define OP_MASK_FS 0x1f
-#define OP_SH_FS 11
-#define OP_MASK_PREFX 0x1f
-#define OP_SH_PREFX 11
-#define OP_MASK_CCC 0x7
-#define OP_SH_CCC 8
-#define OP_MASK_CODE20 0xfffff /* 20 bit syscall/breakpoint code. */
-#define OP_SH_CODE20 6
-#define OP_MASK_SHAMT 0x1f
-#define OP_SH_SHAMT 6
-#define OP_MASK_FD 0x1f
-#define OP_SH_FD 6
-#define OP_MASK_TARGET 0x3ffffff
-#define OP_SH_TARGET 0
-#define OP_MASK_COPZ 0x1ffffff
-#define OP_SH_COPZ 0
-#define OP_MASK_IMMEDIATE 0xffff
-#define OP_SH_IMMEDIATE 0
-#define OP_MASK_DELTA 0xffff
-#define OP_SH_DELTA 0
-#define OP_MASK_FUNCT 0x3f
-#define OP_SH_FUNCT 0
-#define OP_MASK_SPEC 0x3f
-#define OP_SH_SPEC 0
-#define OP_SH_LOCC 8 /* FP condition code. */
-#define OP_SH_HICC 18 /* FP condition code. */
-#define OP_MASK_CC 0x7
-#define OP_SH_COP1NORM 25 /* Normal COP1 encoding. */
-#define OP_MASK_COP1NORM 0x1 /* a single bit. */
-#define OP_SH_COP1SPEC 21 /* COP1 encodings. */
-#define OP_MASK_COP1SPEC 0xf
-#define OP_MASK_COP1SCLR 0x4
-#define OP_MASK_COP1CMP 0x3
-#define OP_SH_COP1CMP 4
-#define OP_SH_FORMAT 21 /* FP short format field. */
-#define OP_MASK_FORMAT 0x7
-#define OP_SH_TRUE 16
-#define OP_MASK_TRUE 0x1
-#define OP_SH_GE 17
-#define OP_MASK_GE 0x01
-#define OP_SH_UNSIGNED 16
-#define OP_MASK_UNSIGNED 0x1
-#define OP_SH_HINT 16
-#define OP_MASK_HINT 0x1f
-#define OP_SH_MMI 0 /* Multimedia (parallel) op. */
-#define OP_MASK_MMI 0x3f
-#define OP_SH_MMISUB 6
-#define OP_MASK_MMISUB 0x1f
-#define OP_MASK_PERFREG 0x1f /* Performance monitoring. */
-#define OP_SH_PERFREG 1
-#define OP_SH_SEL 0 /* Coprocessor select field. */
-#define OP_MASK_SEL 0x7 /* The sel field of mfcZ and mtcZ. */
-#define OP_SH_CODE19 6 /* 19 bit wait code. */
-#define OP_MASK_CODE19 0x7ffff
-#define OP_SH_ALN 21
-#define OP_MASK_ALN 0x7
-#define OP_SH_VSEL 21
-#define OP_MASK_VSEL 0x1f
-#define OP_MASK_VECBYTE 0x7 /* Selector field is really 4 bits,
- but 0x8-0xf don't select bytes. */
-#define OP_SH_VECBYTE 22
-#define OP_MASK_VECALIGN 0x7 /* Vector byte-align (alni.ob) op. */
-#define OP_SH_VECALIGN 21
-#define OP_MASK_INSMSB 0x1f /* "ins" MSB. */
-#define OP_SH_INSMSB 11
-#define OP_MASK_EXTMSBD 0x1f /* "ext" MSBD. */
-#define OP_SH_EXTMSBD 11
-
-#define OP_OP_COP0 0x10
-#define OP_OP_COP1 0x11
-#define OP_OP_COP2 0x12
-#define OP_OP_COP3 0x13
-#define OP_OP_LWC1 0x31
-#define OP_OP_LWC2 0x32
-#define OP_OP_LWC3 0x33 /* a.k.a. pref */
-#define OP_OP_LDC1 0x35
-#define OP_OP_LDC2 0x36
-#define OP_OP_LDC3 0x37 /* a.k.a. ld */
-#define OP_OP_SWC1 0x39
-#define OP_OP_SWC2 0x3a
-#define OP_OP_SWC3 0x3b
-#define OP_OP_SDC1 0x3d
-#define OP_OP_SDC2 0x3e
-#define OP_OP_SDC3 0x3f /* a.k.a. sd */
-
-/* Values in the 'VSEL' field. */
-#define MDMX_FMTSEL_IMM_QH 0x1d
-#define MDMX_FMTSEL_IMM_OB 0x1e
-#define MDMX_FMTSEL_VEC_QH 0x15
-#define MDMX_FMTSEL_VEC_OB 0x16
-
-/* This structure holds information for a particular instruction. */
-
-struct mips_opcode
-{
- /* The name of the instruction. */
- const char *name;
- /* A string describing the arguments for this instruction. */
- const char *args;
- /* The basic opcode for the instruction. When assembling, this
- opcode is modified by the arguments to produce the actual opcode
- that is used. If pinfo is INSN_MACRO, then this is 0. */
- unsigned long match;
- /* If pinfo is not INSN_MACRO, then this is a bit mask for the
- relevant portions of the opcode when disassembling. If the
- actual opcode anded with the match field equals the opcode field,
- then we have found the correct instruction. If pinfo is
- INSN_MACRO, then this field is the macro identifier. */
- unsigned long mask;
- /* For a macro, this is INSN_MACRO. Otherwise, it is a collection
- of bits describing the instruction, notably any relevant hazard
- information. */
- unsigned long pinfo;
- /* A collection of bits describing the instruction sets of which this
- instruction or macro is a member. */
- unsigned long membership;
-};
-
-/* These are the characters which may appear in the args field of an
- instruction. They appear in the order in which the fields appear
- when the instruction is used. Commas and parentheses in the args
- string are ignored when assembling, and written into the output
- when disassembling.
-
- Each of these characters corresponds to a mask field defined above.
-
- "<" 5 bit shift amount (OP_*_SHAMT)
- ">" shift amount between 32 and 63, stored after subtracting 32 (OP_*_SHAMT)
- "a" 26 bit target address (OP_*_TARGET)
- "b" 5 bit base register (OP_*_RS)
- "c" 10 bit breakpoint code (OP_*_CODE)
- "d" 5 bit destination register specifier (OP_*_RD)
- "h" 5 bit prefx hint (OP_*_PREFX)
- "i" 16 bit unsigned immediate (OP_*_IMMEDIATE)
- "j" 16 bit signed immediate (OP_*_DELTA)
- "k" 5 bit cache opcode in target register position (OP_*_CACHE)
- Also used for immediate operands in vr5400 vector insns.
- "o" 16 bit signed offset (OP_*_DELTA)
- "p" 16 bit PC relative branch target address (OP_*_DELTA)
- "q" 10 bit extra breakpoint code (OP_*_CODE2)
- "r" 5 bit same register used as both source and target (OP_*_RS)
- "s" 5 bit source register specifier (OP_*_RS)
- "t" 5 bit target register (OP_*_RT)
- "u" 16 bit upper 16 bits of address (OP_*_IMMEDIATE)
- "v" 5 bit same register used as both source and destination (OP_*_RS)
- "w" 5 bit same register used as both target and destination (OP_*_RT)
- "U" 5 bit same destination register in both OP_*_RD and OP_*_RT
- (used by clo and clz)
- "C" 25 bit coprocessor function code (OP_*_COPZ)
- "B" 20 bit syscall/breakpoint function code (OP_*_CODE20)
- "J" 19 bit wait function code (OP_*_CODE19)
- "x" accept and ignore register name
- "z" must be zero register
- "K" 5 bit Hardware Register (rdhwr instruction) (OP_*_RD)
- "+A" 5 bit ins/ext position, which becomes LSB (OP_*_SHAMT).
- Enforces: 0 <= pos < 32.
- "+B" 5 bit ins size, which becomes MSB (OP_*_INSMSB).
- Requires that "+A" or "+E" occur first to set position.
- Enforces: 0 < (pos+size) <= 32.
- "+C" 5 bit ext size, which becomes MSBD (OP_*_EXTMSBD).
- Requires that "+A" or "+E" occur first to set position.
- Enforces: 0 < (pos+size) <= 32.
- (Also used by "dext" w/ different limits, but limits for
- that are checked by the M_DEXT macro.)
- "+E" 5 bit dins/dext position, which becomes LSB-32 (OP_*_SHAMT).
- Enforces: 32 <= pos < 64.
- "+F" 5 bit "dinsm" size, which becomes MSB-32 (OP_*_INSMSB).
- Requires that "+A" or "+E" occur first to set position.
- Enforces: 32 < (pos+size) <= 64.
- "+G" 5 bit "dextm" size, which becomes MSBD-32 (OP_*_EXTMSBD).
- Requires that "+A" or "+E" occur first to set position.
- Enforces: 32 < (pos+size) <= 64.
- "+H" 5 bit "dextu" size, which becomes MSBD (OP_*_EXTMSBD).
- Requires that "+A" or "+E" occur first to set position.
- Enforces: 32 < (pos+size) <= 64.
-
- Floating point instructions:
- "D" 5 bit destination register (OP_*_FD)
- "M" 3 bit compare condition code (OP_*_CCC) (only used for mips4 and up)
- "N" 3 bit branch condition code (OP_*_BCC) (only used for mips4 and up)
- "S" 5 bit fs source 1 register (OP_*_FS)
- "T" 5 bit ft source 2 register (OP_*_FT)
- "R" 5 bit fr source 3 register (OP_*_FR)
- "V" 5 bit same register used as floating source and destination (OP_*_FS)
- "W" 5 bit same register used as floating target and destination (OP_*_FT)
-
- Coprocessor instructions:
- "E" 5 bit target register (OP_*_RT)
- "G" 5 bit destination register (OP_*_RD)
- "H" 3 bit sel field for (d)mtc* and (d)mfc* (OP_*_SEL)
- "P" 5 bit performance-monitor register (OP_*_PERFREG)
- "e" 5 bit vector register byte specifier (OP_*_VECBYTE)
- "%" 3 bit immediate vr5400 vector alignment operand (OP_*_VECALIGN)
- see also "k" above
- "+D" Combined destination register ("G") and sel ("H") for CP0 ops,
- for pretty-printing in disassembly only.
-
- Macro instructions:
- "A" General 32 bit expression
- "I" 32 bit immediate (value placed in imm_expr).
- "+I" 32 bit immediate (value placed in imm2_expr).
- "F" 64 bit floating point constant in .rdata
- "L" 64 bit floating point constant in .lit8
- "f" 32 bit floating point constant
- "l" 32 bit floating point constant in .lit4
-
- MDMX instruction operands (note that while these use the FP register
- fields, they accept both $fN and $vN names for the registers):
- "O" MDMX alignment offset (OP_*_ALN)
- "Q" MDMX vector/scalar/immediate source (OP_*_VSEL and OP_*_FT)
- "X" MDMX destination register (OP_*_FD)
- "Y" MDMX source register (OP_*_FS)
- "Z" MDMX source register (OP_*_FT)
-
- Other:
- "()" parens surrounding optional value
- "," separates operands
- "[]" brackets around index for vector-op scalar operand specifier (vr5400)
- "+" Start of extension sequence.
-
- Characters used so far, for quick reference when adding more:
- "%[]<>(),+"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefhijklopqrstuvwxz"
-
- Extension character sequences used so far ("+" followed by the
- following), for quick reference when adding more:
- "ABCDEFGHI"
-*/
-
-/* These are the bits which may be set in the pinfo field of an
- instructions, if it is not equal to INSN_MACRO. */
-
-/* Modifies the general purpose register in OP_*_RD. */
-#define INSN_WRITE_GPR_D 0x00000001
-/* Modifies the general purpose register in OP_*_RT. */
-#define INSN_WRITE_GPR_T 0x00000002
-/* Modifies general purpose register 31. */
-#define INSN_WRITE_GPR_31 0x00000004
-/* Modifies the floating point register in OP_*_FD. */
-#define INSN_WRITE_FPR_D 0x00000008
-/* Modifies the floating point register in OP_*_FS. */
-#define INSN_WRITE_FPR_S 0x00000010
-/* Modifies the floating point register in OP_*_FT. */
-#define INSN_WRITE_FPR_T 0x00000020
-/* Reads the general purpose register in OP_*_RS. */
-#define INSN_READ_GPR_S 0x00000040
-/* Reads the general purpose register in OP_*_RT. */
-#define INSN_READ_GPR_T 0x00000080
-/* Reads the floating point register in OP_*_FS. */
-#define INSN_READ_FPR_S 0x00000100
-/* Reads the floating point register in OP_*_FT. */
-#define INSN_READ_FPR_T 0x00000200
-/* Reads the floating point register in OP_*_FR. */
-#define INSN_READ_FPR_R 0x00000400
-/* Modifies coprocessor condition code. */
-#define INSN_WRITE_COND_CODE 0x00000800
-/* Reads coprocessor condition code. */
-#define INSN_READ_COND_CODE 0x00001000
-/* TLB operation. */
-#define INSN_TLB 0x00002000
-/* Reads coprocessor register other than floating point register. */
-#define INSN_COP 0x00004000
-/* Instruction loads value from memory, requiring delay. */
-#define INSN_LOAD_MEMORY_DELAY 0x00008000
-/* Instruction loads value from coprocessor, requiring delay. */
-#define INSN_LOAD_COPROC_DELAY 0x00010000
-/* Instruction has unconditional branch delay slot. */
-#define INSN_UNCOND_BRANCH_DELAY 0x00020000
-/* Instruction has conditional branch delay slot. */
-#define INSN_COND_BRANCH_DELAY 0x00040000
-/* Conditional branch likely: if branch not taken, insn nullified. */
-#define INSN_COND_BRANCH_LIKELY 0x00080000
-/* Moves to coprocessor register, requiring delay. */
-#define INSN_COPROC_MOVE_DELAY 0x00100000
-/* Loads coprocessor register from memory, requiring delay. */
-#define INSN_COPROC_MEMORY_DELAY 0x00200000
-/* Reads the HI register. */
-#define INSN_READ_HI 0x00400000
-/* Reads the LO register. */
-#define INSN_READ_LO 0x00800000
-/* Modifies the HI register. */
-#define INSN_WRITE_HI 0x01000000
-/* Modifies the LO register. */
-#define INSN_WRITE_LO 0x02000000
-/* Takes a trap (easier to keep out of delay slot). */
-#define INSN_TRAP 0x04000000
-/* Instruction stores value into memory. */
-#define INSN_STORE_MEMORY 0x08000000
-/* Instruction uses single precision floating point. */
-#define FP_S 0x10000000
-/* Instruction uses double precision floating point. */
-#define FP_D 0x20000000
-/* Instruction is part of the tx39's integer multiply family. */
-#define INSN_MULT 0x40000000
-/* Instruction synchronize shared memory. */
-#define INSN_SYNC 0x80000000
-/* Instruction reads MDMX accumulator. XXX FIXME: No bits left! */
-#define INSN_READ_MDMX_ACC 0
-/* Instruction writes MDMX accumulator. XXX FIXME: No bits left! */
-#define INSN_WRITE_MDMX_ACC 0
-
-/* Instruction is actually a macro. It should be ignored by the
- disassembler, and requires special treatment by the assembler. */
-#define INSN_MACRO 0xffffffff
-
-/* Masks used to mark instructions to indicate which MIPS ISA level
- they were introduced in. ISAs, as defined below, are logical
- ORs of these bits, indicating that they support the instructions
- defined at the given level. */
-
-#define INSN_ISA_MASK 0x00000fff
-#define INSN_ISA1 0x00000001
-#define INSN_ISA2 0x00000002
-#define INSN_ISA3 0x00000004
-#define INSN_ISA4 0x00000008
-#define INSN_ISA5 0x00000010
-#define INSN_ISA32 0x00000020
-#define INSN_ISA64 0x00000040
-#define INSN_ISA32R2 0x00000080
-#define INSN_ISA64R2 0x00000100
-
-/* Masks used for MIPS-defined ASEs. */
-#define INSN_ASE_MASK 0x0000f000
-
-/* MIPS 16 ASE */
-#define INSN_MIPS16 0x00002000
-/* MIPS-3D ASE */
-#define INSN_MIPS3D 0x00004000
-/* MDMX ASE */
-#define INSN_MDMX 0x00008000
-
-/* Chip specific instructions. These are bitmasks. */
-
-/* MIPS R4650 instruction. */
-#define INSN_4650 0x00010000
-/* LSI R4010 instruction. */
-#define INSN_4010 0x00020000
-/* NEC VR4100 instruction. */
-#define INSN_4100 0x00040000
-/* Toshiba R3900 instruction. */
-#define INSN_3900 0x00080000
-/* MIPS R10000 instruction. */
-#define INSN_10000 0x00100000
-/* Broadcom SB-1 instruction. */
-#define INSN_SB1 0x00200000
-/* NEC VR4111/VR4181 instruction. */
-#define INSN_4111 0x00400000
-/* NEC VR4120 instruction. */
-#define INSN_4120 0x00800000
-/* NEC VR5400 instruction. */
-#define INSN_5400 0x01000000
-/* NEC VR5500 instruction. */
-#define INSN_5500 0x02000000
-
-/* MIPS ISA defines, use instead of hardcoding ISA level. */
-
-#define ISA_UNKNOWN 0 /* Gas internal use. */
-#define ISA_MIPS1 (INSN_ISA1)
-#define ISA_MIPS2 (ISA_MIPS1 | INSN_ISA2)
-#define ISA_MIPS3 (ISA_MIPS2 | INSN_ISA3)
-#define ISA_MIPS4 (ISA_MIPS3 | INSN_ISA4)
-#define ISA_MIPS5 (ISA_MIPS4 | INSN_ISA5)
-
-#define ISA_MIPS32 (ISA_MIPS2 | INSN_ISA32)
-#define ISA_MIPS64 (ISA_MIPS5 | INSN_ISA32 | INSN_ISA64)
-
-#define ISA_MIPS32R2 (ISA_MIPS32 | INSN_ISA32R2)
-#define ISA_MIPS64R2 (ISA_MIPS64 | INSN_ISA32R2 | INSN_ISA64R2)
-
-
-/* CPU defines, use instead of hardcoding processor number. Keep this
- in sync with bfd/archures.c in order for machine selection to work. */
-#define CPU_UNKNOWN 0 /* Gas internal use. */
-#define CPU_R3000 3000
-#define CPU_R3900 3900
-#define CPU_R4000 4000
-#define CPU_R4010 4010
-#define CPU_VR4100 4100
-#define CPU_R4111 4111
-#define CPU_VR4120 4120
-#define CPU_R4300 4300
-#define CPU_R4400 4400
-#define CPU_R4600 4600
-#define CPU_R4650 4650
-#define CPU_R5000 5000
-#define CPU_VR5400 5400
-#define CPU_VR5500 5500
-#define CPU_R6000 6000
-#define CPU_RM7000 7000
-#define CPU_R8000 8000
-#define CPU_R10000 10000
-#define CPU_R12000 12000
-#define CPU_MIPS16 16
-#define CPU_MIPS32 32
-#define CPU_MIPS32R2 33
-#define CPU_MIPS5 5
-#define CPU_MIPS64 64
-#define CPU_MIPS64R2 65
-#define CPU_SB1 12310201 /* octal 'SB', 01. */
-
-/* Test for membership in an ISA including chip specific ISAs. INSN
- is pointer to an element of the opcode table; ISA is the specified
- ISA/ASE bitmask to test against; and CPU is the CPU specific ISA to
- test, or zero if no CPU specific ISA test is desired. */
-
-#if 0
-#define OPCODE_IS_MEMBER(insn, isa, cpu) \
- (((insn)->membership & isa) != 0 \
- || (cpu == CPU_R4650 && ((insn)->membership & INSN_4650) != 0) \
- || (cpu == CPU_RM7000 && ((insn)->membership & INSN_4650) != 0) \
- || (cpu == CPU_R4010 && ((insn)->membership & INSN_4010) != 0) \
- || (cpu == CPU_VR4100 && ((insn)->membership & INSN_4100) != 0) \
- || (cpu == CPU_R3900 && ((insn)->membership & INSN_3900) != 0) \
- || ((cpu == CPU_R10000 || cpu == CPU_R12000) \
- && ((insn)->membership & INSN_10000) != 0) \
- || (cpu == CPU_SB1 && ((insn)->membership & INSN_SB1) != 0) \
- || (cpu == CPU_R4111 && ((insn)->membership & INSN_4111) != 0) \
- || (cpu == CPU_VR4120 && ((insn)->membership & INSN_4120) != 0) \
- || (cpu == CPU_VR5400 && ((insn)->membership & INSN_5400) != 0) \
- || (cpu == CPU_VR5500 && ((insn)->membership & INSN_5500) != 0) \
- || 0) /* Please keep this term for easier source merging. */
-#else
-#define OPCODE_IS_MEMBER(insn, isa, cpu) \
- (1 != 0)
-#endif
-
-/* This is a list of macro expanded instructions.
-
- _I appended means immediate
- _A appended means address
- _AB appended means address with base register
- _D appended means 64 bit floating point constant
- _S appended means 32 bit floating point constant. */
-
-enum
-{
- M_ABS,
- M_ADD_I,
- M_ADDU_I,
- M_AND_I,
- M_BEQ,
- M_BEQ_I,
- M_BEQL_I,
- M_BGE,
- M_BGEL,
- M_BGE_I,
- M_BGEL_I,
- M_BGEU,
- M_BGEUL,
- M_BGEU_I,
- M_BGEUL_I,
- M_BGT,
- M_BGTL,
- M_BGT_I,
- M_BGTL_I,
- M_BGTU,
- M_BGTUL,
- M_BGTU_I,
- M_BGTUL_I,
- M_BLE,
- M_BLEL,
- M_BLE_I,
- M_BLEL_I,
- M_BLEU,
- M_BLEUL,
- M_BLEU_I,
- M_BLEUL_I,
- M_BLT,
- M_BLTL,
- M_BLT_I,
- M_BLTL_I,
- M_BLTU,
- M_BLTUL,
- M_BLTU_I,
- M_BLTUL_I,
- M_BNE,
- M_BNE_I,
- M_BNEL_I,
- M_DABS,
- M_DADD_I,
- M_DADDU_I,
- M_DDIV_3,
- M_DDIV_3I,
- M_DDIVU_3,
- M_DDIVU_3I,
- M_DEXT,
- M_DINS,
- M_DIV_3,
- M_DIV_3I,
- M_DIVU_3,
- M_DIVU_3I,
- M_DLA_AB,
- M_DLCA_AB,
- M_DLI,
- M_DMUL,
- M_DMUL_I,
- M_DMULO,
- M_DMULO_I,
- M_DMULOU,
- M_DMULOU_I,
- M_DREM_3,
- M_DREM_3I,
- M_DREMU_3,
- M_DREMU_3I,
- M_DSUB_I,
- M_DSUBU_I,
- M_DSUBU_I_2,
- M_J_A,
- M_JAL_1,
- M_JAL_2,
- M_JAL_A,
- M_L_DOB,
- M_L_DAB,
- M_LA_AB,
- M_LB_A,
- M_LB_AB,
- M_LBU_A,
- M_LBU_AB,
- M_LCA_AB,
- M_LD_A,
- M_LD_OB,
- M_LD_AB,
- M_LDC1_AB,
- M_LDC2_AB,
- M_LDC3_AB,
- M_LDL_AB,
- M_LDR_AB,
- M_LH_A,
- M_LH_AB,
- M_LHU_A,
- M_LHU_AB,
- M_LI,
- M_LI_D,
- M_LI_DD,
- M_LI_S,
- M_LI_SS,
- M_LL_AB,
- M_LLD_AB,
- M_LS_A,
- M_LW_A,
- M_LW_AB,
- M_LWC0_A,
- M_LWC0_AB,
- M_LWC1_A,
- M_LWC1_AB,
- M_LWC2_A,
- M_LWC2_AB,
- M_LWC3_A,
- M_LWC3_AB,
- M_LWL_A,
- M_LWL_AB,
- M_LWR_A,
- M_LWR_AB,
- M_LWU_AB,
- M_MOVE,
- M_MUL,
- M_MUL_I,
- M_MULO,
- M_MULO_I,
- M_MULOU,
- M_MULOU_I,
- M_NOR_I,
- M_OR_I,
- M_REM_3,
- M_REM_3I,
- M_REMU_3,
- M_REMU_3I,
- M_DROL,
- M_ROL,
- M_DROL_I,
- M_ROL_I,
- M_DROR,
- M_ROR,
- M_DROR_I,
- M_ROR_I,
- M_S_DA,
- M_S_DOB,
- M_S_DAB,
- M_S_S,
- M_SC_AB,
- M_SCD_AB,
- M_SD_A,
- M_SD_OB,
- M_SD_AB,
- M_SDC1_AB,
- M_SDC2_AB,
- M_SDC3_AB,
- M_SDL_AB,
- M_SDR_AB,
- M_SEQ,
- M_SEQ_I,
- M_SGE,
- M_SGE_I,
- M_SGEU,
- M_SGEU_I,
- M_SGT,
- M_SGT_I,
- M_SGTU,
- M_SGTU_I,
- M_SLE,
- M_SLE_I,
- M_SLEU,
- M_SLEU_I,
- M_SLT_I,
- M_SLTU_I,
- M_SNE,
- M_SNE_I,
- M_SB_A,
- M_SB_AB,
- M_SH_A,
- M_SH_AB,
- M_SW_A,
- M_SW_AB,
- M_SWC0_A,
- M_SWC0_AB,
- M_SWC1_A,
- M_SWC1_AB,
- M_SWC2_A,
- M_SWC2_AB,
- M_SWC3_A,
- M_SWC3_AB,
- M_SWL_A,
- M_SWL_AB,
- M_SWR_A,
- M_SWR_AB,
- M_SUB_I,
- M_SUBU_I,
- M_SUBU_I_2,
- M_TEQ_I,
- M_TGE_I,
- M_TGEU_I,
- M_TLT_I,
- M_TLTU_I,
- M_TNE_I,
- M_TRUNCWD,
- M_TRUNCWS,
- M_ULD,
- M_ULD_A,
- M_ULH,
- M_ULH_A,
- M_ULHU,
- M_ULHU_A,
- M_ULW,
- M_ULW_A,
- M_USH,
- M_USH_A,
- M_USW,
- M_USW_A,
- M_USD,
- M_USD_A,
- M_XOR_I,
- M_COP0,
- M_COP1,
- M_COP2,
- M_COP3,
- M_NUM_MACROS
-};
-
-
-/* The order of overloaded instructions matters. Label arguments and
- register arguments look the same. Instructions that can have either
- for arguments must apear in the correct order in this table for the
- assembler to pick the right one. In other words, entries with
- immediate operands must apear after the same instruction with
- registers.
-
- Many instructions are short hand for other instructions (i.e., The
- jal <register> instruction is short for jalr <register>). */
-
-extern const struct mips_opcode mips_builtin_opcodes[];
-extern const int bfd_mips_num_builtin_opcodes;
-extern struct mips_opcode *mips_opcodes;
-extern int bfd_mips_num_opcodes;
-#define NUMOPCODES bfd_mips_num_opcodes
-
-
-/* The rest of this file adds definitions for the mips16 TinyRISC
- processor. */
-
-/* These are the bitmasks and shift counts used for the different
- fields in the instruction formats. Other than OP, no masks are
- provided for the fixed portions of an instruction, since they are
- not needed.
-
- The I format uses IMM11.
-
- The RI format uses RX and IMM8.
-
- The RR format uses RX, and RY.
-
- The RRI format uses RX, RY, and IMM5.
-
- The RRR format uses RX, RY, and RZ.
-
- The RRI_A format uses RX, RY, and IMM4.
-
- The SHIFT format uses RX, RY, and SHAMT.
-
- The I8 format uses IMM8.
-
- The I8_MOVR32 format uses RY and REGR32.
-
- The IR_MOV32R format uses REG32R and MOV32Z.
-
- The I64 format uses IMM8.
-
- The RI64 format uses RY and IMM5.
- */
-
-#define MIPS16OP_MASK_OP 0x1f
-#define MIPS16OP_SH_OP 11
-#define MIPS16OP_MASK_IMM11 0x7ff
-#define MIPS16OP_SH_IMM11 0
-#define MIPS16OP_MASK_RX 0x7
-#define MIPS16OP_SH_RX 8
-#define MIPS16OP_MASK_IMM8 0xff
-#define MIPS16OP_SH_IMM8 0
-#define MIPS16OP_MASK_RY 0x7
-#define MIPS16OP_SH_RY 5
-#define MIPS16OP_MASK_IMM5 0x1f
-#define MIPS16OP_SH_IMM5 0
-#define MIPS16OP_MASK_RZ 0x7
-#define MIPS16OP_SH_RZ 2
-#define MIPS16OP_MASK_IMM4 0xf
-#define MIPS16OP_SH_IMM4 0
-#define MIPS16OP_MASK_REGR32 0x1f
-#define MIPS16OP_SH_REGR32 0
-#define MIPS16OP_MASK_REG32R 0x1f
-#define MIPS16OP_SH_REG32R 3
-#define MIPS16OP_EXTRACT_REG32R(i) ((((i) >> 5) & 7) | ((i) & 0x18))
-#define MIPS16OP_MASK_MOVE32Z 0x7
-#define MIPS16OP_SH_MOVE32Z 0
-#define MIPS16OP_MASK_IMM6 0x3f
-#define MIPS16OP_SH_IMM6 5
-
-/* These are the characters which may appears in the args field of an
- instruction. They appear in the order in which the fields appear
- when the instruction is used. Commas and parentheses in the args
- string are ignored when assembling, and written into the output
- when disassembling.
-
- "y" 3 bit register (MIPS16OP_*_RY)
- "x" 3 bit register (MIPS16OP_*_RX)
- "z" 3 bit register (MIPS16OP_*_RZ)
- "Z" 3 bit register (MIPS16OP_*_MOVE32Z)
- "v" 3 bit same register as source and destination (MIPS16OP_*_RX)
- "w" 3 bit same register as source and destination (MIPS16OP_*_RY)
- "0" zero register ($0)
- "S" stack pointer ($sp or $29)
- "P" program counter
- "R" return address register ($ra or $31)
- "X" 5 bit MIPS register (MIPS16OP_*_REGR32)
- "Y" 5 bit MIPS register (MIPS16OP_*_REG32R)
- "6" 6 bit unsigned break code (MIPS16OP_*_IMM6)
- "a" 26 bit jump address
- "e" 11 bit extension value
- "l" register list for entry instruction
- "L" register list for exit instruction
-
- The remaining codes may be extended. Except as otherwise noted,
- the full extended operand is a 16 bit signed value.
- "<" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 5 bit unsigned)
- ">" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 5 bit unsigned)
- "[" 3 bit unsigned shift count * 0 (MIPS16OP_*_RZ) (full 6 bit unsigned)
- "]" 3 bit unsigned shift count * 0 (MIPS16OP_*_RX) (full 6 bit unsigned)
- "4" 4 bit signed immediate * 0 (MIPS16OP_*_IMM4) (full 15 bit signed)
- "5" 5 bit unsigned immediate * 0 (MIPS16OP_*_IMM5)
- "H" 5 bit unsigned immediate * 2 (MIPS16OP_*_IMM5)
- "W" 5 bit unsigned immediate * 4 (MIPS16OP_*_IMM5)
- "D" 5 bit unsigned immediate * 8 (MIPS16OP_*_IMM5)
- "j" 5 bit signed immediate * 0 (MIPS16OP_*_IMM5)
- "8" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8)
- "V" 8 bit unsigned immediate * 4 (MIPS16OP_*_IMM8)
- "C" 8 bit unsigned immediate * 8 (MIPS16OP_*_IMM8)
- "U" 8 bit unsigned immediate * 0 (MIPS16OP_*_IMM8) (full 16 bit unsigned)
- "k" 8 bit signed immediate * 0 (MIPS16OP_*_IMM8)
- "K" 8 bit signed immediate * 8 (MIPS16OP_*_IMM8)
- "p" 8 bit conditional branch address (MIPS16OP_*_IMM8)
- "q" 11 bit branch address (MIPS16OP_*_IMM11)
- "A" 8 bit PC relative address * 4 (MIPS16OP_*_IMM8)
- "B" 5 bit PC relative address * 8 (MIPS16OP_*_IMM5)
- "E" 5 bit PC relative address * 4 (MIPS16OP_*_IMM5)
- */
-
-/* For the mips16, we use the same opcode table format and a few of
- the same flags. However, most of the flags are different. */
-
-/* Modifies the register in MIPS16OP_*_RX. */
-#define MIPS16_INSN_WRITE_X 0x00000001
-/* Modifies the register in MIPS16OP_*_RY. */
-#define MIPS16_INSN_WRITE_Y 0x00000002
-/* Modifies the register in MIPS16OP_*_RZ. */
-#define MIPS16_INSN_WRITE_Z 0x00000004
-/* Modifies the T ($24) register. */
-#define MIPS16_INSN_WRITE_T 0x00000008
-/* Modifies the SP ($29) register. */
-#define MIPS16_INSN_WRITE_SP 0x00000010
-/* Modifies the RA ($31) register. */
-#define MIPS16_INSN_WRITE_31 0x00000020
-/* Modifies the general purpose register in MIPS16OP_*_REG32R. */
-#define MIPS16_INSN_WRITE_GPR_Y 0x00000040
-/* Reads the register in MIPS16OP_*_RX. */
-#define MIPS16_INSN_READ_X 0x00000080
-/* Reads the register in MIPS16OP_*_RY. */
-#define MIPS16_INSN_READ_Y 0x00000100
-/* Reads the register in MIPS16OP_*_MOVE32Z. */
-#define MIPS16_INSN_READ_Z 0x00000200
-/* Reads the T ($24) register. */
-#define MIPS16_INSN_READ_T 0x00000400
-/* Reads the SP ($29) register. */
-#define MIPS16_INSN_READ_SP 0x00000800
-/* Reads the RA ($31) register. */
-#define MIPS16_INSN_READ_31 0x00001000
-/* Reads the program counter. */
-#define MIPS16_INSN_READ_PC 0x00002000
-/* Reads the general purpose register in MIPS16OP_*_REGR32. */
-#define MIPS16_INSN_READ_GPR_X 0x00004000
-/* Is a branch insn. */
-#define MIPS16_INSN_BRANCH 0x00010000
-
-/* The following flags have the same value for the mips16 opcode
- table:
- INSN_UNCOND_BRANCH_DELAY
- INSN_COND_BRANCH_DELAY
- INSN_COND_BRANCH_LIKELY (never used)
- INSN_READ_HI
- INSN_READ_LO
- INSN_WRITE_HI
- INSN_WRITE_LO
- INSN_TRAP
- INSN_ISA3
- */
-
-extern const struct mips_opcode mips16_opcodes[];
-extern const int bfd_mips16_num_opcodes;
-
-/* Short hand so the lines aren't too long. */
-
-#define LDD INSN_LOAD_MEMORY_DELAY
-#define LCD INSN_LOAD_COPROC_DELAY
-#define UBD INSN_UNCOND_BRANCH_DELAY
-#define CBD INSN_COND_BRANCH_DELAY
-#define COD INSN_COPROC_MOVE_DELAY
-#define CLD INSN_COPROC_MEMORY_DELAY
-#define CBL INSN_COND_BRANCH_LIKELY
-#define TRAP INSN_TRAP
-#define SM INSN_STORE_MEMORY
-
-#define WR_d INSN_WRITE_GPR_D
-#define WR_t INSN_WRITE_GPR_T
-#define WR_31 INSN_WRITE_GPR_31
-#define WR_D INSN_WRITE_FPR_D
-#define WR_T INSN_WRITE_FPR_T
-#define WR_S INSN_WRITE_FPR_S
-#define RD_s INSN_READ_GPR_S
-#define RD_b INSN_READ_GPR_S
-#define RD_t INSN_READ_GPR_T
-#define RD_S INSN_READ_FPR_S
-#define RD_T INSN_READ_FPR_T
-#define RD_R INSN_READ_FPR_R
-#define WR_CC INSN_WRITE_COND_CODE
-#define RD_CC INSN_READ_COND_CODE
-#define RD_C0 INSN_COP
-#define RD_C1 INSN_COP
-#define RD_C2 INSN_COP
-#define RD_C3 INSN_COP
-#define WR_C0 INSN_COP
-#define WR_C1 INSN_COP
-#define WR_C2 INSN_COP
-#define WR_C3 INSN_COP
-
-#define WR_HI INSN_WRITE_HI
-#define RD_HI INSN_READ_HI
-#define MOD_HI WR_HI|RD_HI
-
-#define WR_LO INSN_WRITE_LO
-#define RD_LO INSN_READ_LO
-#define MOD_LO WR_LO|RD_LO
-
-#define WR_HILO WR_HI|WR_LO
-#define RD_HILO RD_HI|RD_LO
-#define MOD_HILO WR_HILO|RD_HILO
-
-#define IS_M INSN_MULT
-
-#define WR_MACC INSN_WRITE_MDMX_ACC
-#define RD_MACC INSN_READ_MDMX_ACC
-
-#define I1 INSN_ISA1
-#define I2 INSN_ISA2
-#define I3 INSN_ISA3
-#define I4 INSN_ISA4
-#define I5 INSN_ISA5
-#define I32 INSN_ISA32
-#define I64 INSN_ISA64
-#define I33 INSN_ISA32R2
-#define I65 INSN_ISA64R2
-
-/* MIPS64 MIPS-3D ASE support. */
-#define I16 INSN_MIPS16
-
-/* MIPS64 MIPS-3D ASE support. */
-#define M3D INSN_MIPS3D
-
-/* MIPS64 MDMX ASE support. */
-#define MX INSN_MDMX
-
-#define P3 INSN_4650
-#define L1 INSN_4010
-#define V1 (INSN_4100 | INSN_4111 | INSN_4120)
-#define T3 INSN_3900
-#define M1 INSN_10000
-#define SB1 INSN_SB1
-#define N411 INSN_4111
-#define N412 INSN_4120
-#define N5 (INSN_5400 | INSN_5500)
-#define N54 INSN_5400
-#define N55 INSN_5500
-
-#define G1 (T3 \
- )
-
-#define G2 (T3 \
- )
-
-#define G3 (I4 \
- )
-
-/* The order of overloaded instructions matters. Label arguments and
- register arguments look the same. Instructions that can have either
- for arguments must apear in the correct order in this table for the
- assembler to pick the right one. In other words, entries with
- immediate operands must apear after the same instruction with
- registers.
-
- Because of the lookup algorithm used, entries with the same opcode
- name must be contiguous.
-
- Many instructions are short hand for other instructions (i.e., The
- jal <register> instruction is short for jalr <register>). */
-
-const struct mips_opcode mips_builtin_opcodes[] =
-{
-/* These instructions appear first so that the disassembler will find
- them first. The assemblers uses a hash table based on the
- instruction name anyhow. */
-/* name, args, match, mask, pinfo, membership */
-{"pref", "k,o(b)", 0xcc000000, 0xfc000000, RD_b, I4|I32|G3 },
-{"prefx", "h,t(b)", 0x4c00000f, 0xfc0007ff, RD_b|RD_t, I4 },
-{"nop", "", 0x00000000, 0xffffffff, 0, I1 }, /* sll */
-{"ssnop", "", 0x00000040, 0xffffffff, 0, I32|N55 }, /* sll */
-{"ehb", "", 0x000000c0, 0xffffffff, 0, I33 }, /* sll */
-{"li", "t,j", 0x24000000, 0xffe00000, WR_t, I1 }, /* addiu */
-{"li", "t,i", 0x34000000, 0xffe00000, WR_t, I1 }, /* ori */
-{"li", "t,I", 0, (int) M_LI, INSN_MACRO, I1 },
-{"move", "d,s", 0, (int) M_MOVE, INSN_MACRO, I1 },
-{"move", "d,s", 0x0000002d, 0xfc1f07ff, WR_d|RD_s, I3 },/* daddu */
-{"move", "d,s", 0x00000021, 0xfc1f07ff, WR_d|RD_s, I1 },/* addu */
-{"move", "d,s", 0x00000025, 0xfc1f07ff, WR_d|RD_s, I1 },/* or */
-{"b", "p", 0x10000000, 0xffff0000, UBD, I1 },/* beq 0,0 */
-{"b", "p", 0x04010000, 0xffff0000, UBD, I1 },/* bgez 0 */
-{"bal", "p", 0x04110000, 0xffff0000, UBD|WR_31, I1 },/* bgezal 0*/
-
-{"abs", "d,v", 0, (int) M_ABS, INSN_MACRO, I1 },
-{"abs.s", "D,V", 0x46000005, 0xffff003f, WR_D|RD_S|FP_S, I1 },
-{"abs.d", "D,V", 0x46200005, 0xffff003f, WR_D|RD_S|FP_D, I1 },
-{"abs.ps", "D,V", 0x46c00005, 0xffff003f, WR_D|RD_S|FP_D, I5 },
-{"add", "d,v,t", 0x00000020, 0xfc0007ff, WR_d|RD_s|RD_t, I1 },
-{"add", "t,r,I", 0, (int) M_ADD_I, INSN_MACRO, I1 },
-{"add.s", "D,V,T", 0x46000000, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 },
-{"add.d", "D,V,T", 0x46200000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 },
-{"add.ob", "X,Y,Q", 0x7800000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"add.ob", "D,S,T", 0x4ac0000b, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"add.ob", "D,S,T[e]", 0x4800000b, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"add.ob", "D,S,k", 0x4bc0000b, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"add.ps", "D,V,T", 0x46c00000, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 },
-{"add.qh", "X,Y,Q", 0x7820000b, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"adda.ob", "Y,Q", 0x78000037, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 },
-{"adda.qh", "Y,Q", 0x78200037, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX },
-{"addi", "t,r,j", 0x20000000, 0xfc000000, WR_t|RD_s, I1 },
-{"addiu", "t,r,j", 0x24000000, 0xfc000000, WR_t|RD_s, I1 },
-{"addl.ob", "Y,Q", 0x78000437, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 },
-{"addl.qh", "Y,Q", 0x78200437, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX },
-{"addr.ps", "D,S,T", 0x46c00018, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D },
-{"addu", "d,v,t", 0x00000021, 0xfc0007ff, WR_d|RD_s|RD_t, I1 },
-{"addu", "t,r,I", 0, (int) M_ADDU_I, INSN_MACRO, I1 },
-{"alni.ob", "X,Y,Z,O", 0x78000018, 0xff00003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"alni.ob", "D,S,T,%", 0x48000018, 0xff00003f, WR_D|RD_S|RD_T, N54 },
-{"alni.qh", "X,Y,Z,O", 0x7800001a, 0xff00003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"alnv.ps", "D,V,T,s", 0x4c00001e, 0xfc00003f, WR_D|RD_S|RD_T|FP_D, I5 },
-{"alnv.ob", "X,Y,Z,s", 0x78000019, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, MX|SB1 },
-{"alnv.qh", "X,Y,Z,s", 0x7800001b, 0xfc00003f, WR_D|RD_S|RD_T|RD_s|FP_D, MX },
-{"and", "d,v,t", 0x00000024, 0xfc0007ff, WR_d|RD_s|RD_t, I1 },
-{"and", "t,r,I", 0, (int) M_AND_I, INSN_MACRO, I1 },
-{"and.ob", "X,Y,Q", 0x7800000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"and.ob", "D,S,T", 0x4ac0000c, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"and.ob", "D,S,T[e]", 0x4800000c, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"and.ob", "D,S,k", 0x4bc0000c, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"and.qh", "X,Y,Q", 0x7820000c, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"andi", "t,r,i", 0x30000000, 0xfc000000, WR_t|RD_s, I1 },
-/* b is at the top of the table. */
-/* bal is at the top of the table. */
-{"bc0f", "p", 0x41000000, 0xffff0000, CBD|RD_CC, I1 },
-{"bc0fl", "p", 0x41020000, 0xffff0000, CBL|RD_CC, I2|T3 },
-{"bc0t", "p", 0x41010000, 0xffff0000, CBD|RD_CC, I1 },
-{"bc0tl", "p", 0x41030000, 0xffff0000, CBL|RD_CC, I2|T3 },
-{"bc1any2f", "N,p", 0x45200000, 0xffe30000, CBD|RD_CC|FP_S, M3D },
-{"bc1any2t", "N,p", 0x45210000, 0xffe30000, CBD|RD_CC|FP_S, M3D },
-{"bc1any4f", "N,p", 0x45400000, 0xffe30000, CBD|RD_CC|FP_S, M3D },
-{"bc1any4t", "N,p", 0x45410000, 0xffe30000, CBD|RD_CC|FP_S, M3D },
-{"bc1f", "p", 0x45000000, 0xffff0000, CBD|RD_CC|FP_S, I1 },
-{"bc1f", "N,p", 0x45000000, 0xffe30000, CBD|RD_CC|FP_S, I4|I32 },
-{"bc1fl", "p", 0x45020000, 0xffff0000, CBL|RD_CC|FP_S, I2|T3 },
-{"bc1fl", "N,p", 0x45020000, 0xffe30000, CBL|RD_CC|FP_S, I4|I32 },
-{"bc1t", "p", 0x45010000, 0xffff0000, CBD|RD_CC|FP_S, I1 },
-{"bc1t", "N,p", 0x45010000, 0xffe30000, CBD|RD_CC|FP_S, I4|I32 },
-{"bc1tl", "p", 0x45030000, 0xffff0000, CBL|RD_CC|FP_S, I2|T3 },
-{"bc1tl", "N,p", 0x45030000, 0xffe30000, CBL|RD_CC|FP_S, I4|I32 },
-/* bc2* are at the bottom of the table. */
-{"bc3f", "p", 0x4d000000, 0xffff0000, CBD|RD_CC, I1 },
-{"bc3fl", "p", 0x4d020000, 0xffff0000, CBL|RD_CC, I2|T3 },
-{"bc3t", "p", 0x4d010000, 0xffff0000, CBD|RD_CC, I1 },
-{"bc3tl", "p", 0x4d030000, 0xffff0000, CBL|RD_CC, I2|T3 },
-{"beqz", "s,p", 0x10000000, 0xfc1f0000, CBD|RD_s, I1 },
-{"beqzl", "s,p", 0x50000000, 0xfc1f0000, CBL|RD_s, I2|T3 },
-{"beq", "s,t,p", 0x10000000, 0xfc000000, CBD|RD_s|RD_t, I1 },
-{"beq", "s,I,p", 0, (int) M_BEQ_I, INSN_MACRO, I1 },
-{"beql", "s,t,p", 0x50000000, 0xfc000000, CBL|RD_s|RD_t, I2|T3 },
-{"beql", "s,I,p", 0, (int) M_BEQL_I, INSN_MACRO, I2|T3 },
-{"bge", "s,t,p", 0, (int) M_BGE, INSN_MACRO, I1 },
-{"bge", "s,I,p", 0, (int) M_BGE_I, INSN_MACRO, I1 },
-{"bgel", "s,t,p", 0, (int) M_BGEL, INSN_MACRO, I2|T3 },
-{"bgel", "s,I,p", 0, (int) M_BGEL_I, INSN_MACRO, I2|T3 },
-{"bgeu", "s,t,p", 0, (int) M_BGEU, INSN_MACRO, I1 },
-{"bgeu", "s,I,p", 0, (int) M_BGEU_I, INSN_MACRO, I1 },
-{"bgeul", "s,t,p", 0, (int) M_BGEUL, INSN_MACRO, I2|T3 },
-{"bgeul", "s,I,p", 0, (int) M_BGEUL_I, INSN_MACRO, I2|T3 },
-{"bgez", "s,p", 0x04010000, 0xfc1f0000, CBD|RD_s, I1 },
-{"bgezl", "s,p", 0x04030000, 0xfc1f0000, CBL|RD_s, I2|T3 },
-{"bgezal", "s,p", 0x04110000, 0xfc1f0000, CBD|RD_s|WR_31, I1 },
-{"bgezall", "s,p", 0x04130000, 0xfc1f0000, CBL|RD_s|WR_31, I2|T3 },
-{"bgt", "s,t,p", 0, (int) M_BGT, INSN_MACRO, I1 },
-{"bgt", "s,I,p", 0, (int) M_BGT_I, INSN_MACRO, I1 },
-{"bgtl", "s,t,p", 0, (int) M_BGTL, INSN_MACRO, I2|T3 },
-{"bgtl", "s,I,p", 0, (int) M_BGTL_I, INSN_MACRO, I2|T3 },
-{"bgtu", "s,t,p", 0, (int) M_BGTU, INSN_MACRO, I1 },
-{"bgtu", "s,I,p", 0, (int) M_BGTU_I, INSN_MACRO, I1 },
-{"bgtul", "s,t,p", 0, (int) M_BGTUL, INSN_MACRO, I2|T3 },
-{"bgtul", "s,I,p", 0, (int) M_BGTUL_I, INSN_MACRO, I2|T3 },
-{"bgtz", "s,p", 0x1c000000, 0xfc1f0000, CBD|RD_s, I1 },
-{"bgtzl", "s,p", 0x5c000000, 0xfc1f0000, CBL|RD_s, I2|T3 },
-{"ble", "s,t,p", 0, (int) M_BLE, INSN_MACRO, I1 },
-{"ble", "s,I,p", 0, (int) M_BLE_I, INSN_MACRO, I1 },
-{"blel", "s,t,p", 0, (int) M_BLEL, INSN_MACRO, I2|T3 },
-{"blel", "s,I,p", 0, (int) M_BLEL_I, INSN_MACRO, I2|T3 },
-{"bleu", "s,t,p", 0, (int) M_BLEU, INSN_MACRO, I1 },
-{"bleu", "s,I,p", 0, (int) M_BLEU_I, INSN_MACRO, I1 },
-{"bleul", "s,t,p", 0, (int) M_BLEUL, INSN_MACRO, I2|T3 },
-{"bleul", "s,I,p", 0, (int) M_BLEUL_I, INSN_MACRO, I2|T3 },
-{"blez", "s,p", 0x18000000, 0xfc1f0000, CBD|RD_s, I1 },
-{"blezl", "s,p", 0x58000000, 0xfc1f0000, CBL|RD_s, I2|T3 },
-{"blt", "s,t,p", 0, (int) M_BLT, INSN_MACRO, I1 },
-{"blt", "s,I,p", 0, (int) M_BLT_I, INSN_MACRO, I1 },
-{"bltl", "s,t,p", 0, (int) M_BLTL, INSN_MACRO, I2|T3 },
-{"bltl", "s,I,p", 0, (int) M_BLTL_I, INSN_MACRO, I2|T3 },
-{"bltu", "s,t,p", 0, (int) M_BLTU, INSN_MACRO, I1 },
-{"bltu", "s,I,p", 0, (int) M_BLTU_I, INSN_MACRO, I1 },
-{"bltul", "s,t,p", 0, (int) M_BLTUL, INSN_MACRO, I2|T3 },
-{"bltul", "s,I,p", 0, (int) M_BLTUL_I, INSN_MACRO, I2|T3 },
-{"bltz", "s,p", 0x04000000, 0xfc1f0000, CBD|RD_s, I1 },
-{"bltzl", "s,p", 0x04020000, 0xfc1f0000, CBL|RD_s, I2|T3 },
-{"bltzal", "s,p", 0x04100000, 0xfc1f0000, CBD|RD_s|WR_31, I1 },
-{"bltzall", "s,p", 0x04120000, 0xfc1f0000, CBL|RD_s|WR_31, I2|T3 },
-{"bnez", "s,p", 0x14000000, 0xfc1f0000, CBD|RD_s, I1 },
-{"bnezl", "s,p", 0x54000000, 0xfc1f0000, CBL|RD_s, I2|T3 },
-{"bne", "s,t,p", 0x14000000, 0xfc000000, CBD|RD_s|RD_t, I1 },
-{"bne", "s,I,p", 0, (int) M_BNE_I, INSN_MACRO, I1 },
-{"bnel", "s,t,p", 0x54000000, 0xfc000000, CBL|RD_s|RD_t, I2|T3 },
-{"bnel", "s,I,p", 0, (int) M_BNEL_I, INSN_MACRO, I2|T3 },
-{"break", "", 0x0000000d, 0xffffffff, TRAP, I1 },
-{"break", "c", 0x0000000d, 0xfc00ffff, TRAP, I1 },
-{"break", "c,q", 0x0000000d, 0xfc00003f, TRAP, I1 },
-{"c.f.d", "S,T", 0x46200030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.f.d", "M,S,T", 0x46200030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.f.s", "S,T", 0x46000030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.f.s", "M,S,T", 0x46000030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.f.ps", "S,T", 0x46c00030, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.f.ps", "M,S,T", 0x46c00030, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.un.d", "S,T", 0x46200031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.un.d", "M,S,T", 0x46200031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.un.s", "S,T", 0x46000031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.un.s", "M,S,T", 0x46000031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.un.ps", "S,T", 0x46c00031, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.un.ps", "M,S,T", 0x46c00031, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.eq.d", "S,T", 0x46200032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.eq.d", "M,S,T", 0x46200032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.eq.s", "S,T", 0x46000032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.eq.s", "M,S,T", 0x46000032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.eq.ob", "Y,Q", 0x78000001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX|SB1 },
-{"c.eq.ob", "S,T", 0x4ac00001, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"c.eq.ob", "S,T[e]", 0x48000001, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 },
-{"c.eq.ob", "S,k", 0x4bc00001, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"c.eq.ps", "S,T", 0x46c00032, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.eq.ps", "M,S,T", 0x46c00032, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.eq.qh", "Y,Q", 0x78200001, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX },
-{"c.ueq.d", "S,T", 0x46200033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.ueq.d", "M,S,T", 0x46200033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.ueq.s", "S,T", 0x46000033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.ueq.s", "M,S,T", 0x46000033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.ueq.ps","S,T", 0x46c00033, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ueq.ps","M,S,T", 0x46c00033, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.olt.d", "S,T", 0x46200034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.olt.d", "M,S,T", 0x46200034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.olt.s", "S,T", 0x46000034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.olt.s", "M,S,T", 0x46000034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.olt.ps","S,T", 0x46c00034, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.olt.ps","M,S,T", 0x46c00034, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ult.d", "S,T", 0x46200035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.ult.d", "M,S,T", 0x46200035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.ult.s", "S,T", 0x46000035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.ult.s", "M,S,T", 0x46000035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.ult.ps","S,T", 0x46c00035, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ult.ps","M,S,T", 0x46c00035, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ole.d", "S,T", 0x46200036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.ole.d", "M,S,T", 0x46200036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.ole.s", "S,T", 0x46000036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.ole.s", "M,S,T", 0x46000036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.ole.ps","S,T", 0x46c00036, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ole.ps","M,S,T", 0x46c00036, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ule.d", "S,T", 0x46200037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.ule.d", "M,S,T", 0x46200037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.ule.s", "S,T", 0x46000037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.ule.s", "M,S,T", 0x46000037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.ule.ps","S,T", 0x46c00037, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ule.ps","M,S,T", 0x46c00037, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.sf.d", "S,T", 0x46200038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.sf.d", "M,S,T", 0x46200038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.sf.s", "S,T", 0x46000038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.sf.s", "M,S,T", 0x46000038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.sf.ps", "S,T", 0x46c00038, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.sf.ps", "M,S,T", 0x46c00038, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ngle.d","S,T", 0x46200039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.ngle.d","M,S,T", 0x46200039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.ngle.s","S,T", 0x46000039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.ngle.s","M,S,T", 0x46000039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.ngle.ps","S,T", 0x46c00039, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ngle.ps","M,S,T", 0x46c00039, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.seq.d", "S,T", 0x4620003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.seq.d", "M,S,T", 0x4620003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.seq.s", "S,T", 0x4600003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.seq.s", "M,S,T", 0x4600003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.seq.ps","S,T", 0x46c0003a, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.seq.ps","M,S,T", 0x46c0003a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ngl.d", "S,T", 0x4620003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.ngl.d", "M,S,T", 0x4620003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.ngl.s", "S,T", 0x4600003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.ngl.s", "M,S,T", 0x4600003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.ngl.ps","S,T", 0x46c0003b, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ngl.ps","M,S,T", 0x46c0003b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.lt.d", "S,T", 0x4620003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.lt.d", "M,S,T", 0x4620003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.lt.s", "S,T", 0x4600003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.lt.s", "M,S,T", 0x4600003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.lt.ob", "Y,Q", 0x78000004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX|SB1 },
-{"c.lt.ob", "S,T", 0x4ac00004, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"c.lt.ob", "S,T[e]", 0x48000004, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 },
-{"c.lt.ob", "S,k", 0x4bc00004, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"c.lt.ps", "S,T", 0x46c0003c, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.lt.ps", "M,S,T", 0x46c0003c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.lt.qh", "Y,Q", 0x78200004, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX },
-{"c.nge.d", "S,T", 0x4620003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.nge.d", "M,S,T", 0x4620003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.nge.s", "S,T", 0x4600003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.nge.s", "M,S,T", 0x4600003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.nge.ps","S,T", 0x46c0003d, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.nge.ps","M,S,T", 0x46c0003d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.le.d", "S,T", 0x4620003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.le.d", "M,S,T", 0x4620003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.le.s", "S,T", 0x4600003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.le.s", "M,S,T", 0x4600003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.le.ob", "Y,Q", 0x78000005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX|SB1 },
-{"c.le.ob", "S,T", 0x4ac00005, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"c.le.ob", "S,T[e]", 0x48000005, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 },
-{"c.le.ob", "S,k", 0x4bc00005, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"c.le.ps", "S,T", 0x46c0003e, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.le.ps", "M,S,T", 0x46c0003e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.le.qh", "Y,Q", 0x78200005, 0xfc2007ff, WR_CC|RD_S|RD_T|FP_D, MX },
-{"c.ngt.d", "S,T", 0x4620003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I1 },
-{"c.ngt.d", "M,S,T", 0x4620003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I4|I32 },
-{"c.ngt.s", "S,T", 0x4600003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_S, I1 },
-{"c.ngt.s", "M,S,T", 0x4600003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, I4|I32 },
-{"c.ngt.ps","S,T", 0x46c0003f, 0xffe007ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"c.ngt.ps","M,S,T", 0x46c0003f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, I5 },
-{"cabs.eq.d", "M,S,T", 0x46200072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.eq.ps", "M,S,T", 0x46c00072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.eq.s", "M,S,T", 0x46000072, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.f.d", "M,S,T", 0x46200070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.f.ps", "M,S,T", 0x46c00070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.f.s", "M,S,T", 0x46000070, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.le.d", "M,S,T", 0x4620007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.le.ps", "M,S,T", 0x46c0007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.le.s", "M,S,T", 0x4600007e, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.lt.d", "M,S,T", 0x4620007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.lt.ps", "M,S,T", 0x46c0007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.lt.s", "M,S,T", 0x4600007c, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.nge.d", "M,S,T", 0x4620007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.nge.ps","M,S,T", 0x46c0007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.nge.s", "M,S,T", 0x4600007d, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.ngl.d", "M,S,T", 0x4620007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ngl.ps","M,S,T", 0x46c0007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ngl.s", "M,S,T", 0x4600007b, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.ngle.d","M,S,T", 0x46200079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ngle.ps","M,S,T",0x46c00079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ngle.s","M,S,T", 0x46000079, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.ngt.d", "M,S,T", 0x4620007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ngt.ps","M,S,T", 0x46c0007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ngt.s", "M,S,T", 0x4600007f, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.ole.d", "M,S,T", 0x46200076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ole.ps","M,S,T", 0x46c00076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ole.s", "M,S,T", 0x46000076, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.olt.d", "M,S,T", 0x46200074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.olt.ps","M,S,T", 0x46c00074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.olt.s", "M,S,T", 0x46000074, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.seq.d", "M,S,T", 0x4620007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.seq.ps","M,S,T", 0x46c0007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.seq.s", "M,S,T", 0x4600007a, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.sf.d", "M,S,T", 0x46200078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.sf.ps", "M,S,T", 0x46c00078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.sf.s", "M,S,T", 0x46000078, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.ueq.d", "M,S,T", 0x46200073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ueq.ps","M,S,T", 0x46c00073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ueq.s", "M,S,T", 0x46000073, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.ule.d", "M,S,T", 0x46200077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ule.ps","M,S,T", 0x46c00077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ule.s", "M,S,T", 0x46000077, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.ult.d", "M,S,T", 0x46200075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ult.ps","M,S,T", 0x46c00075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.ult.s", "M,S,T", 0x46000075, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cabs.un.d", "M,S,T", 0x46200071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.un.ps", "M,S,T", 0x46c00071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_D, M3D },
-{"cabs.un.s", "M,S,T", 0x46000071, 0xffe000ff, RD_S|RD_T|WR_CC|FP_S, M3D },
-{"cache", "k,o(b)", 0xbc000000, 0xfc000000, RD_b, I3|I32|T3},
-{"ceil.l.d", "D,S", 0x4620000a, 0xffff003f, WR_D|RD_S|FP_D, I3 },
-{"ceil.l.s", "D,S", 0x4600000a, 0xffff003f, WR_D|RD_S|FP_S, I3 },
-{"ceil.w.d", "D,S", 0x4620000e, 0xffff003f, WR_D|RD_S|FP_D, I2 },
-{"ceil.w.s", "D,S", 0x4600000e, 0xffff003f, WR_D|RD_S|FP_S, I2 },
-{"cfc0", "t,G", 0x40400000, 0xffe007ff, LCD|WR_t|RD_C0, I1 },
-{"cfc1", "t,G", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, I1 },
-{"cfc1", "t,S", 0x44400000, 0xffe007ff, LCD|WR_t|RD_C1|FP_S, I1 },
-/* cfc2 is at the bottom of the table. */
-{"cfc3", "t,G", 0x4c400000, 0xffe007ff, LCD|WR_t|RD_C3, I1 },
-{"clo", "U,s", 0x70000021, 0xfc0007ff, WR_d|WR_t|RD_s, I32|N55 },
-{"clz", "U,s", 0x70000020, 0xfc0007ff, WR_d|WR_t|RD_s, I32|N55 },
-{"ctc0", "t,G", 0x40c00000, 0xffe007ff, COD|RD_t|WR_CC, I1 },
-{"ctc1", "t,G", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, I1 },
-{"ctc1", "t,S", 0x44c00000, 0xffe007ff, COD|RD_t|WR_CC|FP_S, I1 },
-/* ctc2 is at the bottom of the table. */
-{"ctc3", "t,G", 0x4cc00000, 0xffe007ff, COD|RD_t|WR_CC, I1 },
-{"cvt.d.l", "D,S", 0x46a00021, 0xffff003f, WR_D|RD_S|FP_D, I3 },
-{"cvt.d.s", "D,S", 0x46000021, 0xffff003f, WR_D|RD_S|FP_D|FP_S, I1 },
-{"cvt.d.w", "D,S", 0x46800021, 0xffff003f, WR_D|RD_S|FP_D, I1 },
-{"cvt.l.d", "D,S", 0x46200025, 0xffff003f, WR_D|RD_S|FP_D, I3 },
-{"cvt.l.s", "D,S", 0x46000025, 0xffff003f, WR_D|RD_S|FP_S, I3 },
-{"cvt.s.l", "D,S", 0x46a00020, 0xffff003f, WR_D|RD_S|FP_S, I3 },
-{"cvt.s.d", "D,S", 0x46200020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, I1 },
-{"cvt.s.w", "D,S", 0x46800020, 0xffff003f, WR_D|RD_S|FP_S, I1 },
-{"cvt.s.pl","D,S", 0x46c00028, 0xffff003f, WR_D|RD_S|FP_S|FP_D, I5 },
-{"cvt.s.pu","D,S", 0x46c00020, 0xffff003f, WR_D|RD_S|FP_S|FP_D, I5 },
-{"cvt.w.d", "D,S", 0x46200024, 0xffff003f, WR_D|RD_S|FP_D, I1 },
-{"cvt.w.s", "D,S", 0x46000024, 0xffff003f, WR_D|RD_S|FP_S, I1 },
-{"cvt.ps.pw", "D,S", 0x46800026, 0xffff003f, WR_D|RD_S|FP_S|FP_D, M3D },
-{"cvt.ps.s","D,V,T", 0x46000026, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 },
-{"cvt.pw.ps", "D,S", 0x46c00024, 0xffff003f, WR_D|RD_S|FP_S|FP_D, M3D },
-{"dabs", "d,v", 0, (int) M_DABS, INSN_MACRO, I3 },
-{"dadd", "d,v,t", 0x0000002c, 0xfc0007ff, WR_d|RD_s|RD_t, I3 },
-{"dadd", "t,r,I", 0, (int) M_DADD_I, INSN_MACRO, I3 },
-{"daddi", "t,r,j", 0x60000000, 0xfc000000, WR_t|RD_s, I3 },
-{"daddiu", "t,r,j", 0x64000000, 0xfc000000, WR_t|RD_s, I3 },
-{"daddu", "d,v,t", 0x0000002d, 0xfc0007ff, WR_d|RD_s|RD_t, I3 },
-{"daddu", "t,r,I", 0, (int) M_DADDU_I, INSN_MACRO, I3 },
-{"dbreak", "", 0x7000003f, 0xffffffff, 0, N5 },
-{"dclo", "U,s", 0x70000025, 0xfc0007ff, RD_s|WR_d|WR_t, I64|N55 },
-{"dclz", "U,s", 0x70000024, 0xfc0007ff, RD_s|WR_d|WR_t, I64|N55 },
-/* dctr and dctw are used on the r5000. */
-{"dctr", "o(b)", 0xbc050000, 0xfc1f0000, RD_b, I3 },
-{"dctw", "o(b)", 0xbc090000, 0xfc1f0000, RD_b, I3 },
-{"deret", "", 0x4200001f, 0xffffffff, 0, I32|G2 },
-{"dext", "t,r,I,+I", 0, (int) M_DEXT, INSN_MACRO, I65 },
-{"dext", "t,r,+A,+C", 0x7c000003, 0xfc00003f, WR_t|RD_s, I65 },
-{"dextm", "t,r,+A,+G", 0x7c000001, 0xfc00003f, WR_t|RD_s, I65 },
-{"dextu", "t,r,+E,+H", 0x7c000002, 0xfc00003f, WR_t|RD_s, I65 },
-/* For ddiv, see the comments about div. */
-{"ddiv", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 },
-{"ddiv", "d,v,t", 0, (int) M_DDIV_3, INSN_MACRO, I3 },
-{"ddiv", "d,v,I", 0, (int) M_DDIV_3I, INSN_MACRO, I3 },
-/* For ddivu, see the comments about div. */
-{"ddivu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 },
-{"ddivu", "d,v,t", 0, (int) M_DDIVU_3, INSN_MACRO, I3 },
-{"ddivu", "d,v,I", 0, (int) M_DDIVU_3I, INSN_MACRO, I3 },
-{"di", "", 0x41606000, 0xffffffff, WR_t|WR_C0, I33 },
-{"di", "t", 0x41606000, 0xffe0ffff, WR_t|WR_C0, I33 },
-{"dins", "t,r,I,+I", 0, (int) M_DINS, INSN_MACRO, I65 },
-{"dins", "t,r,+A,+B", 0x7c000007, 0xfc00003f, WR_t|RD_s, I65 },
-{"dinsm", "t,r,+A,+F", 0x7c000005, 0xfc00003f, WR_t|RD_s, I65 },
-{"dinsu", "t,r,+E,+F", 0x7c000006, 0xfc00003f, WR_t|RD_s, I65 },
-/* The MIPS assembler treats the div opcode with two operands as
- though the first operand appeared twice (the first operand is both
- a source and a destination). To get the div machine instruction,
- you must use an explicit destination of $0. */
-{"div", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 },
-{"div", "z,t", 0x0000001a, 0xffe0ffff, RD_s|RD_t|WR_HILO, I1 },
-{"div", "d,v,t", 0, (int) M_DIV_3, INSN_MACRO, I1 },
-{"div", "d,v,I", 0, (int) M_DIV_3I, INSN_MACRO, I1 },
-{"div.d", "D,V,T", 0x46200003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 },
-{"div.s", "D,V,T", 0x46000003, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 },
-{"div.ps", "D,V,T", 0x46c00003, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, SB1 },
-/* For divu, see the comments about div. */
-{"divu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 },
-{"divu", "z,t", 0x0000001b, 0xffe0ffff, RD_s|RD_t|WR_HILO, I1 },
-{"divu", "d,v,t", 0, (int) M_DIVU_3, INSN_MACRO, I1 },
-{"divu", "d,v,I", 0, (int) M_DIVU_3I, INSN_MACRO, I1 },
-{"dla", "t,A(b)", 0, (int) M_DLA_AB, INSN_MACRO, I3 },
-{"dlca", "t,A(b)", 0, (int) M_DLCA_AB, INSN_MACRO, I3 },
-{"dli", "t,j", 0x24000000, 0xffe00000, WR_t, I3 }, /* addiu */
-{"dli", "t,i", 0x34000000, 0xffe00000, WR_t, I3 }, /* ori */
-{"dli", "t,I", 0, (int) M_DLI, INSN_MACRO, I3 },
-{"dmacc", "d,s,t", 0x00000029, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 },
-{"dmacchi", "d,s,t", 0x00000229, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 },
-{"dmacchis", "d,s,t", 0x00000629, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 },
-{"dmacchiu", "d,s,t", 0x00000269, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 },
-{"dmacchius", "d,s,t", 0x00000669, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 },
-{"dmaccs", "d,s,t", 0x00000429, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 },
-{"dmaccu", "d,s,t", 0x00000069, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 },
-{"dmaccus", "d,s,t", 0x00000469, 0xfc0007ff, RD_s|RD_t|WR_LO|WR_d, N412 },
-{"dmadd16", "s,t", 0x00000029, 0xfc00ffff, RD_s|RD_t|MOD_LO, N411 },
-{"dmfc0", "t,G", 0x40200000, 0xffe007ff, LCD|WR_t|RD_C0, I3 },
-{"dmfc0", "t,+D", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, I64 },
-{"dmfc0", "t,G,H", 0x40200000, 0xffe007f8, LCD|WR_t|RD_C0, I64 },
-{"dmtc0", "t,G", 0x40a00000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, I3 },
-{"dmtc0", "t,+D", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I64 },
-{"dmtc0", "t,G,H", 0x40a00000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I64 },
-{"dmfc1", "t,S", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I3 },
-{"dmfc1", "t,G", 0x44200000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I3 },
-{"dmtc1", "t,S", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I3 },
-{"dmtc1", "t,G", 0x44a00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I3 },
-/* dmfc2 is at the bottom of the table. */
-/* dmtc2 is at the bottom of the table. */
-{"dmfc3", "t,G", 0x4c200000, 0xffe007ff, LCD|WR_t|RD_C3, I3 },
-{"dmfc3", "t,G,H", 0x4c200000, 0xffe007f8, LCD|WR_t|RD_C3, I64 },
-{"dmtc3", "t,G", 0x4ca00000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, I3 },
-{"dmtc3", "t,G,H", 0x4ca00000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, I64 },
-{"dmul", "d,v,t", 0, (int) M_DMUL, INSN_MACRO, I3 },
-{"dmul", "d,v,I", 0, (int) M_DMUL_I, INSN_MACRO, I3 },
-{"dmulo", "d,v,t", 0, (int) M_DMULO, INSN_MACRO, I3 },
-{"dmulo", "d,v,I", 0, (int) M_DMULO_I, INSN_MACRO, I3 },
-{"dmulou", "d,v,t", 0, (int) M_DMULOU, INSN_MACRO, I3 },
-{"dmulou", "d,v,I", 0, (int) M_DMULOU_I, INSN_MACRO, I3 },
-{"dmult", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 },
-{"dmultu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 },
-{"dneg", "d,w", 0x0000002e, 0xffe007ff, WR_d|RD_t, I3 }, /* dsub 0 */
-{"dnegu", "d,w", 0x0000002f, 0xffe007ff, WR_d|RD_t, I3 }, /* dsubu 0*/
-{"drem", "z,s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 },
-{"drem", "d,v,t", 3, (int) M_DREM_3, INSN_MACRO, I3 },
-{"drem", "d,v,I", 3, (int) M_DREM_3I, INSN_MACRO, I3 },
-{"dremu", "z,s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, I3 },
-{"dremu", "d,v,t", 3, (int) M_DREMU_3, INSN_MACRO, I3 },
-{"dremu", "d,v,I", 3, (int) M_DREMU_3I, INSN_MACRO, I3 },
-{"dret", "", 0x7000003e, 0xffffffff, 0, N5 },
-{"drol", "d,v,t", 0, (int) M_DROL, INSN_MACRO, I3 },
-{"drol", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, I3 },
-{"dror", "d,v,t", 0, (int) M_DROR, INSN_MACRO, I3 },
-{"dror", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, I3 },
-{"dror", "d,w,<", 0x0020003a, 0xffe0003f, WR_d|RD_t, N5|I65 },
-{"drorv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, N5|I65 },
-{"dror32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, N5|I65 },
-{"drotl", "d,v,t", 0, (int) M_DROL, INSN_MACRO, I65 },
-{"drotl", "d,v,I", 0, (int) M_DROL_I, INSN_MACRO, I65 },
-{"drotr", "d,v,t", 0, (int) M_DROR, INSN_MACRO, I65 },
-{"drotr", "d,v,I", 0, (int) M_DROR_I, INSN_MACRO, I65 },
-{"drotrv", "d,t,s", 0x00000056, 0xfc0007ff, RD_t|RD_s|WR_d, I65 },
-{"drotr32", "d,w,<", 0x0020003e, 0xffe0003f, WR_d|RD_t, I65 },
-{"dsbh", "d,w", 0x7c0000a4, 0xffe007ff, WR_d|RD_t, I65 },
-{"dshd", "d,w", 0x7c000164, 0xffe007ff, WR_d|RD_t, I65 },
-{"dsllv", "d,t,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, I3 },
-{"dsll32", "d,w,<", 0x0000003c, 0xffe0003f, WR_d|RD_t, I3 },
-{"dsll", "d,w,s", 0x00000014, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, /* dsllv */
-{"dsll", "d,w,>", 0x0000003c, 0xffe0003f, WR_d|RD_t, I3 }, /* dsll32 */
-{"dsll", "d,w,<", 0x00000038, 0xffe0003f, WR_d|RD_t, I3 },
-{"dsrav", "d,t,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, I3 },
-{"dsra32", "d,w,<", 0x0000003f, 0xffe0003f, WR_d|RD_t, I3 },
-{"dsra", "d,w,s", 0x00000017, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, /* dsrav */
-{"dsra", "d,w,>", 0x0000003f, 0xffe0003f, WR_d|RD_t, I3 }, /* dsra32 */
-{"dsra", "d,w,<", 0x0000003b, 0xffe0003f, WR_d|RD_t, I3 },
-{"dsrlv", "d,t,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, I3 },
-{"dsrl32", "d,w,<", 0x0000003e, 0xffe0003f, WR_d|RD_t, I3 },
-{"dsrl", "d,w,s", 0x00000016, 0xfc0007ff, WR_d|RD_t|RD_s, I3 }, /* dsrlv */
-{"dsrl", "d,w,>", 0x0000003e, 0xffe0003f, WR_d|RD_t, I3 }, /* dsrl32 */
-{"dsrl", "d,w,<", 0x0000003a, 0xffe0003f, WR_d|RD_t, I3 },
-{"dsub", "d,v,t", 0x0000002e, 0xfc0007ff, WR_d|RD_s|RD_t, I3 },
-{"dsub", "d,v,I", 0, (int) M_DSUB_I, INSN_MACRO, I3 },
-{"dsubu", "d,v,t", 0x0000002f, 0xfc0007ff, WR_d|RD_s|RD_t, I3 },
-{"dsubu", "d,v,I", 0, (int) M_DSUBU_I, INSN_MACRO, I3 },
-{"ei", "", 0x41606020, 0xffffffff, WR_t|WR_C0, I33 },
-{"ei", "t", 0x41606020, 0xffe0ffff, WR_t|WR_C0, I33 },
-{"eret", "", 0x42000018, 0xffffffff, 0, I3|I32 },
-{"ext", "t,r,+A,+C", 0x7c000000, 0xfc00003f, WR_t|RD_s, I33 },
-{"floor.l.d", "D,S", 0x4620000b, 0xffff003f, WR_D|RD_S|FP_D, I3 },
-{"floor.l.s", "D,S", 0x4600000b, 0xffff003f, WR_D|RD_S|FP_S, I3 },
-{"floor.w.d", "D,S", 0x4620000f, 0xffff003f, WR_D|RD_S|FP_D, I2 },
-{"floor.w.s", "D,S", 0x4600000f, 0xffff003f, WR_D|RD_S|FP_S, I2 },
-{"flushi", "", 0xbc010000, 0xffffffff, 0, L1 },
-{"flushd", "", 0xbc020000, 0xffffffff, 0, L1 },
-{"flushid", "", 0xbc030000, 0xffffffff, 0, L1 },
-{"hibernate","", 0x42000023, 0xffffffff, 0, V1 },
-{"ins", "t,r,+A,+B", 0x7c000004, 0xfc00003f, WR_t|RD_s, I33 },
-{"jr", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, I1 },
-{"jr.hb", "s", 0x00000408, 0xfc1fffff, UBD|RD_s, I33 },
-{"j", "s", 0x00000008, 0xfc1fffff, UBD|RD_s, I1 }, /* jr */
-/* SVR4 PIC code requires special handling for j, so it must be a
- macro. */
-{"j", "a", 0, (int) M_J_A, INSN_MACRO, I1 },
-/* This form of j is used by the disassembler and internally by the
- assembler, but will never match user input (because the line above
- will match first). */
-{"j", "a", 0x08000000, 0xfc000000, UBD, I1 },
-{"jalr", "s", 0x0000f809, 0xfc1fffff, UBD|RD_s|WR_d, I1 },
-{"jalr", "d,s", 0x00000009, 0xfc1f07ff, UBD|RD_s|WR_d, I1 },
-{"jalr.hb", "s", 0x0000fc09, 0xfc1fffff, UBD|RD_s|WR_d, I33 },
-{"jalr.hb", "d,s", 0x00000409, 0xfc1f07ff, UBD|RD_s|WR_d, I33 },
-/* SVR4 PIC code requires special handling for jal, so it must be a
- macro. */
-{"jal", "d,s", 0, (int) M_JAL_2, INSN_MACRO, I1 },
-{"jal", "s", 0, (int) M_JAL_1, INSN_MACRO, I1 },
-{"jal", "a", 0, (int) M_JAL_A, INSN_MACRO, I1 },
-/* This form of jal is used by the disassembler and internally by the
- assembler, but will never match user input (because the line above
- will match first). */
-{"jal", "a", 0x0c000000, 0xfc000000, UBD|WR_31, I1 },
-{"jalx", "a", 0x74000000, 0xfc000000, UBD|WR_31, I16 },
-{"la", "t,A(b)", 0, (int) M_LA_AB, INSN_MACRO, I1 },
-{"lb", "t,o(b)", 0x80000000, 0xfc000000, LDD|RD_b|WR_t, I1 },
-{"lb", "t,A(b)", 0, (int) M_LB_AB, INSN_MACRO, I1 },
-{"lbu", "t,o(b)", 0x90000000, 0xfc000000, LDD|RD_b|WR_t, I1 },
-{"lbu", "t,A(b)", 0, (int) M_LBU_AB, INSN_MACRO, I1 },
-{"lca", "t,A(b)", 0, (int) M_LCA_AB, INSN_MACRO, I1 },
-{"ld", "t,o(b)", 0xdc000000, 0xfc000000, WR_t|RD_b, I3 },
-{"ld", "t,o(b)", 0, (int) M_LD_OB, INSN_MACRO, I1 },
-{"ld", "t,A(b)", 0, (int) M_LD_AB, INSN_MACRO, I1 },
-{"ldc1", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, I2 },
-{"ldc1", "E,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, I2 },
-{"ldc1", "T,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, I2 },
-{"ldc1", "E,A(b)", 0, (int) M_LDC1_AB, INSN_MACRO, I2 },
-{"l.d", "T,o(b)", 0xd4000000, 0xfc000000, CLD|RD_b|WR_T|FP_D, I2 }, /* ldc1 */
-{"l.d", "T,o(b)", 0, (int) M_L_DOB, INSN_MACRO, I1 },
-{"l.d", "T,A(b)", 0, (int) M_L_DAB, INSN_MACRO, I1 },
-{"ldc2", "E,o(b)", 0xd8000000, 0xfc000000, CLD|RD_b|WR_CC, I2 },
-{"ldc2", "E,A(b)", 0, (int) M_LDC2_AB, INSN_MACRO, I2 },
-{"ldc3", "E,o(b)", 0xdc000000, 0xfc000000, CLD|RD_b|WR_CC, I2 },
-{"ldc3", "E,A(b)", 0, (int) M_LDC3_AB, INSN_MACRO, I2 },
-{"ldl", "t,o(b)", 0x68000000, 0xfc000000, LDD|WR_t|RD_b, I3 },
-{"ldl", "t,A(b)", 0, (int) M_LDL_AB, INSN_MACRO, I3 },
-{"ldr", "t,o(b)", 0x6c000000, 0xfc000000, LDD|WR_t|RD_b, I3 },
-{"ldr", "t,A(b)", 0, (int) M_LDR_AB, INSN_MACRO, I3 },
-{"ldxc1", "D,t(b)", 0x4c000001, 0xfc00f83f, LDD|WR_D|RD_t|RD_b, I4 },
-{"lh", "t,o(b)", 0x84000000, 0xfc000000, LDD|RD_b|WR_t, I1 },
-{"lh", "t,A(b)", 0, (int) M_LH_AB, INSN_MACRO, I1 },
-{"lhu", "t,o(b)", 0x94000000, 0xfc000000, LDD|RD_b|WR_t, I1 },
-{"lhu", "t,A(b)", 0, (int) M_LHU_AB, INSN_MACRO, I1 },
-/* li is at the start of the table. */
-{"li.d", "t,F", 0, (int) M_LI_D, INSN_MACRO, I1 },
-{"li.d", "T,L", 0, (int) M_LI_DD, INSN_MACRO, I1 },
-{"li.s", "t,f", 0, (int) M_LI_S, INSN_MACRO, I1 },
-{"li.s", "T,l", 0, (int) M_LI_SS, INSN_MACRO, I1 },
-{"ll", "t,o(b)", 0xc0000000, 0xfc000000, LDD|RD_b|WR_t, I2 },
-{"ll", "t,A(b)", 0, (int) M_LL_AB, INSN_MACRO, I2 },
-{"lld", "t,o(b)", 0xd0000000, 0xfc000000, LDD|RD_b|WR_t, I3 },
-{"lld", "t,A(b)", 0, (int) M_LLD_AB, INSN_MACRO, I3 },
-{"lui", "t,u", 0x3c000000, 0xffe00000, WR_t, I1 },
-{"luxc1", "D,t(b)", 0x4c000005, 0xfc00f83f, LDD|WR_D|RD_t|RD_b, I5|N55 },
-{"lw", "t,o(b)", 0x8c000000, 0xfc000000, LDD|RD_b|WR_t, I1 },
-{"lw", "t,A(b)", 0, (int) M_LW_AB, INSN_MACRO, I1 },
-{"lwc0", "E,o(b)", 0xc0000000, 0xfc000000, CLD|RD_b|WR_CC, I1 },
-{"lwc0", "E,A(b)", 0, (int) M_LWC0_AB, INSN_MACRO, I1 },
-{"lwc1", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, I1 },
-{"lwc1", "E,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, I1 },
-{"lwc1", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, I1 },
-{"lwc1", "E,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, I1 },
-{"l.s", "T,o(b)", 0xc4000000, 0xfc000000, CLD|RD_b|WR_T|FP_S, I1 }, /* lwc1 */
-{"l.s", "T,A(b)", 0, (int) M_LWC1_AB, INSN_MACRO, I1 },
-{"lwc2", "E,o(b)", 0xc8000000, 0xfc000000, CLD|RD_b|WR_CC, I1 },
-{"lwc2", "E,A(b)", 0, (int) M_LWC2_AB, INSN_MACRO, I1 },
-{"lwc3", "E,o(b)", 0xcc000000, 0xfc000000, CLD|RD_b|WR_CC, I1 },
-{"lwc3", "E,A(b)", 0, (int) M_LWC3_AB, INSN_MACRO, I1 },
-{"lwl", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, I1 },
-{"lwl", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, I1 },
-{"lcache", "t,o(b)", 0x88000000, 0xfc000000, LDD|RD_b|WR_t, I2 }, /* same */
-{"lcache", "t,A(b)", 0, (int) M_LWL_AB, INSN_MACRO, I2 }, /* as lwl */
-{"lwr", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, I1 },
-{"lwr", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, I1 },
-{"flush", "t,o(b)", 0x98000000, 0xfc000000, LDD|RD_b|WR_t, I2 }, /* same */
-{"flush", "t,A(b)", 0, (int) M_LWR_AB, INSN_MACRO, I2 }, /* as lwr */
-{"lwu", "t,o(b)", 0x9c000000, 0xfc000000, LDD|RD_b|WR_t, I3 },
-{"lwu", "t,A(b)", 0, (int) M_LWU_AB, INSN_MACRO, I3 },
-{"lwxc1", "D,t(b)", 0x4c000000, 0xfc00f83f, LDD|WR_D|RD_t|RD_b, I4 },
-{"macc", "d,s,t", 0x00000028, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 },
-{"macc", "d,s,t", 0x00000158, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"maccs", "d,s,t", 0x00000428, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 },
-{"macchi", "d,s,t", 0x00000228, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 },
-{"macchi", "d,s,t", 0x00000358, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"macchis", "d,s,t", 0x00000628, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 },
-{"macchiu", "d,s,t", 0x00000268, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 },
-{"macchiu", "d,s,t", 0x00000359, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"macchius","d,s,t", 0x00000668, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 },
-{"maccu", "d,s,t", 0x00000068, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 },
-{"maccu", "d,s,t", 0x00000159, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"maccus", "d,s,t", 0x00000468, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N412 },
-{"mad", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, P3 },
-{"madu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, P3 },
-{"madd.d", "D,R,S,T", 0x4c000021, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 },
-{"madd.s", "D,R,S,T", 0x4c000020, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 },
-{"madd.ps", "D,R,S,T", 0x4c000026, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 },
-{"madd", "s,t", 0x0000001c, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 },
-{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55},
-{"madd", "s,t", 0x70000000, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, G1 },
-{"madd", "d,s,t", 0x70000000, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 },
-{"maddu", "s,t", 0x0000001d, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 },
-{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55},
-{"maddu", "s,t", 0x70000001, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, G1 },
-{"maddu", "d,s,t", 0x70000001, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 },
-{"madd16", "s,t", 0x00000028, 0xfc00ffff, RD_s|RD_t|MOD_HILO, N411 },
-{"max.ob", "X,Y,Q", 0x78000007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"max.ob", "D,S,T", 0x4ac00007, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"max.ob", "D,S,T[e]", 0x48000007, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"max.ob", "D,S,k", 0x4bc00007, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"max.qh", "X,Y,Q", 0x78200007, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"mfpc", "t,P", 0x4000c801, 0xffe0ffc1, LCD|WR_t|RD_C0, M1|N5 },
-{"mfps", "t,P", 0x4000c800, 0xffe0ffc1, LCD|WR_t|RD_C0, M1|N5 },
-{"mfc0", "t,G", 0x40000000, 0xffe007ff, LCD|WR_t|RD_C0, I1 },
-{"mfc0", "t,+D", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, I32 },
-{"mfc0", "t,G,H", 0x40000000, 0xffe007f8, LCD|WR_t|RD_C0, I32 },
-{"mfc1", "t,S", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I1 },
-{"mfc1", "t,G", 0x44000000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I1 },
-{"mfhc1", "t,S", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I33 },
-{"mfhc1", "t,G", 0x44600000, 0xffe007ff, LCD|WR_t|RD_S|FP_S, I33 },
-/* mfc2 is at the bottom of the table. */
-/* mfhc2 is at the bottom of the table. */
-{"mfc3", "t,G", 0x4c000000, 0xffe007ff, LCD|WR_t|RD_C3, I1 },
-{"mfc3", "t,G,H", 0x4c000000, 0xffe007f8, LCD|WR_t|RD_C3, I32 },
-{"mfdr", "t,G", 0x7000003d, 0xffe007ff, LCD|WR_t|RD_C0, N5 },
-{"mfhi", "d", 0x00000010, 0xffff07ff, WR_d|RD_HI, I1 },
-{"mflo", "d", 0x00000012, 0xffff07ff, WR_d|RD_LO, I1 },
-{"min.ob", "X,Y,Q", 0x78000006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"min.ob", "D,S,T", 0x4ac00006, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"min.ob", "D,S,T[e]", 0x48000006, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"min.ob", "D,S,k", 0x4bc00006, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"min.qh", "X,Y,Q", 0x78200006, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"mov.d", "D,S", 0x46200006, 0xffff003f, WR_D|RD_S|FP_D, I1 },
-{"mov.s", "D,S", 0x46000006, 0xffff003f, WR_D|RD_S|FP_S, I1 },
-{"mov.ps", "D,S", 0x46c00006, 0xffff003f, WR_D|RD_S|FP_D, I5 },
-{"movf", "d,s,N", 0x00000001, 0xfc0307ff, WR_d|RD_s|RD_CC|FP_D|FP_S, I4|I32},
-{"movf.d", "D,S,N", 0x46200011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I4|I32 },
-{"movf.l", "D,S,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 },
-{"movf.l", "X,Y,N", 0x46a00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 },
-{"movf.s", "D,S,N", 0x46000011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, I4|I32 },
-{"movf.ps", "D,S,N", 0x46c00011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I5 },
-{"movn", "d,v,t", 0x0000000b, 0xfc0007ff, WR_d|RD_s|RD_t, I4|I32 },
-{"ffc", "d,v", 0x0000000b, 0xfc1f07ff, WR_d|RD_s, L1 },
-{"movn.d", "D,S,t", 0x46200013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I4|I32 },
-{"movn.l", "D,S,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 },
-{"movn.l", "X,Y,t", 0x46a00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 },
-{"movn.s", "D,S,t", 0x46000013, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, I4|I32 },
-{"movn.ps", "D,S,t", 0x46c00013, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I5 },
-{"movt", "d,s,N", 0x00010001, 0xfc0307ff, WR_d|RD_s|RD_CC, I4|I32 },
-{"movt.d", "D,S,N", 0x46210011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I4|I32 },
-{"movt.l", "D,S,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 },
-{"movt.l", "X,Y,N", 0x46a10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, MX|SB1 },
-{"movt.s", "D,S,N", 0x46010011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_S, I4|I32 },
-{"movt.ps", "D,S,N", 0x46c10011, 0xffe3003f, WR_D|RD_S|RD_CC|FP_D, I5 },
-{"movz", "d,v,t", 0x0000000a, 0xfc0007ff, WR_d|RD_s|RD_t, I4|I32 },
-{"ffs", "d,v", 0x0000000a, 0xfc1f07ff, WR_d|RD_s, L1 },
-{"movz.d", "D,S,t", 0x46200012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I4|I32 },
-{"movz.l", "D,S,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 },
-{"movz.l", "X,Y,t", 0x46a00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, MX|SB1 },
-{"movz.s", "D,S,t", 0x46000012, 0xffe0003f, WR_D|RD_S|RD_t|FP_S, I4|I32 },
-{"movz.ps", "D,S,t", 0x46c00012, 0xffe0003f, WR_D|RD_S|RD_t|FP_D, I5 },
-{"msac", "d,s,t", 0x000001d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"msacu", "d,s,t", 0x000001d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"msachi", "d,s,t", 0x000003d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"msachiu", "d,s,t", 0x000003d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-/* move is at the top of the table. */
-{"msgn.qh", "X,Y,Q", 0x78200000, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"msub.d", "D,R,S,T", 0x4c000029, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 },
-{"msub.s", "D,R,S,T", 0x4c000028, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 },
-{"msub.ps", "D,R,S,T", 0x4c00002e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 },
-{"msub", "s,t", 0x0000001e, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 },
-{"msub", "s,t", 0x70000004, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55 },
-{"msubu", "s,t", 0x0000001f, 0xfc00ffff, RD_s|RD_t|WR_HILO, L1 },
-{"msubu", "s,t", 0x70000005, 0xfc00ffff, RD_s|RD_t|MOD_HILO, I32|N55 },
-{"mtpc", "t,P", 0x4080c801, 0xffe0ffc1, COD|RD_t|WR_C0, M1|N5 },
-{"mtps", "t,P", 0x4080c800, 0xffe0ffc1, COD|RD_t|WR_C0, M1|N5 },
-{"mtc0", "t,G", 0x40800000, 0xffe007ff, COD|RD_t|WR_C0|WR_CC, I1 },
-{"mtc0", "t,+D", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I32 },
-{"mtc0", "t,G,H", 0x40800000, 0xffe007f8, COD|RD_t|WR_C0|WR_CC, I32 },
-{"mtc1", "t,S", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I1 },
-{"mtc1", "t,G", 0x44800000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I1 },
-{"mthc1", "t,S", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I33 },
-{"mthc1", "t,G", 0x44e00000, 0xffe007ff, COD|RD_t|WR_S|FP_S, I33 },
-/* mtc2 is at the bottom of the table. */
-/* mthc2 is at the bottom of the table. */
-{"mtc3", "t,G", 0x4c800000, 0xffe007ff, COD|RD_t|WR_C3|WR_CC, I1 },
-{"mtc3", "t,G,H", 0x4c800000, 0xffe007f8, COD|RD_t|WR_C3|WR_CC, I32 },
-{"mtdr", "t,G", 0x7080003d, 0xffe007ff, COD|RD_t|WR_C0, N5 },
-{"mthi", "s", 0x00000011, 0xfc1fffff, RD_s|WR_HI, I1 },
-{"mtlo", "s", 0x00000013, 0xfc1fffff, RD_s|WR_LO, I1 },
-{"mul.d", "D,V,T", 0x46200002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 },
-{"mul.s", "D,V,T", 0x46000002, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 },
-{"mul.ob", "X,Y,Q", 0x78000030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"mul.ob", "D,S,T", 0x4ac00030, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"mul.ob", "D,S,T[e]", 0x48000030, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"mul.ob", "D,S,k", 0x4bc00030, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"mul.ps", "D,V,T", 0x46c00002, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 },
-{"mul.qh", "X,Y,Q", 0x78200030, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"mul", "d,v,t", 0x70000002, 0xfc0007ff, WR_d|RD_s|RD_t|WR_HILO, I32|P3|N55},
-{"mul", "d,s,t", 0x00000058, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N54 },
-{"mul", "d,v,t", 0, (int) M_MUL, INSN_MACRO, I1 },
-{"mul", "d,v,I", 0, (int) M_MUL_I, INSN_MACRO, I1 },
-{"mula.ob", "Y,Q", 0x78000033, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 },
-{"mula.ob", "S,T", 0x4ac00033, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"mula.ob", "S,T[e]", 0x48000033, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 },
-{"mula.ob", "S,k", 0x4bc00033, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"mula.qh", "Y,Q", 0x78200033, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX },
-{"mulhi", "d,s,t", 0x00000258, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"mulhiu", "d,s,t", 0x00000259, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"mull.ob", "Y,Q", 0x78000433, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 },
-{"mull.ob", "S,T", 0x4ac00433, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"mull.ob", "S,T[e]", 0x48000433, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 },
-{"mull.ob", "S,k", 0x4bc00433, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"mull.qh", "Y,Q", 0x78200433, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX },
-{"mulo", "d,v,t", 0, (int) M_MULO, INSN_MACRO, I1 },
-{"mulo", "d,v,I", 0, (int) M_MULO_I, INSN_MACRO, I1 },
-{"mulou", "d,v,t", 0, (int) M_MULOU, INSN_MACRO, I1 },
-{"mulou", "d,v,I", 0, (int) M_MULOU_I, INSN_MACRO, I1 },
-{"mulr.ps", "D,S,T", 0x46c0001a, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D },
-{"muls", "d,s,t", 0x000000d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"mulsu", "d,s,t", 0x000000d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"mulshi", "d,s,t", 0x000002d8, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"mulshiu", "d,s,t", 0x000002d9, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"muls.ob", "Y,Q", 0x78000032, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 },
-{"muls.ob", "S,T", 0x4ac00032, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"muls.ob", "S,T[e]", 0x48000032, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 },
-{"muls.ob", "S,k", 0x4bc00032, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"muls.qh", "Y,Q", 0x78200032, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX },
-{"mulsl.ob", "Y,Q", 0x78000432, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 },
-{"mulsl.ob", "S,T", 0x4ac00432, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"mulsl.ob", "S,T[e]", 0x48000432, 0xfe2007ff, WR_CC|RD_S|RD_T, N54 },
-{"mulsl.ob", "S,k", 0x4bc00432, 0xffe007ff, WR_CC|RD_S|RD_T, N54 },
-{"mulsl.qh", "Y,Q", 0x78200432, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX },
-{"mult", "s,t", 0x00000018, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, I1 },
-{"mult", "d,s,t", 0x00000018, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 },
-{"multu", "s,t", 0x00000019, 0xfc00ffff, RD_s|RD_t|WR_HILO|IS_M, I1 },
-{"multu", "d,s,t", 0x00000019, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d|IS_M, G1 },
-{"mulu", "d,s,t", 0x00000059, 0xfc0007ff, RD_s|RD_t|WR_HILO|WR_d, N5 },
-{"neg", "d,w", 0x00000022, 0xffe007ff, WR_d|RD_t, I1 }, /* sub 0 */
-{"negu", "d,w", 0x00000023, 0xffe007ff, WR_d|RD_t, I1 }, /* subu 0 */
-{"neg.d", "D,V", 0x46200007, 0xffff003f, WR_D|RD_S|FP_D, I1 },
-{"neg.s", "D,V", 0x46000007, 0xffff003f, WR_D|RD_S|FP_S, I1 },
-{"neg.ps", "D,V", 0x46c00007, 0xffff003f, WR_D|RD_S|FP_D, I5 },
-{"nmadd.d", "D,R,S,T", 0x4c000031, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 },
-{"nmadd.s", "D,R,S,T", 0x4c000030, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 },
-{"nmadd.ps","D,R,S,T", 0x4c000036, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 },
-{"nmsub.d", "D,R,S,T", 0x4c000039, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I4 },
-{"nmsub.s", "D,R,S,T", 0x4c000038, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_S, I4 },
-{"nmsub.ps","D,R,S,T", 0x4c00003e, 0xfc00003f, RD_R|RD_S|RD_T|WR_D|FP_D, I5 },
-/* nop is at the start of the table. */
-{"nor", "d,v,t", 0x00000027, 0xfc0007ff, WR_d|RD_s|RD_t, I1 },
-{"nor", "t,r,I", 0, (int) M_NOR_I, INSN_MACRO, I1 },
-{"nor.ob", "X,Y,Q", 0x7800000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"nor.ob", "D,S,T", 0x4ac0000f, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"nor.ob", "D,S,T[e]", 0x4800000f, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"nor.ob", "D,S,k", 0x4bc0000f, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"nor.qh", "X,Y,Q", 0x7820000f, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"not", "d,v", 0x00000027, 0xfc1f07ff, WR_d|RD_s|RD_t, I1 },/*nor d,s,0*/
-{"or", "d,v,t", 0x00000025, 0xfc0007ff, WR_d|RD_s|RD_t, I1 },
-{"or", "t,r,I", 0, (int) M_OR_I, INSN_MACRO, I1 },
-{"or.ob", "X,Y,Q", 0x7800000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"or.ob", "D,S,T", 0x4ac0000e, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"or.ob", "D,S,T[e]", 0x4800000e, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"or.ob", "D,S,k", 0x4bc0000e, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"or.qh", "X,Y,Q", 0x7820000e, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"ori", "t,r,i", 0x34000000, 0xfc000000, WR_t|RD_s, I1 },
-{"pabsdiff.ob", "X,Y,Q",0x78000009, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, SB1 },
-{"pabsdiffc.ob", "Y,Q", 0x78000035, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, SB1 },
-{"pavg.ob", "X,Y,Q", 0x78000008, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, SB1 },
-{"pickf.ob", "X,Y,Q", 0x78000002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"pickf.ob", "D,S,T", 0x4ac00002, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"pickf.ob", "D,S,T[e]",0x48000002, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"pickf.ob", "D,S,k", 0x4bc00002, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"pickf.qh", "X,Y,Q", 0x78200002, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"pickt.ob", "X,Y,Q", 0x78000003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"pickt.ob", "D,S,T", 0x4ac00003, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"pickt.ob", "D,S,T[e]",0x48000003, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"pickt.ob", "D,S,k", 0x4bc00003, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"pickt.qh", "X,Y,Q", 0x78200003, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"pll.ps", "D,V,T", 0x46c0002c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 },
-{"plu.ps", "D,V,T", 0x46c0002d, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 },
- /* pref and prefx are at the start of the table. */
-{"pul.ps", "D,V,T", 0x46c0002e, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 },
-{"puu.ps", "D,V,T", 0x46c0002f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 },
-{"rach.ob", "X", 0x7a00003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX|SB1 },
-{"rach.ob", "D", 0x4a00003f, 0xfffff83f, WR_D, N54 },
-{"rach.qh", "X", 0x7a20003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX },
-{"racl.ob", "X", 0x7800003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX|SB1 },
-{"racl.ob", "D", 0x4800003f, 0xfffff83f, WR_D, N54 },
-{"racl.qh", "X", 0x7820003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX },
-{"racm.ob", "X", 0x7900003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX|SB1 },
-{"racm.ob", "D", 0x4900003f, 0xfffff83f, WR_D, N54 },
-{"racm.qh", "X", 0x7920003f, 0xfffff83f, WR_D|RD_MACC|FP_D, MX },
-{"recip.d", "D,S", 0x46200015, 0xffff003f, WR_D|RD_S|FP_D, I4 },
-{"recip.ps","D,S", 0x46c00015, 0xffff003f, WR_D|RD_S|FP_D, SB1 },
-{"recip.s", "D,S", 0x46000015, 0xffff003f, WR_D|RD_S|FP_S, I4 },
-{"recip1.d", "D,S", 0x4620001d, 0xffff003f, WR_D|RD_S|FP_D, M3D },
-{"recip1.ps", "D,S", 0x46c0001d, 0xffff003f, WR_D|RD_S|FP_S, M3D },
-{"recip1.s", "D,S", 0x4600001d, 0xffff003f, WR_D|RD_S|FP_S, M3D },
-{"recip2.d", "D,S,T", 0x4620001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D },
-{"recip2.ps", "D,S,T", 0x46c0001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D },
-{"recip2.s", "D,S,T", 0x4600001c, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D },
-{"rem", "z,s,t", 0x0000001a, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 },
-{"rem", "d,v,t", 0, (int) M_REM_3, INSN_MACRO, I1 },
-{"rem", "d,v,I", 0, (int) M_REM_3I, INSN_MACRO, I1 },
-{"remu", "z,s,t", 0x0000001b, 0xfc00ffff, RD_s|RD_t|WR_HILO, I1 },
-{"remu", "d,v,t", 0, (int) M_REMU_3, INSN_MACRO, I1 },
-{"remu", "d,v,I", 0, (int) M_REMU_3I, INSN_MACRO, I1 },
-{"rdhwr", "t,K", 0x7c00003b, 0xffe007ff, WR_t, I33 },
-{"rdpgpr", "d,w", 0x41400000, 0xffe007ff, WR_d, I33 },
-{"rfe", "", 0x42000010, 0xffffffff, 0, I1|T3 },
-{"rnas.qh", "X,Q", 0x78200025, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX },
-{"rnau.ob", "X,Q", 0x78000021, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX|SB1 },
-{"rnau.qh", "X,Q", 0x78200021, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX },
-{"rnes.qh", "X,Q", 0x78200026, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX },
-{"rneu.ob", "X,Q", 0x78000022, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX|SB1 },
-{"rneu.qh", "X,Q", 0x78200022, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX },
-{"rol", "d,v,t", 0, (int) M_ROL, INSN_MACRO, I1 },
-{"rol", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, I1 },
-{"ror", "d,v,t", 0, (int) M_ROR, INSN_MACRO, I1 },
-{"ror", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, I1 },
-{"ror", "d,w,<", 0x00200002, 0xffe0003f, WR_d|RD_t, N5|I33 },
-{"rorv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, N5|I33 },
-{"rotl", "d,v,t", 0, (int) M_ROL, INSN_MACRO, I33 },
-{"rotl", "d,v,I", 0, (int) M_ROL_I, INSN_MACRO, I33 },
-{"rotr", "d,v,t", 0, (int) M_ROR, INSN_MACRO, I33 },
-{"rotr", "d,v,I", 0, (int) M_ROR_I, INSN_MACRO, I33 },
-{"rotrv", "d,t,s", 0x00000046, 0xfc0007ff, RD_t|RD_s|WR_d, I33 },
-{"round.l.d", "D,S", 0x46200008, 0xffff003f, WR_D|RD_S|FP_D, I3 },
-{"round.l.s", "D,S", 0x46000008, 0xffff003f, WR_D|RD_S|FP_S, I3 },
-{"round.w.d", "D,S", 0x4620000c, 0xffff003f, WR_D|RD_S|FP_D, I2 },
-{"round.w.s", "D,S", 0x4600000c, 0xffff003f, WR_D|RD_S|FP_S, I2 },
-{"rsqrt.d", "D,S", 0x46200016, 0xffff003f, WR_D|RD_S|FP_D, I4 },
-{"rsqrt.ps","D,S", 0x46c00016, 0xffff003f, WR_D|RD_S|FP_D, SB1 },
-{"rsqrt.s", "D,S", 0x46000016, 0xffff003f, WR_D|RD_S|FP_S, I4 },
-{"rsqrt1.d", "D,S", 0x4620001e, 0xffff003f, WR_D|RD_S|FP_D, M3D },
-{"rsqrt1.ps", "D,S", 0x46c0001e, 0xffff003f, WR_D|RD_S|FP_S, M3D },
-{"rsqrt1.s", "D,S", 0x4600001e, 0xffff003f, WR_D|RD_S|FP_S, M3D },
-{"rsqrt2.d", "D,S,T", 0x4620001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, M3D },
-{"rsqrt2.ps", "D,S,T", 0x46c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D },
-{"rsqrt2.s", "D,S,T", 0x4600001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, M3D },
-{"rzs.qh", "X,Q", 0x78200024, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX },
-{"rzu.ob", "X,Q", 0x78000020, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX|SB1 },
-{"rzu.ob", "D,k", 0x4bc00020, 0xffe0f83f, WR_D|RD_S|RD_T, N54 },
-{"rzu.qh", "X,Q", 0x78200020, 0xfc20f83f, WR_D|RD_MACC|RD_T|FP_D, MX },
-{"sb", "t,o(b)", 0xa0000000, 0xfc000000, SM|RD_t|RD_b, I1 },
-{"sb", "t,A(b)", 0, (int) M_SB_AB, INSN_MACRO, I1 },
-{"sc", "t,o(b)", 0xe0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, I2 },
-{"sc", "t,A(b)", 0, (int) M_SC_AB, INSN_MACRO, I2 },
-{"scd", "t,o(b)", 0xf0000000, 0xfc000000, SM|RD_t|WR_t|RD_b, I3 },
-{"scd", "t,A(b)", 0, (int) M_SCD_AB, INSN_MACRO, I3 },
-{"sd", "t,o(b)", 0xfc000000, 0xfc000000, SM|RD_t|RD_b, I3 },
-{"sd", "t,o(b)", 0, (int) M_SD_OB, INSN_MACRO, I1 },
-{"sd", "t,A(b)", 0, (int) M_SD_AB, INSN_MACRO, I1 },
-{"sdbbp", "", 0x0000000e, 0xffffffff, TRAP, G2 },
-{"sdbbp", "c", 0x0000000e, 0xfc00ffff, TRAP, G2 },
-{"sdbbp", "c,q", 0x0000000e, 0xfc00003f, TRAP, G2 },
-{"sdbbp", "", 0x7000003f, 0xffffffff, TRAP, I32 },
-{"sdbbp", "B", 0x7000003f, 0xfc00003f, TRAP, I32 },
-{"sdc1", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, I2 },
-{"sdc1", "E,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, I2 },
-{"sdc1", "T,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, I2 },
-{"sdc1", "E,A(b)", 0, (int) M_SDC1_AB, INSN_MACRO, I2 },
-{"sdc2", "E,o(b)", 0xf8000000, 0xfc000000, SM|RD_C2|RD_b, I2 },
-{"sdc2", "E,A(b)", 0, (int) M_SDC2_AB, INSN_MACRO, I2 },
-{"sdc3", "E,o(b)", 0xfc000000, 0xfc000000, SM|RD_C3|RD_b, I2 },
-{"sdc3", "E,A(b)", 0, (int) M_SDC3_AB, INSN_MACRO, I2 },
-{"s.d", "T,o(b)", 0xf4000000, 0xfc000000, SM|RD_T|RD_b|FP_D, I2 },
-{"s.d", "T,o(b)", 0, (int) M_S_DOB, INSN_MACRO, I1 },
-{"s.d", "T,A(b)", 0, (int) M_S_DAB, INSN_MACRO, I1 },
-{"sdl", "t,o(b)", 0xb0000000, 0xfc000000, SM|RD_t|RD_b, I3 },
-{"sdl", "t,A(b)", 0, (int) M_SDL_AB, INSN_MACRO, I3 },
-{"sdr", "t,o(b)", 0xb4000000, 0xfc000000, SM|RD_t|RD_b, I3 },
-{"sdr", "t,A(b)", 0, (int) M_SDR_AB, INSN_MACRO, I3 },
-{"sdxc1", "S,t(b)", 0x4c000009, 0xfc0007ff, SM|RD_S|RD_t|RD_b, I4 },
-{"seb", "d,w", 0x7c000420, 0xffe007ff, WR_d|RD_t, I33 },
-{"seh", "d,w", 0x7c000620, 0xffe007ff, WR_d|RD_t, I33 },
-{"selsl", "d,v,t", 0x00000005, 0xfc0007ff, WR_d|RD_s|RD_t, L1 },
-{"selsr", "d,v,t", 0x00000001, 0xfc0007ff, WR_d|RD_s|RD_t, L1 },
-{"seq", "d,v,t", 0, (int) M_SEQ, INSN_MACRO, I1 },
-{"seq", "d,v,I", 0, (int) M_SEQ_I, INSN_MACRO, I1 },
-{"sge", "d,v,t", 0, (int) M_SGE, INSN_MACRO, I1 },
-{"sge", "d,v,I", 0, (int) M_SGE_I, INSN_MACRO, I1 },
-{"sgeu", "d,v,t", 0, (int) M_SGEU, INSN_MACRO, I1 },
-{"sgeu", "d,v,I", 0, (int) M_SGEU_I, INSN_MACRO, I1 },
-{"sgt", "d,v,t", 0, (int) M_SGT, INSN_MACRO, I1 },
-{"sgt", "d,v,I", 0, (int) M_SGT_I, INSN_MACRO, I1 },
-{"sgtu", "d,v,t", 0, (int) M_SGTU, INSN_MACRO, I1 },
-{"sgtu", "d,v,I", 0, (int) M_SGTU_I, INSN_MACRO, I1 },
-{"sh", "t,o(b)", 0xa4000000, 0xfc000000, SM|RD_t|RD_b, I1 },
-{"sh", "t,A(b)", 0, (int) M_SH_AB, INSN_MACRO, I1 },
-{"shfl.bfla.qh", "X,Y,Z", 0x7a20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"shfl.mixh.ob", "X,Y,Z", 0x7980001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"shfl.mixh.ob", "D,S,T", 0x4980001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"shfl.mixh.qh", "X,Y,Z", 0x7820001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"shfl.mixl.ob", "X,Y,Z", 0x79c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"shfl.mixl.ob", "D,S,T", 0x49c0001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"shfl.mixl.qh", "X,Y,Z", 0x78a0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"shfl.pach.ob", "X,Y,Z", 0x7900001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"shfl.pach.ob", "D,S,T", 0x4900001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"shfl.pach.qh", "X,Y,Z", 0x7920001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"shfl.pacl.ob", "D,S,T", 0x4940001f, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"shfl.repa.qh", "X,Y,Z", 0x7b20001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"shfl.repb.qh", "X,Y,Z", 0x7ba0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"shfl.upsl.ob", "X,Y,Z", 0x78c0001f, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"sle", "d,v,t", 0, (int) M_SLE, INSN_MACRO, I1 },
-{"sle", "d,v,I", 0, (int) M_SLE_I, INSN_MACRO, I1 },
-{"sleu", "d,v,t", 0, (int) M_SLEU, INSN_MACRO, I1 },
-{"sleu", "d,v,I", 0, (int) M_SLEU_I, INSN_MACRO, I1 },
-{"sllv", "d,t,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, I1 },
-{"sll", "d,w,s", 0x00000004, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, /* sllv */
-{"sll", "d,w,<", 0x00000000, 0xffe0003f, WR_d|RD_t, I1 },
-{"sll.ob", "X,Y,Q", 0x78000010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"sll.ob", "D,S,T[e]", 0x48000010, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"sll.ob", "D,S,k", 0x4bc00010, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"sll.qh", "X,Y,Q", 0x78200010, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"slt", "d,v,t", 0x0000002a, 0xfc0007ff, WR_d|RD_s|RD_t, I1 },
-{"slt", "d,v,I", 0, (int) M_SLT_I, INSN_MACRO, I1 },
-{"slti", "t,r,j", 0x28000000, 0xfc000000, WR_t|RD_s, I1 },
-{"sltiu", "t,r,j", 0x2c000000, 0xfc000000, WR_t|RD_s, I1 },
-{"sltu", "d,v,t", 0x0000002b, 0xfc0007ff, WR_d|RD_s|RD_t, I1 },
-{"sltu", "d,v,I", 0, (int) M_SLTU_I, INSN_MACRO, I1 },
-{"sne", "d,v,t", 0, (int) M_SNE, INSN_MACRO, I1 },
-{"sne", "d,v,I", 0, (int) M_SNE_I, INSN_MACRO, I1 },
-{"sqrt.d", "D,S", 0x46200004, 0xffff003f, WR_D|RD_S|FP_D, I2 },
-{"sqrt.s", "D,S", 0x46000004, 0xffff003f, WR_D|RD_S|FP_S, I2 },
-{"sqrt.ps", "D,S", 0x46c00004, 0xffff003f, WR_D|RD_S|FP_D, SB1 },
-{"srav", "d,t,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, I1 },
-{"sra", "d,w,s", 0x00000007, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, /* srav */
-{"sra", "d,w,<", 0x00000003, 0xffe0003f, WR_d|RD_t, I1 },
-{"sra.qh", "X,Y,Q", 0x78200013, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"srlv", "d,t,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, I1 },
-{"srl", "d,w,s", 0x00000006, 0xfc0007ff, WR_d|RD_t|RD_s, I1 }, /* srlv */
-{"srl", "d,w,<", 0x00000002, 0xffe0003f, WR_d|RD_t, I1 },
-{"srl.ob", "X,Y,Q", 0x78000012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"srl.ob", "D,S,T[e]", 0x48000012, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"srl.ob", "D,S,k", 0x4bc00012, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"srl.qh", "X,Y,Q", 0x78200012, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-/* ssnop is at the start of the table. */
-{"standby", "", 0x42000021, 0xffffffff, 0, V1 },
-{"sub", "d,v,t", 0x00000022, 0xfc0007ff, WR_d|RD_s|RD_t, I1 },
-{"sub", "d,v,I", 0, (int) M_SUB_I, INSN_MACRO, I1 },
-{"sub.d", "D,V,T", 0x46200001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I1 },
-{"sub.s", "D,V,T", 0x46000001, 0xffe0003f, WR_D|RD_S|RD_T|FP_S, I1 },
-{"sub.ob", "X,Y,Q", 0x7800000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"sub.ob", "D,S,T", 0x4ac0000a, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"sub.ob", "D,S,T[e]", 0x4800000a, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"sub.ob", "D,S,k", 0x4bc0000a, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"sub.ps", "D,V,T", 0x46c00001, 0xffe0003f, WR_D|RD_S|RD_T|FP_D, I5 },
-{"sub.qh", "X,Y,Q", 0x7820000a, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"suba.ob", "Y,Q", 0x78000036, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 },
-{"suba.qh", "Y,Q", 0x78200036, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX },
-{"subl.ob", "Y,Q", 0x78000436, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 },
-{"subl.qh", "Y,Q", 0x78200436, 0xfc2007ff, WR_MACC|RD_S|RD_T|FP_D, MX },
-{"subu", "d,v,t", 0x00000023, 0xfc0007ff, WR_d|RD_s|RD_t, I1 },
-{"subu", "d,v,I", 0, (int) M_SUBU_I, INSN_MACRO, I1 },
-{"suspend", "", 0x42000022, 0xffffffff, 0, V1 },
-{"suxc1", "S,t(b)", 0x4c00000d, 0xfc0007ff, SM|RD_S|RD_t|RD_b, I5|N55 },
-{"sw", "t,o(b)", 0xac000000, 0xfc000000, SM|RD_t|RD_b, I1 },
-{"sw", "t,A(b)", 0, (int) M_SW_AB, INSN_MACRO, I1 },
-{"swc0", "E,o(b)", 0xe0000000, 0xfc000000, SM|RD_C0|RD_b, I1 },
-{"swc0", "E,A(b)", 0, (int) M_SWC0_AB, INSN_MACRO, I1 },
-{"swc1", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, I1 },
-{"swc1", "E,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, I1 },
-{"swc1", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, I1 },
-{"swc1", "E,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, I1 },
-{"s.s", "T,o(b)", 0xe4000000, 0xfc000000, SM|RD_T|RD_b|FP_S, I1 }, /* swc1 */
-{"s.s", "T,A(b)", 0, (int) M_SWC1_AB, INSN_MACRO, I1 },
-{"swc2", "E,o(b)", 0xe8000000, 0xfc000000, SM|RD_C2|RD_b, I1 },
-{"swc2", "E,A(b)", 0, (int) M_SWC2_AB, INSN_MACRO, I1 },
-{"swc3", "E,o(b)", 0xec000000, 0xfc000000, SM|RD_C3|RD_b, I1 },
-{"swc3", "E,A(b)", 0, (int) M_SWC3_AB, INSN_MACRO, I1 },
-{"swl", "t,o(b)", 0xa8000000, 0xfc000000, SM|RD_t|RD_b, I1 },
-{"swl", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, I1 },
-{"scache", "t,o(b)", 0xa8000000, 0xfc000000, RD_t|RD_b, I2 }, /* same */
-{"scache", "t,A(b)", 0, (int) M_SWL_AB, INSN_MACRO, I2 }, /* as swl */
-{"swr", "t,o(b)", 0xb8000000, 0xfc000000, SM|RD_t|RD_b, I1 },
-{"swr", "t,A(b)", 0, (int) M_SWR_AB, INSN_MACRO, I1 },
-{"invalidate", "t,o(b)",0xb8000000, 0xfc000000, RD_t|RD_b, I2 }, /* same */
-{"invalidate", "t,A(b)",0, (int) M_SWR_AB, INSN_MACRO, I2 }, /* as swr */
-{"swxc1", "S,t(b)", 0x4c000008, 0xfc0007ff, SM|RD_S|RD_t|RD_b, I4 },
-{"sync", "", 0x0000000f, 0xffffffff, INSN_SYNC, I2|G1 },
-{"sync.p", "", 0x0000040f, 0xffffffff, INSN_SYNC, I2 },
-{"sync.l", "", 0x0000000f, 0xffffffff, INSN_SYNC, I2 },
-{"synci", "o(b)", 0x041f0000, 0xfc1f0000, SM|RD_b, I33 },
-{"syscall", "", 0x0000000c, 0xffffffff, TRAP, I1 },
-{"syscall", "B", 0x0000000c, 0xfc00003f, TRAP, I1 },
-{"teqi", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, I2 },
-{"teq", "s,t", 0x00000034, 0xfc00ffff, RD_s|RD_t|TRAP, I2 },
-{"teq", "s,t,q", 0x00000034, 0xfc00003f, RD_s|RD_t|TRAP, I2 },
-{"teq", "s,j", 0x040c0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* teqi */
-{"teq", "s,I", 0, (int) M_TEQ_I, INSN_MACRO, I2 },
-{"tgei", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, I2 },
-{"tge", "s,t", 0x00000030, 0xfc00ffff, RD_s|RD_t|TRAP, I2 },
-{"tge", "s,t,q", 0x00000030, 0xfc00003f, RD_s|RD_t|TRAP, I2 },
-{"tge", "s,j", 0x04080000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tgei */
-{"tge", "s,I", 0, (int) M_TGE_I, INSN_MACRO, I2 },
-{"tgeiu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, I2 },
-{"tgeu", "s,t", 0x00000031, 0xfc00ffff, RD_s|RD_t|TRAP, I2 },
-{"tgeu", "s,t,q", 0x00000031, 0xfc00003f, RD_s|RD_t|TRAP, I2 },
-{"tgeu", "s,j", 0x04090000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tgeiu */
-{"tgeu", "s,I", 0, (int) M_TGEU_I, INSN_MACRO, I2 },
-{"tlbp", "", 0x42000008, 0xffffffff, INSN_TLB, I1 },
-{"tlbr", "", 0x42000001, 0xffffffff, INSN_TLB, I1 },
-{"tlbwi", "", 0x42000002, 0xffffffff, INSN_TLB, I1 },
-{"tlbwr", "", 0x42000006, 0xffffffff, INSN_TLB, I1 },
-{"tlti", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, I2 },
-{"tlt", "s,t", 0x00000032, 0xfc00ffff, RD_s|RD_t|TRAP, I2 },
-{"tlt", "s,t,q", 0x00000032, 0xfc00003f, RD_s|RD_t|TRAP, I2 },
-{"tlt", "s,j", 0x040a0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tlti */
-{"tlt", "s,I", 0, (int) M_TLT_I, INSN_MACRO, I2 },
-{"tltiu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, I2 },
-{"tltu", "s,t", 0x00000033, 0xfc00ffff, RD_s|RD_t|TRAP, I2 },
-{"tltu", "s,t,q", 0x00000033, 0xfc00003f, RD_s|RD_t|TRAP, I2 },
-{"tltu", "s,j", 0x040b0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tltiu */
-{"tltu", "s,I", 0, (int) M_TLTU_I, INSN_MACRO, I2 },
-{"tnei", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, I2 },
-{"tne", "s,t", 0x00000036, 0xfc00ffff, RD_s|RD_t|TRAP, I2 },
-{"tne", "s,t,q", 0x00000036, 0xfc00003f, RD_s|RD_t|TRAP, I2 },
-{"tne", "s,j", 0x040e0000, 0xfc1f0000, RD_s|TRAP, I2 }, /* tnei */
-{"tne", "s,I", 0, (int) M_TNE_I, INSN_MACRO, I2 },
-{"trunc.l.d", "D,S", 0x46200009, 0xffff003f, WR_D|RD_S|FP_D, I3 },
-{"trunc.l.s", "D,S", 0x46000009, 0xffff003f, WR_D|RD_S|FP_S, I3 },
-{"trunc.w.d", "D,S", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_D, I2 },
-{"trunc.w.d", "D,S,x", 0x4620000d, 0xffff003f, WR_D|RD_S|FP_D, I2 },
-{"trunc.w.d", "D,S,t", 0, (int) M_TRUNCWD, INSN_MACRO, I1 },
-{"trunc.w.s", "D,S", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, I2 },
-{"trunc.w.s", "D,S,x", 0x4600000d, 0xffff003f, WR_D|RD_S|FP_S, I2 },
-{"trunc.w.s", "D,S,t", 0, (int) M_TRUNCWS, INSN_MACRO, I1 },
-{"uld", "t,o(b)", 0, (int) M_ULD, INSN_MACRO, I3 },
-{"uld", "t,A(b)", 0, (int) M_ULD_A, INSN_MACRO, I3 },
-{"ulh", "t,o(b)", 0, (int) M_ULH, INSN_MACRO, I1 },
-{"ulh", "t,A(b)", 0, (int) M_ULH_A, INSN_MACRO, I1 },
-{"ulhu", "t,o(b)", 0, (int) M_ULHU, INSN_MACRO, I1 },
-{"ulhu", "t,A(b)", 0, (int) M_ULHU_A, INSN_MACRO, I1 },
-{"ulw", "t,o(b)", 0, (int) M_ULW, INSN_MACRO, I1 },
-{"ulw", "t,A(b)", 0, (int) M_ULW_A, INSN_MACRO, I1 },
-{"usd", "t,o(b)", 0, (int) M_USD, INSN_MACRO, I3 },
-{"usd", "t,A(b)", 0, (int) M_USD_A, INSN_MACRO, I3 },
-{"ush", "t,o(b)", 0, (int) M_USH, INSN_MACRO, I1 },
-{"ush", "t,A(b)", 0, (int) M_USH_A, INSN_MACRO, I1 },
-{"usw", "t,o(b)", 0, (int) M_USW, INSN_MACRO, I1 },
-{"usw", "t,A(b)", 0, (int) M_USW_A, INSN_MACRO, I1 },
-{"wach.ob", "Y", 0x7a00003e, 0xffff07ff, WR_MACC|RD_S|FP_D, MX|SB1 },
-{"wach.ob", "S", 0x4a00003e, 0xffff07ff, RD_S, N54 },
-{"wach.qh", "Y", 0x7a20003e, 0xffff07ff, WR_MACC|RD_S|FP_D, MX },
-{"wacl.ob", "Y,Z", 0x7800003e, 0xffe007ff, WR_MACC|RD_S|RD_T|FP_D, MX|SB1 },
-{"wacl.ob", "S,T", 0x4800003e, 0xffe007ff, RD_S|RD_T, N54 },
-{"wacl.qh", "Y,Z", 0x7820003e, 0xffe007ff, WR_MACC|RD_S|RD_T|FP_D, MX },
-{"wait", "", 0x42000020, 0xffffffff, TRAP, I3|I32 },
-{"wait", "J", 0x42000020, 0xfe00003f, TRAP, I32|N55 },
-{"waiti", "", 0x42000020, 0xffffffff, TRAP, L1 },
-{"wb", "o(b)", 0xbc040000, 0xfc1f0000, SM|RD_b, L1 },
-{"wrpgpr", "d,w", 0x41c00000, 0xffe007ff, RD_t, I33 },
-{"wsbh", "d,w", 0x7c0000a0, 0xffe007ff, WR_d|RD_t, I33 },
-{"xor", "d,v,t", 0x00000026, 0xfc0007ff, WR_d|RD_s|RD_t, I1 },
-{"xor", "t,r,I", 0, (int) M_XOR_I, INSN_MACRO, I1 },
-{"xor.ob", "X,Y,Q", 0x7800000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX|SB1 },
-{"xor.ob", "D,S,T", 0x4ac0000d, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"xor.ob", "D,S,T[e]", 0x4800000d, 0xfe20003f, WR_D|RD_S|RD_T, N54 },
-{"xor.ob", "D,S,k", 0x4bc0000d, 0xffe0003f, WR_D|RD_S|RD_T, N54 },
-{"xor.qh", "X,Y,Q", 0x7820000d, 0xfc20003f, WR_D|RD_S|RD_T|FP_D, MX },
-{"xori", "t,r,i", 0x38000000, 0xfc000000, WR_t|RD_s, I1 },
-
-/* Coprocessor 2 move/branch operations overlap with VR5400 .ob format
- instructions so they are here for the latters to take precedence. */
-{"bc2f", "p", 0x49000000, 0xffff0000, CBD|RD_CC, I1 },
-{"bc2fl", "p", 0x49020000, 0xffff0000, CBL|RD_CC, I2|T3 },
-{"bc2t", "p", 0x49010000, 0xffff0000, CBD|RD_CC, I1 },
-{"bc2tl", "p", 0x49030000, 0xffff0000, CBL|RD_CC, I2|T3 },
-{"cfc2", "t,G", 0x48400000, 0xffe007ff, LCD|WR_t|RD_C2, I1 },
-{"ctc2", "t,G", 0x48c00000, 0xffe007ff, COD|RD_t|WR_CC, I1 },
-{"dmfc2", "t,G", 0x48200000, 0xffe007ff, LCD|WR_t|RD_C2, I3 },
-{"dmfc2", "t,G,H", 0x48200000, 0xffe007f8, LCD|WR_t|RD_C2, I64 },
-{"dmtc2", "t,G", 0x48a00000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, I3 },
-{"dmtc2", "t,G,H", 0x48a00000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, I64 },
-{"mfc2", "t,G", 0x48000000, 0xffe007ff, LCD|WR_t|RD_C2, I1 },
-{"mfc2", "t,G,H", 0x48000000, 0xffe007f8, LCD|WR_t|RD_C2, I32 },
-{"mfhc2", "t,i", 0x48600000, 0xffe00000, LCD|WR_t|RD_C2, I33 },
-{"mtc2", "t,G", 0x48800000, 0xffe007ff, COD|RD_t|WR_C2|WR_CC, I1 },
-{"mtc2", "t,G,H", 0x48800000, 0xffe007f8, COD|RD_t|WR_C2|WR_CC, I32 },
-{"mthc2", "t,i", 0x48e00000, 0xffe00000, COD|RD_t|WR_C2|WR_CC, I33 },
-
-/* No hazard protection on coprocessor instructions--they shouldn't
- change the state of the processor and if they do it's up to the
- user to put in nops as necessary. These are at the end so that the
- disassembler recognizes more specific versions first. */
-{"c0", "C", 0x42000000, 0xfe000000, 0, I1 },
-{"c1", "C", 0x46000000, 0xfe000000, 0, I1 },
-{"c2", "C", 0x4a000000, 0xfe000000, 0, I1 },
-{"c3", "C", 0x4e000000, 0xfe000000, 0, I1 },
-{"cop0", "C", 0, (int) M_COP0, INSN_MACRO, I1 },
-{"cop1", "C", 0, (int) M_COP1, INSN_MACRO, I1 },
-{"cop2", "C", 0, (int) M_COP2, INSN_MACRO, I1 },
-{"cop3", "C", 0, (int) M_COP3, INSN_MACRO, I1 },
-
- /* Conflicts with the 4650's "mul" instruction. Nobody's using the
- 4010 any more, so move this insn out of the way. If the object
- format gave us more info, we could do this right. */
-{"addciu", "t,r,j", 0x70000000, 0xfc000000, WR_t|RD_s, L1 },
-};
-
-#define MIPS_NUM_OPCODES \
- ((sizeof mips_builtin_opcodes) / (sizeof (mips_builtin_opcodes[0])))
-const int bfd_mips_num_builtin_opcodes = MIPS_NUM_OPCODES;
-
-/* const removed from the following to allow for dynamic extensions to the
- * built-in instruction set. */
-struct mips_opcode *mips_opcodes =
- (struct mips_opcode *) mips_builtin_opcodes;
-int bfd_mips_num_opcodes = MIPS_NUM_OPCODES;
-#undef MIPS_NUM_OPCODES
-
-/* Mips instructions are at maximum this many bytes long. */
-#define INSNLEN 4
-
-static void set_default_mips_dis_options
- PARAMS ((struct disassemble_info *));
-static void parse_mips_dis_option
- PARAMS ((const char *, unsigned int));
-static void parse_mips_dis_options
- PARAMS ((const char *));
-static int _print_insn_mips
- PARAMS ((bfd_vma, struct disassemble_info *, enum bfd_endian));
-static int print_insn_mips
- PARAMS ((bfd_vma, unsigned long int, struct disassemble_info *));
-static void print_insn_args
- PARAMS ((const char *, unsigned long, bfd_vma, struct disassemble_info *));
-#if 0
-static int print_insn_mips16
- PARAMS ((bfd_vma, struct disassemble_info *));
-#endif
-#if 0
-static int is_newabi
- PARAMS ((Elf32_Ehdr *));
-#endif
-#if 0
-static void print_mips16_insn_arg
- PARAMS ((int, const struct mips_opcode *, int, bfd_boolean, int, bfd_vma,
- struct disassemble_info *));
-#endif
-
-/* FIXME: These should be shared with gdb somehow. */
-
-struct mips_cp0sel_name {
- unsigned int cp0reg;
- unsigned int sel;
- const char * const name;
-};
-
-/* The mips16 register names. */
-static const char * const mips16_reg_names[] = {
- "s0", "s1", "v0", "v1", "a0", "a1", "a2", "a3"
-};
-
-static const char * const mips_gpr_names_numeric[32] = {
- "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
- "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
- "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
-};
-
-static const char * const mips_gpr_names_oldabi[32] = {
- "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
-};
-
-static const char * const mips_gpr_names_newabi[32] = {
- "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "a4", "a5", "a6", "a7", "t0", "t1", "t2", "t3",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
-};
-
-static const char * const mips_fpr_names_numeric[32] = {
- "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
- "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
- "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
- "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "$f30", "$f31"
-};
-
-static const char * const mips_fpr_names_32[32] = {
- "fv0", "fv0f", "fv1", "fv1f", "ft0", "ft0f", "ft1", "ft1f",
- "ft2", "ft2f", "ft3", "ft3f", "fa0", "fa0f", "fa1", "fa1f",
- "ft4", "ft4f", "ft5", "ft5f", "fs0", "fs0f", "fs1", "fs1f",
- "fs2", "fs2f", "fs3", "fs3f", "fs4", "fs4f", "fs5", "fs5f"
-};
-
-static const char * const mips_fpr_names_n32[32] = {
- "fv0", "ft14", "fv1", "ft15", "ft0", "ft1", "ft2", "ft3",
- "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3",
- "fa4", "fa5", "fa6", "fa7", "fs0", "ft8", "fs1", "ft9",
- "fs2", "ft10", "fs3", "ft11", "fs4", "ft12", "fs5", "ft13"
-};
-
-static const char * const mips_fpr_names_64[32] = {
- "fv0", "ft12", "fv1", "ft13", "ft0", "ft1", "ft2", "ft3",
- "ft4", "ft5", "ft6", "ft7", "fa0", "fa1", "fa2", "fa3",
- "fa4", "fa5", "fa6", "fa7", "ft8", "ft9", "ft10", "ft11",
- "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7"
-};
-
-static const char * const mips_cp0_names_numeric[32] = {
- "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
- "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
- "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
-};
-
-static const char * const mips_cp0_names_mips3264[32] = {
- "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
- "c0_context", "c0_pagemask", "c0_wired", "$7",
- "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
- "c0_status", "c0_cause", "c0_epc", "c0_prid",
- "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
- "c0_xcontext", "$21", "$22", "c0_debug",
- "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr",
- "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave",
-};
-
-static const struct mips_cp0sel_name mips_cp0sel_names_mips3264[] = {
- { 16, 1, "c0_config1" },
- { 16, 2, "c0_config2" },
- { 16, 3, "c0_config3" },
- { 18, 1, "c0_watchlo,1" },
- { 18, 2, "c0_watchlo,2" },
- { 18, 3, "c0_watchlo,3" },
- { 18, 4, "c0_watchlo,4" },
- { 18, 5, "c0_watchlo,5" },
- { 18, 6, "c0_watchlo,6" },
- { 18, 7, "c0_watchlo,7" },
- { 19, 1, "c0_watchhi,1" },
- { 19, 2, "c0_watchhi,2" },
- { 19, 3, "c0_watchhi,3" },
- { 19, 4, "c0_watchhi,4" },
- { 19, 5, "c0_watchhi,5" },
- { 19, 6, "c0_watchhi,6" },
- { 19, 7, "c0_watchhi,7" },
- { 25, 1, "c0_perfcnt,1" },
- { 25, 2, "c0_perfcnt,2" },
- { 25, 3, "c0_perfcnt,3" },
- { 25, 4, "c0_perfcnt,4" },
- { 25, 5, "c0_perfcnt,5" },
- { 25, 6, "c0_perfcnt,6" },
- { 25, 7, "c0_perfcnt,7" },
- { 27, 1, "c0_cacheerr,1" },
- { 27, 2, "c0_cacheerr,2" },
- { 27, 3, "c0_cacheerr,3" },
- { 28, 1, "c0_datalo" },
- { 29, 1, "c0_datahi" }
-};
-
-static const char * const mips_cp0_names_mips3264r2[32] = {
- "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
- "c0_context", "c0_pagemask", "c0_wired", "c0_hwrena",
- "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
- "c0_status", "c0_cause", "c0_epc", "c0_prid",
- "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
- "c0_xcontext", "$21", "$22", "c0_debug",
- "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr",
- "c0_taglo", "c0_taghi", "c0_errorepc", "c0_desave",
-};
-
-static const struct mips_cp0sel_name mips_cp0sel_names_mips3264r2[] = {
- { 4, 1, "c0_contextconfig" },
- { 5, 1, "c0_pagegrain" },
- { 12, 1, "c0_intctl" },
- { 12, 2, "c0_srsctl" },
- { 12, 3, "c0_srsmap" },
- { 15, 1, "c0_ebase" },
- { 16, 1, "c0_config1" },
- { 16, 2, "c0_config2" },
- { 16, 3, "c0_config3" },
- { 18, 1, "c0_watchlo,1" },
- { 18, 2, "c0_watchlo,2" },
- { 18, 3, "c0_watchlo,3" },
- { 18, 4, "c0_watchlo,4" },
- { 18, 5, "c0_watchlo,5" },
- { 18, 6, "c0_watchlo,6" },
- { 18, 7, "c0_watchlo,7" },
- { 19, 1, "c0_watchhi,1" },
- { 19, 2, "c0_watchhi,2" },
- { 19, 3, "c0_watchhi,3" },
- { 19, 4, "c0_watchhi,4" },
- { 19, 5, "c0_watchhi,5" },
- { 19, 6, "c0_watchhi,6" },
- { 19, 7, "c0_watchhi,7" },
- { 23, 1, "c0_tracecontrol" },
- { 23, 2, "c0_tracecontrol2" },
- { 23, 3, "c0_usertracedata" },
- { 23, 4, "c0_tracebpc" },
- { 25, 1, "c0_perfcnt,1" },
- { 25, 2, "c0_perfcnt,2" },
- { 25, 3, "c0_perfcnt,3" },
- { 25, 4, "c0_perfcnt,4" },
- { 25, 5, "c0_perfcnt,5" },
- { 25, 6, "c0_perfcnt,6" },
- { 25, 7, "c0_perfcnt,7" },
- { 27, 1, "c0_cacheerr,1" },
- { 27, 2, "c0_cacheerr,2" },
- { 27, 3, "c0_cacheerr,3" },
- { 28, 1, "c0_datalo" },
- { 28, 2, "c0_taglo1" },
- { 28, 3, "c0_datalo1" },
- { 28, 4, "c0_taglo2" },
- { 28, 5, "c0_datalo2" },
- { 28, 6, "c0_taglo3" },
- { 28, 7, "c0_datalo3" },
- { 29, 1, "c0_datahi" },
- { 29, 2, "c0_taghi1" },
- { 29, 3, "c0_datahi1" },
- { 29, 4, "c0_taghi2" },
- { 29, 5, "c0_datahi2" },
- { 29, 6, "c0_taghi3" },
- { 29, 7, "c0_datahi3" },
-};
-
-/* SB-1: MIPS64 (mips_cp0_names_mips3264) with minor mods. */
-static const char * const mips_cp0_names_sb1[32] = {
- "c0_index", "c0_random", "c0_entrylo0", "c0_entrylo1",
- "c0_context", "c0_pagemask", "c0_wired", "$7",
- "c0_badvaddr", "c0_count", "c0_entryhi", "c0_compare",
- "c0_status", "c0_cause", "c0_epc", "c0_prid",
- "c0_config", "c0_lladdr", "c0_watchlo", "c0_watchhi",
- "c0_xcontext", "$21", "$22", "c0_debug",
- "c0_depc", "c0_perfcnt", "c0_errctl", "c0_cacheerr_i",
- "c0_taglo_i", "c0_taghi_i", "c0_errorepc", "c0_desave",
-};
-
-static const struct mips_cp0sel_name mips_cp0sel_names_sb1[] = {
- { 16, 1, "c0_config1" },
- { 18, 1, "c0_watchlo,1" },
- { 19, 1, "c0_watchhi,1" },
- { 22, 0, "c0_perftrace" },
- { 23, 3, "c0_edebug" },
- { 25, 1, "c0_perfcnt,1" },
- { 25, 2, "c0_perfcnt,2" },
- { 25, 3, "c0_perfcnt,3" },
- { 25, 4, "c0_perfcnt,4" },
- { 25, 5, "c0_perfcnt,5" },
- { 25, 6, "c0_perfcnt,6" },
- { 25, 7, "c0_perfcnt,7" },
- { 26, 1, "c0_buserr_pa" },
- { 27, 1, "c0_cacheerr_d" },
- { 27, 3, "c0_cacheerr_d_pa" },
- { 28, 1, "c0_datalo_i" },
- { 28, 2, "c0_taglo_d" },
- { 28, 3, "c0_datalo_d" },
- { 29, 1, "c0_datahi_i" },
- { 29, 2, "c0_taghi_d" },
- { 29, 3, "c0_datahi_d" },
-};
-
-static const char * const mips_hwr_names_numeric[32] = {
- "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
- "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
- "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
- "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
-};
-
-static const char * const mips_hwr_names_mips3264r2[32] = {
- "hwr_cpunum", "hwr_synci_step", "hwr_cc", "hwr_ccres",
- "$4", "$5", "$6", "$7",
- "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
- "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
- "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31"
-};
-
-struct mips_abi_choice {
- const char *name;
- const char * const *gpr_names;
- const char * const *fpr_names;
-};
-
-struct mips_abi_choice mips_abi_choices[] = {
- { "numeric", mips_gpr_names_numeric, mips_fpr_names_numeric },
- { "32", mips_gpr_names_oldabi, mips_fpr_names_32 },
- { "n32", mips_gpr_names_newabi, mips_fpr_names_n32 },
- { "64", mips_gpr_names_newabi, mips_fpr_names_64 },
-};
-
-struct mips_arch_choice {
- const char *name;
- int bfd_mach_valid;
- unsigned long bfd_mach;
- int processor;
- int isa;
- const char * const *cp0_names;
- const struct mips_cp0sel_name *cp0sel_names;
- unsigned int cp0sel_names_len;
- const char * const *hwr_names;
-};
-
-#define bfd_mach_mips3000 3000
-#define bfd_mach_mips3900 3900
-#define bfd_mach_mips4000 4000
-#define bfd_mach_mips4010 4010
-#define bfd_mach_mips4100 4100
-#define bfd_mach_mips4111 4111
-#define bfd_mach_mips4120 4120
-#define bfd_mach_mips4300 4300
-#define bfd_mach_mips4400 4400
-#define bfd_mach_mips4600 4600
-#define bfd_mach_mips4650 4650
-#define bfd_mach_mips5000 5000
-#define bfd_mach_mips5400 5400
-#define bfd_mach_mips5500 5500
-#define bfd_mach_mips6000 6000
-#define bfd_mach_mips7000 7000
-#define bfd_mach_mips8000 8000
-#define bfd_mach_mips10000 10000
-#define bfd_mach_mips12000 12000
-#define bfd_mach_mips16 16
-#define bfd_mach_mips5 5
-#define bfd_mach_mips_sb1 12310201 /* octal 'SB', 01 */
-#define bfd_mach_mipsisa32 32
-#define bfd_mach_mipsisa32r2 33
-#define bfd_mach_mipsisa64 64
-#define bfd_mach_mipsisa64r2 65
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
-
-const struct mips_arch_choice mips_arch_choices[] = {
- { "numeric", 0, 0, 0, 0,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
-
- { "r3000", 1, bfd_mach_mips3000, CPU_R3000, ISA_MIPS1,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r3900", 1, bfd_mach_mips3900, CPU_R3900, ISA_MIPS1,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r4000", 1, bfd_mach_mips4000, CPU_R4000, ISA_MIPS3,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r4010", 1, bfd_mach_mips4010, CPU_R4010, ISA_MIPS2,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "vr4100", 1, bfd_mach_mips4100, CPU_VR4100, ISA_MIPS3,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "vr4111", 1, bfd_mach_mips4111, CPU_R4111, ISA_MIPS3,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "vr4120", 1, bfd_mach_mips4120, CPU_VR4120, ISA_MIPS3,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r4300", 1, bfd_mach_mips4300, CPU_R4300, ISA_MIPS3,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r4400", 1, bfd_mach_mips4400, CPU_R4400, ISA_MIPS3,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r4600", 1, bfd_mach_mips4600, CPU_R4600, ISA_MIPS3,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r4650", 1, bfd_mach_mips4650, CPU_R4650, ISA_MIPS3,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r5000", 1, bfd_mach_mips5000, CPU_R5000, ISA_MIPS4,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "vr5400", 1, bfd_mach_mips5400, CPU_VR5400, ISA_MIPS4,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "vr5500", 1, bfd_mach_mips5500, CPU_VR5500, ISA_MIPS4,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r6000", 1, bfd_mach_mips6000, CPU_R6000, ISA_MIPS2,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "rm7000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "rm9000", 1, bfd_mach_mips7000, CPU_RM7000, ISA_MIPS4,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r8000", 1, bfd_mach_mips8000, CPU_R8000, ISA_MIPS4,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r10000", 1, bfd_mach_mips10000, CPU_R10000, ISA_MIPS4,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "r12000", 1, bfd_mach_mips12000, CPU_R12000, ISA_MIPS4,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
- { "mips5", 1, bfd_mach_mips5, CPU_MIPS5, ISA_MIPS5,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
-
- /* For stock MIPS32, disassemble all applicable MIPS-specified ASEs.
- Note that MIPS-3D and MDMX are not applicable to MIPS32. (See
- _MIPS32 Architecture For Programmers Volume I: Introduction to the
- MIPS32 Architecture_ (MIPS Document Number MD00082, Revision 0.95),
- page 1. */
- { "mips32", 1, bfd_mach_mipsisa32, CPU_MIPS32,
- ISA_MIPS32 | INSN_MIPS16,
- mips_cp0_names_mips3264,
- mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
- mips_hwr_names_numeric },
-
- { "mips32r2", 1, bfd_mach_mipsisa32r2, CPU_MIPS32R2,
- ISA_MIPS32R2 | INSN_MIPS16,
- mips_cp0_names_mips3264r2,
- mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
- mips_hwr_names_mips3264r2 },
-
- /* For stock MIPS64, disassemble all applicable MIPS-specified ASEs. */
- { "mips64", 1, bfd_mach_mipsisa64, CPU_MIPS64,
- ISA_MIPS64 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
- mips_cp0_names_mips3264,
- mips_cp0sel_names_mips3264, ARRAY_SIZE (mips_cp0sel_names_mips3264),
- mips_hwr_names_numeric },
-
- { "mips64r2", 1, bfd_mach_mipsisa64r2, CPU_MIPS64R2,
- ISA_MIPS64R2 | INSN_MIPS16 | INSN_MIPS3D | INSN_MDMX,
- mips_cp0_names_mips3264r2,
- mips_cp0sel_names_mips3264r2, ARRAY_SIZE (mips_cp0sel_names_mips3264r2),
- mips_hwr_names_mips3264r2 },
-
- { "sb1", 1, bfd_mach_mips_sb1, CPU_SB1,
- ISA_MIPS64 | INSN_MIPS3D | INSN_SB1,
- mips_cp0_names_sb1,
- mips_cp0sel_names_sb1, ARRAY_SIZE (mips_cp0sel_names_sb1),
- mips_hwr_names_numeric },
-
- /* This entry, mips16, is here only for ISA/processor selection; do
- not print its name. */
- { "", 1, bfd_mach_mips16, CPU_MIPS16, ISA_MIPS3 | INSN_MIPS16,
- mips_cp0_names_numeric, NULL, 0, mips_hwr_names_numeric },
-};
-
-/* ISA and processor type to disassemble for, and register names to use.
- set_default_mips_dis_options and parse_mips_dis_options fill in these
- values. */
-static int mips_processor;
-static int mips_isa;
-static const char * const *mips_gpr_names;
-static const char * const *mips_fpr_names;
-static const char * const *mips_cp0_names;
-static const struct mips_cp0sel_name *mips_cp0sel_names;
-static int mips_cp0sel_names_len;
-static const char * const *mips_hwr_names;
-
-static const struct mips_abi_choice *choose_abi_by_name
- PARAMS ((const char *, unsigned int));
-static const struct mips_arch_choice *choose_arch_by_name
- PARAMS ((const char *, unsigned int));
-static const struct mips_arch_choice *choose_arch_by_number
- PARAMS ((unsigned long));
-static const struct mips_cp0sel_name *lookup_mips_cp0sel_name
- PARAMS ((const struct mips_cp0sel_name *, unsigned int, unsigned int,
- unsigned int));
-
-static const struct mips_abi_choice *
-choose_abi_by_name (name, namelen)
- const char *name;
- unsigned int namelen;
-{
- const struct mips_abi_choice *c;
- unsigned int i;
-
- for (i = 0, c = NULL; i < ARRAY_SIZE (mips_abi_choices) && c == NULL; i++)
- {
- if (strncmp (mips_abi_choices[i].name, name, namelen) == 0
- && strlen (mips_abi_choices[i].name) == namelen)
- c = &mips_abi_choices[i];
- }
- return c;
-}
-
-static const struct mips_arch_choice *
-choose_arch_by_name (name, namelen)
- const char *name;
- unsigned int namelen;
-{
- const struct mips_arch_choice *c = NULL;
- unsigned int i;
-
- for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
- {
- if (strncmp (mips_arch_choices[i].name, name, namelen) == 0
- && strlen (mips_arch_choices[i].name) == namelen)
- c = &mips_arch_choices[i];
- }
- return c;
-}
-
-static const struct mips_arch_choice *
-choose_arch_by_number (mach)
- unsigned long mach;
-{
- static unsigned long hint_bfd_mach;
- static const struct mips_arch_choice *hint_arch_choice;
- const struct mips_arch_choice *c;
- unsigned int i;
-
- /* We optimize this because even if the user specifies no
- flags, this will be done for every instruction! */
- if (hint_bfd_mach == mach
- && hint_arch_choice != NULL
- && hint_arch_choice->bfd_mach == hint_bfd_mach)
- return hint_arch_choice;
-
- for (i = 0, c = NULL; i < ARRAY_SIZE (mips_arch_choices) && c == NULL; i++)
- {
- if (mips_arch_choices[i].bfd_mach_valid
- && mips_arch_choices[i].bfd_mach == mach)
- {
- c = &mips_arch_choices[i];
- hint_bfd_mach = mach;
- hint_arch_choice = c;
- }
- }
- return c;
-}
-
-void
-set_default_mips_dis_options (info)
- struct disassemble_info *info;
-{
- const struct mips_arch_choice *chosen_arch;
-
- /* Defaults: mipsIII/r3000 (?!), (o)32-style ("oldabi") GPR names,
- and numeric FPR, CP0 register, and HWR names. */
- mips_isa = ISA_MIPS3;
- mips_processor = CPU_R3000;
- mips_gpr_names = mips_gpr_names_oldabi;
- mips_fpr_names = mips_fpr_names_numeric;
- mips_cp0_names = mips_cp0_names_numeric;
- mips_cp0sel_names = NULL;
- mips_cp0sel_names_len = 0;
- mips_hwr_names = mips_hwr_names_numeric;
-
- /* If an ELF "newabi" binary, use the n32/(n)64 GPR names. */
-#if 0
- if (info->flavour == bfd_target_elf_flavour && info->section != NULL)
- {
- Elf_Internal_Ehdr *header;
-
- header = elf_elfheader (info->section->owner);
- if (is_newabi (header))
- mips_gpr_names = mips_gpr_names_newabi;
- }
-#endif
-
- /* Set ISA, architecture, and cp0 register names as best we can. */
-#if ! SYMTAB_AVAILABLE && 0
- /* This is running out on a target machine, not in a host tool.
- FIXME: Where does mips_target_info come from? */
- target_processor = mips_target_info.processor;
- mips_isa = mips_target_info.isa;
-#else
- chosen_arch = choose_arch_by_number (info->mach);
- if (chosen_arch != NULL)
- {
- mips_processor = chosen_arch->processor;
- mips_isa = chosen_arch->isa;
- mips_cp0_names = chosen_arch->cp0_names;
- mips_cp0sel_names = chosen_arch->cp0sel_names;
- mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
- mips_hwr_names = chosen_arch->hwr_names;
- }
-#endif
-}
-
-void
-parse_mips_dis_option (option, len)
- const char *option;
- unsigned int len;
-{
- unsigned int i, optionlen, vallen;
- const char *val;
- const struct mips_abi_choice *chosen_abi;
- const struct mips_arch_choice *chosen_arch;
-
- /* Look for the = that delimits the end of the option name. */
- for (i = 0; i < len; i++)
- {
- if (option[i] == '=')
- break;
- }
- if (i == 0) /* Invalid option: no name before '='. */
- return;
- if (i == len) /* Invalid option: no '='. */
- return;
- if (i == (len - 1)) /* Invalid option: no value after '='. */
- return;
-
- optionlen = i;
- val = option + (optionlen + 1);
- vallen = len - (optionlen + 1);
-
- if (strncmp("gpr-names", option, optionlen) == 0
- && strlen("gpr-names") == optionlen)
- {
- chosen_abi = choose_abi_by_name (val, vallen);
- if (chosen_abi != NULL)
- mips_gpr_names = chosen_abi->gpr_names;
- return;
- }
-
- if (strncmp("fpr-names", option, optionlen) == 0
- && strlen("fpr-names") == optionlen)
- {
- chosen_abi = choose_abi_by_name (val, vallen);
- if (chosen_abi != NULL)
- mips_fpr_names = chosen_abi->fpr_names;
- return;
- }
-
- if (strncmp("cp0-names", option, optionlen) == 0
- && strlen("cp0-names") == optionlen)
- {
- chosen_arch = choose_arch_by_name (val, vallen);
- if (chosen_arch != NULL)
- {
- mips_cp0_names = chosen_arch->cp0_names;
- mips_cp0sel_names = chosen_arch->cp0sel_names;
- mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
- }
- return;
- }
-
- if (strncmp("hwr-names", option, optionlen) == 0
- && strlen("hwr-names") == optionlen)
- {
- chosen_arch = choose_arch_by_name (val, vallen);
- if (chosen_arch != NULL)
- mips_hwr_names = chosen_arch->hwr_names;
- return;
- }
-
- if (strncmp("reg-names", option, optionlen) == 0
- && strlen("reg-names") == optionlen)
- {
- /* We check both ABI and ARCH here unconditionally, so
- that "numeric" will do the desirable thing: select
- numeric register names for all registers. Other than
- that, a given name probably won't match both. */
- chosen_abi = choose_abi_by_name (val, vallen);
- if (chosen_abi != NULL)
- {
- mips_gpr_names = chosen_abi->gpr_names;
- mips_fpr_names = chosen_abi->fpr_names;
- }
- chosen_arch = choose_arch_by_name (val, vallen);
- if (chosen_arch != NULL)
- {
- mips_cp0_names = chosen_arch->cp0_names;
- mips_cp0sel_names = chosen_arch->cp0sel_names;
- mips_cp0sel_names_len = chosen_arch->cp0sel_names_len;
- mips_hwr_names = chosen_arch->hwr_names;
- }
- return;
- }
-
- /* Invalid option. */
-}
-
-void
-parse_mips_dis_options (options)
- const char *options;
-{
- const char *option_end;
-
- if (options == NULL)
- return;
-
- while (*options != '\0')
- {
- /* Skip empty options. */
- if (*options == ',')
- {
- options++;
- continue;
- }
-
- /* We know that *options is neither NUL or a comma. */
- option_end = options + 1;
- while (*option_end != ',' && *option_end != '\0')
- option_end++;
-
- parse_mips_dis_option (options, option_end - options);
-
- /* Go on to the next one. If option_end points to a comma, it
- will be skipped above. */
- options = option_end;
- }
-}
-
-static const struct mips_cp0sel_name *
-lookup_mips_cp0sel_name(names, len, cp0reg, sel)
- const struct mips_cp0sel_name *names;
- unsigned int len, cp0reg, sel;
-{
- unsigned int i;
-
- for (i = 0; i < len; i++)
- if (names[i].cp0reg == cp0reg && names[i].sel == sel)
- return &names[i];
- return NULL;
-}
-
-/* Print insn arguments for 32/64-bit code. */
-
-static void
-print_insn_args (d, l, pc, info)
- const char *d;
- register unsigned long int l;
- bfd_vma pc;
- struct disassemble_info *info;
-{
- int op, delta;
- unsigned int lsb, msb, msbd;
-
- lsb = 0;
-
- for (; *d != '\0'; d++)
- {
- switch (*d)
- {
- case ',':
- case '(':
- case ')':
- case '[':
- case ']':
- (*info->fprintf_func) (info->stream, "%c", *d);
- break;
-
- case '+':
- /* Extension character; switch for second char. */
- d++;
- switch (*d)
- {
- case '\0':
- /* xgettext:c-format */
- (*info->fprintf_func) (info->stream,
- _("# internal error, incomplete extension sequence (+)"));
- return;
-
- case 'A':
- lsb = (l >> OP_SH_SHAMT) & OP_MASK_SHAMT;
- (*info->fprintf_func) (info->stream, "0x%x", lsb);
- break;
-
- case 'B':
- msb = (l >> OP_SH_INSMSB) & OP_MASK_INSMSB;
- (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
- break;
-
- case 'C':
- case 'H':
- msbd = (l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD;
- (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
- break;
-
- case 'D':
- {
- const struct mips_cp0sel_name *n;
- unsigned int cp0reg, sel;
-
- cp0reg = (l >> OP_SH_RD) & OP_MASK_RD;
- sel = (l >> OP_SH_SEL) & OP_MASK_SEL;
-
- /* CP0 register including 'sel' code for mtcN (et al.), to be
- printed textually if known. If not known, print both
- CP0 register name and sel numerically since CP0 register
- with sel 0 may have a name unrelated to register being
- printed. */
- n = lookup_mips_cp0sel_name(mips_cp0sel_names,
- mips_cp0sel_names_len, cp0reg, sel);
- if (n != NULL)
- (*info->fprintf_func) (info->stream, "%s", n->name);
- else
- (*info->fprintf_func) (info->stream, "$%d,%d", cp0reg, sel);
- break;
- }
-
- case 'E':
- lsb = ((l >> OP_SH_SHAMT) & OP_MASK_SHAMT) + 32;
- (*info->fprintf_func) (info->stream, "0x%x", lsb);
- break;
-
- case 'F':
- msb = ((l >> OP_SH_INSMSB) & OP_MASK_INSMSB) + 32;
- (*info->fprintf_func) (info->stream, "0x%x", msb - lsb + 1);
- break;
-
- case 'G':
- msbd = ((l >> OP_SH_EXTMSBD) & OP_MASK_EXTMSBD) + 32;
- (*info->fprintf_func) (info->stream, "0x%x", msbd + 1);
- break;
-
- default:
- /* xgettext:c-format */
- (*info->fprintf_func) (info->stream,
- _("# internal error, undefined extension sequence (+%c)"),
- *d);
- return;
- }
- break;
-
- case 's':
- case 'b':
- case 'r':
- case 'v':
- (*info->fprintf_func) (info->stream, "%s",
- mips_gpr_names[(l >> OP_SH_RS) & OP_MASK_RS]);
- break;
-
- case 't':
- case 'w':
- (*info->fprintf_func) (info->stream, "%s",
- mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
- break;
-
- case 'i':
- case 'u':
- (*info->fprintf_func) (info->stream, "0x%x",
- (l >> OP_SH_IMMEDIATE) & OP_MASK_IMMEDIATE);
- break;
-
- case 'j': /* Same as i, but sign-extended. */
- case 'o':
- delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
- if (delta & 0x8000)
- delta |= ~0xffff;
- (*info->fprintf_func) (info->stream, "%d",
- delta);
- break;
-
- case 'h':
- (*info->fprintf_func) (info->stream, "0x%x",
- (unsigned int) ((l >> OP_SH_PREFX)
- & OP_MASK_PREFX));
- break;
-
- case 'k':
- (*info->fprintf_func) (info->stream, "0x%x",
- (unsigned int) ((l >> OP_SH_CACHE)
- & OP_MASK_CACHE));
- break;
-
- case 'a':
- info->target = (((pc + 4) & ~(bfd_vma) 0x0fffffff)
- | (((l >> OP_SH_TARGET) & OP_MASK_TARGET) << 2));
- (*info->print_address_func) (info->target, info);
- break;
-
- case 'p':
- /* Sign extend the displacement. */
- delta = (l >> OP_SH_DELTA) & OP_MASK_DELTA;
- if (delta & 0x8000)
- delta |= ~0xffff;
- info->target = (delta << 2) + pc + INSNLEN;
- (*info->print_address_func) (info->target, info);
- break;
-
- case 'd':
- (*info->fprintf_func) (info->stream, "%s",
- mips_gpr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
- break;
-
- case 'U':
- {
- /* First check for both rd and rt being equal. */
- unsigned int reg = (l >> OP_SH_RD) & OP_MASK_RD;
- if (reg == ((l >> OP_SH_RT) & OP_MASK_RT))
- (*info->fprintf_func) (info->stream, "%s",
- mips_gpr_names[reg]);
- else
- {
- /* If one is zero use the other. */
- if (reg == 0)
- (*info->fprintf_func) (info->stream, "%s",
- mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
- else if (((l >> OP_SH_RT) & OP_MASK_RT) == 0)
- (*info->fprintf_func) (info->stream, "%s",
- mips_gpr_names[reg]);
- else /* Bogus, result depends on processor. */
- (*info->fprintf_func) (info->stream, "%s or %s",
- mips_gpr_names[reg],
- mips_gpr_names[(l >> OP_SH_RT) & OP_MASK_RT]);
- }
- }
- break;
-
- case 'z':
- (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
- break;
-
- case '<':
- (*info->fprintf_func) (info->stream, "0x%x",
- (l >> OP_SH_SHAMT) & OP_MASK_SHAMT);
- break;
-
- case 'c':
- (*info->fprintf_func) (info->stream, "0x%x",
- (l >> OP_SH_CODE) & OP_MASK_CODE);
- break;
-
- case 'q':
- (*info->fprintf_func) (info->stream, "0x%x",
- (l >> OP_SH_CODE2) & OP_MASK_CODE2);
- break;
-
- case 'C':
- (*info->fprintf_func) (info->stream, "0x%x",
- (l >> OP_SH_COPZ) & OP_MASK_COPZ);
- break;
-
- case 'B':
- (*info->fprintf_func) (info->stream, "0x%x",
- (l >> OP_SH_CODE20) & OP_MASK_CODE20);
- break;
-
- case 'J':
- (*info->fprintf_func) (info->stream, "0x%x",
- (l >> OP_SH_CODE19) & OP_MASK_CODE19);
- break;
-
- case 'S':
- case 'V':
- (*info->fprintf_func) (info->stream, "%s",
- mips_fpr_names[(l >> OP_SH_FS) & OP_MASK_FS]);
- break;
-
- case 'T':
- case 'W':
- (*info->fprintf_func) (info->stream, "%s",
- mips_fpr_names[(l >> OP_SH_FT) & OP_MASK_FT]);
- break;
-
- case 'D':
- (*info->fprintf_func) (info->stream, "%s",
- mips_fpr_names[(l >> OP_SH_FD) & OP_MASK_FD]);
- break;
-
- case 'R':
- (*info->fprintf_func) (info->stream, "%s",
- mips_fpr_names[(l >> OP_SH_FR) & OP_MASK_FR]);
- break;
-
- case 'E':
- /* Coprocessor register for lwcN instructions, et al.
-
- Note that there is no load/store cp0 instructions, and
- that FPU (cp1) instructions disassemble this field using
- 'T' format. Therefore, until we gain understanding of
- cp2 register names, we can simply print the register
- numbers. */
- (*info->fprintf_func) (info->stream, "$%d",
- (l >> OP_SH_RT) & OP_MASK_RT);
- break;
-
- case 'G':
- /* Coprocessor register for mtcN instructions, et al. Note
- that FPU (cp1) instructions disassemble this field using
- 'S' format. Therefore, we only need to worry about cp0,
- cp2, and cp3. */
- op = (l >> OP_SH_OP) & OP_MASK_OP;
- if (op == OP_OP_COP0)
- (*info->fprintf_func) (info->stream, "%s",
- mips_cp0_names[(l >> OP_SH_RD) & OP_MASK_RD]);
- else
- (*info->fprintf_func) (info->stream, "$%d",
- (l >> OP_SH_RD) & OP_MASK_RD);
- break;
-
- case 'K':
- (*info->fprintf_func) (info->stream, "%s",
- mips_hwr_names[(l >> OP_SH_RD) & OP_MASK_RD]);
- break;
-
- case 'N':
- (*info->fprintf_func) (info->stream, "$fcc%d",
- (l >> OP_SH_BCC) & OP_MASK_BCC);
- break;
-
- case 'M':
- (*info->fprintf_func) (info->stream, "$fcc%d",
- (l >> OP_SH_CCC) & OP_MASK_CCC);
- break;
-
- case 'P':
- (*info->fprintf_func) (info->stream, "%d",
- (l >> OP_SH_PERFREG) & OP_MASK_PERFREG);
- break;
-
- case 'e':
- (*info->fprintf_func) (info->stream, "%d",
- (l >> OP_SH_VECBYTE) & OP_MASK_VECBYTE);
- break;
-
- case '%':
- (*info->fprintf_func) (info->stream, "%d",
- (l >> OP_SH_VECALIGN) & OP_MASK_VECALIGN);
- break;
-
- case 'H':
- (*info->fprintf_func) (info->stream, "%d",
- (l >> OP_SH_SEL) & OP_MASK_SEL);
- break;
-
- case 'O':
- (*info->fprintf_func) (info->stream, "%d",
- (l >> OP_SH_ALN) & OP_MASK_ALN);
- break;
-
- case 'Q':
- {
- unsigned int vsel = (l >> OP_SH_VSEL) & OP_MASK_VSEL;
- if ((vsel & 0x10) == 0)
- {
- int fmt;
- vsel &= 0x0f;
- for (fmt = 0; fmt < 3; fmt++, vsel >>= 1)
- if ((vsel & 1) == 0)
- break;
- (*info->fprintf_func) (info->stream, "$v%d[%d]",
- (l >> OP_SH_FT) & OP_MASK_FT,
- vsel >> 1);
- }
- else if ((vsel & 0x08) == 0)
- {
- (*info->fprintf_func) (info->stream, "$v%d",
- (l >> OP_SH_FT) & OP_MASK_FT);
- }
- else
- {
- (*info->fprintf_func) (info->stream, "0x%x",
- (l >> OP_SH_FT) & OP_MASK_FT);
- }
- }
- break;
-
- case 'X':
- (*info->fprintf_func) (info->stream, "$v%d",
- (l >> OP_SH_FD) & OP_MASK_FD);
- break;
-
- case 'Y':
- (*info->fprintf_func) (info->stream, "$v%d",
- (l >> OP_SH_FS) & OP_MASK_FS);
- break;
-
- case 'Z':
- (*info->fprintf_func) (info->stream, "$v%d",
- (l >> OP_SH_FT) & OP_MASK_FT);
- break;
-
- default:
- /* xgettext:c-format */
- (*info->fprintf_func) (info->stream,
- _("# internal error, undefined modifier(%c)"),
- *d);
- return;
- }
- }
-}
-
-/* Check if the object uses NewABI conventions. */
-#if 0
-static int
-is_newabi (header)
- Elf_Internal_Ehdr *header;
-{
- /* There are no old-style ABIs which use 64-bit ELF. */
- if (header->e_ident[EI_CLASS] == ELFCLASS64)
- return 1;
-
- /* If a 32-bit ELF file, n32 is a new-style ABI. */
- if ((header->e_flags & EF_MIPS_ABI2) != 0)
- return 1;
-
- return 0;
-}
-#endif
-
-/* Print the mips instruction at address MEMADDR in debugged memory,
- on using INFO. Returns length of the instruction, in bytes, which is
- always INSNLEN. BIGENDIAN must be 1 if this is big-endian code, 0 if
- this is little-endian code. */
-
-static int
-print_insn_mips (memaddr, word, info)
- bfd_vma memaddr;
- unsigned long int word;
- struct disassemble_info *info;
-{
- register const struct mips_opcode *op;
- static bfd_boolean init = 0;
- static const struct mips_opcode *mips_hash[OP_MASK_OP + 1];
-
- /* Build a hash table to shorten the search time. */
- if (! init)
- {
- unsigned int i;
-
- for (i = 0; i <= OP_MASK_OP; i++)
- {
- for (op = mips_opcodes; op < &mips_opcodes[NUMOPCODES]; op++)
- {
- if (op->pinfo == INSN_MACRO)
- continue;
- if (i == ((op->match >> OP_SH_OP) & OP_MASK_OP))
- {
- mips_hash[i] = op;
- break;
- }
- }
- }
-
- init = 1;
- }
-
- info->bytes_per_chunk = INSNLEN;
- info->display_endian = info->endian;
- info->insn_info_valid = 1;
- info->branch_delay_insns = 0;
- info->data_size = 0;
- info->insn_type = dis_nonbranch;
- info->target = 0;
- info->target2 = 0;
-
- op = mips_hash[(word >> OP_SH_OP) & OP_MASK_OP];
- if (op != NULL)
- {
- for (; op < &mips_opcodes[NUMOPCODES]; op++)
- {
- if (op->pinfo != INSN_MACRO && (word & op->mask) == op->match)
- {
- register const char *d;
-
- /* We always allow to disassemble the jalx instruction. */
- if (! OPCODE_IS_MEMBER (op, mips_isa, mips_processor)
- && strcmp (op->name, "jalx"))
- continue;
-
- /* Figure out instruction type and branch delay information. */
- if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
- {
- if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
- info->insn_type = dis_jsr;
- else
- info->insn_type = dis_branch;
- info->branch_delay_insns = 1;
- }
- else if ((op->pinfo & (INSN_COND_BRANCH_DELAY
- | INSN_COND_BRANCH_LIKELY)) != 0)
- {
- if ((info->insn_type & INSN_WRITE_GPR_31) != 0)
- info->insn_type = dis_condjsr;
- else
- info->insn_type = dis_condbranch;
- info->branch_delay_insns = 1;
- }
- else if ((op->pinfo & (INSN_STORE_MEMORY
- | INSN_LOAD_MEMORY_DELAY)) != 0)
- info->insn_type = dis_dref;
-
- (*info->fprintf_func) (info->stream, "%s", op->name);
-
- d = op->args;
- if (d != NULL && *d != '\0')
- {
- (*info->fprintf_func) (info->stream, "\t");
- print_insn_args (d, word, memaddr, info);
- }
-
- return INSNLEN;
- }
- }
- }
-
- /* Handle undefined instructions. */
- info->insn_type = dis_noninsn;
- (*info->fprintf_func) (info->stream, "0x%x", word);
- return INSNLEN;
-}
-
-/* In an environment where we do not know the symbol type of the
- instruction we are forced to assume that the low order bit of the
- instructions' address may mark it as a mips16 instruction. If we
- are single stepping, or the pc is within the disassembled function,
- this works. Otherwise, we need a clue. Sometimes. */
-
-static int
-_print_insn_mips (memaddr, info, endianness)
- bfd_vma memaddr;
- struct disassemble_info *info;
- enum bfd_endian endianness;
-{
- bfd_byte buffer[INSNLEN];
- int status;
-
- set_default_mips_dis_options (info);
- parse_mips_dis_options (info->disassembler_options);
-
-#if 0
-#if 1
- /* FIXME: If odd address, this is CLEARLY a mips 16 instruction. */
- /* Only a few tools will work this way. */
- if (memaddr & 0x01)
- return print_insn_mips16 (memaddr, info);
-#endif
-
-#if SYMTAB_AVAILABLE
- if (info->mach == bfd_mach_mips16
- || (info->flavour == bfd_target_elf_flavour
- && info->symbols != NULL
- && ((*(elf_symbol_type **) info->symbols)->internal_elf_sym.st_other
- == STO_MIPS16)))
- return print_insn_mips16 (memaddr, info);
-#endif
-#endif
-
- status = (*info->read_memory_func) (memaddr, buffer, INSNLEN, info);
- if (status == 0)
- {
- unsigned long insn;
-
- if (endianness == BFD_ENDIAN_BIG)
- insn = (unsigned long) bfd_getb32 (buffer);
- else
- insn = (unsigned long) bfd_getl32 (buffer);
-
- return print_insn_mips (memaddr, insn, info);
- }
- else
- {
- (*info->memory_error_func) (status, memaddr, info);
- return -1;
- }
-}
-
-int
-print_insn_big_mips (memaddr, info)
- bfd_vma memaddr;
- struct disassemble_info *info;
-{
- return _print_insn_mips (memaddr, info, BFD_ENDIAN_BIG);
-}
-
-int
-print_insn_little_mips (memaddr, info)
- bfd_vma memaddr;
- struct disassemble_info *info;
-{
- return _print_insn_mips (memaddr, info, BFD_ENDIAN_LITTLE);
-}
-
-/* Disassemble mips16 instructions. */
-#if 0
-static int
-print_insn_mips16 (memaddr, info)
- bfd_vma memaddr;
- struct disassemble_info *info;
-{
- int status;
- bfd_byte buffer[2];
- int length;
- int insn;
- bfd_boolean use_extend;
- int extend = 0;
- const struct mips_opcode *op, *opend;
-
- info->bytes_per_chunk = 2;
- info->display_endian = info->endian;
- info->insn_info_valid = 1;
- info->branch_delay_insns = 0;
- info->data_size = 0;
- info->insn_type = dis_nonbranch;
- info->target = 0;
- info->target2 = 0;
-
- status = (*info->read_memory_func) (memaddr, buffer, 2, info);
- if (status != 0)
- {
- (*info->memory_error_func) (status, memaddr, info);
- return -1;
- }
-
- length = 2;
-
- if (info->endian == BFD_ENDIAN_BIG)
- insn = bfd_getb16 (buffer);
- else
- insn = bfd_getl16 (buffer);
-
- /* Handle the extend opcode specially. */
- use_extend = FALSE;
- if ((insn & 0xf800) == 0xf000)
- {
- use_extend = TRUE;
- extend = insn & 0x7ff;
-
- memaddr += 2;
-
- status = (*info->read_memory_func) (memaddr, buffer, 2, info);
- if (status != 0)
- {
- (*info->fprintf_func) (info->stream, "extend 0x%x",
- (unsigned int) extend);
- (*info->memory_error_func) (status, memaddr, info);
- return -1;
- }
-
- if (info->endian == BFD_ENDIAN_BIG)
- insn = bfd_getb16 (buffer);
- else
- insn = bfd_getl16 (buffer);
-
- /* Check for an extend opcode followed by an extend opcode. */
- if ((insn & 0xf800) == 0xf000)
- {
- (*info->fprintf_func) (info->stream, "extend 0x%x",
- (unsigned int) extend);
- info->insn_type = dis_noninsn;
- return length;
- }
-
- length += 2;
- }
-
- /* FIXME: Should probably use a hash table on the major opcode here. */
-
- opend = mips16_opcodes + bfd_mips16_num_opcodes;
- for (op = mips16_opcodes; op < opend; op++)
- {
- if (op->pinfo != INSN_MACRO && (insn & op->mask) == op->match)
- {
- const char *s;
-
- if (strchr (op->args, 'a') != NULL)
- {
- if (use_extend)
- {
- (*info->fprintf_func) (info->stream, "extend 0x%x",
- (unsigned int) extend);
- info->insn_type = dis_noninsn;
- return length - 2;
- }
-
- use_extend = FALSE;
-
- memaddr += 2;
-
- status = (*info->read_memory_func) (memaddr, buffer, 2,
- info);
- if (status == 0)
- {
- use_extend = TRUE;
- if (info->endian == BFD_ENDIAN_BIG)
- extend = bfd_getb16 (buffer);
- else
- extend = bfd_getl16 (buffer);
- length += 2;
- }
- }
-
- (*info->fprintf_func) (info->stream, "%s", op->name);
- if (op->args[0] != '\0')
- (*info->fprintf_func) (info->stream, "\t");
-
- for (s = op->args; *s != '\0'; s++)
- {
- if (*s == ','
- && s[1] == 'w'
- && (((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)
- == ((insn >> MIPS16OP_SH_RY) & MIPS16OP_MASK_RY)))
- {
- /* Skip the register and the comma. */
- ++s;
- continue;
- }
- if (*s == ','
- && s[1] == 'v'
- && (((insn >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ)
- == ((insn >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX)))
- {
- /* Skip the register and the comma. */
- ++s;
- continue;
- }
- print_mips16_insn_arg (*s, op, insn, use_extend, extend, memaddr,
- info);
- }
-
- if ((op->pinfo & INSN_UNCOND_BRANCH_DELAY) != 0)
- {
- info->branch_delay_insns = 1;
- if (info->insn_type != dis_jsr)
- info->insn_type = dis_branch;
- }
-
- return length;
- }
- }
-
- if (use_extend)
- (*info->fprintf_func) (info->stream, "0x%x", extend | 0xf000);
- (*info->fprintf_func) (info->stream, "0x%x", insn);
- info->insn_type = dis_noninsn;
-
- return length;
-}
-
-/* Disassemble an operand for a mips16 instruction. */
-
-static void
-print_mips16_insn_arg (type, op, l, use_extend, extend, memaddr, info)
- char type;
- const struct mips_opcode *op;
- int l;
- bfd_boolean use_extend;
- int extend;
- bfd_vma memaddr;
- struct disassemble_info *info;
-{
- switch (type)
- {
- case ',':
- case '(':
- case ')':
- (*info->fprintf_func) (info->stream, "%c", type);
- break;
-
- case 'y':
- case 'w':
- (*info->fprintf_func) (info->stream, "%s",
- mips16_reg_names[((l >> MIPS16OP_SH_RY)
- & MIPS16OP_MASK_RY)]);
- break;
-
- case 'x':
- case 'v':
- (*info->fprintf_func) (info->stream, "%s",
- mips16_reg_names[((l >> MIPS16OP_SH_RX)
- & MIPS16OP_MASK_RX)]);
- break;
-
- case 'z':
- (*info->fprintf_func) (info->stream, "%s",
- mips16_reg_names[((l >> MIPS16OP_SH_RZ)
- & MIPS16OP_MASK_RZ)]);
- break;
-
- case 'Z':
- (*info->fprintf_func) (info->stream, "%s",
- mips16_reg_names[((l >> MIPS16OP_SH_MOVE32Z)
- & MIPS16OP_MASK_MOVE32Z)]);
- break;
-
- case '0':
- (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[0]);
- break;
-
- case 'S':
- (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[29]);
- break;
-
- case 'P':
- (*info->fprintf_func) (info->stream, "$pc");
- break;
-
- case 'R':
- (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[31]);
- break;
-
- case 'X':
- (*info->fprintf_func) (info->stream, "%s",
- mips_gpr_names[((l >> MIPS16OP_SH_REGR32)
- & MIPS16OP_MASK_REGR32)]);
- break;
-
- case 'Y':
- (*info->fprintf_func) (info->stream, "%s",
- mips_gpr_names[MIPS16OP_EXTRACT_REG32R (l)]);
- break;
-
- case '<':
- case '>':
- case '[':
- case ']':
- case '4':
- case '5':
- case 'H':
- case 'W':
- case 'D':
- case 'j':
- case '6':
- case '8':
- case 'V':
- case 'C':
- case 'U':
- case 'k':
- case 'K':
- case 'p':
- case 'q':
- case 'A':
- case 'B':
- case 'E':
- {
- int immed, nbits, shift, signedp, extbits, pcrel, extu, branch;
-
- shift = 0;
- signedp = 0;
- extbits = 16;
- pcrel = 0;
- extu = 0;
- branch = 0;
- switch (type)
- {
- case '<':
- nbits = 3;
- immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
- extbits = 5;
- extu = 1;
- break;
- case '>':
- nbits = 3;
- immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
- extbits = 5;
- extu = 1;
- break;
- case '[':
- nbits = 3;
- immed = (l >> MIPS16OP_SH_RZ) & MIPS16OP_MASK_RZ;
- extbits = 6;
- extu = 1;
- break;
- case ']':
- nbits = 3;
- immed = (l >> MIPS16OP_SH_RX) & MIPS16OP_MASK_RX;
- extbits = 6;
- extu = 1;
- break;
- case '4':
- nbits = 4;
- immed = (l >> MIPS16OP_SH_IMM4) & MIPS16OP_MASK_IMM4;
- signedp = 1;
- extbits = 15;
- break;
- case '5':
- nbits = 5;
- immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
- info->insn_type = dis_dref;
- info->data_size = 1;
- break;
- case 'H':
- nbits = 5;
- shift = 1;
- immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
- info->insn_type = dis_dref;
- info->data_size = 2;
- break;
- case 'W':
- nbits = 5;
- shift = 2;
- immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
- if ((op->pinfo & MIPS16_INSN_READ_PC) == 0
- && (op->pinfo & MIPS16_INSN_READ_SP) == 0)
- {
- info->insn_type = dis_dref;
- info->data_size = 4;
- }
- break;
- case 'D':
- nbits = 5;
- shift = 3;
- immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
- info->insn_type = dis_dref;
- info->data_size = 8;
- break;
- case 'j':
- nbits = 5;
- immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
- signedp = 1;
- break;
- case '6':
- nbits = 6;
- immed = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
- break;
- case '8':
- nbits = 8;
- immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
- break;
- case 'V':
- nbits = 8;
- shift = 2;
- immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
- /* FIXME: This might be lw, or it might be addiu to $sp or
- $pc. We assume it's load. */
- info->insn_type = dis_dref;
- info->data_size = 4;
- break;
- case 'C':
- nbits = 8;
- shift = 3;
- immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
- info->insn_type = dis_dref;
- info->data_size = 8;
- break;
- case 'U':
- nbits = 8;
- immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
- extu = 1;
- break;
- case 'k':
- nbits = 8;
- immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
- signedp = 1;
- break;
- case 'K':
- nbits = 8;
- shift = 3;
- immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
- signedp = 1;
- break;
- case 'p':
- nbits = 8;
- immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
- signedp = 1;
- pcrel = 1;
- branch = 1;
- info->insn_type = dis_condbranch;
- break;
- case 'q':
- nbits = 11;
- immed = (l >> MIPS16OP_SH_IMM11) & MIPS16OP_MASK_IMM11;
- signedp = 1;
- pcrel = 1;
- branch = 1;
- info->insn_type = dis_branch;
- break;
- case 'A':
- nbits = 8;
- shift = 2;
- immed = (l >> MIPS16OP_SH_IMM8) & MIPS16OP_MASK_IMM8;
- pcrel = 1;
- /* FIXME: This can be lw or la. We assume it is lw. */
- info->insn_type = dis_dref;
- info->data_size = 4;
- break;
- case 'B':
- nbits = 5;
- shift = 3;
- immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
- pcrel = 1;
- info->insn_type = dis_dref;
- info->data_size = 8;
- break;
- case 'E':
- nbits = 5;
- shift = 2;
- immed = (l >> MIPS16OP_SH_IMM5) & MIPS16OP_MASK_IMM5;
- pcrel = 1;
- break;
- default:
- abort ();
- }
-
- if (! use_extend)
- {
- if (signedp && immed >= (1 << (nbits - 1)))
- immed -= 1 << nbits;
- immed <<= shift;
- if ((type == '<' || type == '>' || type == '[' || type == ']')
- && immed == 0)
- immed = 8;
- }
- else
- {
- if (extbits == 16)
- immed |= ((extend & 0x1f) << 11) | (extend & 0x7e0);
- else if (extbits == 15)
- immed |= ((extend & 0xf) << 11) | (extend & 0x7f0);
- else
- immed = ((extend >> 6) & 0x1f) | (extend & 0x20);
- immed &= (1 << extbits) - 1;
- if (! extu && immed >= (1 << (extbits - 1)))
- immed -= 1 << extbits;
- }
-
- if (! pcrel)
- (*info->fprintf_func) (info->stream, "%d", immed);
- else
- {
- bfd_vma baseaddr;
-
- if (branch)
- {
- immed *= 2;
- baseaddr = memaddr + 2;
- }
- else if (use_extend)
- baseaddr = memaddr - 2;
- else
- {
- int status;
- bfd_byte buffer[2];
-
- baseaddr = memaddr;
-
- /* If this instruction is in the delay slot of a jr
- instruction, the base address is the address of the
- jr instruction. If it is in the delay slot of jalr
- instruction, the base address is the address of the
- jalr instruction. This test is unreliable: we have
- no way of knowing whether the previous word is
- instruction or data. */
- status = (*info->read_memory_func) (memaddr - 4, buffer, 2,
- info);
- if (status == 0
- && (((info->endian == BFD_ENDIAN_BIG
- ? bfd_getb16 (buffer)
- : bfd_getl16 (buffer))
- & 0xf800) == 0x1800))
- baseaddr = memaddr - 4;
- else
- {
- status = (*info->read_memory_func) (memaddr - 2, buffer,
- 2, info);
- if (status == 0
- && (((info->endian == BFD_ENDIAN_BIG
- ? bfd_getb16 (buffer)
- : bfd_getl16 (buffer))
- & 0xf81f) == 0xe800))
- baseaddr = memaddr - 2;
- }
- }
- info->target = (baseaddr & ~((1 << shift) - 1)) + immed;
- (*info->print_address_func) (info->target, info);
- }
- }
- break;
-
- case 'a':
- if (! use_extend)
- extend = 0;
- l = ((l & 0x1f) << 23) | ((l & 0x3e0) << 13) | (extend << 2);
- info->target = ((memaddr + 4) & ~(bfd_vma) 0x0fffffff) | l;
- (*info->print_address_func) (info->target, info);
- info->insn_type = dis_jsr;
- info->branch_delay_insns = 1;
- break;
-
- case 'l':
- case 'L':
- {
- int need_comma, amask, smask;
-
- need_comma = 0;
-
- l = (l >> MIPS16OP_SH_IMM6) & MIPS16OP_MASK_IMM6;
-
- amask = (l >> 3) & 7;
-
- if (amask > 0 && amask < 5)
- {
- (*info->fprintf_func) (info->stream, "%s", mips_gpr_names[4]);
- if (amask > 1)
- (*info->fprintf_func) (info->stream, "-%s",
- mips_gpr_names[amask + 3]);
- need_comma = 1;
- }
-
- smask = (l >> 1) & 3;
- if (smask == 3)
- {
- (*info->fprintf_func) (info->stream, "%s??",
- need_comma ? "," : "");
- need_comma = 1;
- }
- else if (smask > 0)
- {
- (*info->fprintf_func) (info->stream, "%s%s",
- need_comma ? "," : "",
- mips_gpr_names[16]);
- if (smask > 1)
- (*info->fprintf_func) (info->stream, "-%s",
- mips_gpr_names[smask + 15]);
- need_comma = 1;
- }
-
- if (l & 1)
- {
- (*info->fprintf_func) (info->stream, "%s%s",
- need_comma ? "," : "",
- mips_gpr_names[31]);
- need_comma = 1;
- }
-
- if (amask == 5 || amask == 6)
- {
- (*info->fprintf_func) (info->stream, "%s$f0",
- need_comma ? "," : "");
- if (amask == 6)
- (*info->fprintf_func) (info->stream, "-$f1");
- }
- }
- break;
-
- default:
- /* xgettext:c-format */
- (*info->fprintf_func)
- (info->stream,
- _("# internal disassembler error, unrecognised modifier (%c)"),
- type);
- abort ();
- }
-}
-#endif
-
-void
-print_mips_disassembler_options (stream)
- FILE *stream;
-{
- unsigned int i;
-
- fprintf (stream, _("\n\
-The following MIPS specific disassembler options are supported for use\n\
-with the -M switch (multiple options should be separated by commas):\n"));
-
- fprintf (stream, _("\n\
- gpr-names=ABI Print GPR names according to specified ABI.\n\
- Default: based on binary being disassembled.\n"));
-
- fprintf (stream, _("\n\
- fpr-names=ABI Print FPR names according to specified ABI.\n\
- Default: numeric.\n"));
-
- fprintf (stream, _("\n\
- cp0-names=ARCH Print CP0 register names according to\n\
- specified architecture.\n\
- Default: based on binary being disassembled.\n"));
-
- fprintf (stream, _("\n\
- hwr-names=ARCH Print HWR names according to specified \n\
- architecture.\n\
- Default: based on binary being disassembled.\n"));
-
- fprintf (stream, _("\n\
- reg-names=ABI Print GPR and FPR names according to\n\
- specified ABI.\n"));
-
- fprintf (stream, _("\n\
- reg-names=ARCH Print CP0 register and HWR names according to\n\
- specified architecture.\n"));
-
- fprintf (stream, _("\n\
- For the options above, the following values are supported for \"ABI\":\n\
- "));
- for (i = 0; i < ARRAY_SIZE (mips_abi_choices); i++)
- fprintf (stream, " %s", mips_abi_choices[i].name);
- fprintf (stream, _("\n"));
-
- fprintf (stream, _("\n\
- For the options above, The following values are supported for \"ARCH\":\n\
- "));
- for (i = 0; i < ARRAY_SIZE (mips_arch_choices); i++)
- if (*mips_arch_choices[i].name != '\0')
- fprintf (stream, " %s", mips_arch_choices[i].name);
- fprintf (stream, _("\n"));
-
- fprintf (stream, _("\n"));
-}
diff --git a/monitor.c b/monitor.c
index 09a0299..600a173 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1,8 +1,8 @@
/*
* QEMU monitor
- *
+ *
* Copyright (c) 2003-2004 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
@@ -34,7 +34,7 @@
/*
* Supported types:
- *
+ *
* 'F' filename
* 'B' block device name
* 's' string (accept optional quote)
@@ -69,7 +69,7 @@ CPUState *mon_cpu = NULL;
void term_flush(void)
{
if (term_outbuf_index > 0) {
- qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index);
+ qemu_chr_write(monitor_hd, (uint8_t*)term_outbuf, term_outbuf_index);
term_outbuf_index = 0;
}
}
@@ -185,7 +185,7 @@ static void do_info(const char *item)
if (!item)
goto help;
for(cmd = info_cmds; cmd->name != NULL; cmd++) {
- if (compare_cmd(item, cmd->name))
+ if (compare_cmd(item, cmd->name))
goto found;
}
help:
@@ -237,7 +237,7 @@ static void do_info_registers(void)
cpu_dump_state(env, NULL, monitor_fprintf,
X86_DUMP_FPU);
#else
- cpu_dump_state(env, NULL, monitor_fprintf,
+ cpu_dump_state(env, NULL, monitor_fprintf,
0);
#endif
}
@@ -250,7 +250,7 @@ static void do_info_cpus(void)
mon_get_cpu();
for(env = first_cpu; env != NULL; env = env->next_cpu) {
- term_printf("%c CPU #%d:",
+ term_printf("%c CPU #%d:",
(env == mon_cpu) ? '*' : ' ',
env->cpu_index);
#if defined(TARGET_I386)
@@ -285,7 +285,7 @@ static void do_info_history (void)
{
int i;
const char *str;
-
+
i = 0;
for(;;) {
str = readline_get_history(i);
@@ -364,7 +364,7 @@ static void do_screen_dump(const char *filename)
static void do_log(const char *items)
{
int mask;
-
+
if (!strcmp(items, "none")) {
mask = 0;
} else {
@@ -385,7 +385,7 @@ static void do_savevm(const char *filename)
static void do_loadvm(const char *filename)
{
- if (qemu_loadvm(filename) < 0)
+ if (qemu_loadvm(filename) < 0)
term_printf("I/O error when loading VM from '%s'\n", filename);
}
@@ -439,7 +439,7 @@ static void term_printc(int c)
term_printf("'");
}
-static void memory_dump(int count, int format, int wsize,
+static void memory_dump(int count, int format, int wsize,
target_ulong addr, int is_physical)
{
CPUState *env;
@@ -463,7 +463,7 @@ static void memory_dump(int count, int format, int wsize,
flags = 0;
if (env) {
#ifdef TARGET_X86_64
- if ((env->efer & MSR_EFER_LMA) &&
+ if ((env->efer & MSR_EFER_LMA) &&
(env->segs[R_CS].flags & DESC_L_MASK))
flags = 2;
else
@@ -515,7 +515,7 @@ static void memory_dump(int count, int format, int wsize,
break;
cpu_memory_rw_debug(env, addr, buf, l, 0);
}
- i = 0;
+ i = 0;
while (i < l) {
switch(wsize) {
default:
@@ -564,7 +564,7 @@ static void memory_dump(int count, int format, int wsize,
#define GET_TLONG(h, l) (l)
#endif
-static void do_memory_dump(int count, int format, int size,
+static void do_memory_dump(int count, int format, int size,
uint32_t addrh, uint32_t addrl)
{
target_long addr = GET_TLONG(addrh, addrl);
@@ -648,7 +648,7 @@ typedef struct {
static const KeyDef key_defs[] = {
{ 0x2a, "shift" },
{ 0x36, "shift_r" },
-
+
{ 0x38, "alt" },
{ 0xb8, "alt_r" },
{ 0x1d, "ctrl" },
@@ -703,7 +703,7 @@ static const KeyDef key_defs[] = {
{ 0x30, "b" },
{ 0x31, "n" },
{ 0x32, "m" },
-
+
{ 0x39, "spc" },
{ 0x3a, "caps_lock" },
{ 0x3b, "f1" },
@@ -736,7 +736,7 @@ static const KeyDef key_defs[] = {
{ 0x47, "kp_7" },
{ 0x48, "kp_8" },
{ 0x49, "kp_9" },
-
+
{ 0x56, "<" },
{ 0x57, "f11" },
@@ -783,7 +783,7 @@ static void do_send_key(const char *string)
uint8_t keycodes[16];
const char *p;
int nb_keycodes, keycode, i;
-
+
nb_keycodes = 0;
p = string;
while (*p != '\0') {
@@ -823,14 +823,14 @@ static void do_send_key(const char *string)
static int mouse_button_state;
-static void do_mouse_move(const char *dx_str, const char *dy_str,
+static void do_mouse_move(const char *dx_str, const char *dy_str,
const char *dz_str)
{
int dx, dy, dz;
dx = strtol(dx_str, NULL, 0);
dy = strtol(dy_str, NULL, 0);
dz = 0;
- if (dz_str)
+ if (dz_str)
dz = strtol(dz_str, NULL, 0);
kbd_mouse_event(dx, dy, dz, mouse_button_state);
}
@@ -884,7 +884,7 @@ static void do_system_powerdown(void)
#if defined(TARGET_I386)
static void print_pte(uint32_t addr, uint32_t pte, uint32_t mask)
{
- term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n",
+ term_printf("%08x: %08x %c%c%c%c%c%c%c%c\n",
addr,
pte & mask,
pte & PG_GLOBAL_MASK ? 'G' : '-',
@@ -920,12 +920,12 @@ static void tlb_info(void)
print_pte((l1 << 22), pde, ~((1 << 20) - 1));
} else {
for(l2 = 0; l2 < 1024; l2++) {
- cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
+ cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
(uint8_t *)&pte, 4);
pte = le32_to_cpu(pte);
if (pte & PG_PRESENT_MASK) {
- print_pte((l1 << 22) + (l2 << 12),
- pte & ~PG_PSE_MASK,
+ print_pte((l1 << 22) + (l2 << 12),
+ pte & ~PG_PSE_MASK,
~0xfff);
}
}
@@ -934,7 +934,7 @@ static void tlb_info(void)
}
}
-static void mem_print(uint32_t *pstart, int *plast_prot,
+static void mem_print(uint32_t *pstart, int *plast_prot,
uint32_t end, int prot)
{
int prot1;
@@ -942,7 +942,7 @@ static void mem_print(uint32_t *pstart, int *plast_prot,
if (prot != prot1) {
if (*pstart != -1) {
term_printf("%08x-%08x %08x %c%c%c\n",
- *pstart, end, end - *pstart,
+ *pstart, end, end - *pstart,
prot1 & PG_USER_MASK ? 'u' : '-',
'r',
prot1 & PG_RW_MASK ? 'w' : '-');
@@ -982,7 +982,7 @@ static void mem_info(void)
mem_print(&start, &last_prot, end, prot);
} else {
for(l2 = 0; l2 < 1024; l2++) {
- cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
+ cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
(uint8_t *)&pte, 4);
pte = le32_to_cpu(pte);
end = (l1 << 22) + (l2 << 12);
@@ -1030,7 +1030,7 @@ static void do_info_kqemu(void)
#else
term_printf("kqemu support: not compiled\n");
#endif
-}
+}
#ifdef CONFIG_PROFILER
@@ -1130,15 +1130,16 @@ static void do_wav_capture (const char *path,
if (wav_start_capture (s, path, freq, bits, nchannels)) {
term_printf ("Faied to add wave capture\n");
qemu_free (s);
+ return;
}
LIST_INSERT_HEAD (&capture_head, s, entries);
}
#endif
static term_cmd_t term_cmds[] = {
- { "help|?", "s?", do_help,
+ { "help|?", "s?", do_help,
"[cmd]", "show the help" },
- { "commit", "", do_commit,
+ { "commit", "", do_commit,
"", "commit changes to the disk images (if -snapshot is used)" },
{ "info", "s?", do_info,
"subcommand", "show various information about the system state" },
@@ -1148,48 +1149,48 @@ static term_cmd_t term_cmds[] = {
"[-f] device", "eject a removable media (use -f to force it)" },
{ "change", "BF", do_change,
"device filename", "change a removable media" },
- { "screendump", "F", do_screen_dump,
+ { "screendump", "F", do_screen_dump,
"filename", "save screen into PPM image 'filename'" },
{ "log", "s", do_log,
- "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
+ "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
{ "savevm", "F", do_savevm,
- "filename", "save the whole virtual machine state to 'filename'" },
+ "filename", "save the whole virtual machine state to 'filename'" },
{ "loadvm", "F", do_loadvm,
- "filename", "restore the whole virtual machine state from 'filename'" },
- { "stop", "", do_stop,
+ "filename", "restore the whole virtual machine state from 'filename'" },
+ { "stop", "", do_stop,
"", "stop emulation", },
- { "c|cont", "", do_cont,
+ { "c|cont", "", do_cont,
"", "resume emulation", },
#ifdef CONFIG_GDBSTUB
- { "gdbserver", "i?", do_gdbserver,
+ { "gdbserver", "i?", do_gdbserver,
"[port]", "start gdbserver session (default port=1234)", },
#endif
- { "x", "/l", do_memory_dump,
+ { "x", "/l", do_memory_dump,
"/fmt addr", "virtual memory dump starting at 'addr'", },
- { "xp", "/l", do_physical_memory_dump,
+ { "xp", "/l", do_physical_memory_dump,
"/fmt addr", "physical memory dump starting at 'addr'", },
- { "p|print", "/l", do_print,
+ { "p|print", "/l", do_print,
"/fmt expr", "print expression value (use $reg for CPU register access)", },
- { "i", "/ii.", do_ioport_read,
+ { "i", "/ii.", do_ioport_read,
"/fmt addr", "I/O port read" },
- { "sendkey", "s", do_send_key,
+ { "sendkey", "s", do_send_key,
"keys", "send keys to the VM (e.g. 'sendkey ctrl-alt-f1')" },
- { "system_reset", "", do_system_reset,
+ { "system_reset", "", do_system_reset,
"", "reset the system" },
- { "system_powerdown", "", do_system_powerdown,
+ { "system_powerdown", "", do_system_powerdown,
"", "send system power down event" },
- { "sum", "ii", do_sum,
+ { "sum", "ii", do_sum,
"addr size", "compute the checksum of a memory region" },
{ "usb_add", "s", do_usb_add,
"device", "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')" },
{ "usb_del", "s", do_usb_del,
"device", "remove USB device 'bus.addr'" },
- { "cpu", "i", do_cpu_set,
+ { "cpu", "i", do_cpu_set,
"index", "set the default CPU" },
- { "mouse_move", "sss?", do_mouse_move,
+ { "mouse_move", "sss?", do_mouse_move,
"dx dy [dz]", "send mouse move events" },
- { "mouse_button", "i", do_mouse_button,
+ { "mouse_button", "i", do_mouse_button,
"state", "change mouse button state (1=L, 2=M, 4=R)" },
#ifdef HAS_AUDIO
{ "wavcapture", "si?i?i?", do_wav_capture,
@@ -1198,7 +1199,7 @@ static term_cmd_t term_cmds[] = {
#endif
{ "stopcapture", "i", do_stop_capture,
"capture index", "stop capture" },
- { NULL, NULL, },
+ { NULL, NULL, },
};
static term_cmd_t info_cmds[] = {
@@ -1556,11 +1557,32 @@ static MonitorDef monitor_defs[] = {
{ "cleanwin", offsetof(CPUState, cleanwin) },
{ "fprs", offsetof(CPUState, fprs) },
#endif
+#elif defined(TARGET_ARM)
+ { "r0", offsetof(CPUState, regs[0]) },
+ { "r1", offsetof(CPUState, regs[1]) },
+ { "r2", offsetof(CPUState, regs[2]) },
+ { "r3", offsetof(CPUState, regs[3]) },
+ { "r4", offsetof(CPUState, regs[4]) },
+ { "r5", offsetof(CPUState, regs[5]) },
+ { "r6", offsetof(CPUState, regs[6]) },
+ { "r7", offsetof(CPUState, regs[7]) },
+ { "r8", offsetof(CPUState, regs[8]) },
+ { "r9", offsetof(CPUState, regs[9]) },
+ { "r10", offsetof(CPUState, regs[10]) },
+ { "r11", offsetof(CPUState, regs[11]) },
+ { "r12", offsetof(CPUState, regs[12]) },
+ { "r13", offsetof(CPUState, regs[13]) },
+ { "r14", offsetof(CPUState, regs[14]) },
+ { "r15", offsetof(CPUState, regs[15]) },
+ /* some interesting aliases */
+ { "sp", offsetof(CPUState, regs[13]) },
+ { "lr", offsetof(CPUState, regs[14]) },
+ { "pc", offsetof(CPUState, regs[15]) },
#endif
{ NULL },
};
-static void expr_error(const char *fmt)
+static void expr_error(const char *fmt)
{
term_printf(fmt);
term_printf("\n");
@@ -1613,7 +1635,7 @@ static target_long expr_sum(void);
static target_long expr_unary(void)
{
- target_long n;
+ target_long n = 0;
char *p;
int ret;
@@ -1651,7 +1673,7 @@ static target_long expr_unary(void)
case '$':
{
char buf[128], *q;
-
+
pch++;
q = buf;
while ((*pch >= 'a' && *pch <= 'z') ||
@@ -1668,7 +1690,7 @@ static target_long expr_unary(void)
ret = get_monitor_def(&n, buf);
if (ret == -1)
expr_error("unknown register");
- else if (ret == -2)
+ else if (ret == -2)
expr_error("no cpu defined");
}
break;
@@ -1698,7 +1720,7 @@ static target_long expr_prod(void)
{
target_long val, val2;
int op;
-
+
val = expr_unary();
for(;;) {
op = *pch;
@@ -1713,7 +1735,7 @@ static target_long expr_prod(void)
break;
case '/':
case '%':
- if (val2 == 0)
+ if (val2 == 0)
expr_error("division by zero");
if (op == '/')
val /= val2;
@@ -1871,7 +1893,7 @@ static void monitor_handle_command(const char *cmdline)
#ifdef DEBUG
term_printf("command='%s'\n", cmdline);
#endif
-
+
/* extract the command name */
p = cmdline;
q = cmdname;
@@ -1887,10 +1909,10 @@ static void monitor_handle_command(const char *cmdline)
len = sizeof(cmdname) - 1;
memcpy(cmdname, pstart, len);
cmdname[len] = '\0';
-
+
/* find the command */
for(cmd = term_cmds; cmd->name != NULL; cmd++) {
- if (compare_cmd(cmdname, cmd->name))
+ if (compare_cmd(cmdname, cmd->name))
goto found;
}
term_printf("unknown command: '%s'\n", cmdname);
@@ -1899,7 +1921,7 @@ static void monitor_handle_command(const char *cmdline)
for(i = 0; i < MAX_ARGS; i++)
str_allocated[i] = NULL;
-
+
/* parse the parameters */
typestr = cmd->args_type;
nb_args = 0;
@@ -1915,8 +1937,8 @@ static void monitor_handle_command(const char *cmdline)
{
int ret;
char *str;
-
- while (isspace(*p))
+
+ while (isspace(*p))
p++;
if (*typestr == '?') {
typestr++;
@@ -1956,7 +1978,7 @@ static void monitor_handle_command(const char *cmdline)
case '/':
{
int count, format, size;
-
+
while (isspace(*p))
p++;
if (*p == '/') {
@@ -2037,7 +2059,7 @@ static void monitor_handle_command(const char *cmdline)
case 'l':
{
target_long val;
- while (isspace(*p))
+ while (isspace(*p))
p++;
if (*typestr == '?' || *typestr == '.') {
if (*typestr == '?') {
@@ -2048,7 +2070,7 @@ static void monitor_handle_command(const char *cmdline)
} else {
if (*p == '.') {
p++;
- while (isspace(*p))
+ while (isspace(*p))
p++;
has_arg = 1;
} else {
@@ -2089,17 +2111,17 @@ static void monitor_handle_command(const char *cmdline)
{
int has_option;
/* option */
-
+
c = *typestr++;
if (c == '\0')
goto bad_type;
- while (isspace(*p))
+ while (isspace(*p))
p++;
has_option = 0;
if (*p == '-') {
p++;
if (*p != c) {
- term_printf("%s: unsupported option -%c\n",
+ term_printf("%s: unsupported option -%c\n",
cmdname, *p);
goto fail;
}
@@ -2121,7 +2143,7 @@ static void monitor_handle_command(const char *cmdline)
while (isspace(*p))
p++;
if (*p != '\0') {
- term_printf("%s: extraneous characters at the end of line\n",
+ term_printf("%s: extraneous characters at the end of line\n",
cmdname);
goto fail;
}
@@ -2196,7 +2218,7 @@ static void file_completion(const char *input)
int input_path_len;
const char *p;
- p = strrchr(input, '/');
+ p = strrchr(input, '/');
if (!p) {
input_path_len = 0;
pstrcpy(file_prefix, sizeof(file_prefix), input);
diff --git a/offset_layout.py b/offset_layout.py
new file mode 100755
index 0000000..6c2f879
--- /dev/null
+++ b/offset_layout.py
@@ -0,0 +1,111 @@
+#!/usr/bin/python
+
+import re
+import sys
+import getopt
+
+DX = DY = PX = PY = KX = KY = 0
+
+_RE_LINE = re.compile("^\s*(?P<keyword>[\w-]+)\s+{\s*$")
+_RE_XY = re.compile("^(?P<start>\s*)(?P<xy>[x|y]\s+)(?P<num>\d+)(?P<end>\s*)$")
+
+def main():
+ ParseArgs()
+ ParseInput()
+
+def Usage():
+ print >>sys.stderr, """
+ Usage: %s --dx offset-x-display --dy offset-y-display --px offset-x-phone-buttons --py offset-y-phone-buttons --kx offset-x-keyboard --ky offset-y-keyboard < layout > layout2.
+
+ Unspecified offsets default to 0 (unchanged).
+ Reads from stdin, outputs to stdout.
+ Phone buttons: soft-left/top/righ/bottom, home, dpad, dial, power, etc.
+ Keyboard is the soft keyboard.
+
+ If your shell doesn't let you use negative integers, use _ for minus sign,
+ i.e. --dx _40 --dy _42 for <-40,-42).
+ """ % (sys.argv[0])
+ sys.exit(1)
+
+def ParseArgs():
+ global DX, DY, PX, PY, KX, KY
+ try:
+ options, args = getopt.getopt(sys.argv[1:], "", ["dx=", "dy=", "px=", "py=", "kx=", "ky="])
+ for opt, value in options:
+ if opt in ["--dx"]:
+ DX = int(value.replace("_", "-"))
+ elif opt in ["--dy"]:
+ DY = int(value.replace("_", "-"))
+ elif opt in ["--px"]:
+ PX = int(value.replace("_", "-"))
+ elif opt in ["--py"]:
+ PY = int(value.replace("_", "-"))
+ elif opt in ["--kx"]:
+ KX = int(value.replace("_", "-"))
+ elif opt in ["--ky"]:
+ KY = int(value.replace("_", "-"))
+ else:
+ Usage()
+ except getopt.error, msg:
+ Usage()
+
+def ParseInput():
+ global DX, DY, PX, PY, KX, KY
+
+ PHONE = [ "soft-left", "home", "back", "dpad-up", "dpad-down", "dpad-left", "dpad-right", "dpad-center", "phone-dial", "phone-hangup", "power", "volume-up", "volume-down" ]
+ KEYBOARD = [ "DEL", "CAP", "CAP2", "PERIOD", "ENTER", "ALT", "SYM", "AT", "SPACE", "SLASH", "COMMA", "ALT2" ]
+
+ mode = None
+ while True:
+ line = sys.stdin.readline()
+ if not line:
+ return
+ m_line = _RE_LINE.match(line)
+ if m_line:
+ keyword = m_line.group("keyword")
+ if keyword in ["display", "button"]:
+ mode = keyword
+ is_phone = False
+ is_keyboard = False
+ print >>sys.stderr, "Mode:", mode
+ else:
+ if mode == "button" and "{" in line:
+ is_phone = keyword in PHONE
+ is_keyboard = (len(keyword) == 1 and keyword.isalnum())
+ if not is_keyboard:
+ is_keyboard = keyword in KEYBOARD
+ elif "}" in line:
+ is_phone = False
+ is_keyboard = False
+ if mode == "display":
+ mode = None
+ else:
+ m_xy = _RE_XY.match(line)
+ if m_xy:
+ x = 0
+ y = 0
+ if mode == "display":
+ x = DX
+ y = DY
+ elif mode == "button" and is_phone:
+ x = PX
+ y = PY
+ elif mode == "button" and is_keyboard:
+ x = KX
+ y = KY
+ if x or y:
+ d = m_xy.groupdict()
+ n = int(d["num"])
+ if d["xy"].startswith("x"):
+ n += x
+ else:
+ n += y
+ d["num"] = n
+ line = "%(start)s%(xy)s%(num)s%(end)s" % d
+ sys.stdout.write(line)
+
+
+
+
+if __name__ == "__main__":
+ main()
diff --git a/osdep.c b/osdep.c
index ffa29fe..b623e13 100644
--- a/osdep.c
+++ b/osdep.c
@@ -1,8 +1,8 @@
/*
* QEMU low level functions
- *
+ *
* 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
@@ -89,7 +89,7 @@ __asm__ volatile ("int $0x80" \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3)),"S" ((long)(arg4))); \
return __res; \
-}
+}
#define QEMU_SYSCALL5(name,arg1,arg2,arg3,arg4,arg5) \
{ \
@@ -122,8 +122,8 @@ int qemu_write(int fd, const void *buf, size_t n)
/****************************************************************/
/* shmat replacement */
-int qemu_ipc(int call, unsigned long first,
- unsigned long second, unsigned long third,
+int qemu_ipc(int call, unsigned long first,
+ unsigned long second, unsigned long third,
void *ptr, unsigned long fifth)
{
QEMU_SYSCALL6(ipc, call, first, second, third, ptr, fifth);
@@ -149,14 +149,14 @@ void *shmat(int shmid, const void *shmaddr, int shmflg)
/****************************************************************/
/* sigaction bypassing the threads */
-static int kernel_sigaction(int signum, const struct qemu_sigaction *act,
- struct qemu_sigaction *oldact,
+static int kernel_sigaction(int signum, const struct qemu_sigaction *act,
+ struct qemu_sigaction *oldact,
int sigsetsize)
{
QEMU_SYSCALL4(rt_sigaction, signum, act, oldact, sigsetsize);
}
-int qemu_sigaction(int signum, const struct qemu_sigaction *act,
+int qemu_sigaction(int signum, const struct qemu_sigaction *act,
struct qemu_sigaction *oldact)
{
return kernel_sigaction(signum, act, oldact, 8);
@@ -185,8 +185,8 @@ static void *malloc_get_space(size_t size)
{
void *ptr;
size = TARGET_PAGE_ALIGN(size);
- ptr = mmap((void *)malloc_addr, size,
- PROT_WRITE | PROT_READ,
+ ptr = mmap((void *)malloc_addr, size,
+ PROT_WRITE | PROT_READ,
MAP_PRIVATE | MAP_FIXED | MAP_ANON, -1, 0);
if (ptr == MAP_FAILED)
return NULL;
@@ -199,7 +199,7 @@ void *qemu_malloc(size_t size)
MemoryBlock *mb, *mb1, **pmb;
void *ptr;
size_t size1, area_size;
-
+
if (size == 0)
return NULL;
@@ -353,7 +353,7 @@ void *kqemu_vmalloc(size_t size)
free_space = (int64_t)stfs.f_bavail * stfs.f_bsize;
if ((ram_size + 8192 * 1024) >= free_space) {
ram_mb = (ram_size / (1024 * 1024));
- fprintf(stderr,
+ fprintf(stderr,
"You do not have enough space in '%s' for the %d MB of QEMU virtual RAM.\n",
tmpdir, ram_mb);
if (strcmp(tmpdir, "/dev/shm") == 0) {
@@ -362,7 +362,7 @@ void *kqemu_vmalloc(size_t size)
"mount -t tmpfs -o size=%dm none /dev/shm\n",
ram_mb + 16);
} else {
- fprintf(stderr,
+ fprintf(stderr,
"Use the '-m' option of QEMU to diminish the amount of virtual RAM or use the\n"
"QEMU_TMPDIR environment variable to set another directory where the QEMU\n"
"temporary RAM file will be opened.\n");
@@ -371,25 +371,25 @@ void *kqemu_vmalloc(size_t size)
exit(1);
}
}
- snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
+ snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
tmpdir);
if (mkstemp(phys_ram_file) < 0) {
- fprintf(stderr,
+ fprintf(stderr,
"warning: could not create temporary file in '%s'.\n"
"Use QEMU_TMPDIR to select a directory in a tmpfs filesystem.\n"
"Using '/tmp' as fallback.\n",
tmpdir);
- snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
+ snprintf(phys_ram_file, sizeof(phys_ram_file), "%s/qemuXXXXXX",
"/tmp");
if (mkstemp(phys_ram_file) < 0) {
- fprintf(stderr, "Could not create temporary memory file '%s'\n",
+ fprintf(stderr, "Could not create temporary memory file '%s'\n",
phys_ram_file);
exit(1);
}
}
- phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR, 0600);
+ phys_ram_fd = open(phys_ram_file, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, 0600);
if (phys_ram_fd < 0) {
- fprintf(stderr, "Could not open temporary memory file '%s'\n",
+ fprintf(stderr, "Could not open temporary memory file '%s'\n",
phys_ram_file);
exit(1);
}
@@ -397,9 +397,9 @@ void *kqemu_vmalloc(size_t size)
}
size = (size + 4095) & ~4095;
ftruncate(phys_ram_fd, phys_ram_size + size);
- ptr = mmap(NULL,
- size,
- PROT_WRITE | PROT_READ, MAP_SHARED,
+ ptr = mmap(NULL,
+ size,
+ PROT_WRITE | PROT_READ, MAP_SHARED,
phys_ram_fd, phys_ram_size);
if (ptr == MAP_FAILED) {
fprintf(stderr, "Could not map physical memory\n");
@@ -627,7 +627,7 @@ void qemu_vprintf(const char *fmt, va_list ap)
{
char buf[1024];
int len;
-
+
len = qemu_vsnprintf(buf, sizeof(buf), fmt, ap);
qemu_write(1, buf, len);
}
diff --git a/osdep.h b/osdep.h
index 29a261c..68d87bf 100644
--- a/osdep.h
+++ b/osdep.h
@@ -2,6 +2,8 @@
#define QEMU_OSDEP_H
#include <stdarg.h>
+#include <setjmp.h>
+#include "config.h"
int qemu_vsnprintf(char *buf, int buflen, const char *fmt, va_list args);
void qemu_vprintf(const char *fmt, va_list ap);
@@ -40,7 +42,7 @@ struct qemu_sigaction {
sigset_t sa_mask; /* mask last for extensibility */
};
-int qemu_sigaction(int signum, const struct qemu_sigaction *act,
+int qemu_sigaction(int signum, const struct qemu_sigaction *act,
struct qemu_sigaction *oldact);
#undef sigaction
diff --git a/proxy/proxy_common.c b/proxy/proxy_common.c
new file mode 100644
index 0000000..c5762dc
--- /dev/null
+++ b/proxy/proxy_common.c
@@ -0,0 +1,502 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "proxy_int.h"
+#include "sockets.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "vl.h"
+
+int proxy_log = 0;
+
+void
+proxy_LOG(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+
+void
+proxy_set_verbose(int mode)
+{
+ proxy_log = mode;
+}
+
+/** Global connection list
+ **/
+
+static ProxyConnection s_connections[1];
+
+static void
+hex_dump( void* base, int size, const char* prefix )
+{
+ uint8_t* p = (uint8_t*)base;
+ const int max_count = 16;
+
+ while (size > 0) {
+ int count = size > max_count ? max_count : size;
+ int n;
+ const char* space = prefix;
+
+ for (n = 0; n < count; n++) {
+ proxy_LOG( "%s%02x", space, p[n] );
+ space = " ";
+ }
+
+ proxy_LOG( "%-*s", 4 + 3*(max_count-n), "" );
+
+ for (n = 0; n < count; n++) {
+ int c = p[n];
+
+ if (c < 32 || c > 127)
+ c = '.';
+ proxy_LOG( "%c", c );
+ }
+ proxy_LOG( "\n" );
+ size -= count;
+ p += count;
+ }
+}
+
+
+void
+proxy_connection_init( ProxyConnection* conn,
+ int socket,
+ struct sockaddr_in* address,
+ ProxyService* service )
+{
+ conn->socket = socket;
+ conn->address = address[0];
+ conn->service = service;
+ conn->next = NULL;
+
+ {
+ uint32_t ip = ntohl(address->sin_addr.s_addr);
+ uint16_t port = ntohs(address->sin_port);
+ int type = socket_get_type(socket);
+
+ snprintf( conn->name, sizeof(conn->name),
+ "%s:%d.%d.%d.%d:%d(%d)",
+ (type == SOCK_STREAM) ? "tcp" : "udp",
+ (ip >> 24) & 255, (ip >> 16) & 255,
+ (ip >> 8) & 255, ip & 255, port,
+ socket );
+
+ /* just in case */
+ conn->name[sizeof(conn->name)-1] = 0;
+ }
+
+ conn->buffer_pos = 0;
+ conn->buffer_len = 0;
+ conn->buffer = conn->buffer0;
+}
+
+void
+proxy_connection_done( ProxyConnection* conn )
+{
+ if (conn->buffer != conn->buffer0) {
+ qemu_free(conn->buffer);
+ }
+}
+
+
+int
+proxy_connection_send( ProxyConnection* conn )
+{
+ int result = -1;
+ int fd = conn->socket;
+ int avail = conn->buffer_len - conn->buffer_pos;
+
+ if (proxy_log) {
+ PROXY_LOG("%s: sending %d bytes:\n", conn->name, avail );
+ hex_dump( conn->buffer + conn->buffer_pos, avail, ">> " );
+ }
+
+ while (avail > 0) {
+ int n = send(fd, conn->buffer + conn->buffer_pos, avail, 0);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ return 0;
+ PROXY_LOG("%s: error: %s\n", conn->name, strerror(errno));
+ return -1;
+ }
+ conn->buffer_pos += n;
+ avail -= n;
+ }
+ return 1;
+}
+
+int
+proxy_connection_receive( ProxyConnection* conn )
+{
+ int result = -1;
+ int fd = conn->socket;
+ int avail = conn->buffer_len - conn->buffer_pos;
+
+ while (avail > 0) {
+ int n = recv(fd, conn->buffer + conn->buffer_pos, avail, 0);
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ return 0;
+ PROXY_LOG("%s: error: %s\n", conn->name, strerror(errno));
+ return -1;
+ }
+
+ if (proxy_log) {
+ PROXY_LOG("%s: received %d bytes:\n", conn->name, n );
+ hex_dump( conn->buffer + conn->buffer_pos, n, ">> " );
+ }
+
+ conn->buffer_pos += n;
+ avail -= n;
+ }
+ return 1;
+}
+
+int
+proxy_connection_receive_line( ProxyConnection* conn )
+{
+ int result = -1;
+ int fd = conn->socket;
+
+ for (;;) {
+ char c;
+ int n = recv(fd, &c, 1, 0);
+ if (n == 0) {
+ PROXY_LOG("%s: disconnected from server\n", conn->name );
+ return -1;
+ }
+ if (n < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno == EWOULDBLOCK || errno == EAGAIN) {
+ PROXY_LOG("%s: blocked\n", conn->name);
+ return 0;
+ }
+ PROXY_LOG("%s: error: %s\n", conn->name, strerror(errno));
+ return -1;
+ }
+
+ if (c == '\n') {
+ if (conn->buffer_pos > 0 && conn->buffer[conn->buffer_pos-1] == '\r')
+ conn->buffer_pos -= 1;
+
+ conn->buffer[conn->buffer_pos] = 0;
+
+ PROXY_LOG("%s: received '%.*s'\n", conn->name,
+ conn->buffer_pos, conn->buffer);
+ return 1;
+ }
+
+ conn->buffer[ conn->buffer_pos++ ] = c;
+ if (conn->buffer_pos == conn->buffer_len) {
+ PROXY_LOG("%s: line received from proxy is too long\n", conn->name);
+ return -1;
+ }
+ }
+}
+
+
+
+static void
+proxy_connection_insert( ProxyConnection* conn, ProxyConnection* after )
+{
+ conn->next = after->next;
+ after->next->prev = conn;
+ after->next = conn;
+ conn->prev = after;
+}
+
+static void
+proxy_connection_remove( ProxyConnection* conn )
+{
+ conn->prev->next = conn->next;
+ conn->next->prev = conn->prev;
+
+ conn->next = conn->prev = conn;
+}
+
+/** Global service list
+ **/
+
+#define MAX_SERVICES 4
+
+static ProxyService* s_services[ MAX_SERVICES ];
+static int s_num_services;
+static int s_init;
+
+static void proxy_manager_atexit( void );
+
+static void
+proxy_manager_init(void)
+{
+ s_init = 1;
+ s_connections->next = s_connections;
+ s_connections->prev = s_connections;
+ atexit( proxy_manager_atexit );
+}
+
+
+extern int
+proxy_manager_add_service( ProxyService* service )
+{
+ if (!service || s_num_services >= MAX_SERVICES)
+ return -1;
+
+ if (!s_init)
+ proxy_manager_init();
+
+ s_services[s_num_services++] = service;
+ return 0;
+}
+
+
+extern void
+proxy_manager_atexit( void )
+{
+ ProxyConnection* conn = s_connections->next;
+ int n;
+
+ /* free all proxy connections */
+ while (conn != s_connections) {
+ ProxyConnection* next = conn->next;
+ conn->service->conn_free( conn );
+ conn = next;
+ }
+ conn->next = conn;
+ conn->prev = conn;
+
+ /* free all proxy services */
+ for (n = s_num_services; n-- > 0;) {
+ ProxyService* service = s_services[n];
+ service->serv_free( service->opaque );
+ }
+ s_num_services = 0;
+}
+
+
+void
+proxy_connection_free( ProxyConnection* conn,
+ ProxyEvent event )
+{
+ if (conn) {
+ int fd = conn->socket;
+
+ proxy_connection_remove(conn);
+
+ if (event != PROXY_EVENT_NONE)
+ conn->ev_func( conn->ev_opaque, event );
+
+ conn->service->conn_free(conn);
+ }
+}
+
+
+int
+proxy_manager_add( int socket,
+ struct sockaddr_in* address,
+ void* ev_opaque,
+ ProxyEventFunc ev_func )
+{
+ int n;
+
+ if (!s_init) {
+ proxy_manager_init();
+ }
+
+ socket_set_nonblock(socket);
+
+ for (n = 0; n < s_num_services; n++) {
+ ProxyService* service = s_services[n];
+ ProxyConnection* conn = service->serv_connect( service->opaque,
+ socket,
+ address );
+ if (conn != NULL) {
+ conn->ev_opaque = ev_opaque;
+ conn->ev_func = ev_func;
+ proxy_connection_insert(conn, s_connections->prev);
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+/* remove an on-going proxified socket connection from the manager's list.
+ * this is only necessary when the socket connection must be canceled before
+ * the connection accept/refusal occured
+ */
+void
+proxy_manager_del( int socket )
+{
+ ProxyConnection* conn = s_connections->next;
+ for ( ; conn != s_connections; conn = conn->next ) {
+ if (conn->socket == socket) {
+ int fd = conn->socket;
+ proxy_connection_remove(conn);
+ conn->service->conn_free(conn);
+ socket_close(fd);
+ return;
+ }
+ }
+}
+
+/* this function is called to update the select file descriptor sets
+ * with those of the proxified connection sockets that are currently managed */
+void
+proxy_manager_select_fill( int *pcount, fd_set* read_fds, fd_set* write_fds, fd_set* err_fds)
+{
+ ProxyConnection* conn;
+
+ if (!s_init)
+ proxy_manager_init();
+
+ conn = s_connections->next;
+ for ( ; conn != s_connections; conn = conn->next ) {
+ unsigned flags = conn->service->conn_select(conn);
+ int fd = conn->socket;
+
+ if (!flags)
+ continue;
+
+ if (*pcount < fd+1)
+ *pcount = fd+1;
+
+ if (flags & PROXY_SELECT_READ) {
+ FD_SET( fd, read_fds );
+ }
+ if (flags & PROXY_SELECT_WRITE) {
+ FD_SET( fd, write_fds );
+ }
+ if (flags & PROXY_SELECT_ERROR) {
+ FD_SET( fd, err_fds );
+ }
+ }
+}
+
+/* this function is called to act on proxified connection sockets when network events arrive */
+void
+proxy_manager_poll( fd_set* read_fds, fd_set* write_fds, fd_set* err_fds )
+{
+ ProxyConnection* conn = s_connections->next;
+ while (conn != s_connections) {
+ ProxyConnection* next = conn->next;
+ int fd = conn->socket;
+ unsigned flags = 0;
+
+ if ( FD_ISSET(fd, read_fds) )
+ flags |= PROXY_SELECT_READ;
+ if ( FD_ISSET(fd, write_fds) )
+ flags |= PROXY_SELECT_WRITE;
+ if ( FD_ISSET(fd, err_fds) )
+ flags |= PROXY_SELECT_ERROR;
+
+ if (flags != 0) {
+ conn->service->conn_poll( conn, flags );
+ }
+ conn = next;
+ }
+}
+
+
+int
+proxy_base64_encode( const char* src, int srclen,
+ char* dst, int dstlen )
+{
+ static const char cb64[64]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ const char* srcend = src + srclen;
+ int result = 0;
+
+ while (src+3 <= srcend && result+4 <= dstlen)
+ {
+ dst[result+0] = cb64[ src[0] >> 2 ];
+ dst[result+1] = cb64[ ((src[0] & 3) << 4) | ((src[1] & 0xf0) >> 4) ];
+ dst[result+2] = cb64[ ((src[1] & 0xf) << 2) | ((src[2] & 0xc0) >> 6) ];
+ dst[result+3] = cb64[ src[2] & 0x3f ];
+ src += 3;
+ result += 4;
+ }
+
+ if (src < srcend) {
+ unsigned char in[4];
+
+ if (result+4 > dstlen)
+ return -1;
+
+ in[0] = src[0];
+ in[1] = src+1 < srcend ? src[1] : 0;
+ in[2] = src+2 < srcend ? src[2] : 0;
+
+ dst[result+0] = cb64[ in[0] >> 2 ];
+ dst[result+1] = cb64[ ((in[0] & 3) << 4) | ((in[1] & 0xf0) >> 4) ];
+ dst[result+2] = (unsigned char) (src+1 < srcend ? cb64[ ((in[1] & 0xf) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
+ dst[result+3] = (unsigned char) (src+2 < srcend ? cb64[ in[2] & 0x3f ] : '=');
+ result += 4;
+ }
+ return result;
+}
+
+int
+proxy_resolve_server( struct sockaddr_in* addr,
+ const char* servername,
+ int servernamelen,
+ int serverport )
+{
+ char name0[64], *name = name0;
+ int result = -1;
+ struct hostent* host;
+
+ if (servernamelen < 0)
+ servernamelen = strlen(servername);
+
+ memset(addr, 0, sizeof(*addr));
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(serverport);
+
+ if (servernamelen >= sizeof(name0)) {
+ name = qemu_malloc(servernamelen+1);
+ if (name == NULL)
+ return -1;
+ }
+
+ memcpy(name, servername, servernamelen);
+ name[servernamelen] = 0;
+
+ host = gethostbyname(name);
+ if (host == NULL) {
+ PROXY_LOG("%s: can't resolve proxy server name '%s'\n",
+ __FUNCTION__, name);
+ goto Exit;
+ }
+
+ addr->sin_addr = *(struct in_addr*)host->h_addr;
+ {
+ uint32_t a = ntohl(addr->sin_addr.s_addr);
+ PROXY_LOG("server name '%s' resolved to %d.%d.%d.%d\n", name, (a>>24)&255, (a>>16)&255,(a>>8)&255,a&255);
+ }
+ result = 0;
+
+Exit:
+ if (name != name0)
+ qemu_free(name);
+
+ return result;
+}
+
+
diff --git a/proxy/proxy_common.h b/proxy/proxy_common.h
new file mode 100644
index 0000000..54889cf
--- /dev/null
+++ b/proxy/proxy_common.h
@@ -0,0 +1,79 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _PROXY_COMMON_H_
+#define _PROXY_COMMON_H_
+
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/select.h>
+#include <netinet/in.h>
+#endif
+
+/* types and definitions used by all proxy connections */
+
+typedef enum {
+ PROXY_EVENT_NONE,
+ PROXY_EVENT_CONNECTED,
+ PROXY_EVENT_CONNECTION_REFUSED,
+ PROXY_EVENT_SERVER_ERROR
+} ProxyEvent;
+
+/* event can't be NONE when this callback is called */
+typedef void (*ProxyEventFunc)( void* opaque, ProxyEvent event );
+
+extern void proxy_set_verbose(int mode);
+
+
+typedef enum {
+ PROXY_OPTION_AUTH_USERNAME = 1,
+ PROXY_OPTION_AUTH_PASSWORD,
+
+ PROXY_OPTION_HTTP_NOCACHE = 100,
+ PROXY_OPTION_HTTP_KEEPALIVE,
+ PROXY_OPTION_HTTP_USER_AGENT,
+
+ PROXY_OPTION_MAX
+
+} ProxyOptionType;
+
+
+typedef struct {
+ ProxyOptionType type;
+ const char* string;
+ int string_len;
+} ProxyOption;
+
+
+/* add a new proxified socket connection to the manager's list. the event function
+ * will be called when the connection is established or refused.
+ *
+ * only IPv4 is supported at the moment, since our slirp code cannot handle IPv6
+ *
+ * returns 0 on success, or -1 if there is no proxy service for this type of connection
+ */
+extern int proxy_manager_add( int socket, struct sockaddr_in* address, void* ev_opaque, ProxyEventFunc ev_func );
+
+/* remove an on-going proxified socket connection from the manager's list.
+ * this is only necessary when the socket connection must be canceled before
+ * the connection accept/refusal occured
+ */
+extern void proxy_manager_del( int socket );
+
+/* this function is called to update the select file descriptor sets
+ * with those of the proxified connection sockets that are currently managed */
+extern void proxy_manager_select_fill( int *pcount, fd_set* read_fds, fd_set* write_fds, fd_set* err_fds);
+
+/* this function is called to act on proxified connection sockets when network events arrive */
+extern void proxy_manager_poll( fd_set* read_fds, fd_set* write_fds, fd_set* err_fds );
+
+#endif /* END */
diff --git a/proxy/proxy_http.c b/proxy/proxy_http.c
new file mode 100644
index 0000000..83982a7
--- /dev/null
+++ b/proxy/proxy_http.c
@@ -0,0 +1,371 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "proxy_int.h"
+#include "proxy_http.h"
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include "vl.h"
+
+typedef enum {
+ HTTP_NONE = 0,
+ HTTP_CONNECTING, /* connecting to the server */
+ HTTP_SEND_HEADER, /* connected, sending header to the server */
+ HTTP_RECEIVE_ANSWER_LINE1,
+ HTTP_RECEIVE_ANSWER_LINE2 /* connected, reading server's answer */
+} HttpConnectionState;
+
+
+typedef struct {
+ ProxyConnection root[1];
+ HttpConnectionState state;
+} HttpConnection;
+
+
+typedef struct {
+ ProxyService root[1];
+ struct sockaddr_in server_addr; /* server address and port */
+ char* footer; /* the footer contains the static parts of the */
+ int footer_len; /* connection header, we generate it only once */
+ char footer0[512];
+} HttpService;
+
+
+static void
+http_connection_free( HttpConnection* conn )
+{
+ proxy_connection_done(conn->root);
+ qemu_free(conn);
+}
+
+
+#define HTTP_VERSION "1.1"
+
+static int
+http_connection_init( HttpConnection* conn )
+{
+ HttpService* service = (HttpService*) conn->root->service;
+ ProxyConnection* root = conn->root;
+ char* p = root->buffer0;
+ char* end = p + sizeof(root->buffer0);
+ int wlen, ret;
+ uint32_t address = ntohl(conn->root->address.sin_addr.s_addr);
+ int port = ntohs(conn->root->address.sin_port);
+
+ root->buffer_pos = 0;
+ root->buffer = p;
+
+ p += snprintf(p, end-p, "CONNECT %d.%d.%d.%d:%d HTTP/" HTTP_VERSION "\r\n",
+ (address >> 24) & 0xff, (address >> 16) & 0xff,
+ (address >> 8) & 0xff, address & 0xff, port);
+ if (p >= end) goto Overflow;
+
+ p += snprintf(p, end-p, "%.*s", service->footer_len, service->footer);
+
+ if (p >= end) {
+ Overflow:
+ PROXY_LOG("%s: buffer overflow in proxy connection header\n", root->name);
+ return -1;
+ }
+
+ root->buffer_len = (p - root->buffer);
+
+ ret = connect( root->socket,
+ (struct sockaddr*) &service->server_addr,
+ sizeof(service->server_addr) );
+ if (ret == 0) {
+ /* immediate connection ?? */
+ conn->state = HTTP_SEND_HEADER;
+ PROXY_LOG("%s: immediate connection\n", root->name);
+ }
+ else {
+ if (socket_errno == EINPROGRESS || socket_errno == EWOULDBLOCK) {
+ conn->state = HTTP_CONNECTING;
+ PROXY_LOG("%s: connecting\n", conn->root->name);
+ }
+ else {
+ PROXY_LOG("%s: cannot connect to proxy: %s\n", root->name, strerror(errno));
+ return -1;
+ }
+ }
+ return 0;
+}
+
+
+static unsigned
+http_connection_select( HttpConnection* conn )
+{
+ unsigned flags;
+
+ switch (conn->state) {
+ case HTTP_RECEIVE_ANSWER_LINE1:
+ case HTTP_RECEIVE_ANSWER_LINE2:
+ flags = PROXY_SELECT_READ;
+ break;
+
+ case HTTP_CONNECTING:
+ case HTTP_SEND_HEADER:
+ flags = PROXY_SELECT_WRITE;
+ break;
+
+ default:
+ flags = 0;
+ };
+ return flags;
+}
+
+static void
+http_connection_poll( HttpConnection* conn,
+ unsigned flags )
+{
+ int ret;
+ ProxyConnection* root = conn->root;
+
+ switch (conn->state)
+ {
+ case HTTP_CONNECTING:
+ PROXY_LOG("%s: connected to http proxy, sending header\n", root->name);
+ conn->state = HTTP_SEND_HEADER;
+ break;
+
+ case HTTP_SEND_HEADER:
+ {
+ int ret = proxy_connection_send(root);
+
+ if (ret < 0) {
+ proxy_connection_free( root, PROXY_EVENT_SERVER_ERROR );
+ return;
+ }
+ if (ret == 0)
+ return;
+
+ root->buffer_len = sizeof(root->buffer0);
+ root->buffer_pos = 0;
+ conn->state = HTTP_RECEIVE_ANSWER_LINE1;
+ PROXY_LOG("%s: header sent, receiving first answer line\n", root->name);
+ }
+ break;
+
+ case HTTP_RECEIVE_ANSWER_LINE1:
+ case HTTP_RECEIVE_ANSWER_LINE2:
+ {
+ int ret = proxy_connection_receive_line(root);
+
+ if (ret < 0) {
+ proxy_connection_free( root, PROXY_EVENT_SERVER_ERROR );
+ return;
+ }
+ if (ret == 0)
+ return;
+
+ if (conn->state == HTTP_RECEIVE_ANSWER_LINE1) {
+ int http1, http2, codenum;
+
+ if ( sscanf(root->buffer, "HTTP/%d.%d %d", &http1, &http2, &codenum) != 3 ) {
+ PROXY_LOG( "%s: invalid answer from proxy: '%s'\n",
+ root->name, root->buffer );
+ proxy_connection_free( root, PROXY_EVENT_SERVER_ERROR );
+ return;
+ }
+
+ /* success is 2xx */
+ if (codenum/2 != 100) {
+ PROXY_LOG( "%s: connection refused, error=%d\n",
+ root->name, codenum );
+ proxy_connection_free( root, PROXY_EVENT_CONNECTION_REFUSED );
+ return;
+ }
+ PROXY_LOG("%s: receiving second answer line\n", root->name);
+ conn->state = HTTP_RECEIVE_ANSWER_LINE2;
+ root->buffer_pos = 0;
+ } else {
+ /* ok, we're connected */
+ PROXY_LOG("%s: connection succeeded\n", root->name);
+ proxy_connection_free( root, PROXY_EVENT_CONNECTED );
+ }
+ }
+ break;
+
+ default:
+ PROXY_LOG("%s: invalid state for read event: %d\n", root->name, conn->state);
+ }
+}
+
+static void
+http_service_free( HttpService* service )
+{
+ PROXY_LOG("%s\n", __FUNCTION__);
+ if (service->footer != service->footer0)
+ qemu_free(service->footer);
+ qemu_free(service);
+}
+
+
+static ProxyConnection*
+http_service_connect( HttpService* service,
+ int socket,
+ struct sockaddr_in* address )
+{
+ HttpConnection* conn = qemu_mallocz(sizeof(*conn));
+ int sock_type = socket_get_type(socket);
+
+ /* the HTTP proxy can only handle TCP connections */
+ if (sock_type != SOCK_STREAM)
+ return NULL;
+
+ /* if the client tries to directly connect to the proxy, let it do so */
+ if (address->sin_addr.s_addr == service->server_addr.sin_addr.s_addr &&
+ address->sin_port == service->server_addr.sin_port)
+ return NULL;
+
+ proxy_connection_init( conn->root, socket, address, service->root );
+
+ if ( http_connection_init( conn ) < 0 ) {
+ http_connection_free( conn );
+ return NULL;
+ }
+
+ return conn->root;
+}
+
+
+int
+proxy_http_setup( const char* servername,
+ int servernamelen,
+ int serverport,
+ int num_options,
+ const ProxyOption* options )
+{
+ HttpService* service;
+ struct sockaddr_in server_addr;
+ const ProxyOption* opt_nocache = NULL;
+ const ProxyOption* opt_keepalive = NULL;
+ const ProxyOption* opt_auth_user = NULL;
+ const ProxyOption* opt_auth_pass = NULL;
+ const ProxyOption* opt_user_agent = NULL;
+
+ if (servernamelen < 0)
+ servernamelen = strlen(servername);
+
+ PROXY_LOG( "%s: creating http proxy service connecting to: %.*s:%d\n",
+ __FUNCTION__, servernamelen, servername, serverport );
+
+ /* resolve server address */
+ if (proxy_resolve_server(&server_addr, servername,
+ servernamelen, serverport) < 0)
+ {
+ return -1;
+ }
+
+ /* create service object */
+ service = qemu_mallocz(sizeof(*service));
+ if (service == NULL) {
+ PROXY_LOG("%s: not enough memory to allocate new proxy service\n", __FUNCTION__);
+ return -1;
+ }
+
+ service->server_addr = server_addr;
+
+ /* parse options */
+ {
+ const ProxyOption* opt = options;
+ const ProxyOption* end = opt + num_options;
+
+ for ( ; opt < end; opt++ ) {
+ switch (opt->type) {
+ case PROXY_OPTION_HTTP_NOCACHE: opt_nocache = opt; break;
+ case PROXY_OPTION_HTTP_KEEPALIVE: opt_keepalive = opt; break;
+ case PROXY_OPTION_AUTH_USERNAME: opt_auth_user = opt; break;
+ case PROXY_OPTION_AUTH_PASSWORD: opt_auth_pass = opt; break;
+ case PROXY_OPTION_HTTP_USER_AGENT: opt_user_agent = opt; break;
+ default: ;
+ }
+ }
+ }
+
+ /* prepare footer */
+ {
+ int wlen;
+ char* p = service->footer0;
+ char* end = p + sizeof(service->footer0);
+
+ /* no-cache */
+ if (opt_nocache) {
+ p += snprintf(p, end-p, "Pragma: no-cache\r\nCache-Control: no-cache\r\n");
+ if (p >= end) goto FooterOverflow;
+ }
+ /* keep-alive */
+ if (opt_keepalive) {
+ p += snprintf(p, end-p, "Connection: Keep-Alive\r\nProxy-Connection: Keep-Alive\r\n");
+ if (p >= end) goto FooterOverflow;
+ }
+ /* authentication */
+ if (opt_auth_user && opt_auth_pass) {
+ char user_pass[256];
+ char encoded[512];
+ int uplen;
+
+ uplen = snprintf( user_pass, sizeof(user_pass), "%.*s:%.*s",
+ opt_auth_user->string_len, opt_auth_user->string,
+ opt_auth_pass->string_len, opt_auth_pass->string );
+
+ if (uplen >= sizeof(user_pass)) goto FooterOverflow;
+
+ wlen = proxy_base64_encode(user_pass, uplen, encoded, (int)sizeof(encoded));
+ if (wlen < 0) {
+ PROXY_LOG( "could not base64 encode '%.*s'\n", uplen, user_pass);
+ goto FooterOverflow;
+ }
+
+ p += snprintf(p, end-p, "Proxy-authorization: Basic %.*s\r\n", wlen, encoded);
+ if (p >= end) goto FooterOverflow;
+ }
+ /* user agent */
+ if (opt_user_agent) {
+ p += snprintf(p, end-p, "User-Agent: %.*s\r\n",
+ opt_user_agent->string_len,
+ opt_user_agent->string);
+ if (p >= end) goto FooterOverflow;
+ }
+
+ p += snprintf(p, end-p, "\r\n");
+
+ if (p >= end) {
+ FooterOverflow:
+ PROXY_LOG( "%s: buffer overflow when creating connection footer\n",
+ __FUNCTION__);
+ http_service_free(service);
+ return -1;
+ }
+
+ service->footer = service->footer0;
+ service->footer_len = (p - service->footer);
+ }
+
+ PROXY_LOG( "%s: creating HTTP Proxy Service Footer is (len=%d):\n'%.*s'\n",
+ __FUNCTION__, service->footer_len,
+ service->footer_len, service->footer );
+
+ service->root->opaque = service;
+ service->root->serv_free = (ProxyServiceFreeFunc) http_service_free;
+ service->root->serv_connect = (ProxyServiceConnectFunc) http_service_connect;
+ service->root->conn_free = (ProxyConnectionFreeFunc) http_connection_free;
+ service->root->conn_select = (ProxyConnectionSelectFunc) http_connection_select;
+ service->root->conn_poll = (ProxyConnectionPollFunc) http_connection_poll;
+
+ if (proxy_manager_add_service( service->root ) < 0) {
+ http_service_free(service);
+ return -1;
+ }
+ return 0;
+}
+
diff --git a/proxy/proxy_http.h b/proxy/proxy_http.h
new file mode 100644
index 0000000..a2e2917
--- /dev/null
+++ b/proxy/proxy_http.h
@@ -0,0 +1,24 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _PROXY_HTTP_H
+#define _PROXY_HTTP_H
+
+#include "proxy_common.h"
+
+extern int
+proxy_http_setup( const char* servername,
+ int servernamelen,
+ int serverport,
+ int num_options,
+ const ProxyOption* options );
+
+#endif /* END */
diff --git a/proxy/proxy_int.h b/proxy/proxy_int.h
new file mode 100644
index 0000000..9d91169
--- /dev/null
+++ b/proxy/proxy_int.h
@@ -0,0 +1,145 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _PROXY_INT_H
+#define _PROXY_INT_H
+
+#include "proxy_common.h"
+#include "sockets.h"
+
+extern int proxy_log;
+
+extern void
+proxy_LOG(const char* fmt, ...);
+
+#define PROXY_LOG(...) \
+ do { if (proxy_log) proxy_LOG(__VA_ARGS__); } while (0)
+
+
+/* sockets proxy manager internals */
+
+typedef struct ProxyConnection ProxyConnection;
+typedef struct ProxyService ProxyService;
+
+
+/* root ProxyConnection object */
+struct ProxyConnection {
+ int socket;
+ struct sockaddr_in address; /* for debugging */
+ ProxyConnection* next;
+ ProxyConnection* prev;
+ ProxyEventFunc ev_func;
+ void* ev_opaque;
+ ProxyService* service;
+
+ /* the following is useful for all types of services */
+ char name[64]; /* for debugging purposes */
+ int buffer_pos;
+ int buffer_len;
+ char* buffer;
+ char buffer0[ 1024 ];
+
+ /* rest of data depend on ProxyService */
+};
+
+
+
+extern void
+proxy_connection_init( ProxyConnection* conn,
+ int socket,
+ struct sockaddr_in* address,
+ ProxyService* service );
+
+extern void
+proxy_connection_done( ProxyConnection* conn );
+
+extern void
+proxy_connection_free( ProxyConnection* conn,
+ ProxyEvent event );
+
+/* tries to send data from the connection's buffer to the proxy.
+ * returns 1 when all data has been sent (i.e. buffer_pos == buffer_len),
+ * 0 if there is still some data to send, or -1 in case of error
+ */
+extern int
+proxy_connection_send( ProxyConnection* conn );
+
+/* tries to receive data from the connection's buffer from the proxy
+ * returns 1 when all data has been received (buffer_pos == buffer_len)
+ * returns 0 if there is still some data to receive
+ * returns -1 in case of error
+ */
+extern int
+proxy_connection_receive( ProxyConnection* conn );
+
+/* tries to receive a line of text from the proxy
+ * returns 1 when a line has been received
+ * returns 0 if there is still some data to receive
+ * returns -1 in case of error
+ */
+extern int
+proxy_connection_receive_line( ProxyConnection* conn );
+
+/* base64 encode a source string, returns size of encoded result,
+ * or -1 if there was not enough room in the destination buffer
+ */
+extern int
+proxy_base64_encode( const char* src, int srclen,
+ char* dst, int dstlen );
+
+extern int
+proxy_resolve_server( struct sockaddr_in* addr,
+ const char* servername,
+ int servernamelen,
+ int serverport );
+
+/* a ProxyService is really a proxy server and associated options */
+
+enum {
+ PROXY_SELECT_READ = (1 << 0),
+ PROXY_SELECT_WRITE = (1 << 1),
+ PROXY_SELECT_ERROR = (1 << 2)
+};
+
+/* destroy a given proxy service */
+typedef void (*ProxyServiceFreeFunc) ( void* opaque );
+
+/* tries to create a new proxified connection, returns NULL if the service can't
+ * handle this address */
+typedef ProxyConnection* (*ProxyServiceConnectFunc)( void* opaque,
+ int socket,
+ struct sockaddr_in* address );
+
+/* free a given proxified connection */
+typedef void (*ProxyConnectionFreeFunc) ( ProxyConnection* conn );
+
+/* return flags corresponding to the select() events to wait to a proxified connection */
+typedef unsigned (*ProxyConnectionSelectFunc) ( ProxyConnection* conn );
+
+/* action a proxy connection when select() returns certain events for its socket */
+typedef void (*ProxyConnectionPollFunc) ( ProxyConnection* conn,
+ unsigned select_flags );
+
+struct ProxyService {
+ void* opaque;
+ ProxyServiceFreeFunc serv_free;
+ ProxyServiceConnectFunc serv_connect;
+ ProxyConnectionFreeFunc conn_free;
+ ProxyConnectionSelectFunc conn_select;
+ ProxyConnectionPollFunc conn_poll;
+};
+
+extern int
+proxy_manager_add_service( ProxyService* service );
+
+
+#endif /* _PROXY_INT_H */
+
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 1e49ccf..ddf0456 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -526,6 +526,8 @@ Write output to filename. No character can be read.
[Unix only] standard input/output
@item pipe:filename
name pipe @var{filename}
+@item fdpair:fd1:fd2
+[Unix only] Use fd1 as input and fd2 as output (from the point of view of the emulator).
@item COMn
[Windows only] Use host serial port @var{n}
@item udp:[remote_host]:remote_port[@@[src_ip]:src_port]
@@ -741,8 +743,6 @@ show emulated PCI device
show USB devices plugged on the virtual USB hub
@item info usbhost
show all USB host devices
-@item info capture
-show information about active capturing
@end table
@item q or quit
@@ -757,23 +757,6 @@ Change a removable media.
@item screendump filename
Save screen into PPM image @var{filename}.
-@item wavcapture filename [frequency [bits [channels]]]
-Capture audio into @var{filename}. Using sample rate @var{frequency}
-bits per sample @var{bits} and number of channels @var{channels}.
-
-Defaults:
-@itemize @minus
-@item Sample rate = 44100 Hz - CD quality
-@item Bits = 16
-@item Number of channels = 2 - Stereo
-@end itemize
-
-@item stopcapture index
-Stop capture with a given @var{index}, index can be obtained with
-@example
-info capture
-@end example
-
@item log item1[,...]
Activate logging of the specified items to @file{/tmp/qemu.log}.
diff --git a/qemu_file.h b/qemu_file.h
new file mode 100644
index 0000000..2172390
--- /dev/null
+++ b/qemu_file.h
@@ -0,0 +1,121 @@
+#ifndef _QEMU_FILE_H
+#define _QEMU_FILE_H
+
+#include <stddef.h>
+
+typedef FILE QEMUFile;
+
+void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
+void qemu_put_byte(QEMUFile *f, int v);
+void qemu_put_be16(QEMUFile *f, unsigned int v);
+void qemu_put_be32(QEMUFile *f, unsigned int v);
+void qemu_put_be64(QEMUFile *f, uint64_t v);
+
+int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size);
+int qemu_get_byte(QEMUFile *f);
+unsigned int qemu_get_be16(QEMUFile *f);
+unsigned int qemu_get_be32(QEMUFile *f);
+uint64_t qemu_get_be64(QEMUFile *f);
+
+static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
+{
+ qemu_put_be64(f, *pv);
+}
+
+static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv)
+{
+ qemu_put_be32(f, *pv);
+}
+
+static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv)
+{
+ qemu_put_be16(f, *pv);
+}
+
+static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv)
+{
+ qemu_put_byte(f, *pv);
+}
+
+static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv)
+{
+ *pv = qemu_get_be64(f);
+}
+
+static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv)
+{
+ *pv = qemu_get_be32(f);
+}
+
+static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv)
+{
+ *pv = qemu_get_be16(f);
+}
+
+static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv)
+{
+ *pv = qemu_get_byte(f);
+}
+
+#if TARGET_LONG_BITS == 64
+#define qemu_put_betl qemu_put_be64
+#define qemu_get_betl qemu_get_be64
+#define qemu_put_betls qemu_put_be64s
+#define qemu_get_betls qemu_get_be64s
+#else
+#define qemu_put_betl qemu_put_be32
+#define qemu_get_betl qemu_get_be32
+#define qemu_put_betls qemu_put_be32s
+#define qemu_get_betls qemu_get_be32s
+#endif
+
+int64_t qemu_ftell(QEMUFile *f);
+int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence);
+
+typedef enum {
+ Q_FIELD_END, /* mark end of field list */
+ Q_FIELD_BYTE, /* for 1-byte fields */
+ Q_FIELD_INT16, /* for 2-byte fields */
+ Q_FIELD_INT32, /* for 4-byte fields */
+ Q_FIELD_INT64, /* for 8-byte fields */
+ Q_FIELD_BUFFER, /* for buffer fields */
+ Q_FIELD_BUFFER_SIZE, /* to specify the size of buffers */
+
+#if TARGET_LONG_BITS == 64
+ Q_FIELD_TL = Q_FIELD_INT64, /* target long, either 4 or 8 bytes */
+#else
+ Q_FIELD_TL = Q_FIELD_INT32
+#endif
+
+} QFieldType;
+
+typedef struct {
+ QFieldType type : 16; /* field type */
+ uint16_t offset; /* offset of field in structure */
+} QField;
+
+#define QFIELD_BEGIN(name) \
+ static const QField name[] = {
+
+#define _QFIELD_(t, f) { t, offsetof(QFIELD_STRUCT,f) }
+#define QFIELD_BYTE(f) _QFIELD_(Q_FIELD_BYTE, f)
+#define QFIELD_INT16(f) _QFIELD_(Q_FIELD_INT16, f)
+#define QFIELD_INT32(f) _QFIELD_(Q_FIELD_INT32, f)
+#define QFIELD_INT64(f) _QFIELD_(Q_FIELD_INT64, f)
+#define QFIELD_TL(f) _QFIELD_(Q_FIELD_TL, f)
+
+#define _QFIELD_SIZEOF(f) sizeof(((QFIELD_STRUCT*)0)->f)
+
+#define QFIELD_BUFFER(f) \
+ _QFIELD_(Q_FIELD_BUFFER, f), \
+ { Q_FIELD_BUFFER_SIZE, (uint16_t)(_QFIELD_SIZEOF(f) >> 16) }, \
+ { Q_FIELD_BUFFER_SIZE, (uint16_t) _QFIELD_SIZEOF(f) }
+
+#define QFIELD_END \
+ { Q_FIELD_END, 0 }, \
+ };
+
+extern void qemu_put_struct(QEMUFile* f, const QField* fields, const void* s);
+extern int qemu_get_struct(QEMUFile* f, const QField* fields, void* s);
+
+#endif /* _QEMU_FILE_H */
diff --git a/qemu_socket.h b/qemu_socket.h
deleted file mode 100644
index 64b7d4e..0000000
--- a/qemu_socket.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* headers to use the BSD sockets */
-#ifndef QEMU_SOCKET_H
-#define QEMU_SOCKET_H
-
-#ifdef _WIN32
-
-#include <windows.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-
-#define socket_error() WSAGetLastError()
-#undef EINTR
-#define EWOULDBLOCK WSAEWOULDBLOCK
-#define EINTR WSAEINTR
-#define EINPROGRESS WSAEINPROGRESS
-
-#else
-
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-
-#define socket_error() errno
-#define closesocket(s) close(s)
-
-#endif /* !_WIN32 */
-
-void socket_set_nonblock(int fd);
-
-#endif /* QEMU_SOCKET_H */
diff --git a/qemu_timers.c b/qemu_timers.c
new file mode 100644
index 0000000..2dc0806
--- /dev/null
+++ b/qemu_timers.c
@@ -0,0 +1,1103 @@
+#include "vl.h"
+
+#include <sys/time.h>
+#include <time.h>
+#include "android_utils.h"
+#include "android.h"
+
+#include <signal.h>
+
+#define D(...) VERBOSE_PRINT(init,__VA_ARGS__)
+
+
+#ifdef _WIN32
+#include <sys/timeb.h>
+#else
+#include <sys/ioctl.h>
+#endif
+
+#ifdef __linux__
+#include <linux/rtc.h>
+#include "hpet.h"
+#endif
+
+#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
+
+QEMUClock *rt_clock;
+QEMUClock *vm_clock;
+
+/***********************************************************/
+/* real time host monotonic timer */
+
+/* digit: the following two variables are used to implement high-resolution
+ * poll-based interrupts. the idea is to be able to generate an emulated
+ * interrupt every millisecond, even on non-Linux platforms which don't have
+ * a /dev/rtc
+ */
+static int64_t milli_last_ns;
+static int64_t milli_next_ns;
+
+/* digit: the following global boolean is set when we need to perform
+ * high-resolution polling. If not, we'll use host interrupts instead
+ */
+int qemu_milli_needed = 0;
+
+#ifdef WIN32
+
+static int64_t clock_freq;
+
+static void init_get_clock(void)
+{
+ LARGE_INTEGER freq;
+ int ret;
+ ret = QueryPerformanceFrequency(&freq);
+ if (ret == 0) {
+ fprintf(stderr, "Could not calibrate ticks\n");
+ exit(1);
+ }
+ clock_freq = freq.QuadPart;
+
+ {
+ LARGE_INTEGER ti;
+ QueryPerformanceCounter(&ti);
+ milli_last_ns = muldiv64(ti.QuadPart,QEMU_TIMER_BASE,clock_freq);
+ milli_next_ns = milli_last_ns + 1000000;
+ }
+}
+
+static int64_t get_clock(void)
+{
+ LARGE_INTEGER ti;
+ QueryPerformanceCounter(&ti);
+ return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq);
+}
+
+
+
+#elif defined(__APPLE__)
+
+#include <mach/mach_time.h>
+
+static mach_timebase_info_data_t _mach_timebase_info;
+static int64_t _mach_timebase;
+
+static int64_t get_clock(void)
+{
+ int64_t elapsed = mach_absolute_time() - _mach_timebase;
+ int64_t numer = _mach_timebase_info.numer;
+ int64_t denom = _mach_timebase_info.denom;
+
+ /* return elapsed time in nanoseconds */
+ return elapsed * numer / denom;
+}
+
+static void init_get_clock(void)
+{
+ mach_timebase_info( &_mach_timebase_info );
+ _mach_timebase = mach_absolute_time();
+
+ milli_last_ns = get_clock();
+ milli_next_ns = milli_last_ns + 1000000;
+}
+
+
+#else
+
+static int use_rt_clock;
+
+static int64_t get_clock(void)
+{
+#if defined(__linux__)
+ if (use_rt_clock) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec * 1000000000LL + ts.tv_nsec;
+ } else
+#endif
+ {
+ /* XXX: using gettimeofday leads to problems if the date
+ changes, so it should be avoided. */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
+ }
+}
+
+static void init_get_clock(void)
+{
+ use_rt_clock = 0;
+#if defined(__linux__)
+ {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ use_rt_clock = 1;
+ }
+ }
+#endif
+ milli_last_ns = get_clock();
+ milli_next_ns = milli_last_ns + 1000000;
+}
+
+
+#endif
+
+int64_t qemu_get_elapsed_ns(void)
+{
+ return get_clock();
+}
+
+void qemu_polling_enable( void )
+{
+ if (++qemu_milli_needed == 1) {
+ milli_last_ns = get_clock();
+ milli_next_ns = milli_last_ns + 1000000;
+ }
+}
+
+void qemu_polling_disable( void )
+{
+ --qemu_milli_needed;
+}
+
+int qemu_milli_check(void)
+{
+ int result = 0;
+ int64_t now_ns = get_clock();
+
+ //fprintf(stderr,"MilliCheck: now=%.4fms next=%.4fms\n", (double)now_ns/1000000.0, (double)milli_next_ns/1000000.0);
+ if (now_ns < milli_last_ns) { /* software suspend ? */
+ milli_last_ns = now_ns;
+ milli_next_ns = now_ns + 1000000;
+ return 1;
+ }
+
+ while (now_ns >= milli_next_ns)
+ {
+ milli_last_ns = milli_next_ns;
+ milli_next_ns = milli_last_ns + 1000000;
+ result += 1;
+ }
+ return result;
+}
+
+/***********************************************************/
+/* guest cycle counter */
+
+static int64_t cpu_ticks_prev;
+static int64_t cpu_ticks_offset;
+static int64_t cpu_clock_offset;
+static int cpu_ticks_enabled;
+
+/* return the host CPU cycle counter and handle stop/restart */
+int64_t cpu_get_ticks(void)
+{
+ if (!cpu_ticks_enabled) {
+ return cpu_ticks_offset;
+ } else {
+ int64_t ticks;
+ ticks = cpu_get_real_ticks();
+ if (cpu_ticks_prev > ticks) {
+ /* Note: non increasing ticks may happen if the host uses
+ software suspend */
+ cpu_ticks_offset += cpu_ticks_prev - ticks;
+ }
+ cpu_ticks_prev = ticks;
+ return ticks + cpu_ticks_offset;
+ }
+}
+
+/* return the host CPU monotonic timer and handle stop/restart */
+static int64_t cpu_get_clock(void)
+{
+ int64_t ti;
+ if (!cpu_ticks_enabled) {
+ return cpu_clock_offset;
+ } else {
+ ti = get_clock();
+ return ti + cpu_clock_offset;
+ }
+}
+
+/* enable cpu_get_ticks() */
+void cpu_enable_ticks(void)
+{
+ if (!cpu_ticks_enabled) {
+ cpu_ticks_offset -= cpu_get_real_ticks();
+ cpu_clock_offset -= get_clock();
+ cpu_ticks_enabled = 1;
+ }
+}
+
+/* disable cpu_get_ticks() : the clock is stopped. You must not call
+ cpu_get_ticks() after that. */
+void cpu_disable_ticks(void)
+{
+ if (cpu_ticks_enabled) {
+ cpu_ticks_offset = cpu_get_ticks();
+ cpu_clock_offset = cpu_get_clock();
+ cpu_ticks_enabled = 0;
+ }
+}
+
+/***********************************************************/
+/* timers */
+
+#define QEMU_TIMER_REALTIME 0
+#define QEMU_TIMER_VIRTUAL 1
+
+struct QEMUClock {
+ int type;
+ /* XXX: add frequency */
+};
+
+struct QEMUTimer {
+ QEMUClock *clock;
+ int64_t expire_time;
+ QEMUTimerCB *cb;
+ void *opaque;
+ struct QEMUTimer *next;
+};
+
+struct qemu_alarm_timer {
+ char const *name;
+ unsigned int flags;
+
+ int (*start)(struct qemu_alarm_timer *t);
+ void (*stop)(struct qemu_alarm_timer *t);
+ void (*rearm)(struct qemu_alarm_timer *t);
+ void (*signal)(void);
+ void *priv;
+};
+
+#define ALARM_FLAG_DYNTICKS 0x1
+#define ALARM_FLAG_EXPIRED 0x2
+
+static inline int alarm_timer_has_dynticks(struct qemu_alarm_timer *t)
+{
+ return t && t->flags & ALARM_FLAG_DYNTICKS;
+}
+
+static void alarm_timer_rearm(struct qemu_alarm_timer *t)
+{
+ if (!alarm_timer_has_dynticks(t))
+ return;
+
+ t->rearm(t);
+}
+
+/* TODO: MIN_TIMER_REARM_US should be optimized */
+#define MIN_TIMER_REARM_US 250
+
+static struct qemu_alarm_timer *alarm_timer;
+
+#ifdef _WIN32
+#define USE_WIN32_TIMER 1
+#define USE_WIN32_DYNTICKS_TIMER 1
+#else
+#define USE_UNIX_TIMER 1
+#endif
+
+#ifdef __linux__
+#define DONT_USE_DYNTICKS_TIMER 1 /* it freezes the Android emulator hard */
+#define USE_HPET_TIMER 1
+#define USE_RTC_TIMER 1
+#endif
+
+
+#if defined(USE_WIN32_TIMER) || defined(USE_WIN32_DYNTICKS_TIMER)
+struct qemu_alarm_win32 {
+ MMRESULT timerId;
+ HANDLE host_alarm;
+ unsigned int period;
+} alarm_win32_data = {0, NULL, -1};
+
+static int win32_start_timer(struct qemu_alarm_timer *t);
+static void win32_stop_timer(struct qemu_alarm_timer *t);
+#endif
+
+#ifdef USE_WIN32_DYNTICKS_TIMER
+static void win32_rearm_timer(struct qemu_alarm_timer *t);
+#endif
+
+#ifdef USE_UNIX_TIMER
+static int unix_start_timer(struct qemu_alarm_timer *t);
+static void unix_stop_timer(struct qemu_alarm_timer *t);
+#endif
+
+#ifdef USE_DYNTICKS_TIMER
+static int dynticks_start_timer(struct qemu_alarm_timer *t);
+static void dynticks_stop_timer(struct qemu_alarm_timer *t);
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
+#endif
+
+#ifdef USE_HPET_TIMER
+static int hpet_start_timer(struct qemu_alarm_timer *t);
+static void hpet_stop_timer(struct qemu_alarm_timer *t);
+#endif
+
+#ifdef USE_RTC_TIMER
+static int rtc_start_timer(struct qemu_alarm_timer *t);
+static void rtc_stop_timer(struct qemu_alarm_timer *t);
+#endif
+
+
+static struct qemu_alarm_timer alarm_timers[] = {
+#ifdef USE_DYNTICKS_TIMER
+ {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer,
+ dynticks_stop_timer, dynticks_rearm_timer, NULL, NULL},
+#endif
+#ifdef USE_HPET_TIMER
+ /* HPET - if available - is preferred */
+ {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL, NULL},
+#endif
+#ifdef USE_RTC_TIMER
+ /* ...otherwise try RTC */
+ {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL, NULL},
+#endif
+#ifdef USE_UNIX_TIMER
+ {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL, NULL},
+#endif
+#ifdef USE_WIN32_DYNTICKS_TIMER
+ {"dynticks", ALARM_FLAG_DYNTICKS, win32_start_timer,
+ win32_stop_timer, win32_rearm_timer, NULL, &alarm_win32_data},
+#endif
+#ifdef USE_WIN32_TIMER
+ {"win32", 0, win32_start_timer,
+ win32_stop_timer, NULL, NULL, &alarm_win32_data},
+#endif
+ {NULL, }
+};
+
+static void show_available_alarms()
+{
+ int i;
+
+ printf("Available alarm timers, in order of precedence:\n");
+ for (i = 0; alarm_timers[i].name; i++)
+ printf("%s\n", alarm_timers[i].name);
+}
+
+void qemu_configure_alarms(char const *opt)
+{
+ int i;
+ int cur = 0;
+ int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1;
+ char *arg;
+ char *name;
+
+ if (!strcmp(opt, "help")) {
+ show_available_alarms();
+ exit(0);
+ }
+
+ arg = strdup(opt);
+
+ /* Reorder the array */
+ name = strtok(arg, ",");
+ while (name) {
+ struct qemu_alarm_timer tmp;
+
+ for (i = 0; i < count && alarm_timers[i].name; i++) {
+ if (!strcmp(alarm_timers[i].name, name))
+ break;
+ }
+
+ if (i == count) {
+ fprintf(stderr, "Unknown clock %s\n", name);
+ goto next;
+ }
+
+ if (i < cur)
+ /* Ignore */
+ goto next;
+
+ /* Swap */
+ tmp = alarm_timers[i];
+ alarm_timers[i] = alarm_timers[cur];
+ alarm_timers[cur] = tmp;
+
+ cur++;
+next:
+ name = strtok(NULL, ",");
+ }
+
+ free(arg);
+
+ if (cur) {
+ /* Disable remaining timers */
+ for (i = cur; i < count; i++)
+ alarm_timers[i].name = NULL;
+ }
+
+ /* debug */
+ show_available_alarms();
+}
+
+QEMUClock *rt_clock;
+QEMUClock *vm_clock;
+
+static QEMUTimer *active_timers[2];
+#if defined(USE_WIN32_TIMER) || defined(USE_WIN32_DYNTICKS_TIMER)
+static MMRESULT timerID;
+static HANDLE host_alarm = NULL;
+static unsigned int period = 1;
+#endif
+
+QEMUClock *qemu_new_clock(int type)
+{
+ QEMUClock *clock;
+ clock = qemu_mallocz(sizeof(QEMUClock));
+ if (!clock)
+ return NULL;
+ clock->type = type;
+ return clock;
+}
+
+QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque)
+{
+ QEMUTimer *ts;
+
+ ts = qemu_mallocz(sizeof(QEMUTimer));
+ ts->clock = clock;
+ ts->cb = cb;
+ ts->opaque = opaque;
+ return ts;
+}
+
+void qemu_free_timer(QEMUTimer *ts)
+{
+ qemu_free(ts);
+}
+
+/* stop a timer, but do not dealloc it */
+void qemu_del_timer(QEMUTimer *ts)
+{
+ QEMUTimer **pt, *t;
+
+ /* NOTE: this code must be signal safe because
+ qemu_timer_expired() can be called from a signal. */
+ pt = &active_timers[ts->clock->type];
+ for(;;) {
+ t = *pt;
+ if (!t)
+ break;
+ if (t == ts) {
+ *pt = t->next;
+ break;
+ }
+ pt = &t->next;
+ }
+}
+
+/* modify the current timer so that it will be fired when current_time
+ >= expire_time. The corresponding callback will be called. */
+void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
+{
+ QEMUTimer **pt, *t;
+
+ qemu_del_timer(ts);
+
+ /* add the timer in the sorted list */
+ /* NOTE: this code must be signal safe because
+ qemu_timer_expired() can be called from a signal. */
+ pt = &active_timers[ts->clock->type];
+ for(;;) {
+ t = *pt;
+ if (!t)
+ break;
+ if (t->expire_time > expire_time)
+ break;
+ pt = &t->next;
+ }
+ ts->expire_time = expire_time;
+ ts->next = *pt;
+ *pt = ts;
+
+ /* Rearm if necessary */
+ if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0 &&
+ pt == &active_timers[ts->clock->type])
+ alarm_timer_rearm(alarm_timer);
+}
+
+int qemu_timer_pending(QEMUTimer *ts)
+{
+ QEMUTimer *t;
+ for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
+ if (t == ts)
+ return 1;
+ }
+ return 0;
+}
+
+static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
+{
+ if (!timer_head)
+ return 0;
+ return (timer_head->expire_time <= current_time);
+}
+
+#define QEMU_TIMER_MAX_TIMEOUT 10
+
+static inline int qemu_timer_next_timeout(QEMUTimer* timer_head)
+{
+ int64_t now, diff;
+
+ if (!timer_head)
+ return QEMU_TIMER_MAX_TIMEOUT;
+
+ now = qemu_get_clock(timer_head->clock);
+ diff = timer_head->expire_time - now;
+ if (timer_head->clock == vm_clock)
+ diff /= 1000000;
+
+ if (diff > QEMU_TIMER_MAX_TIMEOUT)
+ return QEMU_TIMER_MAX_TIMEOUT;
+ if (diff < 1)
+ diff = 1;
+ return (int) diff;
+}
+
+
+static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time)
+{
+ QEMUTimer *ts;
+
+ for(;;) {
+ ts = *ptimer_head;
+ if (!ts || ts->expire_time > current_time)
+ break;
+ /* remove timer from the list before calling the callback */
+ *ptimer_head = ts->next;
+ ts->next = NULL;
+
+ /* run the callback (the timer list can be modified) */
+ ts->cb(ts->opaque);
+ }
+}
+
+int64_t qemu_get_clock(QEMUClock *clock)
+{
+ switch(clock->type) {
+ case QEMU_TIMER_REALTIME:
+ return get_clock() / 1000000;
+ default:
+ case QEMU_TIMER_VIRTUAL:
+ return cpu_get_clock();
+ }
+}
+
+void init_timers(void)
+{
+ static int inited;
+ if (!inited) {
+ init_get_clock();
+ ticks_per_sec = QEMU_TIMER_BASE;
+ rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
+ vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
+ inited = 1;
+ }
+}
+
+/* save a timer */
+void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
+{
+ uint64_t expire_time;
+
+ if (qemu_timer_pending(ts)) {
+ expire_time = ts->expire_time;
+ } else {
+ expire_time = -1;
+ }
+ qemu_put_be64(f, expire_time);
+}
+
+void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
+{
+ uint64_t expire_time;
+
+ expire_time = qemu_get_be64(f);
+ if (expire_time != -1) {
+ qemu_mod_timer(ts, expire_time);
+ } else {
+ qemu_del_timer(ts);
+ }
+}
+
+void timer_save(QEMUFile *f, void *opaque)
+{
+ if (cpu_ticks_enabled) {
+ hw_error("cannot save state if virtual timers are running");
+ }
+ qemu_put_be64s(f, (uint64_t*)&cpu_ticks_offset);
+ qemu_put_be64s(f, (uint64_t*)&ticks_per_sec);
+}
+
+int timer_load(QEMUFile *f, void *opaque, int version_id)
+{
+ if (version_id != 1)
+ return -EINVAL;
+ if (cpu_ticks_enabled) {
+ return -EINVAL;
+ }
+ qemu_get_be64s(f, (uint64_t*)&cpu_ticks_offset);
+ qemu_get_be64s(f, (uint64_t*)&ticks_per_sec);
+ return 0;
+}
+
+#ifdef _WIN32
+void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
+ DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
+#else
+static void host_alarm_handler(int host_signum)
+#endif
+{
+#if 0
+ //write( 2, "|", 1 );
+#define DISP_FREQ 1000
+ {
+ static int64_t delta_min = INT64_MAX;
+ static int64_t delta_max, delta_cum, last_clock, delta, ti;
+ static int count;
+ ti = qemu_get_clock(vm_clock);
+ if (last_clock != 0) {
+ delta = ti - last_clock;
+ if (delta < delta_min)
+ delta_min = delta;
+ if (delta > delta_max)
+ delta_max = delta;
+ delta_cum += delta;
+ if (++count == DISP_FREQ) {
+ printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
+ muldiv64(delta_min, 1000000, ticks_per_sec),
+ muldiv64(delta_max, 1000000, ticks_per_sec),
+ muldiv64(delta_cum, 1000000 / DISP_FREQ, ticks_per_sec),
+ (double)ticks_per_sec / ((double)delta_cum / DISP_FREQ));
+ count = 0;
+ delta_min = INT64_MAX;
+ delta_max = 0;
+ delta_cum = 0;
+ }
+ }
+ last_clock = ti;
+ }
+#endif
+ if (alarm_timer_has_dynticks(alarm_timer) ||
+ qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
+ qemu_get_clock(vm_clock)) ||
+ qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
+ qemu_get_clock(rt_clock))) {
+#ifdef _WIN32
+ struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;
+ SetEvent(data->host_alarm);
+#endif
+ alarm_timer->flags |= ALARM_FLAG_EXPIRED;
+
+ if (alarm_timer->signal)
+ alarm_timer->signal();
+ }
+}
+
+static uint64_t qemu_next_deadline(void)
+{
+ int64_t nearest_delta_us = INT64_MAX;
+ int64_t vmdelta_us;
+
+ if (active_timers[QEMU_TIMER_REALTIME])
+ nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time -
+ qemu_get_clock(rt_clock))*1000;
+
+ if (active_timers[QEMU_TIMER_VIRTUAL]) {
+ /* round up */
+ vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time -
+ qemu_get_clock(vm_clock)+999)/1000;
+ if (vmdelta_us < nearest_delta_us)
+ nearest_delta_us = vmdelta_us;
+ }
+
+ /* Avoid arming the timer to negative, zero, or too low values */
+ if (nearest_delta_us <= MIN_TIMER_REARM_US)
+ nearest_delta_us = MIN_TIMER_REARM_US;
+
+ return nearest_delta_us;
+}
+
+#define RTC_FREQ 1024
+
+#if defined(USE_HPET_TIMER) || defined(USE_RTC_TIMER)
+static void enable_sigio_timer(int fd)
+{
+ struct sigaction act;
+
+ /* timer signal */
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = host_alarm_handler;
+
+ sigaction(SIGIO, &act, NULL);
+ fcntl(fd, F_SETFL, O_ASYNC);
+ fcntl(fd, F_SETOWN, getpid());
+}
+#endif
+
+#ifdef USE_HPET_TIMER
+static int hpet_start_timer(struct qemu_alarm_timer *t)
+{
+ struct hpet_info info;
+ int r, fd;
+
+ fd = open("/dev/hpet", O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ /* Set frequency */
+ r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);
+ if (r < 0) {
+ fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"
+ "error, but for better emulation accuracy type:\n"
+ "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");
+ goto fail;
+ }
+
+ /* Check capabilities */
+ r = ioctl(fd, HPET_INFO, &info);
+ if (r < 0)
+ goto fail;
+
+ /* Enable periodic mode */
+ r = ioctl(fd, HPET_EPI, 0);
+ if (info.hi_flags && (r < 0))
+ goto fail;
+
+ /* Enable interrupt */
+ r = ioctl(fd, HPET_IE_ON, 0);
+ if (r < 0)
+ goto fail;
+
+ enable_sigio_timer(fd);
+ t->priv = (void *)(long)fd;
+
+ return 0;
+fail:
+ close(fd);
+ return -1;
+}
+
+static void hpet_stop_timer(struct qemu_alarm_timer *t)
+{
+ int fd = (long)t->priv;
+
+ close(fd);
+}
+#endif
+
+#ifdef USE_RTC_TIMER
+static int rtc_start_timer(struct qemu_alarm_timer *t)
+{
+ int rtc_fd;
+ unsigned long current_rtc_freq = 0;
+
+ TFR(rtc_fd = open("/dev/rtc", O_RDONLY));
+ if (rtc_fd < 0)
+ return -1;
+ ioctl(rtc_fd, RTC_IRQP_READ, &current_rtc_freq);
+ if (current_rtc_freq != RTC_FREQ &&
+ ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
+ fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"
+ "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"
+ "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");
+ goto fail;
+ }
+ if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {
+ fail:
+ close(rtc_fd);
+ return -1;
+ }
+
+ enable_sigio_timer(rtc_fd);
+
+ t->priv = (void *)(long)rtc_fd;
+
+ return 0;
+}
+
+static void rtc_stop_timer(struct qemu_alarm_timer *t)
+{
+ int rtc_fd = (long)t->priv;
+
+ close(rtc_fd);
+}
+#endif
+
+#ifdef USE_DYNTICKS_TIMER
+static int dynticks_start_timer(struct qemu_alarm_timer *t)
+{
+ struct sigevent ev;
+ timer_t host_timer;
+ struct sigaction act;
+
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = host_alarm_handler;
+
+ sigaction(SIGALRM, &act, NULL);
+
+ ev.sigev_value.sival_int = 0;
+ ev.sigev_notify = SIGEV_SIGNAL;
+ ev.sigev_signo = SIGALRM;
+
+ if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
+ perror("timer_create");
+
+ /* disable dynticks */
+ fprintf(stderr, "Dynamic Ticks disabled\n");
+
+ return -1;
+ }
+
+ t->priv = (void *)host_timer;
+
+ return 0;
+}
+
+static void dynticks_stop_timer(struct qemu_alarm_timer *t)
+{
+ timer_t host_timer = (timer_t)t->priv;
+
+ timer_delete(host_timer);
+}
+
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
+{
+ timer_t host_timer = (timer_t)t->priv;
+ struct itimerspec timeout;
+ int64_t nearest_delta_us = INT64_MAX;
+ int64_t current_us;
+
+ if (!active_timers[QEMU_TIMER_REALTIME] &&
+ !active_timers[QEMU_TIMER_VIRTUAL]) {
+ return;
+ }
+ nearest_delta_us = qemu_next_deadline();
+
+ /* check whether a timer is already running */
+ if (timer_gettime(host_timer, &timeout)) {
+ perror("gettime");
+ fprintf(stderr, "Internal timer error: aborting\n");
+ exit(1);
+ }
+ current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000;
+ if (current_us && current_us <= nearest_delta_us)
+ return;
+
+ timeout.it_interval.tv_sec = 0;
+ timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
+ timeout.it_value.tv_sec = nearest_delta_us / 1000000;
+ timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000;
+ if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) {
+ perror("settime");
+ fprintf(stderr, "Internal timer error: aborting\n");
+ exit(1);
+ }
+}
+#endif /* USE_DYNTICKS_TIMER */
+
+#ifdef USE_UNIX_TIMER
+static int unix_start_timer(struct qemu_alarm_timer *t)
+{
+ struct sigaction act;
+ struct itimerval itv;
+ int err;
+
+ /* timer signal */
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = host_alarm_handler;
+
+ sigaction(SIGALRM, &act, NULL);
+
+ itv.it_interval.tv_sec = 0;
+ /* for i386 kernel 2.6 to get 1 ms */
+ itv.it_interval.tv_usec = 999;
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 10 * 1000;
+
+ err = setitimer(ITIMER_REAL, &itv, NULL);
+ if (err)
+ return -1;
+
+ return 0;
+}
+
+static void unix_stop_timer(struct qemu_alarm_timer *t)
+{
+ struct itimerval itv;
+
+ memset(&itv, 0, sizeof(itv));
+ setitimer(ITIMER_REAL, &itv, NULL);
+}
+
+#endif /* USE_UNIX_TIMER */
+
+#if defined(USE_WIN32_TIMER) || defined(USE_WIN32_DYNTICKS_TIMER)
+static int win32_start_timer(struct qemu_alarm_timer *t)
+{
+ TIMECAPS tc;
+ struct qemu_alarm_win32 *data = t->priv;
+ UINT flags;
+
+ data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!data->host_alarm) {
+ perror("Failed CreateEvent");
+ return -1;
+ }
+
+ memset(&tc, 0, sizeof(tc));
+ timeGetDevCaps(&tc, sizeof(tc));
+
+ if (data->period < tc.wPeriodMin)
+ data->period = tc.wPeriodMin;
+
+ timeBeginPeriod(data->period);
+
+ flags = TIME_CALLBACK_FUNCTION;
+ if (alarm_timer_has_dynticks(t))
+ flags |= TIME_ONESHOT;
+ else
+ flags |= TIME_PERIODIC;
+
+ data->timerId = timeSetEvent(1, // interval (ms)
+ data->period, // resolution
+ host_alarm_handler, // function
+ (DWORD)t, // parameter
+ flags);
+
+ if (!data->timerId) {
+ perror("Failed to initialize win32 alarm timer");
+
+ timeEndPeriod(data->period);
+ CloseHandle(data->host_alarm);
+ return -1;
+ }
+
+ qemu_add_wait_object(data->host_alarm, NULL, NULL);
+
+ return 0;
+}
+
+static void win32_stop_timer(struct qemu_alarm_timer *t)
+{
+ struct qemu_alarm_win32 *data = t->priv;
+
+ timeKillEvent(data->timerId);
+ timeEndPeriod(data->period);
+
+ CloseHandle(data->host_alarm);
+}
+#endif /* USE_WIN32_TIMER || USE_WIN32_DYNTICKS_TIMER */
+
+#ifdef USE_WIN32_DYNTICKS_TIMER
+static void win32_rearm_timer(struct qemu_alarm_timer *t)
+{
+ struct qemu_alarm_win32 *data = t->priv;
+ uint64_t nearest_delta_us;
+
+ if (!active_timers[QEMU_TIMER_REALTIME] &&
+ !active_timers[QEMU_TIMER_VIRTUAL])
+ return;
+
+ nearest_delta_us = qemu_next_deadline();
+ nearest_delta_us /= 1000;
+
+ timeKillEvent(data->timerId);
+
+ data->timerId = timeSetEvent(1,
+ data->period,
+ host_alarm_handler,
+ (DWORD)t,
+ TIME_ONESHOT | TIME_PERIODIC);
+
+ if (!data->timerId) {
+ perror("Failed to re-arm win32 alarm timer");
+
+ timeEndPeriod(data->period);
+ CloseHandle(data->host_alarm);
+ exit(1);
+ }
+}
+#endif /* USE_WIN32_DYNTICKS_TIMER */
+
+void qemu_init_alarm_timer(void (*cb)(void))
+{
+ struct qemu_alarm_timer *t;
+ int i, err = -1;
+
+ /* on UNIX, ensure that SIGALRM is not blocked for some reason */
+#ifndef _WIN32
+ {
+ sigset_t ss;
+ sigemptyset( &ss );
+ sigaddset( &ss, SIGALRM );
+ sigprocmask( SIG_UNBLOCK, &ss, NULL );
+ }
+#endif
+
+ for (i = 0; alarm_timers[i].name; i++) {
+ t = &alarm_timers[i];
+
+ err = t->start(t);
+ if (!err)
+ break;
+ }
+
+ if (err) {
+ fprintf(stderr, "Unable to find any suitable alarm timer.\n");
+ fprintf(stderr, "Terminating\n");
+ exit(1);
+ }
+
+ t->signal = cb;
+ D( "using '%s' alarm timer", t->name );
+ alarm_timer = t;
+}
+
+#if 0
+static void quit_timers(void)
+{
+ alarm_timer->stop(alarm_timer);
+ alarm_timer = NULL;
+}
+#endif
+
+void
+qemu_run_virtual_timers(void)
+{
+ qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock));
+}
+
+void
+qemu_run_realtime_timers(void)
+{
+ qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock));
+}
+
+void
+qemu_start_alarm_timer(void)
+{
+ alarm_timer_rearm(alarm_timer);
+}
+
+
+void
+qemu_rearm_alarm_timer(void)
+{
+ if (alarm_timer->flags & ALARM_FLAG_EXPIRED) {
+ alarm_timer->flags &= ~(ALARM_FLAG_EXPIRED);
+ alarm_timer_rearm(alarm_timer);
+ }
+}
+
+void
+qemu_stop_alarm_timer(void)
+{
+ alarm_timer->stop(alarm_timer);
+}
diff --git a/qemu_timers.h b/qemu_timers.h
new file mode 100644
index 0000000..3ab541e
--- /dev/null
+++ b/qemu_timers.h
@@ -0,0 +1,62 @@
+#ifndef _QEMU_TIMERS_H
+#define _QEMU_TIMERS_H
+
+#include "qemu_file.h"
+
+#define QEMU_TIMER_BASE 1000000000LL
+
+/* timers */
+
+typedef struct QEMUClock QEMUClock;
+typedef struct QEMUTimer QEMUTimer;
+
+typedef void QEMUTimerCB(void *opaque);
+
+/* The real time clock should be used only for stuff which does not
+ change the virtual machine state, as it is run even if the virtual
+ machine is stopped. The real time clock has a frequency of 1000
+ Hz. */
+extern QEMUClock *rt_clock;
+
+/* The virtual clock is only run during the emulation. It is stopped
+ when the virtual machine is stopped. Virtual timers use a high
+ precision clock, usually cpu cycles (use ticks_per_sec). */
+extern QEMUClock *vm_clock;
+
+/* return the elapsed host time in nanoseconds */
+int64_t qemu_get_elapsed_ns(void);
+
+int64_t qemu_get_clock(QEMUClock *clock);
+
+QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque);
+
+void qemu_free_timer(QEMUTimer *ts);
+void qemu_del_timer(QEMUTimer *ts);
+void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
+int qemu_timer_pending(QEMUTimer *ts);
+
+extern int64_t ticks_per_sec;
+extern int pit_min_timer_count;
+
+int64_t cpu_get_ticks(void);
+void cpu_enable_ticks(void);
+void cpu_disable_ticks(void);
+
+void init_timers(void);
+
+void init_alarm_timer(void (*cb)(void));
+
+void timer_save(QEMUFile *f, void *opaque);
+int timer_load(QEMUFile *f, void *opaque, int version_id);
+
+void qemu_run_virtual_timers(void);
+void qemu_run_realtime_timers(void);
+
+void qemu_init_alarm_timer( void(*cb)(void) );
+void qemu_start_alarm_timer(void);
+void qemu_rearm_alarm_timer(void);
+void qemu_stop_alarm_timer(void);
+
+void qemu_configure_alarms(char const *opt);
+
+#endif /* _QEMU_TIMERS_H */
diff --git a/s390.ld b/s390.ld
deleted file mode 100644
index 7f14ea9..0000000
--- a/s390.ld
+++ /dev/null
@@ -1,204 +0,0 @@
-OUTPUT_FORMAT("elf32-s390", "elf32-s390",
- "elf32-s390")
-OUTPUT_ARCH(s390:31-bit)
-ENTRY(_start)
-SEARCH_DIR("/usr/s390-redhat-linux/lib"); SEARCH_DIR("/usr/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib");
-/* Do we need any of these for elf?
- __DYNAMIC = 0; */
-SECTIONS
-{
- /* Read-only sections, merged into text segment: */
- . = 0x60000000 + SIZEOF_HEADERS;
- .interp : { *(.interp) }
- .hash : { *(.hash) }
- .dynsym : { *(.dynsym) }
- .dynstr : { *(.dynstr) }
- .gnu.version : { *(.gnu.version) }
- .gnu.version_d : { *(.gnu.version_d) }
- .gnu.version_r : { *(.gnu.version_r) }
- .rel.dyn :
- {
- *(.rel.init)
- *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
- *(.rel.fini)
- *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
- *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
- *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
- *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
- *(.rel.ctors)
- *(.rel.dtors)
- *(.rel.got)
- *(.rel.sdata .rel.sdata.* .rel.gnu.linkonce.s.*)
- *(.rel.sbss .rel.sbss.* .rel.gnu.linkonce.sb.*)
- *(.rel.sdata2 .rel.sdata2.* .rel.gnu.linkonce.s2.*)
- *(.rel.sbss2 .rel.sbss2.* .rel.gnu.linkonce.sb2.*)
- *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
- }
- .rela.dyn :
- {
- *(.rela.init)
- *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
- *(.rela.fini)
- *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
- *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
- *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
- *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
- *(.rela.ctors)
- *(.rela.dtors)
- *(.rela.got)
- *(.rela.sdata .rela.sdata.* .rela.gnu.linkonce.s.*)
- *(.rela.sbss .rela.sbss.* .rela.gnu.linkonce.sb.*)
- *(.rela.sdata2 .rela.sdata2.* .rela.gnu.linkonce.s2.*)
- *(.rela.sbss2 .rela.sbss2.* .rela.gnu.linkonce.sb2.*)
- *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
- }
- .rel.plt : { *(.rel.plt) }
- .rela.plt : { *(.rela.plt) }
- .init :
- {
- KEEP (*(.init))
- } =0x07070707
- .plt : { *(.plt) }
- .text :
- {
- *(.text .stub .text.* .gnu.linkonce.t.*)
- /* .gnu.warning sections are handled specially by elf32.em. */
- *(.gnu.warning)
- } =0x07070707
- .fini :
- {
- KEEP (*(.fini))
- } =0x07070707
- PROVIDE (__etext = .);
- PROVIDE (_etext = .);
- PROVIDE (etext = .);
- .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
- .rodata1 : { *(.rodata1) }
- .sdata2 : { *(.sdata2 .sdata2.* .gnu.linkonce.s2.*) }
- .sbss2 : { *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*) }
- .eh_frame_hdr : { *(.eh_frame_hdr) }
- /* Adjust the address for the data segment. We want to adjust up to
- the same address within the page on the next page up. */
- . = ALIGN(0x1000) + (. & (0x1000 - 1));
- /* Ensure the __preinit_array_start label is properly aligned. We
- could instead move the label definition inside the section, but
- the linker would then create the section even if it turns out to
- be empty, which isn't pretty. */
- . = ALIGN(32 / 8);
- PROVIDE (__preinit_array_start = .);
- .preinit_array : { *(.preinit_array) }
- PROVIDE (__preinit_array_end = .);
- PROVIDE (__init_array_start = .);
- .init_array : { *(.init_array) }
- PROVIDE (__init_array_end = .);
- PROVIDE (__fini_array_start = .);
- .fini_array : { *(.fini_array) }
- PROVIDE (__fini_array_end = .);
- .data :
- {
- *(.data .data.* .gnu.linkonce.d.*)
- SORT(CONSTRUCTORS)
- }
- .data1 : { *(.data1) }
- .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
- .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
- .eh_frame : { KEEP (*(.eh_frame)) }
- .gcc_except_table : { *(.gcc_except_table) }
- .dynamic : { *(.dynamic) }
- .ctors :
- {
- /* gcc uses crtbegin.o to find the start of
- the constructors, so we make sure it is
- first. Because this is a wildcard, it
- doesn't matter if the user does not
- actually link against crtbegin.o; the
- linker won't look for a file to match a
- wildcard. The wildcard also means that it
- doesn't matter which directory crtbegin.o
- is in. */
- KEEP (*crtbegin.o(.ctors))
- /* We don't want to include the .ctor section from
- from the crtend.o file until after the sorted ctors.
- The .ctor section from the crtend file contains the
- end of ctors marker and it must be last */
- KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
- KEEP (*(SORT(.ctors.*)))
- KEEP (*(.ctors))
- }
- .dtors :
- {
- KEEP (*crtbegin.o(.dtors))
- KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
- KEEP (*(SORT(.dtors.*)))
- KEEP (*(.dtors))
- }
- .jcr : { KEEP (*(.jcr)) }
- .got : { *(.got.plt) *(.got) }
- /* We want the small data sections together, so single-instruction offsets
- can access them all, and initialized data all before uninitialized, so
- we can shorten the on-disk segment size. */
- .sdata :
- {
- *(.sdata .sdata.* .gnu.linkonce.s.*)
- }
- _edata = .;
- PROVIDE (edata = .);
- __bss_start = .;
- .sbss :
- {
- PROVIDE (__sbss_start = .);
- PROVIDE (___sbss_start = .);
- *(.dynsbss)
- *(.sbss .sbss.* .gnu.linkonce.sb.*)
- *(.scommon)
- PROVIDE (__sbss_end = .);
- PROVIDE (___sbss_end = .);
- }
- .bss :
- {
- *(.dynbss)
- *(.bss .bss.* .gnu.linkonce.b.*)
- *(COMMON)
- /* Align here to ensure that the .bss section occupies space up to
- _end. Align after .bss to ensure correct alignment even if the
- .bss section disappears because there are no input sections. */
- . = ALIGN(32 / 8);
- }
- . = ALIGN(32 / 8);
- _end = .;
- PROVIDE (end = .);
- /* Stabs debugging sections. */
- .stab 0 : { *(.stab) }
- .stabstr 0 : { *(.stabstr) }
- .stab.excl 0 : { *(.stab.excl) }
- .stab.exclstr 0 : { *(.stab.exclstr) }
- .stab.index 0 : { *(.stab.index) }
- .stab.indexstr 0 : { *(.stab.indexstr) }
- .comment 0 : { *(.comment) }
- /* DWARF debug sections.
- Symbols in the DWARF debugging sections are relative to the beginning
- of the section so we begin them at 0. */
- /* DWARF 1 */
- .debug 0 : { *(.debug) }
- .line 0 : { *(.line) }
- /* GNU DWARF 1 extensions */
- .debug_srcinfo 0 : { *(.debug_srcinfo) }
- .debug_sfnames 0 : { *(.debug_sfnames) }
- /* DWARF 1.1 and DWARF 2 */
- .debug_aranges 0 : { *(.debug_aranges) }
- .debug_pubnames 0 : { *(.debug_pubnames) }
- /* DWARF 2 */
- .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
- .debug_abbrev 0 : { *(.debug_abbrev) }
- .debug_line 0 : { *(.debug_line) }
- .debug_frame 0 : { *(.debug_frame) }
- .debug_str 0 : { *(.debug_str) }
- .debug_loc 0 : { *(.debug_loc) }
- .debug_macinfo 0 : { *(.debug_macinfo) }
- /* SGI/MIPS DWARF 2 extensions */
- .debug_weaknames 0 : { *(.debug_weaknames) }
- .debug_funcnames 0 : { *(.debug_funcnames) }
- .debug_typenames 0 : { *(.debug_typenames) }
- .debug_varnames 0 : { *(.debug_varnames) }
-}
-
diff --git a/sdl.c b/sdl.c
index 38d7553..d82745d 100644
--- a/sdl.c
+++ b/sdl.c
@@ -50,7 +50,7 @@ static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
SDL_UpdateRect(screen, x, y, w, h);
}
-static void sdl_resize(DisplayState *ds, int w, int h)
+static void sdl_resize(DisplayState *ds, int w, int h, int rotation)
{
int flags;
@@ -64,7 +64,7 @@ static void sdl_resize(DisplayState *ds, int w, int h)
height = h;
again:
- screen = SDL_SetVideoMode(w, h, 0, flags);
+ screen = SDL_SetVideoMode(w, h, 16, flags);
if (!screen) {
fprintf(stderr, "Could not open SDL display\n");
exit(1);
@@ -350,7 +350,7 @@ static void sdl_send_mouse_event(int dz)
static void toggle_full_screen(DisplayState *ds)
{
gui_fullscreen = !gui_fullscreen;
- sdl_resize(ds, screen->w, screen->h);
+ sdl_resize(ds, screen->w, screen->h, 0);
if (gui_fullscreen) {
gui_saved_grab = gui_grab;
sdl_grab_start();
@@ -551,7 +551,8 @@ void sdl_display_init(DisplayState *ds, int full_screen)
ds->dpy_resize = sdl_resize;
ds->dpy_refresh = sdl_refresh;
- sdl_resize(ds, 640, 400);
+// sdl_resize(ds, 640, 400, 0);
+ sdl_resize(ds, 240, 320, 0);
sdl_update_caption();
SDL_EnableKeyRepeat(250, 50);
SDL_EnableUNICODE(1);
diff --git a/sh4-dis.c b/sh4-dis.c
deleted file mode 100644
index 5f45e5e..0000000
--- a/sh4-dis.c
+++ /dev/null
@@ -1,2096 +0,0 @@
-/* Disassemble SH instructions.
- Copyright 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003, 2004
- Free Software Foundation, Inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include <stdio.h>
-#include "dis-asm.h"
-
-#define DEFINE_TABLE
-
-typedef enum
- {
- HEX_0,
- HEX_1,
- HEX_2,
- HEX_3,
- HEX_4,
- HEX_5,
- HEX_6,
- HEX_7,
- HEX_8,
- HEX_9,
- HEX_A,
- HEX_B,
- HEX_C,
- HEX_D,
- HEX_E,
- HEX_F,
- HEX_XX00,
- HEX_00YY,
- REG_N,
- REG_N_D, /* nnn0 */
- REG_N_B01, /* nn01 */
- REG_M,
- SDT_REG_N,
- REG_NM,
- REG_B,
- BRANCH_12,
- BRANCH_8,
- IMM0_4,
- IMM0_4BY2,
- IMM0_4BY4,
- IMM1_4,
- IMM1_4BY2,
- IMM1_4BY4,
- PCRELIMM_8BY2,
- PCRELIMM_8BY4,
- IMM0_8,
- IMM0_8BY2,
- IMM0_8BY4,
- IMM1_8,
- IMM1_8BY2,
- IMM1_8BY4,
- PPI,
- NOPX,
- NOPY,
- MOVX,
- MOVY,
- MOVX_NOPY,
- MOVY_NOPX,
- PSH,
- PMUL,
- PPI3,
- PPI3NC,
- PDC,
- PPIC,
- REPEAT,
- IMM0_3c, /* xxxx 0iii */
- IMM0_3s, /* xxxx 1iii */
- IMM0_3Uc, /* 0iii xxxx */
- IMM0_3Us, /* 1iii xxxx */
- IMM0_20_4,
- IMM0_20, /* follows IMM0_20_4 */
- IMM0_20BY8, /* follows IMM0_20_4 */
- DISP0_12,
- DISP0_12BY2,
- DISP0_12BY4,
- DISP0_12BY8,
- DISP1_12,
- DISP1_12BY2,
- DISP1_12BY4,
- DISP1_12BY8
- }
-sh_nibble_type;
-
-typedef enum
- {
- A_END,
- A_BDISP12,
- A_BDISP8,
- A_DEC_M,
- A_DEC_N,
- A_DISP_GBR,
- A_PC,
- A_DISP_PC,
- A_DISP_PC_ABS,
- A_DISP_REG_M,
- A_DISP_REG_N,
- A_GBR,
- A_IMM,
- A_INC_M,
- A_INC_N,
- A_IND_M,
- A_IND_N,
- A_IND_R0_REG_M,
- A_IND_R0_REG_N,
- A_MACH,
- A_MACL,
- A_PR,
- A_R0,
- A_R0_GBR,
- A_REG_M,
- A_REG_N,
- A_REG_B,
- A_SR,
- A_VBR,
- A_TBR,
- A_DISP_TBR,
- A_DISP2_TBR,
- A_DEC_R15,
- A_INC_R15,
- A_MOD,
- A_RE,
- A_RS,
- A_DSR,
- DSP_REG_M,
- DSP_REG_N,
- DSP_REG_X,
- DSP_REG_Y,
- DSP_REG_E,
- DSP_REG_F,
- DSP_REG_G,
- DSP_REG_A_M,
- DSP_REG_AX,
- DSP_REG_XY,
- DSP_REG_AY,
- DSP_REG_YX,
- AX_INC_N,
- AY_INC_N,
- AXY_INC_N,
- AYX_INC_N,
- AX_IND_N,
- AY_IND_N,
- AXY_IND_N,
- AYX_IND_N,
- AX_PMOD_N,
- AXY_PMOD_N,
- AY_PMOD_N,
- AYX_PMOD_N,
- AS_DEC_N,
- AS_INC_N,
- AS_IND_N,
- AS_PMOD_N,
- A_A0,
- A_X0,
- A_X1,
- A_Y0,
- A_Y1,
- A_SSR,
- A_SPC,
- A_SGR,
- A_DBR,
- F_REG_N,
- F_REG_M,
- D_REG_N,
- D_REG_M,
- X_REG_N, /* Only used for argument parsing. */
- X_REG_M, /* Only used for argument parsing. */
- DX_REG_N,
- DX_REG_M,
- V_REG_N,
- V_REG_M,
- XMTRX_M4,
- F_FR0,
- FPUL_N,
- FPUL_M,
- FPSCR_N,
- FPSCR_M
- }
-sh_arg_type;
-
-typedef enum
- {
- A_A1_NUM = 5,
- A_A0_NUM = 7,
- A_X0_NUM, A_X1_NUM, A_Y0_NUM, A_Y1_NUM,
- A_M0_NUM, A_A1G_NUM, A_M1_NUM, A_A0G_NUM
- }
-sh_dsp_reg_nums;
-
-#define arch_sh1_base 0x0001
-#define arch_sh2_base 0x0002
-#define arch_sh3_base 0x0004
-#define arch_sh4_base 0x0008
-#define arch_sh4a_base 0x0010
-#define arch_sh2a_base 0x0020
-
-/* This is an annotation on instruction types, but we abuse the arch
- field in instructions to denote it. */
-#define arch_op32 0x00100000 /* This is a 32-bit opcode. */
-
-#define arch_sh_no_mmu 0x04000000
-#define arch_sh_has_mmu 0x08000000
-#define arch_sh_no_co 0x10000000 /* neither FPU nor DSP co-processor */
-#define arch_sh_sp_fpu 0x20000000 /* single precision FPU */
-#define arch_sh_dp_fpu 0x40000000 /* double precision FPU */
-#define arch_sh_has_dsp 0x80000000
-
-
-#define arch_sh_base_mask 0x0000003f
-#define arch_opann_mask 0x00100000
-#define arch_sh_mmu_mask 0x0c000000
-#define arch_sh_co_mask 0xf0000000
-
-
-#define arch_sh1 (arch_sh1_base|arch_sh_no_mmu|arch_sh_no_co)
-#define arch_sh2 (arch_sh2_base|arch_sh_no_mmu|arch_sh_no_co)
-#define arch_sh2a (arch_sh2a_base|arch_sh_no_mmu|arch_sh_dp_fpu)
-#define arch_sh2a_nofpu (arch_sh2a_base|arch_sh_no_mmu|arch_sh_no_co)
-#define arch_sh2e (arch_sh2_base|arch_sh2a_base|arch_sh_no_mmu|arch_sh_sp_fpu)
-#define arch_sh_dsp (arch_sh2_base|arch_sh_no_mmu|arch_sh_has_dsp)
-#define arch_sh3_nommu (arch_sh3_base|arch_sh_no_mmu|arch_sh_no_co)
-#define arch_sh3 (arch_sh3_base|arch_sh_has_mmu|arch_sh_no_co)
-#define arch_sh3e (arch_sh3_base|arch_sh_has_mmu|arch_sh_sp_fpu)
-#define arch_sh3_dsp (arch_sh3_base|arch_sh_has_mmu|arch_sh_has_dsp)
-#define arch_sh4 (arch_sh4_base|arch_sh_has_mmu|arch_sh_dp_fpu)
-#define arch_sh4a (arch_sh4a_base|arch_sh_has_mmu|arch_sh_dp_fpu)
-#define arch_sh4al_dsp (arch_sh4a_base|arch_sh_has_mmu|arch_sh_has_dsp)
-#define arch_sh4_nofpu (arch_sh4_base|arch_sh_has_mmu|arch_sh_no_co)
-#define arch_sh4a_nofpu (arch_sh4a_base|arch_sh_has_mmu|arch_sh_no_co)
-#define arch_sh4_nommu_nofpu (arch_sh4_base|arch_sh_no_mmu|arch_sh_no_co)
-
-#define SH_MERGE_ARCH_SET(SET1, SET2) ((SET1) & (SET2))
-#define SH_VALID_BASE_ARCH_SET(SET) (((SET) & arch_sh_base_mask) != 0)
-#define SH_VALID_MMU_ARCH_SET(SET) (((SET) & arch_sh_mmu_mask) != 0)
-#define SH_VALID_CO_ARCH_SET(SET) (((SET) & arch_sh_co_mask) != 0)
-#define SH_VALID_ARCH_SET(SET) \
- (SH_VALID_BASE_ARCH_SET (SET) \
- && SH_VALID_MMU_ARCH_SET (SET) \
- && SH_VALID_CO_ARCH_SET (SET))
-#define SH_MERGE_ARCH_SET_VALID(SET1, SET2) \
- SH_VALID_ARCH_SET (SH_MERGE_ARCH_SET (SET1, SET2))
-
-#define SH_ARCH_SET_HAS_FPU(SET) \
- (((SET) & (arch_sh_sp_fpu | arch_sh_dp_fpu)) != 0)
-#define SH_ARCH_SET_HAS_DSP(SET) \
- (((SET) & arch_sh_has_dsp) != 0)
-
-/* This is returned from the functions below when an error occurs
- (in addition to a call to BFD_FAIL). The value should allow
- the tools to continue to function in most cases - there may
- be some confusion between DSP and FPU etc. */
-#define SH_ARCH_UNKNOWN_ARCH 0xffffffff
-
-/* These are defined in bfd/cpu-sh.c . */
-unsigned int sh_get_arch_from_bfd_mach (unsigned long mach);
-unsigned int sh_get_arch_up_from_bfd_mach (unsigned long mach);
-unsigned long sh_get_bfd_mach_from_arch_set (unsigned int arch_set);
-/* bfd_boolean sh_merge_bfd_arch (bfd *ibfd, bfd *obfd); */
-
-/* Below are the 'architecture sets'.
- They describe the following inheritance graph:
-
- SH1
- |
- SH2
- .------------'|`--------------------.
- / | \
-SH-DSP SH3-nommu SH2E
- | |`--------. |
- | | \ |
- | SH3 SH4-nommu-nofpu |
- | | | |
- | .------------'|`----------+---------. |
- |/ / \|
- | | .-------' |
- | |/ |
-SH3-dsp SH4-nofpu SH3E
- | |`--------------------. |
- | | \|
- | SH4A-nofpu SH4
- | .------------' `--------------------. |
- |/ \|
-SH4AL-dsp SH4A
-
-*/
-
-/* Central branches */
-#define arch_sh1_up (arch_sh1 | arch_sh2_up)
-#define arch_sh2_up (arch_sh2 | arch_sh2e_up | arch_sh2a_nofpu_up | arch_sh3_nommu_up | arch_sh_dsp_up)
-#define arch_sh3_nommu_up (arch_sh3_nommu | arch_sh3_up | arch_sh4_nommu_nofpu_up)
-#define arch_sh3_up (arch_sh3 | arch_sh3e_up | arch_sh3_dsp_up | arch_sh4_nofp_up)
-#define arch_sh4_nommu_nofpu_up (arch_sh4_nommu_nofpu | arch_sh4_nofp_up)
-#define arch_sh4_nofp_up (arch_sh4_nofpu | arch_sh4_up | arch_sh4a_nofp_up)
-#define arch_sh4a_nofp_up (arch_sh4a_nofpu | arch_sh4a_up | arch_sh4al_dsp_up)
-
-/* Right branch */
-#define arch_sh2e_up (arch_sh2e | arch_sh2a_up | arch_sh3e_up)
-#define arch_sh3e_up (arch_sh3e | arch_sh4_up)
-#define arch_sh4_up (arch_sh4 | arch_sh4a_up)
-#define arch_sh4a_up (arch_sh4a)
-
-/* Left branch */
-#define arch_sh_dsp_up (arch_sh_dsp | arch_sh3_dsp_up)
-#define arch_sh3_dsp_up (arch_sh3_dsp | arch_sh4al_dsp_up)
-#define arch_sh4al_dsp_up (arch_sh4al_dsp)
-
-/* SH 2a branched off SH2e, adding a lot but not all of SH4 and SH4a. */
-#define arch_sh2a_up (arch_sh2a)
-#define arch_sh2a_nofpu_up (arch_sh2a_nofpu | arch_sh2a_up)
-
-
-typedef struct
-{
- char *name;
- sh_arg_type arg[4];
- sh_nibble_type nibbles[9];
- unsigned int arch;
-} sh_opcode_info;
-
-#ifdef DEFINE_TABLE
-
-const sh_opcode_info sh_table[] =
- {
-/* 0111nnnni8*1.... add #<imm>,<REG_N> */{"add",{A_IMM,A_REG_N},{HEX_7,REG_N,IMM0_8}, arch_sh1_up},
-
-/* 0011nnnnmmmm1100 add <REG_M>,<REG_N> */{"add",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_C}, arch_sh1_up},
-
-/* 0011nnnnmmmm1110 addc <REG_M>,<REG_N>*/{"addc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_E}, arch_sh1_up},
-
-/* 0011nnnnmmmm1111 addv <REG_M>,<REG_N>*/{"addv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_F}, arch_sh1_up},
-
-/* 11001001i8*1.... and #<imm>,R0 */{"and",{A_IMM,A_R0},{HEX_C,HEX_9,IMM0_8}, arch_sh1_up},
-
-/* 0010nnnnmmmm1001 and <REG_M>,<REG_N> */{"and",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_9}, arch_sh1_up},
-
-/* 11001101i8*1.... and.b #<imm>,@(R0,GBR)*/{"and.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_D,IMM0_8}, arch_sh1_up},
-
-/* 1010i12......... bra <bdisp12> */{"bra",{A_BDISP12},{HEX_A,BRANCH_12}, arch_sh1_up},
-
-/* 1011i12......... bsr <bdisp12> */{"bsr",{A_BDISP12},{HEX_B,BRANCH_12}, arch_sh1_up},
-
-/* 10001001i8p1.... bt <bdisp8> */{"bt",{A_BDISP8},{HEX_8,HEX_9,BRANCH_8}, arch_sh1_up},
-
-/* 10001011i8p1.... bf <bdisp8> */{"bf",{A_BDISP8},{HEX_8,HEX_B,BRANCH_8}, arch_sh1_up},
-
-/* 10001101i8p1.... bt.s <bdisp8> */{"bt.s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}, arch_sh2_up},
-
-/* 10001101i8p1.... bt/s <bdisp8> */{"bt/s",{A_BDISP8},{HEX_8,HEX_D,BRANCH_8}, arch_sh2_up},
-
-/* 10001111i8p1.... bf.s <bdisp8> */{"bf.s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}, arch_sh2_up},
-
-/* 10001111i8p1.... bf/s <bdisp8> */{"bf/s",{A_BDISP8},{HEX_8,HEX_F,BRANCH_8}, arch_sh2_up},
-
-/* 0000000010001000 clrdmxy */{"clrdmxy",{0},{HEX_0,HEX_0,HEX_8,HEX_8}, arch_sh4al_dsp_up},
-
-/* 0000000000101000 clrmac */{"clrmac",{0},{HEX_0,HEX_0,HEX_2,HEX_8}, arch_sh1_up},
-
-/* 0000000001001000 clrs */{"clrs",{0},{HEX_0,HEX_0,HEX_4,HEX_8}, arch_sh1_up},
-
-/* 0000000000001000 clrt */{"clrt",{0},{HEX_0,HEX_0,HEX_0,HEX_8}, arch_sh1_up},
-
-/* 10001000i8*1.... cmp/eq #<imm>,R0 */{"cmp/eq",{A_IMM,A_R0},{HEX_8,HEX_8,IMM0_8}, arch_sh1_up},
-
-/* 0011nnnnmmmm0000 cmp/eq <REG_M>,<REG_N>*/{"cmp/eq",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_0}, arch_sh1_up},
-
-/* 0011nnnnmmmm0011 cmp/ge <REG_M>,<REG_N>*/{"cmp/ge",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_3}, arch_sh1_up},
-
-/* 0011nnnnmmmm0111 cmp/gt <REG_M>,<REG_N>*/{"cmp/gt",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_7}, arch_sh1_up},
-
-/* 0011nnnnmmmm0110 cmp/hi <REG_M>,<REG_N>*/{"cmp/hi",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_6}, arch_sh1_up},
-
-/* 0011nnnnmmmm0010 cmp/hs <REG_M>,<REG_N>*/{"cmp/hs",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_2}, arch_sh1_up},
-
-/* 0100nnnn00010101 cmp/pl <REG_N> */{"cmp/pl",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_5}, arch_sh1_up},
-
-/* 0100nnnn00010001 cmp/pz <REG_N> */{"cmp/pz",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_1}, arch_sh1_up},
-
-/* 0010nnnnmmmm1100 cmp/str <REG_M>,<REG_N>*/{"cmp/str",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_C}, arch_sh1_up},
-
-/* 0010nnnnmmmm0111 div0s <REG_M>,<REG_N>*/{"div0s",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_7}, arch_sh1_up},
-
-/* 0000000000011001 div0u */{"div0u",{0},{HEX_0,HEX_0,HEX_1,HEX_9}, arch_sh1_up},
-
-/* 0011nnnnmmmm0100 div1 <REG_M>,<REG_N>*/{"div1",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_4}, arch_sh1_up},
-
-/* 0110nnnnmmmm1110 exts.b <REG_M>,<REG_N>*/{"exts.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_E}, arch_sh1_up},
-
-/* 0110nnnnmmmm1111 exts.w <REG_M>,<REG_N>*/{"exts.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_F}, arch_sh1_up},
-
-/* 0110nnnnmmmm1100 extu.b <REG_M>,<REG_N>*/{"extu.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_C}, arch_sh1_up},
-
-/* 0110nnnnmmmm1101 extu.w <REG_M>,<REG_N>*/{"extu.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_D}, arch_sh1_up},
-
-/* 0000nnnn11100011 icbi @<REG_N> */{"icbi",{A_IND_N},{HEX_0,REG_N,HEX_E,HEX_3}, arch_sh4a_nofp_up},
-
-/* 0100nnnn00101011 jmp @<REG_N> */{"jmp",{A_IND_N},{HEX_4,REG_N,HEX_2,HEX_B}, arch_sh1_up},
-
-/* 0100nnnn00001011 jsr @<REG_N> */{"jsr",{A_IND_N},{HEX_4,REG_N,HEX_0,HEX_B}, arch_sh1_up},
-
-/* 0100nnnn00001110 ldc <REG_N>,SR */{"ldc",{A_REG_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_E}, arch_sh1_up},
-
-/* 0100nnnn00011110 ldc <REG_N>,GBR */{"ldc",{A_REG_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_E}, arch_sh1_up},
-
-/* 0100nnnn00111010 ldc <REG_N>,SGR */{"ldc",{A_REG_N,A_SGR},{HEX_4,REG_N,HEX_3,HEX_A}, arch_sh4_nommu_nofpu_up},
-
-/* 0100mmmm01001010 ldc <REG_M>,TBR */{"ldc",{A_REG_M,A_TBR},{HEX_4,REG_M,HEX_4,HEX_A}, arch_sh2a_nofpu_up},
-
-/* 0100nnnn00101110 ldc <REG_N>,VBR */{"ldc",{A_REG_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_E}, arch_sh1_up},
-
-/* 0100nnnn01011110 ldc <REG_N>,MOD */{"ldc",{A_REG_N,A_MOD},{HEX_4,REG_N,HEX_5,HEX_E}, arch_sh_dsp_up},
-
-/* 0100nnnn01111110 ldc <REG_N>,RE */{"ldc",{A_REG_N,A_RE},{HEX_4,REG_N,HEX_7,HEX_E}, arch_sh_dsp_up},
-
-/* 0100nnnn01101110 ldc <REG_N>,RS */{"ldc",{A_REG_N,A_RS},{HEX_4,REG_N,HEX_6,HEX_E}, arch_sh_dsp_up},
-
-/* 0100nnnn00111110 ldc <REG_N>,SSR */{"ldc",{A_REG_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_E}, arch_sh3_nommu_up},
-
-/* 0100nnnn01001110 ldc <REG_N>,SPC */{"ldc",{A_REG_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_E}, arch_sh3_nommu_up},
-
-/* 0100nnnn11111010 ldc <REG_N>,DBR */{"ldc",{A_REG_N,A_DBR},{HEX_4,REG_N,HEX_F,HEX_A}, arch_sh4_nommu_nofpu_up},
-
-/* 0100nnnn1xxx1110 ldc <REG_N>,Rn_BANK */{"ldc",{A_REG_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_E}, arch_sh3_nommu_up},
-
-/* 0100nnnn00000111 ldc.l @<REG_N>+,SR */{"ldc.l",{A_INC_N,A_SR},{HEX_4,REG_N,HEX_0,HEX_7}, arch_sh1_up},
-
-/* 0100nnnn00010111 ldc.l @<REG_N>+,GBR */{"ldc.l",{A_INC_N,A_GBR},{HEX_4,REG_N,HEX_1,HEX_7}, arch_sh1_up},
-
-/* 0100nnnn00100111 ldc.l @<REG_N>+,VBR */{"ldc.l",{A_INC_N,A_VBR},{HEX_4,REG_N,HEX_2,HEX_7}, arch_sh1_up},
-
-/* 0100nnnn00110110 ldc.l @<REG_N>+,SGR */{"ldc.l",{A_INC_N,A_SGR},{HEX_4,REG_N,HEX_3,HEX_6}, arch_sh4_nommu_nofpu_up},
-
-/* 0100nnnn01010111 ldc.l @<REG_N>+,MOD */{"ldc.l",{A_INC_N,A_MOD},{HEX_4,REG_N,HEX_5,HEX_7}, arch_sh_dsp_up},
-
-/* 0100nnnn01110111 ldc.l @<REG_N>+,RE */{"ldc.l",{A_INC_N,A_RE},{HEX_4,REG_N,HEX_7,HEX_7}, arch_sh_dsp_up},
-
-/* 0100nnnn01100111 ldc.l @<REG_N>+,RS */{"ldc.l",{A_INC_N,A_RS},{HEX_4,REG_N,HEX_6,HEX_7}, arch_sh_dsp_up},
-
-/* 0100nnnn00110111 ldc.l @<REG_N>+,SSR */{"ldc.l",{A_INC_N,A_SSR},{HEX_4,REG_N,HEX_3,HEX_7}, arch_sh3_nommu_up},
-
-/* 0100nnnn01000111 ldc.l @<REG_N>+,SPC */{"ldc.l",{A_INC_N,A_SPC},{HEX_4,REG_N,HEX_4,HEX_7}, arch_sh3_nommu_up},
-
-/* 0100nnnn11110110 ldc.l @<REG_N>+,DBR */{"ldc.l",{A_INC_N,A_DBR},{HEX_4,REG_N,HEX_F,HEX_6}, arch_sh4_nommu_nofpu_up},
-
-/* 0100nnnn1xxx0111 ldc.l <REG_N>,Rn_BANK */{"ldc.l",{A_INC_N,A_REG_B},{HEX_4,REG_N,REG_B,HEX_7}, arch_sh3_nommu_up},
-
-/* 0100mmmm00110100 ldrc <REG_M> */{"ldrc",{A_REG_M},{HEX_4,REG_M,HEX_3,HEX_4}, arch_sh4al_dsp_up},
-/* 10001010i8*1.... ldrc #<imm> */{"ldrc",{A_IMM},{HEX_8,HEX_A,IMM0_8}, arch_sh4al_dsp_up},
-
-/* 10001110i8p2.... ldre @(<disp>,PC) */{"ldre",{A_DISP_PC},{HEX_8,HEX_E,PCRELIMM_8BY2}, arch_sh_dsp_up},
-
-/* 10001100i8p2.... ldrs @(<disp>,PC) */{"ldrs",{A_DISP_PC},{HEX_8,HEX_C,PCRELIMM_8BY2}, arch_sh_dsp_up},
-
-/* 0100nnnn00001010 lds <REG_N>,MACH */{"lds",{A_REG_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_A}, arch_sh1_up},
-
-/* 0100nnnn00011010 lds <REG_N>,MACL */{"lds",{A_REG_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_A}, arch_sh1_up},
-
-/* 0100nnnn00101010 lds <REG_N>,PR */{"lds",{A_REG_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_A}, arch_sh1_up},
-
-/* 0100nnnn01101010 lds <REG_N>,DSR */{"lds",{A_REG_N,A_DSR},{HEX_4,REG_N,HEX_6,HEX_A}, arch_sh_dsp_up},
-
-/* 0100nnnn01111010 lds <REG_N>,A0 */{"lds",{A_REG_N,A_A0},{HEX_4,REG_N,HEX_7,HEX_A}, arch_sh_dsp_up},
-
-/* 0100nnnn10001010 lds <REG_N>,X0 */{"lds",{A_REG_N,A_X0},{HEX_4,REG_N,HEX_8,HEX_A}, arch_sh_dsp_up},
-
-/* 0100nnnn10011010 lds <REG_N>,X1 */{"lds",{A_REG_N,A_X1},{HEX_4,REG_N,HEX_9,HEX_A}, arch_sh_dsp_up},
-
-/* 0100nnnn10101010 lds <REG_N>,Y0 */{"lds",{A_REG_N,A_Y0},{HEX_4,REG_N,HEX_A,HEX_A}, arch_sh_dsp_up},
-
-/* 0100nnnn10111010 lds <REG_N>,Y1 */{"lds",{A_REG_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up},
-
-/* 0100nnnn01011010 lds <REG_N>,FPUL */{"lds",{A_REG_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_A}, arch_sh2e_up},
-
-/* 0100nnnn01101010 lds <REG_M>,FPSCR */{"lds",{A_REG_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_A}, arch_sh2e_up},
-
-/* 0100nnnn00000110 lds.l @<REG_N>+,MACH*/{"lds.l",{A_INC_N,A_MACH},{HEX_4,REG_N,HEX_0,HEX_6}, arch_sh1_up},
-
-/* 0100nnnn00010110 lds.l @<REG_N>+,MACL*/{"lds.l",{A_INC_N,A_MACL},{HEX_4,REG_N,HEX_1,HEX_6}, arch_sh1_up},
-
-/* 0100nnnn00100110 lds.l @<REG_N>+,PR */{"lds.l",{A_INC_N,A_PR},{HEX_4,REG_N,HEX_2,HEX_6}, arch_sh1_up},
-
-/* 0100nnnn01100110 lds.l @<REG_N>+,DSR */{"lds.l",{A_INC_N,A_DSR},{HEX_4,REG_N,HEX_6,HEX_6}, arch_sh_dsp_up},
-
-/* 0100nnnn01110110 lds.l @<REG_N>+,A0 */{"lds.l",{A_INC_N,A_A0},{HEX_4,REG_N,HEX_7,HEX_6}, arch_sh_dsp_up},
-
-/* 0100nnnn10000110 lds.l @<REG_N>+,X0 */{"lds.l",{A_INC_N,A_X0},{HEX_4,REG_N,HEX_8,HEX_6}, arch_sh_dsp_up},
-
-/* 0100nnnn10010110 lds.l @<REG_N>+,X1 */{"lds.l",{A_INC_N,A_X1},{HEX_4,REG_N,HEX_9,HEX_6}, arch_sh_dsp_up},
-
-/* 0100nnnn10100110 lds.l @<REG_N>+,Y0 */{"lds.l",{A_INC_N,A_Y0},{HEX_4,REG_N,HEX_A,HEX_6}, arch_sh_dsp_up},
-
-/* 0100nnnn10110110 lds.l @<REG_N>+,Y1 */{"lds.l",{A_INC_N,A_Y1},{HEX_4,REG_N,HEX_B,HEX_6}, arch_sh_dsp_up},
-
-/* 0100nnnn01010110 lds.l @<REG_M>+,FPUL*/{"lds.l",{A_INC_M,FPUL_N},{HEX_4,REG_M,HEX_5,HEX_6}, arch_sh2e_up},
-
-/* 0100nnnn01100110 lds.l @<REG_M>+,FPSCR*/{"lds.l",{A_INC_M,FPSCR_N},{HEX_4,REG_M,HEX_6,HEX_6}, arch_sh2e_up},
-
-/* 0000000000111000 ldtlb */{"ldtlb",{0},{HEX_0,HEX_0,HEX_3,HEX_8}, arch_sh3_up},
-
-/* 0100nnnnmmmm1111 mac.w @<REG_M>+,@<REG_N>+*/{"mac.w",{A_INC_M,A_INC_N},{HEX_4,REG_N,REG_M,HEX_F}, arch_sh1_up},
-
-/* 1110nnnni8*1.... mov #<imm>,<REG_N> */{"mov",{A_IMM,A_REG_N},{HEX_E,REG_N,IMM0_8}, arch_sh1_up},
-
-/* 0110nnnnmmmm0011 mov <REG_M>,<REG_N> */{"mov",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_3}, arch_sh1_up},
-
-/* 0000nnnnmmmm0100 mov.b <REG_M>,@(R0,<REG_N>)*/{"mov.b",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_4}, arch_sh1_up},
-
-/* 0010nnnnmmmm0100 mov.b <REG_M>,@-<REG_N>*/{"mov.b",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_4}, arch_sh1_up},
-
-/* 0010nnnnmmmm0000 mov.b <REG_M>,@<REG_N>*/{"mov.b",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_0}, arch_sh1_up},
-
-/* 10000100mmmmi4*1 mov.b @(<disp>,<REG_M>),R0*/{"mov.b",{A_DISP_REG_M,A_R0},{HEX_8,HEX_4,REG_M,IMM0_4}, arch_sh1_up},
-
-/* 11000100i8*1.... mov.b @(<disp>,GBR),R0*/{"mov.b",{A_DISP_GBR,A_R0},{HEX_C,HEX_4,IMM0_8}, arch_sh1_up},
-
-/* 0000nnnnmmmm1100 mov.b @(R0,<REG_M>),<REG_N>*/{"mov.b",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_C}, arch_sh1_up},
-
-/* 0110nnnnmmmm0100 mov.b @<REG_M>+,<REG_N>*/{"mov.b",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_4}, arch_sh1_up},
-
-/* 0110nnnnmmmm0000 mov.b @<REG_M>,<REG_N>*/{"mov.b",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_0}, arch_sh1_up},
-
-/* 10000000mmmmi4*1 mov.b R0,@(<disp>,<REG_M>)*/{"mov.b",{A_R0,A_DISP_REG_M},{HEX_8,HEX_0,REG_M,IMM1_4}, arch_sh1_up},
-
-/* 11000000i8*1.... mov.b R0,@(<disp>,GBR)*/{"mov.b",{A_R0,A_DISP_GBR},{HEX_C,HEX_0,IMM1_8}, arch_sh1_up},
-
-/* 0100nnnn10001011 mov.b R0,@<REG_N>+ */{"mov.b",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_8,HEX_B}, arch_sh2a_nofpu_up},
-/* 0100nnnn11001011 mov.b @-<REG_M>,R0 */{"mov.b",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_C,HEX_B}, arch_sh2a_nofpu_up},
-/* 0011nnnnmmmm0001 0000dddddddddddd mov.b <REG_M>,@(<DISP12>,<REG_N>) */
-{"mov.b",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_0,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
-/* 0011nnnnmmmm0001 0100dddddddddddd mov.b @(<DISP12>,<REG_M>),<REG_N> */
-{"mov.b",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_4,DISP0_12}, arch_sh2a_nofpu_up | arch_op32},
-/* 0001nnnnmmmmi4*4 mov.l <REG_M>,@(<disp>,<REG_N>)*/{"mov.l",{ A_REG_M,A_DISP_REG_N},{HEX_1,REG_N,REG_M,IMM1_4BY4}, arch_sh1_up},
-
-/* 0000nnnnmmmm0110 mov.l <REG_M>,@(R0,<REG_N>)*/{"mov.l",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_6}, arch_sh1_up},
-
-/* 0010nnnnmmmm0110 mov.l <REG_M>,@-<REG_N>*/{"mov.l",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_6}, arch_sh1_up},
-
-/* 0010nnnnmmmm0010 mov.l <REG_M>,@<REG_N>*/{"mov.l",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_2}, arch_sh1_up},
-
-/* 0101nnnnmmmmi4*4 mov.l @(<disp>,<REG_M>),<REG_N>*/{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_5,REG_N,REG_M,IMM0_4BY4}, arch_sh1_up},
-
-/* 11000110i8*4.... mov.l @(<disp>,GBR),R0*/{"mov.l",{A_DISP_GBR,A_R0},{HEX_C,HEX_6,IMM0_8BY4}, arch_sh1_up},
-
-/* 1101nnnni8p4.... mov.l @(<disp>,PC),<REG_N>*/{"mov.l",{A_DISP_PC,A_REG_N},{HEX_D,REG_N,PCRELIMM_8BY4}, arch_sh1_up},
-
-/* 0000nnnnmmmm1110 mov.l @(R0,<REG_M>),<REG_N>*/{"mov.l",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_E}, arch_sh1_up},
-
-/* 0110nnnnmmmm0110 mov.l @<REG_M>+,<REG_N>*/{"mov.l",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_6}, arch_sh1_up},
-
-/* 0110nnnnmmmm0010 mov.l @<REG_M>,<REG_N>*/{"mov.l",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_2}, arch_sh1_up},
-
-/* 11000010i8*4.... mov.l R0,@(<disp>,GBR)*/{"mov.l",{A_R0,A_DISP_GBR},{HEX_C,HEX_2,IMM1_8BY4}, arch_sh1_up},
-
-/* 0100nnnn10101011 mov.l R0,@<REG_N>+ */{"mov.l",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_A,HEX_B}, arch_sh2a_nofpu_up},
-/* 0100nnnn11001011 mov.l @-<REG_M>,R0 */{"mov.l",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_B}, arch_sh2a_nofpu_up},
-/* 0011nnnnmmmm0001 0010dddddddddddd mov.l <REG_M>,@(<DISP12>,<REG_N>) */
-{"mov.l",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_2,DISP1_12BY4}, arch_sh2a_nofpu_up | arch_op32},
-/* 0011nnnnmmmm0001 0110dddddddddddd mov.l @(<DISP12>,<REG_M>),<REG_N> */
-{"mov.l",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_6,DISP0_12BY4}, arch_sh2a_nofpu_up | arch_op32},
-/* 0000nnnnmmmm0101 mov.w <REG_M>,@(R0,<REG_N>)*/{"mov.w",{ A_REG_M,A_IND_R0_REG_N},{HEX_0,REG_N,REG_M,HEX_5}, arch_sh1_up},
-
-/* 0010nnnnmmmm0101 mov.w <REG_M>,@-<REG_N>*/{"mov.w",{ A_REG_M,A_DEC_N},{HEX_2,REG_N,REG_M,HEX_5}, arch_sh1_up},
-
-/* 0010nnnnmmmm0001 mov.w <REG_M>,@<REG_N>*/{"mov.w",{ A_REG_M,A_IND_N},{HEX_2,REG_N,REG_M,HEX_1}, arch_sh1_up},
-
-/* 10000101mmmmi4*2 mov.w @(<disp>,<REG_M>),R0*/{"mov.w",{A_DISP_REG_M,A_R0},{HEX_8,HEX_5,REG_M,IMM0_4BY2}, arch_sh1_up},
-
-/* 11000101i8*2.... mov.w @(<disp>,GBR),R0*/{"mov.w",{A_DISP_GBR,A_R0},{HEX_C,HEX_5,IMM0_8BY2}, arch_sh1_up},
-
-/* 1001nnnni8p2.... mov.w @(<disp>,PC),<REG_N>*/{"mov.w",{A_DISP_PC,A_REG_N},{HEX_9,REG_N,PCRELIMM_8BY2}, arch_sh1_up},
-
-/* 0000nnnnmmmm1101 mov.w @(R0,<REG_M>),<REG_N>*/{"mov.w",{A_IND_R0_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_D}, arch_sh1_up},
-
-/* 0110nnnnmmmm0101 mov.w @<REG_M>+,<REG_N>*/{"mov.w",{A_INC_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_5}, arch_sh1_up},
-
-/* 0110nnnnmmmm0001 mov.w @<REG_M>,<REG_N>*/{"mov.w",{A_IND_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_1}, arch_sh1_up},
-
-/* 10000001mmmmi4*2 mov.w R0,@(<disp>,<REG_M>)*/{"mov.w",{A_R0,A_DISP_REG_M},{HEX_8,HEX_1,REG_M,IMM1_4BY2}, arch_sh1_up},
-
-/* 11000001i8*2.... mov.w R0,@(<disp>,GBR)*/{"mov.w",{A_R0,A_DISP_GBR},{HEX_C,HEX_1,IMM1_8BY2}, arch_sh1_up},
-
-/* 0100nnnn10011011 mov.w R0,@<REG_N>+ */{"mov.w",{A_R0,A_INC_N},{HEX_4,REG_N,HEX_9,HEX_B}, arch_sh2a_nofpu_up},
-/* 0100nnnn11011011 mov.w @-<REG_M>,R0 */{"mov.w",{A_DEC_M,A_R0},{HEX_4,REG_M,HEX_D,HEX_B}, arch_sh2a_nofpu_up},
-/* 0011nnnnmmmm0001 0001dddddddddddd mov.w <REG_M>,@(<DISP12>,<REG_N>) */
-{"mov.w",{A_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_1,DISP1_12BY2}, arch_sh2a_nofpu_up | arch_op32},
-/* 0011nnnnmmmm0001 0101dddddddddddd mov.w @(<DISP12>,<REG_M>),<REG_N> */
-{"mov.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_5,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32},
-/* 11000111i8p4.... mova @(<disp>,PC),R0*/{"mova",{A_DISP_PC,A_R0},{HEX_C,HEX_7,PCRELIMM_8BY4}, arch_sh1_up},
-/* 0000nnnn11000011 movca.l R0,@<REG_N> */{"movca.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_C,HEX_3}, arch_sh4_nommu_nofpu_up},
-
-/* 0000nnnn01110011 movco.l r0,@<REG_N> */{"movco.l",{A_R0,A_IND_N},{HEX_0,REG_N,HEX_7,HEX_3}, arch_sh4a_nofp_up},
-/* 0000mmmm01100011 movli.l @<REG_M>,r0 */{"movli.l",{A_IND_M,A_R0},{HEX_0,REG_M,HEX_6,HEX_3}, arch_sh4a_nofp_up},
-
-/* 0000nnnn00101001 movt <REG_N> */{"movt",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_9}, arch_sh1_up},
-
-/* 0100mmmm10101001 movua.l @<REG_M>,r0 */{"movua.l",{A_IND_M,A_R0},{HEX_4,REG_M,HEX_A,HEX_9}, arch_sh4a_nofp_up},
-/* 0100mmmm11101001 movua.l @<REG_M>+,r0 */{"movua.l",{A_INC_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_9}, arch_sh4a_nofp_up},
-
-/* 0010nnnnmmmm1111 muls.w <REG_M>,<REG_N>*/{"muls.w",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}, arch_sh1_up},
-/* 0010nnnnmmmm1111 muls <REG_M>,<REG_N>*/{"muls",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_F}, arch_sh1_up},
-
-/* 0000nnnnmmmm0111 mul.l <REG_M>,<REG_N>*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}, arch_sh2_up},
-
-/* 0010nnnnmmmm1110 mulu.w <REG_M>,<REG_N>*/{"mulu.w",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}, arch_sh1_up},
-/* 0010nnnnmmmm1110 mulu <REG_M>,<REG_N>*/{"mulu",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_E}, arch_sh1_up},
-
-/* 0110nnnnmmmm1011 neg <REG_M>,<REG_N> */{"neg",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_B}, arch_sh1_up},
-
-/* 0110nnnnmmmm1010 negc <REG_M>,<REG_N>*/{"negc",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_A}, arch_sh1_up},
-
-/* 0000000000001001 nop */{"nop",{0},{HEX_0,HEX_0,HEX_0,HEX_9}, arch_sh1_up},
-
-/* 0110nnnnmmmm0111 not <REG_M>,<REG_N> */{"not",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_7}, arch_sh1_up},
-/* 0000nnnn10010011 ocbi @<REG_N> */{"ocbi",{A_IND_N},{HEX_0,REG_N,HEX_9,HEX_3}, arch_sh4_nommu_nofpu_up},
-
-/* 0000nnnn10100011 ocbp @<REG_N> */{"ocbp",{A_IND_N},{HEX_0,REG_N,HEX_A,HEX_3}, arch_sh4_nommu_nofpu_up},
-
-/* 0000nnnn10110011 ocbwb @<REG_N> */{"ocbwb",{A_IND_N},{HEX_0,REG_N,HEX_B,HEX_3}, arch_sh4_nommu_nofpu_up},
-
-
-/* 11001011i8*1.... or #<imm>,R0 */{"or",{A_IMM,A_R0},{HEX_C,HEX_B,IMM0_8}, arch_sh1_up},
-
-/* 0010nnnnmmmm1011 or <REG_M>,<REG_N> */{"or",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_B}, arch_sh1_up},
-
-/* 11001111i8*1.... or.b #<imm>,@(R0,GBR)*/{"or.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_F,IMM0_8}, arch_sh1_up},
-
-/* 0000nnnn10000011 pref @<REG_N> */{"pref",{A_IND_N},{HEX_0,REG_N,HEX_8,HEX_3}, arch_sh4_nommu_nofpu_up | arch_sh2a_nofpu_up},
-
-/* 0000nnnn11010011 prefi @<REG_N> */{"prefi",{A_IND_N},{HEX_0,REG_N,HEX_D,HEX_3}, arch_sh4a_nofp_up},
-
-/* 0100nnnn00100100 rotcl <REG_N> */{"rotcl",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_4}, arch_sh1_up},
-
-/* 0100nnnn00100101 rotcr <REG_N> */{"rotcr",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_5}, arch_sh1_up},
-
-/* 0100nnnn00000100 rotl <REG_N> */{"rotl",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_4}, arch_sh1_up},
-
-/* 0100nnnn00000101 rotr <REG_N> */{"rotr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_5}, arch_sh1_up},
-
-/* 0000000000101011 rte */{"rte",{0},{HEX_0,HEX_0,HEX_2,HEX_B}, arch_sh1_up},
-
-/* 0000000000001011 rts */{"rts",{0},{HEX_0,HEX_0,HEX_0,HEX_B}, arch_sh1_up},
-
-/* 0000000010011000 setdmx */{"setdmx",{0},{HEX_0,HEX_0,HEX_9,HEX_8}, arch_sh4al_dsp_up},
-/* 0000000011001000 setdmy */{"setdmy",{0},{HEX_0,HEX_0,HEX_C,HEX_8}, arch_sh4al_dsp_up},
-
-/* 0000000001011000 sets */{"sets",{0},{HEX_0,HEX_0,HEX_5,HEX_8}, arch_sh1_up},
-/* 0000000000011000 sett */{"sett",{0},{HEX_0,HEX_0,HEX_1,HEX_8}, arch_sh1_up},
-
-/* 0100nnnn00010100 setrc <REG_N> */{"setrc",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_4}, arch_sh_dsp_up},
-
-/* 10000010i8*1.... setrc #<imm> */{"setrc",{A_IMM},{HEX_8,HEX_2,IMM0_8}, arch_sh_dsp_up},
-
-/* repeat start end <REG_N> */{"repeat",{A_DISP_PC,A_DISP_PC,A_REG_N},{REPEAT,REG_N,HEX_1,HEX_4}, arch_sh_dsp_up},
-
-/* repeat start end #<imm> */{"repeat",{A_DISP_PC,A_DISP_PC,A_IMM},{REPEAT,HEX_2,IMM0_8,HEX_8}, arch_sh_dsp_up},
-
-/* 0100nnnnmmmm1100 shad <REG_M>,<REG_N>*/{"shad",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_C}, arch_sh3_nommu_up | arch_sh2a_nofpu_up},
-
-/* 0100nnnnmmmm1101 shld <REG_M>,<REG_N>*/{"shld",{ A_REG_M,A_REG_N},{HEX_4,REG_N,REG_M,HEX_D}, arch_sh3_nommu_up | arch_sh2a_nofpu_up},
-
-/* 0100nnnn00100000 shal <REG_N> */{"shal",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_0}, arch_sh1_up},
-
-/* 0100nnnn00100001 shar <REG_N> */{"shar",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_1}, arch_sh1_up},
-
-/* 0100nnnn00000000 shll <REG_N> */{"shll",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_0}, arch_sh1_up},
-
-/* 0100nnnn00101000 shll16 <REG_N> */{"shll16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_8}, arch_sh1_up},
-
-/* 0100nnnn00001000 shll2 <REG_N> */{"shll2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_8}, arch_sh1_up},
-
-/* 0100nnnn00011000 shll8 <REG_N> */{"shll8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_8}, arch_sh1_up},
-
-/* 0100nnnn00000001 shlr <REG_N> */{"shlr",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_1}, arch_sh1_up},
-
-/* 0100nnnn00101001 shlr16 <REG_N> */{"shlr16",{A_REG_N},{HEX_4,REG_N,HEX_2,HEX_9}, arch_sh1_up},
-
-/* 0100nnnn00001001 shlr2 <REG_N> */{"shlr2",{A_REG_N},{HEX_4,REG_N,HEX_0,HEX_9}, arch_sh1_up},
-
-/* 0100nnnn00011001 shlr8 <REG_N> */{"shlr8",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_9}, arch_sh1_up},
-
-/* 0000000000011011 sleep */{"sleep",{0},{HEX_0,HEX_0,HEX_1,HEX_B}, arch_sh1_up},
-
-/* 0000nnnn00000010 stc SR,<REG_N> */{"stc",{A_SR,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_2}, arch_sh1_up},
-
-/* 0000nnnn00010010 stc GBR,<REG_N> */{"stc",{A_GBR,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_2}, arch_sh1_up},
-
-/* 0000nnnn00100010 stc VBR,<REG_N> */{"stc",{A_VBR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_2}, arch_sh1_up},
-
-/* 0000nnnn01010010 stc MOD,<REG_N> */{"stc",{A_MOD,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_2}, arch_sh_dsp_up},
-
-/* 0000nnnn01110010 stc RE,<REG_N> */{"stc",{A_RE,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_2}, arch_sh_dsp_up},
-
-/* 0000nnnn01100010 stc RS,<REG_N> */{"stc",{A_RS,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_2}, arch_sh_dsp_up},
-
-/* 0000nnnn00110010 stc SSR,<REG_N> */{"stc",{A_SSR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_2}, arch_sh3_nommu_up},
-
-/* 0000nnnn01000010 stc SPC,<REG_N> */{"stc",{A_SPC,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_2}, arch_sh3_nommu_up},
-
-/* 0000nnnn00111010 stc SGR,<REG_N> */{"stc",{A_SGR,A_REG_N},{HEX_0,REG_N,HEX_3,HEX_A}, arch_sh4_nommu_nofpu_up},
-
-/* 0000nnnn11111010 stc DBR,<REG_N> */{"stc",{A_DBR,A_REG_N},{HEX_0,REG_N,HEX_F,HEX_A}, arch_sh4_nommu_nofpu_up},
-
-/* 0000nnnn1xxx0010 stc Rn_BANK,<REG_N> */{"stc",{A_REG_B,A_REG_N},{HEX_0,REG_N,REG_B,HEX_2}, arch_sh3_nommu_up},
-
-/* 0000nnnn01001010 stc TBR,<REG_N> */ {"stc",{A_TBR,A_REG_N},{HEX_0,REG_N,HEX_4,HEX_A}, arch_sh2a_nofpu_up},
-
-/* 0100nnnn00000011 stc.l SR,@-<REG_N> */{"stc.l",{A_SR,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_3}, arch_sh1_up},
-
-/* 0100nnnn00100011 stc.l VBR,@-<REG_N> */{"stc.l",{A_VBR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_3}, arch_sh1_up},
-
-/* 0100nnnn01010011 stc.l MOD,@-<REG_N> */{"stc.l",{A_MOD,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_3}, arch_sh_dsp_up},
-
-/* 0100nnnn01110011 stc.l RE,@-<REG_N> */{"stc.l",{A_RE,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_3}, arch_sh_dsp_up},
-
-/* 0100nnnn01100011 stc.l RS,@-<REG_N> */{"stc.l",{A_RS,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_3}, arch_sh_dsp_up},
-
-/* 0100nnnn00110011 stc.l SSR,@-<REG_N> */{"stc.l",{A_SSR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_3}, arch_sh3_nommu_up},
-
-/* 0100nnnn01000011 stc.l SPC,@-<REG_N> */{"stc.l",{A_SPC,A_DEC_N},{HEX_4,REG_N,HEX_4,HEX_3}, arch_sh3_nommu_up},
-
-/* 0100nnnn00010011 stc.l GBR,@-<REG_N> */{"stc.l",{A_GBR,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_3}, arch_sh1_up},
-
-/* 0100nnnn00110010 stc.l SGR,@-<REG_N> */{"stc.l",{A_SGR,A_DEC_N},{HEX_4,REG_N,HEX_3,HEX_2}, arch_sh4_nommu_nofpu_up},
-
-/* 0100nnnn11110010 stc.l DBR,@-<REG_N> */{"stc.l",{A_DBR,A_DEC_N},{HEX_4,REG_N,HEX_F,HEX_2}, arch_sh4_nommu_nofpu_up},
-
-/* 0100nnnn1xxx0011 stc.l Rn_BANK,@-<REG_N> */{"stc.l",{A_REG_B,A_DEC_N},{HEX_4,REG_N,REG_B,HEX_3}, arch_sh3_nommu_up},
-
-/* 0000nnnn00001010 sts MACH,<REG_N> */{"sts",{A_MACH,A_REG_N},{HEX_0,REG_N,HEX_0,HEX_A}, arch_sh1_up},
-
-/* 0000nnnn00011010 sts MACL,<REG_N> */{"sts",{A_MACL,A_REG_N},{HEX_0,REG_N,HEX_1,HEX_A}, arch_sh1_up},
-
-/* 0000nnnn00101010 sts PR,<REG_N> */{"sts",{A_PR,A_REG_N},{HEX_0,REG_N,HEX_2,HEX_A}, arch_sh1_up},
-
-/* 0000nnnn01101010 sts DSR,<REG_N> */{"sts",{A_DSR,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh_dsp_up},
-
-/* 0000nnnn01111010 sts A0,<REG_N> */{"sts",{A_A0,A_REG_N},{HEX_0,REG_N,HEX_7,HEX_A}, arch_sh_dsp_up},
-
-/* 0000nnnn10001010 sts X0,<REG_N> */{"sts",{A_X0,A_REG_N},{HEX_0,REG_N,HEX_8,HEX_A}, arch_sh_dsp_up},
-
-/* 0000nnnn10011010 sts X1,<REG_N> */{"sts",{A_X1,A_REG_N},{HEX_0,REG_N,HEX_9,HEX_A}, arch_sh_dsp_up},
-
-/* 0000nnnn10101010 sts Y0,<REG_N> */{"sts",{A_Y0,A_REG_N},{HEX_0,REG_N,HEX_A,HEX_A}, arch_sh_dsp_up},
-
-/* 0000nnnn10111010 sts Y1,<REG_N> */{"sts",{A_Y1,A_REG_N},{HEX_0,REG_N,HEX_B,HEX_A}, arch_sh_dsp_up},
-
-/* 0000nnnn01011010 sts FPUL,<REG_N> */{"sts",{FPUL_M,A_REG_N},{HEX_0,REG_N,HEX_5,HEX_A}, arch_sh2e_up},
-
-/* 0000nnnn01101010 sts FPSCR,<REG_N> */{"sts",{FPSCR_M,A_REG_N},{HEX_0,REG_N,HEX_6,HEX_A}, arch_sh2e_up},
-
-/* 0100nnnn00000010 sts.l MACH,@-<REG_N>*/{"sts.l",{A_MACH,A_DEC_N},{HEX_4,REG_N,HEX_0,HEX_2}, arch_sh1_up},
-
-/* 0100nnnn00010010 sts.l MACL,@-<REG_N>*/{"sts.l",{A_MACL,A_DEC_N},{HEX_4,REG_N,HEX_1,HEX_2}, arch_sh1_up},
-
-/* 0100nnnn00100010 sts.l PR,@-<REG_N> */{"sts.l",{A_PR,A_DEC_N},{HEX_4,REG_N,HEX_2,HEX_2}, arch_sh1_up},
-
-/* 0100nnnn01100110 sts.l DSR,@-<REG_N> */{"sts.l",{A_DSR,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh_dsp_up},
-
-/* 0100nnnn01110110 sts.l A0,@-<REG_N> */{"sts.l",{A_A0,A_DEC_N},{HEX_4,REG_N,HEX_7,HEX_2}, arch_sh_dsp_up},
-
-/* 0100nnnn10000110 sts.l X0,@-<REG_N> */{"sts.l",{A_X0,A_DEC_N},{HEX_4,REG_N,HEX_8,HEX_2}, arch_sh_dsp_up},
-
-/* 0100nnnn10010110 sts.l X1,@-<REG_N> */{"sts.l",{A_X1,A_DEC_N},{HEX_4,REG_N,HEX_9,HEX_2}, arch_sh_dsp_up},
-
-/* 0100nnnn10100110 sts.l Y0,@-<REG_N> */{"sts.l",{A_Y0,A_DEC_N},{HEX_4,REG_N,HEX_A,HEX_2}, arch_sh_dsp_up},
-
-/* 0100nnnn10110110 sts.l Y1,@-<REG_N> */{"sts.l",{A_Y1,A_DEC_N},{HEX_4,REG_N,HEX_B,HEX_2}, arch_sh_dsp_up},
-
-/* 0100nnnn01010010 sts.l FPUL,@-<REG_N>*/{"sts.l",{FPUL_M,A_DEC_N},{HEX_4,REG_N,HEX_5,HEX_2}, arch_sh2e_up},
-
-/* 0100nnnn01100010 sts.l FPSCR,@-<REG_N>*/{"sts.l",{FPSCR_M,A_DEC_N},{HEX_4,REG_N,HEX_6,HEX_2}, arch_sh2e_up},
-
-/* 0011nnnnmmmm1000 sub <REG_M>,<REG_N> */{"sub",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_8}, arch_sh1_up},
-
-/* 0011nnnnmmmm1010 subc <REG_M>,<REG_N>*/{"subc",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_A}, arch_sh1_up},
-
-/* 0011nnnnmmmm1011 subv <REG_M>,<REG_N>*/{"subv",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_B}, arch_sh1_up},
-
-/* 0110nnnnmmmm1000 swap.b <REG_M>,<REG_N>*/{"swap.b",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_8}, arch_sh1_up},
-
-/* 0110nnnnmmmm1001 swap.w <REG_M>,<REG_N>*/{"swap.w",{ A_REG_M,A_REG_N},{HEX_6,REG_N,REG_M,HEX_9}, arch_sh1_up},
-
-/* 0000000010101011 synco */{"synco",{0},{HEX_0,HEX_0,HEX_A,HEX_B}, arch_sh4a_nofp_up},
-
-/* 0100nnnn00011011 tas.b @<REG_N> */{"tas.b",{A_IND_N},{HEX_4,REG_N,HEX_1,HEX_B}, arch_sh1_up},
-
-/* 11000011i8*1.... trapa #<imm> */{"trapa",{A_IMM},{HEX_C,HEX_3,IMM0_8}, arch_sh1_up},
-
-/* 11001000i8*1.... tst #<imm>,R0 */{"tst",{A_IMM,A_R0},{HEX_C,HEX_8,IMM0_8}, arch_sh1_up},
-
-/* 0010nnnnmmmm1000 tst <REG_M>,<REG_N> */{"tst",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_8}, arch_sh1_up},
-
-/* 11001100i8*1.... tst.b #<imm>,@(R0,GBR)*/{"tst.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_C,IMM0_8}, arch_sh1_up},
-
-/* 11001010i8*1.... xor #<imm>,R0 */{"xor",{A_IMM,A_R0},{HEX_C,HEX_A,IMM0_8}, arch_sh1_up},
-
-/* 0010nnnnmmmm1010 xor <REG_M>,<REG_N> */{"xor",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_A}, arch_sh1_up},
-
-/* 11001110i8*1.... xor.b #<imm>,@(R0,GBR)*/{"xor.b",{A_IMM,A_R0_GBR},{HEX_C,HEX_E,IMM0_8}, arch_sh1_up},
-
-/* 0010nnnnmmmm1101 xtrct <REG_M>,<REG_N>*/{"xtrct",{ A_REG_M,A_REG_N},{HEX_2,REG_N,REG_M,HEX_D}, arch_sh1_up},
-
-/* 0000nnnnmmmm0111 mul.l <REG_M>,<REG_N>*/{"mul.l",{ A_REG_M,A_REG_N},{HEX_0,REG_N,REG_M,HEX_7}, arch_sh1_up},
-
-/* 0100nnnn00010000 dt <REG_N> */{"dt",{A_REG_N},{HEX_4,REG_N,HEX_1,HEX_0}, arch_sh2_up},
-
-/* 0011nnnnmmmm1101 dmuls.l <REG_M>,<REG_N>*/{"dmuls.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_D}, arch_sh2_up},
-
-/* 0011nnnnmmmm0101 dmulu.l <REG_M>,<REG_N>*/{"dmulu.l",{ A_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_5}, arch_sh2_up},
-
-/* 0000nnnnmmmm1111 mac.l @<REG_M>+,@<REG_N>+*/{"mac.l",{A_INC_M,A_INC_N},{HEX_0,REG_N,REG_M,HEX_F}, arch_sh2_up},
-
-/* 0000nnnn00100011 braf <REG_N> */{"braf",{A_REG_N},{HEX_0,REG_N,HEX_2,HEX_3}, arch_sh2_up},
-
-/* 0000nnnn00000011 bsrf <REG_N> */{"bsrf",{A_REG_N},{HEX_0,REG_N,HEX_0,HEX_3}, arch_sh2_up},
-
-/* 111101nnmmmm0000 movs.w @-<REG_N>,<DSP_REG_M> */ {"movs.w",{A_DEC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_0}, arch_sh_dsp_up},
-
-/* 111101nnmmmm0001 movs.w @<REG_N>,<DSP_REG_M> */ {"movs.w",{A_IND_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_4}, arch_sh_dsp_up},
-
-/* 111101nnmmmm0010 movs.w @<REG_N>+,<DSP_REG_M> */ {"movs.w",{A_INC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_8}, arch_sh_dsp_up},
-
-/* 111101nnmmmm0011 movs.w @<REG_N>+r8,<DSP_REG_M> */ {"movs.w",{AS_PMOD_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_C}, arch_sh_dsp_up},
-
-/* 111101nnmmmm0100 movs.w <DSP_REG_M>,@-<REG_N> */ {"movs.w",{DSP_REG_M,A_DEC_N},{HEX_F,SDT_REG_N,REG_M,HEX_1}, arch_sh_dsp_up},
-
-/* 111101nnmmmm0101 movs.w <DSP_REG_M>,@<REG_N> */ {"movs.w",{DSP_REG_M,A_IND_N},{HEX_F,SDT_REG_N,REG_M,HEX_5}, arch_sh_dsp_up},
-
-/* 111101nnmmmm0110 movs.w <DSP_REG_M>,@<REG_N>+ */ {"movs.w",{DSP_REG_M,A_INC_N},{HEX_F,SDT_REG_N,REG_M,HEX_9}, arch_sh_dsp_up},
-
-/* 111101nnmmmm0111 movs.w <DSP_REG_M>,@<REG_N>+r8 */ {"movs.w",{DSP_REG_M,AS_PMOD_N},{HEX_F,SDT_REG_N,REG_M,HEX_D}, arch_sh_dsp_up},
-
-/* 111101nnmmmm1000 movs.l @-<REG_N>,<DSP_REG_M> */ {"movs.l",{A_DEC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_2}, arch_sh_dsp_up},
-
-/* 111101nnmmmm1001 movs.l @<REG_N>,<DSP_REG_M> */ {"movs.l",{A_IND_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_6}, arch_sh_dsp_up},
-
-/* 111101nnmmmm1010 movs.l @<REG_N>+,<DSP_REG_M> */ {"movs.l",{A_INC_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_A}, arch_sh_dsp_up},
-
-/* 111101nnmmmm1011 movs.l @<REG_N>+r8,<DSP_REG_M> */ {"movs.l",{AS_PMOD_N,DSP_REG_M},{HEX_F,SDT_REG_N,REG_M,HEX_E}, arch_sh_dsp_up},
-
-/* 111101nnmmmm1100 movs.l <DSP_REG_M>,@-<REG_N> */ {"movs.l",{DSP_REG_M,A_DEC_N},{HEX_F,SDT_REG_N,REG_M,HEX_3}, arch_sh_dsp_up},
-
-/* 111101nnmmmm1101 movs.l <DSP_REG_M>,@<REG_N> */ {"movs.l",{DSP_REG_M,A_IND_N},{HEX_F,SDT_REG_N,REG_M,HEX_7}, arch_sh_dsp_up},
-
-/* 111101nnmmmm1110 movs.l <DSP_REG_M>,@<REG_N>+ */ {"movs.l",{DSP_REG_M,A_INC_N},{HEX_F,SDT_REG_N,REG_M,HEX_B}, arch_sh_dsp_up},
-
-/* 111101nnmmmm1111 movs.l <DSP_REG_M>,@<REG_N>+r8 */ {"movs.l",{DSP_REG_M,AS_PMOD_N},{HEX_F,SDT_REG_N,REG_M,HEX_F}, arch_sh_dsp_up},
-
-/* 0*0*0*00** nopx */ {"nopx",{0},{PPI,NOPX}, arch_sh_dsp_up},
-/* *0*0*0**00 nopy */ {"nopy",{0},{PPI,NOPY}, arch_sh_dsp_up},
-/* n*m*0*01** movx.w @<REG_N>,<DSP_REG_X> */ {"movx.w",{AX_IND_N,DSP_REG_X},{PPI,MOVX,HEX_1}, arch_sh_dsp_up},
-/* n*m*0*10** movx.w @<REG_N>+,<DSP_REG_X> */ {"movx.w",{AX_INC_N,DSP_REG_X},{PPI,MOVX,HEX_2}, arch_sh_dsp_up},
-/* n*m*0*11** movx.w @<REG_N>+r8,<DSP_REG_X> */ {"movx.w",{AX_PMOD_N,DSP_REG_X},{PPI,MOVX,HEX_3}, arch_sh_dsp_up},
-/* n*m*1*01** movx.w <DSP_REG_M>,@<REG_N> */ {"movx.w",{DSP_REG_A_M,AX_IND_N},{PPI,MOVX,HEX_9}, arch_sh_dsp_up},
-/* n*m*1*10** movx.w <DSP_REG_M>,@<REG_N>+ */ {"movx.w",{DSP_REG_A_M,AX_INC_N},{PPI,MOVX,HEX_A}, arch_sh_dsp_up},
-/* n*m*1*11** movx.w <DSP_REG_M>,@<REG_N>+r8 */ {"movx.w",{DSP_REG_A_M,AX_PMOD_N},{PPI,MOVX,HEX_B}, arch_sh_dsp_up},
-
-/* nnmm000100 movx.w @<REG_Axy>,<DSP_REG_XY> */ {"movx.w",{AXY_IND_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_4}, arch_sh4al_dsp_up},
-/* nnmm001000 movx.w @<REG_Axy>+,<DSP_REG_XY> */{"movx.w",{AXY_INC_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_8}, arch_sh4al_dsp_up},
-/* nnmm001100 movx.w @<REG_Axy>+r8,<DSP_REG_XY> */{"movx.w",{AXY_PMOD_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_0,HEX_C}, arch_sh4al_dsp_up},
-/* nnmm100100 movx.w <DSP_REG_AX>,@<REG_Axy> */ {"movx.w",{DSP_REG_AX,AXY_IND_N},{PPI,MOVX_NOPY,HEX_2,HEX_4}, arch_sh4al_dsp_up},
-/* nnmm101000 movx.w <DSP_REG_AX>,@<REG_Axy>+ */{"movx.w",{DSP_REG_AX,AXY_INC_N},{PPI,MOVX_NOPY,HEX_2,HEX_8}, arch_sh4al_dsp_up},
-/* nnmm101100 movx.w <DSP_REG_AX>,@<REG_Axy>+r8 */{"movx.w",{DSP_REG_AX,AXY_PMOD_N},{PPI,MOVX_NOPY,HEX_2,HEX_C}, arch_sh4al_dsp_up},
-
-/* nnmm010100 movx.l @<REG_Axy>,<DSP_REG_XY> */ {"movx.l",{AXY_IND_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_4}, arch_sh4al_dsp_up},
-/* nnmm011000 movx.l @<REG_Axy>+,<DSP_REG_XY> */{"movx.l",{AXY_INC_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_8}, arch_sh4al_dsp_up},
-/* nnmm011100 movx.l @<REG_Axy>+r8,<DSP_REG_XY> */{"movx.l",{AXY_PMOD_N,DSP_REG_XY},{PPI,MOVX_NOPY,HEX_1,HEX_C}, arch_sh4al_dsp_up},
-/* nnmm110100 movx.l <DSP_REG_AX>,@<REG_Axy> */ {"movx.l",{DSP_REG_AX,AXY_IND_N},{PPI,MOVX_NOPY,HEX_3,HEX_4}, arch_sh4al_dsp_up},
-/* nnmm111000 movx.l <DSP_REG_AX>,@<REG_Axy>+ */{"movx.l",{DSP_REG_AX,AXY_INC_N},{PPI,MOVX_NOPY,HEX_3,HEX_8}, arch_sh4al_dsp_up},
-/* nnmm111100 movx.l <DSP_REG_AX>,@<REG_Axy>+r8 */{"movx.l",{DSP_REG_AX,AXY_PMOD_N},{PPI,MOVX_NOPY,HEX_3,HEX_C}, arch_sh4al_dsp_up},
-
-/* *n*m*0**01 movy.w @<REG_N>,<DSP_REG_Y> */ {"movy.w",{AY_IND_N,DSP_REG_Y},{PPI,MOVY,HEX_1}, arch_sh_dsp_up},
-/* *n*m*0**10 movy.w @<REG_N>+,<DSP_REG_Y> */ {"movy.w",{AY_INC_N,DSP_REG_Y},{PPI,MOVY,HEX_2}, arch_sh_dsp_up},
-/* *n*m*0**11 movy.w @<REG_N>+r9,<DSP_REG_Y> */ {"movy.w",{AY_PMOD_N,DSP_REG_Y},{PPI,MOVY,HEX_3}, arch_sh_dsp_up},
-/* *n*m*1**01 movy.w <DSP_REG_M>,@<REG_N> */ {"movy.w",{DSP_REG_A_M,AY_IND_N},{PPI,MOVY,HEX_9}, arch_sh_dsp_up},
-/* *n*m*1**10 movy.w <DSP_REG_M>,@<REG_N>+ */ {"movy.w",{DSP_REG_A_M,AY_INC_N},{PPI,MOVY,HEX_A}, arch_sh_dsp_up},
-/* *n*m*1**11 movy.w <DSP_REG_M>,@<REG_N>+r9 */ {"movy.w",{DSP_REG_A_M,AY_PMOD_N},{PPI,MOVY,HEX_B}, arch_sh_dsp_up},
-
-/* nnmm000001 movy.w @<REG_Ayx>,<DSP_REG_YX> */ {"movy.w",{AYX_IND_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_1}, arch_sh4al_dsp_up},
-/* nnmm000010 movy.w @<REG_Ayx>+,<DSP_REG_YX> */{"movy.w",{AYX_INC_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_2}, arch_sh4al_dsp_up},
-/* nnmm000011 movy.w @<REG_Ayx>+r8,<DSP_REG_YX> */{"movy.w",{AYX_PMOD_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_0,HEX_3}, arch_sh4al_dsp_up},
-/* nnmm010001 movy.w <DSP_REG_AY>,@<REG_Ayx> */ {"movy.w",{DSP_REG_AY,AYX_IND_N},{PPI,MOVY_NOPX,HEX_1,HEX_1}, arch_sh4al_dsp_up},
-/* nnmm010010 movy.w <DSP_REG_AY>,@<REG_Ayx>+ */{"movy.w",{DSP_REG_AY,AYX_INC_N},{PPI,MOVY_NOPX,HEX_1,HEX_2}, arch_sh4al_dsp_up},
-/* nnmm010011 movy.w <DSP_REG_AY>,@<REG_Ayx>+r8 */{"movy.w",{DSP_REG_AY,AYX_PMOD_N},{PPI,MOVY_NOPX,HEX_1,HEX_3}, arch_sh4al_dsp_up},
-
-/* nnmm100001 movy.l @<REG_Ayx>,<DSP_REG_YX> */ {"movy.l",{AYX_IND_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_1}, arch_sh4al_dsp_up},
-/* nnmm100010 movy.l @<REG_Ayx>+,<DSP_REG_YX> */{"movy.l",{AYX_INC_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_2}, arch_sh4al_dsp_up},
-/* nnmm100011 movy.l @<REG_Ayx>+r8,<DSP_REG_YX> */{"movy.l",{AYX_PMOD_N,DSP_REG_YX},{PPI,MOVY_NOPX,HEX_2,HEX_3}, arch_sh4al_dsp_up},
-/* nnmm110001 movy.l <DSP_REG_AY>,@<REG_Ayx> */ {"movy.l",{DSP_REG_AY,AYX_IND_N},{PPI,MOVY_NOPX,HEX_3,HEX_1}, arch_sh4al_dsp_up},
-/* nnmm110010 movy.l <DSP_REG_AY>,@<REG_Ayx>+ */{"movy.l",{DSP_REG_AY,AYX_INC_N},{PPI,MOVY_NOPX,HEX_3,HEX_2}, arch_sh4al_dsp_up},
-/* nnmm110011 movy.l <DSP_REG_AY>,@<REG_Ayx>+r8 */{"movy.l",{DSP_REG_AY,AYX_PMOD_N},{PPI,MOVY_NOPX,HEX_3,HEX_3}, arch_sh4al_dsp_up},
-
-/* 01aaeeffxxyyggnn pmuls Se,Sf,Dg */ {"pmuls",{DSP_REG_E,DSP_REG_F,DSP_REG_G},{PPI,PMUL}, arch_sh_dsp_up},
-/* 10100000xxyynnnn psubc <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"psubc",{DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_A,HEX_0}, arch_sh_dsp_up},
-/* 10110000xxyynnnn paddc <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"paddc",{DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_B,HEX_0}, arch_sh_dsp_up},
-/* 10000100xxyynnnn pcmp <DSP_REG_X>,<DSP_REG_Y> */
-{"pcmp", {DSP_REG_X,DSP_REG_Y},{PPI,PPI3,HEX_8,HEX_4}, arch_sh_dsp_up},
-/* 10100100xxyynnnn pwsb <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"pwsb", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_A,HEX_4}, arch_sh_dsp_up},
-/* 10110100xxyynnnn pwad <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"pwad", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPI3,HEX_B,HEX_4}, arch_sh_dsp_up},
-/* 10001000xxyynnnn pabs <DSP_REG_X>,<DSP_REG_N> */
-{"pabs", {DSP_REG_X,DSP_REG_N},{PPI,PPI3NC,HEX_8,HEX_8}, arch_sh_dsp_up},
-/* 1000100!xx01nnnn pabs <DSP_REG_X>,<DSP_REG_N> */
-{"pabs", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_9,HEX_1}, arch_sh4al_dsp_up},
-/* 10101000xxyynnnn pabs <DSP_REG_Y>,<DSP_REG_N> */
-{"pabs", {DSP_REG_Y,DSP_REG_N},{PPI,PPI3NC,HEX_A,HEX_8}, arch_sh_dsp_up},
-/* 1010100!01yynnnn pabs <DSP_REG_Y>,<DSP_REG_N> */
-{"pabs", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_9,HEX_4}, arch_sh4al_dsp_up},
-/* 10011000xxyynnnn prnd <DSP_REG_X>,<DSP_REG_N> */
-{"prnd", {DSP_REG_X,DSP_REG_N},{PPI,PPI3NC,HEX_9,HEX_8}, arch_sh_dsp_up},
-/* 1001100!xx01nnnn prnd <DSP_REG_X>,<DSP_REG_N> */
-{"prnd", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_9,HEX_1}, arch_sh4al_dsp_up},
-/* 10111000xxyynnnn prnd <DSP_REG_Y>,<DSP_REG_N> */
-{"prnd", {DSP_REG_Y,DSP_REG_N},{PPI,PPI3NC,HEX_B,HEX_8}, arch_sh_dsp_up},
-/* 1011100!01yynnnn prnd <DSP_REG_Y>,<DSP_REG_N> */
-{"prnd", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_9,HEX_4}, arch_sh4al_dsp_up},
-
-{"dct",{0},{PPI,PDC,HEX_1}, arch_sh_dsp_up},
-{"dcf",{0},{PPI,PDC,HEX_2}, arch_sh_dsp_up},
-
-/* 10000001xxyynnnn pshl <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"pshl", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_1}, arch_sh_dsp_up},
-/* 00000iiiiiiinnnn pshl #<imm>,<DSP_REG_N> */ {"pshl",{A_IMM,DSP_REG_N},{PPI,PSH,HEX_0}, arch_sh_dsp_up},
-/* 10010001xxyynnnn psha <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"psha", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_1}, arch_sh_dsp_up},
-/* 00010iiiiiiinnnn psha #<imm>,<DSP_REG_N> */ {"psha",{A_IMM,DSP_REG_N},{PPI,PSH,HEX_1}, arch_sh_dsp_up},
-/* 10100001xxyynnnn psub <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"psub", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_1}, arch_sh_dsp_up},
-/* 10000101xxyynnnn psub <DSP_REG_Y>,<DSP_REG_X>,<DSP_REG_N> */
-{"psub", {DSP_REG_Y,DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_5}, arch_sh4al_dsp_up},
-/* 10110001xxyynnnn padd <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"padd", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_1}, arch_sh_dsp_up},
-/* 10010101xxyynnnn pand <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"pand", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_5}, arch_sh_dsp_up},
-/* 10100101xxyynnnn pxor <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"pxor", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_5}, arch_sh_dsp_up},
-/* 10110101xxyynnnn por <DSP_REG_X>,<DSP_REG_Y>,<DSP_REG_N> */
-{"por", {DSP_REG_X,DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_5}, arch_sh_dsp_up},
-/* 10001001xxyynnnn pdec <DSP_REG_X>,<DSP_REG_N> */
-{"pdec", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_8,HEX_9}, arch_sh_dsp_up},
-/* 10101001xxyynnnn pdec <DSP_REG_Y>,<DSP_REG_N> */
-{"pdec", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_A,HEX_9}, arch_sh_dsp_up},
-/* 10011001xx00nnnn pinc <DSP_REG_X>,<DSP_REG_N> */
-{"pinc", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_9,HEX_XX00}, arch_sh_dsp_up},
-/* 1011100100yynnnn pinc <DSP_REG_Y>,<DSP_REG_N> */
-{"pinc", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_9,HEX_00YY}, arch_sh_dsp_up},
-/* 10001101xxyynnnn pclr <DSP_REG_N> */
-{"pclr", {DSP_REG_N},{PPI,PPIC,HEX_8,HEX_D}, arch_sh_dsp_up},
-/* 10011101xx00nnnn pdmsb <DSP_REG_X>,<DSP_REG_N> */
-{"pdmsb", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_D,HEX_XX00}, arch_sh_dsp_up},
-/* 1011110100yynnnn pdmsb <DSP_REG_Y>,<DSP_REG_N> */
-{"pdmsb", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_D,HEX_00YY}, arch_sh_dsp_up},
-/* 11001001xxyynnnn pneg <DSP_REG_X>,<DSP_REG_N> */
-{"pneg", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_C,HEX_9}, arch_sh_dsp_up},
-/* 11101001xxyynnnn pneg <DSP_REG_Y>,<DSP_REG_N> */
-{"pneg", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_E,HEX_9}, arch_sh_dsp_up},
-/* 11011001xxyynnnn pcopy <DSP_REG_X>,<DSP_REG_N> */
-{"pcopy", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_D,HEX_9}, arch_sh_dsp_up},
-/* 11111001xxyynnnn pcopy <DSP_REG_Y>,<DSP_REG_N> */
-{"pcopy", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_F,HEX_9}, arch_sh_dsp_up},
-/* 11001101xxyynnnn psts MACH,<DSP_REG_N> */
-{"psts", {A_MACH,DSP_REG_N},{PPI,PPIC,HEX_C,HEX_D}, arch_sh_dsp_up},
-/* 11011101xxyynnnn psts MACL,<DSP_REG_N> */
-{"psts", {A_MACL,DSP_REG_N},{PPI,PPIC,HEX_D,HEX_D}, arch_sh_dsp_up},
-/* 11101101xxyynnnn plds <DSP_REG_N>,MACH */
-{"plds", {DSP_REG_N,A_MACH},{PPI,PPIC,HEX_E,HEX_D}, arch_sh_dsp_up},
-/* 11111101xxyynnnn plds <DSP_REG_N>,MACL */
-{"plds", {DSP_REG_N,A_MACL},{PPI,PPIC,HEX_F,HEX_D}, arch_sh_dsp_up},
-/* 10011101xx01zzzz pswap <DSP_REG_X>,<DSP_REG_N> */
-{"pswap", {DSP_REG_X,DSP_REG_N},{PPI,PPIC,HEX_9,HEX_D,HEX_1}, arch_sh4al_dsp_up},
-/* 1011110101yyzzzz pswap <DSP_REG_Y>,<DSP_REG_N> */
-{"pswap", {DSP_REG_Y,DSP_REG_N},{PPI,PPIC,HEX_B,HEX_D,HEX_4}, arch_sh4al_dsp_up},
-
-/* 1111nnnn01011101 fabs <F_REG_N> */{"fabs",{F_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}, arch_sh2e_up},
-/* 1111nnn001011101 fabs <D_REG_N> */{"fabs",{D_REG_N},{HEX_F,REG_N,HEX_5,HEX_D}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm0000 fadd <F_REG_M>,<F_REG_N>*/{"fadd",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_0}, arch_sh2e_up},
-/* 1111nnn0mmm00000 fadd <D_REG_M>,<D_REG_N>*/{"fadd",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_0}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm0100 fcmp/eq <F_REG_M>,<F_REG_N>*/{"fcmp/eq",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_4}, arch_sh2e_up},
-/* 1111nnn0mmm00100 fcmp/eq <D_REG_M>,<D_REG_N>*/{"fcmp/eq",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_4}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm0101 fcmp/gt <F_REG_M>,<F_REG_N>*/{"fcmp/gt",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_5}, arch_sh2e_up},
-/* 1111nnn0mmm00101 fcmp/gt <D_REG_M>,<D_REG_N>*/{"fcmp/gt",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_5}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnn010111101 fcnvds <D_REG_N>,FPUL*/{"fcnvds",{D_REG_N,FPUL_M},{HEX_F,REG_N_D,HEX_B,HEX_D}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnn010101101 fcnvsd FPUL,<D_REG_N>*/{"fcnvsd",{FPUL_M,D_REG_N},{HEX_F,REG_N_D,HEX_A,HEX_D}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm0011 fdiv <F_REG_M>,<F_REG_N>*/{"fdiv",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_3}, arch_sh2e_up},
-/* 1111nnn0mmm00011 fdiv <D_REG_M>,<D_REG_N>*/{"fdiv",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_3}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnmm11101101 fipr <V_REG_M>,<V_REG_N>*/{"fipr",{V_REG_M,V_REG_N},{HEX_F,REG_NM,HEX_E,HEX_D}, arch_sh4_up},
-
-/* 1111nnnn10001101 fldi0 <F_REG_N> */{"fldi0",{F_REG_N},{HEX_F,REG_N,HEX_8,HEX_D}, arch_sh2e_up},
-
-/* 1111nnnn10011101 fldi1 <F_REG_N> */{"fldi1",{F_REG_N},{HEX_F,REG_N,HEX_9,HEX_D}, arch_sh2e_up},
-
-/* 1111nnnn00011101 flds <F_REG_N>,FPUL*/{"flds",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_1,HEX_D}, arch_sh2e_up},
-
-/* 1111nnnn00101101 float FPUL,<F_REG_N>*/{"float",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}, arch_sh2e_up},
-/* 1111nnn000101101 float FPUL,<D_REG_N>*/{"float",{FPUL_M,D_REG_N},{HEX_F,REG_N,HEX_2,HEX_D}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm1110 fmac FR0,<F_REG_M>,<F_REG_N>*/{"fmac",{F_FR0,F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_E}, arch_sh2e_up},
-
-/* 1111nnnnmmmm1100 fmov <F_REG_M>,<F_REG_N>*/{"fmov",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_C}, arch_sh2e_up},
-/* 1111nnn1mmmm1100 fmov <DX_REG_M>,<DX_REG_N>*/{"fmov",{DX_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_C}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm1000 fmov @<REG_M>,<F_REG_N>*/{"fmov",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh2e_up},
-/* 1111nnn1mmmm1000 fmov @<REG_M>,<DX_REG_N>*/{"fmov",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm1010 fmov <F_REG_M>,@<REG_N>*/{"fmov",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh2e_up},
-/* 1111nnnnmmm11010 fmov <DX_REG_M>,@<REG_N>*/{"fmov",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm1001 fmov @<REG_M>+,<F_REG_N>*/{"fmov",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh2e_up},
-/* 1111nnn1mmmm1001 fmov @<REG_M>+,<DX_REG_N>*/{"fmov",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm1011 fmov <F_REG_M>,@-<REG_N>*/{"fmov",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh2e_up},
-/* 1111nnnnmmm11011 fmov <DX_REG_M>,@-<REG_N>*/{"fmov",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm0110 fmov @(R0,<REG_M>),<F_REG_N>*/{"fmov",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh2e_up},
-/* 1111nnn1mmmm0110 fmov @(R0,<REG_M>),<DX_REG_N>*/{"fmov",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmmm0111 fmov <F_REG_M>,@(R0,<REG_N>)*/{"fmov",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh2e_up},
-/* 1111nnnnmmm10111 fmov <DX_REG_M>,@(R0,<REG_N>)*/{"fmov",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnn1mmmm1000 fmov.d @<REG_M>,<DX_REG_N>*/{"fmov.d",{A_IND_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmm11010 fmov.d <DX_REG_M>,@<REG_N>*/{"fmov.d",{DX_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnn1mmmm1001 fmov.d @<REG_M>+,<DX_REG_N>*/{"fmov.d",{A_INC_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmm11011 fmov.d <DX_REG_M>,@-<REG_N>*/{"fmov.d",{DX_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnn1mmmm0110 fmov.d @(R0,<REG_M>),<DX_REG_N>*/{"fmov.d",{A_IND_R0_REG_M,DX_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnnmmm10111 fmov.d <DX_REG_M>,@(R0,<REG_N>)*/{"fmov.d",{DX_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh4_up | arch_sh2a_up},
-/* 0011nnnnmmmm0001 0011dddddddddddd fmov.d <F_REG_M>,@(<DISP12>,<REG_N>) */
-{"fmov.d",{DX_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_3,DISP1_12BY8}, arch_sh2a_up | arch_op32},
-/* 0011nnnnmmmm0001 0111dddddddddddd fmov.d @(<DISP12>,<REG_M>),F_REG_N */
-{"fmov.d",{A_DISP_REG_M,DX_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_7,DISP0_12BY8}, arch_sh2a_up | arch_op32},
-
-/* 1111nnnnmmmm1000 fmov.s @<REG_M>,<F_REG_N>*/{"fmov.s",{A_IND_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_8}, arch_sh2e_up},
-
-/* 1111nnnnmmmm1010 fmov.s <F_REG_M>,@<REG_N>*/{"fmov.s",{F_REG_M,A_IND_N},{HEX_F,REG_N,REG_M,HEX_A}, arch_sh2e_up},
-
-/* 1111nnnnmmmm1001 fmov.s @<REG_M>+,<F_REG_N>*/{"fmov.s",{A_INC_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_9}, arch_sh2e_up},
-
-/* 1111nnnnmmmm1011 fmov.s <F_REG_M>,@-<REG_N>*/{"fmov.s",{F_REG_M,A_DEC_N},{HEX_F,REG_N,REG_M,HEX_B}, arch_sh2e_up},
-
-/* 1111nnnnmmmm0110 fmov.s @(R0,<REG_M>),<F_REG_N>*/{"fmov.s",{A_IND_R0_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_6}, arch_sh2e_up},
-
-/* 1111nnnnmmmm0111 fmov.s <F_REG_M>,@(R0,<REG_N>)*/{"fmov.s",{F_REG_M,A_IND_R0_REG_N},{HEX_F,REG_N,REG_M,HEX_7}, arch_sh2e_up},
-/* 0011nnnnmmmm0001 0011dddddddddddd fmov.s <F_REG_M>,@(<DISP12>,<REG_N>) */
-{"fmov.s",{F_REG_M,A_DISP_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_3,DISP1_12BY4}, arch_sh2a_up | arch_op32},
-/* 0011nnnnmmmm0001 0111dddddddddddd fmov.s @(<DISP12>,<REG_M>),F_REG_N */
-{"fmov.s",{A_DISP_REG_M,F_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_7,DISP0_12BY4}, arch_sh2a_up | arch_op32},
-
-/* 1111nnnnmmmm0010 fmul <F_REG_M>,<F_REG_N>*/{"fmul",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_2}, arch_sh2e_up},
-/* 1111nnn0mmm00010 fmul <D_REG_M>,<D_REG_N>*/{"fmul",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_2}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnn01001101 fneg <F_REG_N> */{"fneg",{F_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}, arch_sh2e_up},
-/* 1111nnn001001101 fneg <D_REG_N> */{"fneg",{D_REG_N},{HEX_F,REG_N,HEX_4,HEX_D}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111011111111101 fpchg */{"fpchg",{0},{HEX_F,HEX_7,HEX_F,HEX_D}, arch_sh4a_up},
-
-/* 1111101111111101 frchg */{"frchg",{0},{HEX_F,HEX_B,HEX_F,HEX_D}, arch_sh4_up},
-
-/* 1111nnn011111101 fsca FPUL,<D_REG_N> */{"fsca",{FPUL_M,D_REG_N},{HEX_F,REG_N_D,HEX_F,HEX_D}, arch_sh4_up},
-
-/* 1111001111111101 fschg */{"fschg",{0},{HEX_F,HEX_3,HEX_F,HEX_D}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnn01101101 fsqrt <F_REG_N> */{"fsqrt",{F_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}, arch_sh3e_up | arch_sh2a_up},
-/* 1111nnn001101101 fsqrt <D_REG_N> */{"fsqrt",{D_REG_N},{HEX_F,REG_N,HEX_6,HEX_D}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnn01111101 fsrra <F_REG_N> */{"fsrra",{F_REG_N},{HEX_F,REG_N,HEX_7,HEX_D}, arch_sh4_up},
-
-/* 1111nnnn00001101 fsts FPUL,<F_REG_N>*/{"fsts",{FPUL_M,F_REG_N},{HEX_F,REG_N,HEX_0,HEX_D}, arch_sh2e_up},
-
-/* 1111nnnnmmmm0001 fsub <F_REG_M>,<F_REG_N>*/{"fsub",{F_REG_M,F_REG_N},{HEX_F,REG_N,REG_M,HEX_1}, arch_sh2e_up},
-/* 1111nnn0mmm00001 fsub <D_REG_M>,<D_REG_N>*/{"fsub",{D_REG_M,D_REG_N},{HEX_F,REG_N,REG_M,HEX_1}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nnnn00111101 ftrc <F_REG_N>,FPUL*/{"ftrc",{F_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}, arch_sh2e_up},
-/* 1111nnnn00111101 ftrc <D_REG_N>,FPUL*/{"ftrc",{D_REG_N,FPUL_M},{HEX_F,REG_N,HEX_3,HEX_D}, arch_sh4_up | arch_sh2a_up},
-
-/* 1111nn0111111101 ftrv XMTRX_M4,<V_REG_n>*/{"ftrv",{XMTRX_M4,V_REG_N},{HEX_F,REG_N_B01,HEX_F,HEX_D}, arch_sh4_up},
-
- /* 10000110nnnn0iii bclr #<imm>, <REG_N> */ {"bclr",{A_IMM, A_REG_N},{HEX_8,HEX_6,REG_N,IMM0_3c}, arch_sh2a_nofpu_up},
- /* 0011nnnn0iii1001 0000dddddddddddd bclr.b #<imm>,@(<DISP12>,<REG_N>) */
-{"bclr.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_0,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
- /* 10000111nnnn1iii bld #<imm>, <REG_N> */ {"bld",{A_IMM, A_REG_N},{HEX_8,HEX_7,REG_N,IMM0_3s}, arch_sh2a_nofpu_up},
- /* 0011nnnn0iii1001 0011dddddddddddd bld.b #<imm>,@(<DISP12>,<REG_N>) */
-{"bld.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_3,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
- /* 10000110nnnn1iii bset #<imm>, <REG_N> */ {"bset",{A_IMM, A_REG_N},{HEX_8,HEX_6,REG_N,IMM0_3s}, arch_sh2a_nofpu_up},
- /* 0011nnnn0iii1001 0001dddddddddddd bset.b #<imm>,@(<DISP12>,<REG_N>) */
-{"bset.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_1,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
- /* 10000111nnnn0iii bst #<imm>, <REG_N> */ {"bst",{A_IMM, A_REG_N},{HEX_8,HEX_7,REG_N,IMM0_3c}, arch_sh2a_nofpu_up},
- /* 0011nnnn0iii1001 0010dddddddddddd bst.b #<imm>,@(<DISP12>,<REG_N>) */
-{"bst.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_2,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
- /* 0100nnnn10010001 clips.b <REG_N> */ {"clips.b",{A_REG_N},{HEX_4,REG_N,HEX_9,HEX_1}, arch_sh2a_nofpu_up},
- /* 0100nnnn10010101 clips.w <REG_N> */ {"clips.w",{A_REG_N},{HEX_4,REG_N,HEX_9,HEX_5}, arch_sh2a_nofpu_up},
- /* 0100nnnn10000001 clipu.b <REG_N> */ {"clipu.b",{A_REG_N},{HEX_4,REG_N,HEX_8,HEX_1}, arch_sh2a_nofpu_up},
- /* 0100nnnn10000101 clipu.w <REG_N> */ {"clipu.w",{A_REG_N},{HEX_4,REG_N,HEX_8,HEX_5}, arch_sh2a_nofpu_up},
- /* 0100nnnn10010100 divs R0,<REG_N> */ {"divs",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_9,HEX_4}, arch_sh2a_nofpu_up},
- /* 0100nnnn10000100 divu R0,<REG_N> */ {"divu",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_8,HEX_4}, arch_sh2a_nofpu_up},
- /* 0100mmmm01001011 jsr/n @<REG_M> */ {"jsr/n",{A_IND_M},{HEX_4,REG_M,HEX_4,HEX_B}, arch_sh2a_nofpu_up},
- /* 10000011dddddddd jsr/n @@(<disp>,TBR) */ {"jsr/n",{A_DISP2_TBR},{HEX_8,HEX_3,IMM0_8BY4}, arch_sh2a_nofpu_up},
- /* 0100mmmm11100101 ldbank @<REG_M>,R0 */ {"ldbank",{A_IND_M,A_R0},{HEX_4,REG_M,HEX_E,HEX_5}, arch_sh2a_nofpu_up},
- /* 0100mmmm11110001 movml.l <REG_M>,@-R15 */ {"movml.l",{A_REG_M,A_DEC_R15},{HEX_4,REG_M,HEX_F,HEX_1}, arch_sh2a_nofpu_up},
- /* 0100mmmm11110101 movml.l @R15+,<REG_M> */ {"movml.l",{A_INC_R15,A_REG_M},{HEX_4,REG_M,HEX_F,HEX_5}, arch_sh2a_nofpu_up},
- /* 0100mmmm11110000 movml.l <REG_M>,@-R15 */ {"movmu.l",{A_REG_M,A_DEC_R15},{HEX_4,REG_M,HEX_F,HEX_0}, arch_sh2a_nofpu_up},
- /* 0100mmmm11110100 movml.l @R15+,<REG_M> */ {"movmu.l",{A_INC_R15,A_REG_M},{HEX_4,REG_M,HEX_F,HEX_4}, arch_sh2a_nofpu_up},
- /* 0000nnnn00111001 movrt <REG_N> */ {"movrt",{A_REG_N},{HEX_0,REG_N,HEX_3,HEX_9}, arch_sh2a_nofpu_up},
- /* 0100nnnn10000000 mulr R0,<REG_N> */ {"mulr",{A_R0,A_REG_N},{HEX_4,REG_N,HEX_8,HEX_0}, arch_sh2a_nofpu_up},
- /* 0000000001101000 nott */ {"nott",{A_END},{HEX_0,HEX_0,HEX_6,HEX_8}, arch_sh2a_nofpu_up},
- /* 0000000001011011 resbank */ {"resbank",{A_END},{HEX_0,HEX_0,HEX_5,HEX_B}, arch_sh2a_nofpu_up},
- /* 0000000001101011 rts/n */ {"rts/n",{A_END},{HEX_0,HEX_0,HEX_6,HEX_B}, arch_sh2a_nofpu_up},
- /* 0000mmmm01111011 rtv/n <REG_M>*/ {"rtv/n",{A_REG_M},{HEX_0,REG_M,HEX_7,HEX_B}, arch_sh2a_nofpu_up},
- /* 0100nnnn11100001 stbank R0,@<REG_N>*/ {"stbank",{A_R0,A_IND_N},{HEX_4,REG_N,HEX_E,HEX_1}, arch_sh2a_nofpu_up},
-
-/* 0011nnnn0iii1001 0100dddddddddddd band.b #<imm>,@(<DISP12>,<REG_N>) */
-{"band.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_4,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
-/* 0011nnnn0iii1001 1100dddddddddddd bandnot.b #<imm>,@(<DISP12>,<REG_N>) */
-{"bandnot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_C,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
-/* 0011nnnn0iii1001 1011dddddddddddd bldnot.b #<imm>,@(<DISP12>,<REG_N>) */
-{"bldnot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_B,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
-/* 0011nnnn0iii1001 0101dddddddddddd bor.b #<imm>,@(<DISP12>,<REG_N>) */
-{"bor.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_5,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
-/* 0011nnnn0iii1001 1101dddddddddddd bornot.b #<imm>,@(<DISP12>,<REG_N>) */
-{"bornot.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_D,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
-/* 0011nnnn0iii1001 0110dddddddddddd bxor.b #<imm>,@(<DISP12>,<REG_N>) */
-{"bxor.b",{A_IMM,A_DISP_REG_N},{HEX_3,REG_N,IMM0_3Uc,HEX_9,HEX_6,DISP1_12}, arch_sh2a_nofpu_up | arch_op32},
-/* 0000nnnniiii0000 iiiiiiiiiiiiiiii movi20 #<imm>,<REG_N> */
-{"movi20",{A_IMM,A_REG_N},{HEX_0,REG_N,IMM0_20_4,HEX_0,IMM0_20}, arch_sh2a_nofpu_up | arch_op32},
-/* 0000nnnniiii0001 iiiiiiiiiiiiiiii movi20s #<imm>,<REG_N> */
-{"movi20s",{A_IMM,A_REG_N},{HEX_0,REG_N,IMM0_20_4,HEX_1,IMM0_20BY8}, arch_sh2a_nofpu_up | arch_op32},
-/* 0011nnnnmmmm0001 1000dddddddddddd movu.b @(<DISP12>,<REG_M>),<REG_N> */
-{"movu.b",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_8,DISP0_12}, arch_sh2a_nofpu_up | arch_op32},
-/* 0011nnnnmmmm0001 1001dddddddddddd movu.w @(<DISP12>,<REG_M>),<REG_N> */
-{"movu.w",{A_DISP_REG_M,A_REG_N},{HEX_3,REG_N,REG_M,HEX_1,HEX_9,DISP0_12BY2}, arch_sh2a_nofpu_up | arch_op32},
-
-{ 0, {0}, {0}, 0 }
-};
-
-#endif
-
-#ifdef ARCH_all
-#define INCLUDE_SHMEDIA
-#endif
-
-static void print_movxy
- PARAMS ((const sh_opcode_info *, int, int, fprintf_ftype, void *));
-static void print_insn_ddt PARAMS ((int, struct disassemble_info *));
-static void print_dsp_reg PARAMS ((int, fprintf_ftype, void *));
-static void print_insn_ppi PARAMS ((int, struct disassemble_info *));
-
-static void
-print_movxy (op, rn, rm, fprintf_fn, stream)
- const sh_opcode_info *op;
- int rn, rm;
- fprintf_ftype fprintf_fn;
- void *stream;
-{
- int n;
-
- fprintf_fn (stream, "%s\t", op->name);
- for (n = 0; n < 2; n++)
- {
- switch (op->arg[n])
- {
- case A_IND_N:
- case AX_IND_N:
- case AXY_IND_N:
- case AY_IND_N:
- case AYX_IND_N:
- fprintf_fn (stream, "@r%d", rn);
- break;
- case A_INC_N:
- case AX_INC_N:
- case AXY_INC_N:
- case AY_INC_N:
- case AYX_INC_N:
- fprintf_fn (stream, "@r%d+", rn);
- break;
- case AX_PMOD_N:
- case AXY_PMOD_N:
- fprintf_fn (stream, "@r%d+r8", rn);
- break;
- case AY_PMOD_N:
- case AYX_PMOD_N:
- fprintf_fn (stream, "@r%d+r9", rn);
- break;
- case DSP_REG_A_M:
- fprintf_fn (stream, "a%c", '0' + rm);
- break;
- case DSP_REG_X:
- fprintf_fn (stream, "x%c", '0' + rm);
- break;
- case DSP_REG_Y:
- fprintf_fn (stream, "y%c", '0' + rm);
- break;
- case DSP_REG_AX:
- fprintf_fn (stream, "%c%c",
- (rm & 1) ? 'x' : 'a',
- (rm & 2) ? '1' : '0');
- break;
- case DSP_REG_XY:
- fprintf_fn (stream, "%c%c",
- (rm & 1) ? 'y' : 'x',
- (rm & 2) ? '1' : '0');
- break;
- case DSP_REG_AY:
- fprintf_fn (stream, "%c%c",
- (rm & 2) ? 'y' : 'a',
- (rm & 1) ? '1' : '0');
- break;
- case DSP_REG_YX:
- fprintf_fn (stream, "%c%c",
- (rm & 2) ? 'x' : 'y',
- (rm & 1) ? '1' : '0');
- break;
- default:
- abort ();
- }
- if (n == 0)
- fprintf_fn (stream, ",");
- }
-}
-
-/* Print a double data transfer insn. INSN is just the lower three
- nibbles of the insn, i.e. field a and the bit that indicates if
- a parallel processing insn follows.
- Return nonzero if a field b of a parallel processing insns follows. */
-
-static void
-print_insn_ddt (insn, info)
- int insn;
- struct disassemble_info *info;
-{
- fprintf_ftype fprintf_fn = info->fprintf_func;
- void *stream = info->stream;
-
- /* If this is just a nop, make sure to emit something. */
- if (insn == 0x000)
- fprintf_fn (stream, "nopx\tnopy");
-
- /* If a parallel processing insn was printed before,
- and we got a non-nop, emit a tab. */
- if ((insn & 0x800) && (insn & 0x3ff))
- fprintf_fn (stream, "\t");
-
- /* Check if either the x or y part is invalid. */
- if (((insn & 0xc) == 0 && (insn & 0x2a0))
- || ((insn & 3) == 0 && (insn & 0x150)))
- if (info->mach != bfd_mach_sh_dsp
- && info->mach != bfd_mach_sh3_dsp)
- {
- static const sh_opcode_info *first_movx, *first_movy;
- const sh_opcode_info *op;
- int is_movy;
-
- if (! first_movx)
- {
- for (first_movx = sh_table; first_movx->nibbles[1] != MOVX_NOPY;)
- first_movx++;
- for (first_movy = first_movx; first_movy->nibbles[1] != MOVY_NOPX;)
- first_movy++;
- }
-
- is_movy = ((insn & 3) != 0);
-
- if (is_movy)
- op = first_movy;
- else
- op = first_movx;
-
- while (op->nibbles[2] != (unsigned) ((insn >> 4) & 3)
- || op->nibbles[3] != (unsigned) (insn & 0xf))
- op++;
-
- print_movxy (op,
- (4 * ((insn & (is_movy ? 0x200 : 0x100)) == 0)
- + 2 * is_movy
- + 1 * ((insn & (is_movy ? 0x100 : 0x200)) != 0)),
- (insn >> 6) & 3,
- fprintf_fn, stream);
- }
- else
- fprintf_fn (stream, ".word 0x%x", insn);
- else
- {
- static const sh_opcode_info *first_movx, *first_movy;
- const sh_opcode_info *opx, *opy;
- unsigned int insn_x, insn_y;
-
- if (! first_movx)
- {
- for (first_movx = sh_table; first_movx->nibbles[1] != MOVX;)
- first_movx++;
- for (first_movy = first_movx; first_movy->nibbles[1] != MOVY;)
- first_movy++;
- }
- insn_x = (insn >> 2) & 0xb;
- if (insn_x)
- {
- for (opx = first_movx; opx->nibbles[2] != insn_x;)
- opx++;
- print_movxy (opx, ((insn >> 9) & 1) + 4, (insn >> 7) & 1,
- fprintf_fn, stream);
- }
- insn_y = (insn & 3) | ((insn >> 1) & 8);
- if (insn_y)
- {
- if (insn_x)
- fprintf_fn (stream, "\t");
- for (opy = first_movy; opy->nibbles[2] != insn_y;)
- opy++;
- print_movxy (opy, ((insn >> 8) & 1) + 6, (insn >> 6) & 1,
- fprintf_fn, stream);
- }
- }
-}
-
-static void
-print_dsp_reg (rm, fprintf_fn, stream)
- int rm;
- fprintf_ftype fprintf_fn;
- void *stream;
-{
- switch (rm)
- {
- case A_A1_NUM:
- fprintf_fn (stream, "a1");
- break;
- case A_A0_NUM:
- fprintf_fn (stream, "a0");
- break;
- case A_X0_NUM:
- fprintf_fn (stream, "x0");
- break;
- case A_X1_NUM:
- fprintf_fn (stream, "x1");
- break;
- case A_Y0_NUM:
- fprintf_fn (stream, "y0");
- break;
- case A_Y1_NUM:
- fprintf_fn (stream, "y1");
- break;
- case A_M0_NUM:
- fprintf_fn (stream, "m0");
- break;
- case A_A1G_NUM:
- fprintf_fn (stream, "a1g");
- break;
- case A_M1_NUM:
- fprintf_fn (stream, "m1");
- break;
- case A_A0G_NUM:
- fprintf_fn (stream, "a0g");
- break;
- default:
- fprintf_fn (stream, "0x%x", rm);
- break;
- }
-}
-
-static void
-print_insn_ppi (field_b, info)
- int field_b;
- struct disassemble_info *info;
-{
- static char *sx_tab[] = { "x0", "x1", "a0", "a1" };
- static char *sy_tab[] = { "y0", "y1", "m0", "m1" };
- fprintf_ftype fprintf_fn = info->fprintf_func;
- void *stream = info->stream;
- unsigned int nib1, nib2, nib3;
- unsigned int altnib1, nib4;
- char *dc = NULL;
- const sh_opcode_info *op;
-
- if ((field_b & 0xe800) == 0)
- {
- fprintf_fn (stream, "psh%c\t#%d,",
- field_b & 0x1000 ? 'a' : 'l',
- (field_b >> 4) & 127);
- print_dsp_reg (field_b & 0xf, fprintf_fn, stream);
- return;
- }
- if ((field_b & 0xc000) == 0x4000 && (field_b & 0x3000) != 0x1000)
- {
- static char *du_tab[] = { "x0", "y0", "a0", "a1" };
- static char *se_tab[] = { "x0", "x1", "y0", "a1" };
- static char *sf_tab[] = { "y0", "y1", "x0", "a1" };
- static char *sg_tab[] = { "m0", "m1", "a0", "a1" };
-
- if (field_b & 0x2000)
- {
- fprintf_fn (stream, "p%s %s,%s,%s\t",
- (field_b & 0x1000) ? "add" : "sub",
- sx_tab[(field_b >> 6) & 3],
- sy_tab[(field_b >> 4) & 3],
- du_tab[(field_b >> 0) & 3]);
- }
- else if ((field_b & 0xf0) == 0x10
- && info->mach != bfd_mach_sh_dsp
- && info->mach != bfd_mach_sh3_dsp)
- {
- fprintf_fn (stream, "pclr %s \t", du_tab[(field_b >> 0) & 3]);
- }
- else if ((field_b & 0xf3) != 0)
- {
- fprintf_fn (stream, ".word 0x%x\t", field_b);
- }
- fprintf_fn (stream, "pmuls%c%s,%s,%s",
- field_b & 0x2000 ? ' ' : '\t',
- se_tab[(field_b >> 10) & 3],
- sf_tab[(field_b >> 8) & 3],
- sg_tab[(field_b >> 2) & 3]);
- return;
- }
-
- nib1 = PPIC;
- nib2 = field_b >> 12 & 0xf;
- nib3 = field_b >> 8 & 0xf;
- nib4 = field_b >> 4 & 0xf;
- switch (nib3 & 0x3)
- {
- case 0:
- dc = "";
- nib1 = PPI3;
- break;
- case 1:
- dc = "";
- break;
- case 2:
- dc = "dct ";
- nib3 -= 1;
- break;
- case 3:
- dc = "dcf ";
- nib3 -= 2;
- break;
- }
- if (nib1 == PPI3)
- altnib1 = PPI3NC;
- else
- altnib1 = nib1;
- for (op = sh_table; op->name; op++)
- {
- if ((op->nibbles[1] == nib1 || op->nibbles[1] == altnib1)
- && op->nibbles[2] == nib2
- && op->nibbles[3] == nib3)
- {
- int n;
-
- switch (op->nibbles[4])
- {
- case HEX_0:
- break;
- case HEX_XX00:
- if ((nib4 & 3) != 0)
- continue;
- break;
- case HEX_1:
- if ((nib4 & 3) != 1)
- continue;
- break;
- case HEX_00YY:
- if ((nib4 & 0xc) != 0)
- continue;
- break;
- case HEX_4:
- if ((nib4 & 0xc) != 4)
- continue;
- break;
- default:
- abort ();
- }
- fprintf_fn (stream, "%s%s\t", dc, op->name);
- for (n = 0; n < 3 && op->arg[n] != A_END; n++)
- {
- if (n && op->arg[1] != A_END)
- fprintf_fn (stream, ",");
- switch (op->arg[n])
- {
- case DSP_REG_N:
- print_dsp_reg (field_b & 0xf, fprintf_fn, stream);
- break;
- case DSP_REG_X:
- fprintf_fn (stream, sx_tab[(field_b >> 6) & 3]);
- break;
- case DSP_REG_Y:
- fprintf_fn (stream, sy_tab[(field_b >> 4) & 3]);
- break;
- case A_MACH:
- fprintf_fn (stream, "mach");
- break;
- case A_MACL:
- fprintf_fn (stream, "macl");
- break;
- default:
- abort ();
- }
- }
- return;
- }
- }
- /* Not found. */
- fprintf_fn (stream, ".word 0x%x", field_b);
-}
-
-/* FIXME mvs: movx insns print as ".word 0x%03x", insn & 0xfff
- (ie. the upper nibble is missing). */
-int
-print_insn_sh (memaddr, info)
- bfd_vma memaddr;
- struct disassemble_info *info;
-{
- fprintf_ftype fprintf_fn = info->fprintf_func;
- void *stream = info->stream;
- unsigned char insn[4];
- unsigned char nibs[8];
- int status;
- bfd_vma relmask = ~(bfd_vma) 0;
- const sh_opcode_info *op;
- unsigned int target_arch;
- int allow_op32;
-
- switch (info->mach)
- {
- case bfd_mach_sh:
- target_arch = arch_sh1;
- break;
- case bfd_mach_sh4:
- target_arch = arch_sh4;
- break;
- case bfd_mach_sh5:
-#ifdef INCLUDE_SHMEDIA
- status = print_insn_sh64 (memaddr, info);
- if (status != -2)
- return status;
-#endif
- /* When we get here for sh64, it's because we want to disassemble
- SHcompact, i.e. arch_sh4. */
- target_arch = arch_sh4;
- break;
- default:
- fprintf (stderr, "sh architecture not supported\n");
- return -1;
- }
-
- status = info->read_memory_func (memaddr, insn, 2, info);
-
- if (status != 0)
- {
- info->memory_error_func (status, memaddr, info);
- return -1;
- }
-
- if (info->endian == BFD_ENDIAN_LITTLE)
- {
- nibs[0] = (insn[1] >> 4) & 0xf;
- nibs[1] = insn[1] & 0xf;
-
- nibs[2] = (insn[0] >> 4) & 0xf;
- nibs[3] = insn[0] & 0xf;
- }
- else
- {
- nibs[0] = (insn[0] >> 4) & 0xf;
- nibs[1] = insn[0] & 0xf;
-
- nibs[2] = (insn[1] >> 4) & 0xf;
- nibs[3] = insn[1] & 0xf;
- }
- status = info->read_memory_func (memaddr + 2, insn + 2, 2, info);
- if (status != 0)
- allow_op32 = 0;
- else
- {
- allow_op32 = 1;
-
- if (info->endian == BFD_ENDIAN_LITTLE)
- {
- nibs[4] = (insn[3] >> 4) & 0xf;
- nibs[5] = insn[3] & 0xf;
-
- nibs[6] = (insn[2] >> 4) & 0xf;
- nibs[7] = insn[2] & 0xf;
- }
- else
- {
- nibs[4] = (insn[2] >> 4) & 0xf;
- nibs[5] = insn[2] & 0xf;
-
- nibs[6] = (insn[3] >> 4) & 0xf;
- nibs[7] = insn[3] & 0xf;
- }
- }
-
- if (nibs[0] == 0xf && (nibs[1] & 4) == 0
- && SH_MERGE_ARCH_SET_VALID (target_arch, arch_sh_dsp_up))
- {
- if (nibs[1] & 8)
- {
- int field_b;
-
- status = info->read_memory_func (memaddr + 2, insn, 2, info);
-
- if (status != 0)
- {
- info->memory_error_func (status, memaddr + 2, info);
- return -1;
- }
-
- if (info->endian == BFD_ENDIAN_LITTLE)
- field_b = insn[1] << 8 | insn[0];
- else
- field_b = insn[0] << 8 | insn[1];
-
- print_insn_ppi (field_b, info);
- print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info);
- return 4;
- }
- print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info);
- return 2;
- }
- for (op = sh_table; op->name; op++)
- {
- int n;
- int imm = 0;
- int rn = 0;
- int rm = 0;
- int rb = 0;
- int disp_pc;
- bfd_vma disp_pc_addr = 0;
- int disp = 0;
- int has_disp = 0;
- int max_n = SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 8 : 4;
-
- if (!allow_op32
- && SH_MERGE_ARCH_SET (op->arch, arch_op32))
- goto fail;
-
- if (!SH_MERGE_ARCH_SET_VALID (op->arch, target_arch))
- goto fail;
- for (n = 0; n < max_n; n++)
- {
- int i = op->nibbles[n];
-
- if (i < 16)
- {
- if (nibs[n] == i)
- continue;
- goto fail;
- }
- switch (i)
- {
- case BRANCH_8:
- imm = (nibs[2] << 4) | (nibs[3]);
- if (imm & 0x80)
- imm |= ~0xff;
- imm = ((char) imm) * 2 + 4;
- goto ok;
- case BRANCH_12:
- imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]);
- if (imm & 0x800)
- imm |= ~0xfff;
- imm = imm * 2 + 4;
- goto ok;
- case IMM0_3c:
- if (nibs[3] & 0x8)
- goto fail;
- imm = nibs[3] & 0x7;
- break;
- case IMM0_3s:
- if (!(nibs[3] & 0x8))
- goto fail;
- imm = nibs[3] & 0x7;
- break;
- case IMM0_3Uc:
- if (nibs[2] & 0x8)
- goto fail;
- imm = nibs[2] & 0x7;
- break;
- case IMM0_3Us:
- if (!(nibs[2] & 0x8))
- goto fail;
- imm = nibs[2] & 0x7;
- break;
- case DISP0_12:
- case DISP1_12:
- disp = (nibs[5] << 8) | (nibs[6] << 4) | nibs[7];
- has_disp = 1;
- goto ok;
- case DISP0_12BY2:
- case DISP1_12BY2:
- disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 1;
- relmask = ~(bfd_vma) 1;
- has_disp = 1;
- goto ok;
- case DISP0_12BY4:
- case DISP1_12BY4:
- disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 2;
- relmask = ~(bfd_vma) 3;
- has_disp = 1;
- goto ok;
- case DISP0_12BY8:
- case DISP1_12BY8:
- disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 3;
- relmask = ~(bfd_vma) 7;
- has_disp = 1;
- goto ok;
- case IMM0_20_4:
- break;
- case IMM0_20:
- imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8)
- | (nibs[6] << 4) | nibs[7]);
- if (imm & 0x80000)
- imm -= 0x100000;
- goto ok;
- case IMM0_20BY8:
- imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8)
- | (nibs[6] << 4) | nibs[7]);
- imm <<= 8;
- if (imm & 0x8000000)
- imm -= 0x10000000;
- goto ok;
- case IMM0_4:
- case IMM1_4:
- imm = nibs[3];
- goto ok;
- case IMM0_4BY2:
- case IMM1_4BY2:
- imm = nibs[3] << 1;
- goto ok;
- case IMM0_4BY4:
- case IMM1_4BY4:
- imm = nibs[3] << 2;
- goto ok;
- case IMM0_8:
- case IMM1_8:
- imm = (nibs[2] << 4) | nibs[3];
- disp = imm;
- has_disp = 1;
- if (imm & 0x80)
- imm -= 0x100;
- goto ok;
- case PCRELIMM_8BY2:
- imm = ((nibs[2] << 4) | nibs[3]) << 1;
- relmask = ~(bfd_vma) 1;
- goto ok;
- case PCRELIMM_8BY4:
- imm = ((nibs[2] << 4) | nibs[3]) << 2;
- relmask = ~(bfd_vma) 3;
- goto ok;
- case IMM0_8BY2:
- case IMM1_8BY2:
- imm = ((nibs[2] << 4) | nibs[3]) << 1;
- goto ok;
- case IMM0_8BY4:
- case IMM1_8BY4:
- imm = ((nibs[2] << 4) | nibs[3]) << 2;
- goto ok;
- case REG_N_D:
- if ((nibs[n] & 1) != 0)
- goto fail;
- /* fall through */
- case REG_N:
- rn = nibs[n];
- break;
- case REG_M:
- rm = nibs[n];
- break;
- case REG_N_B01:
- if ((nibs[n] & 0x3) != 1 /* binary 01 */)
- goto fail;
- rn = (nibs[n] & 0xc) >> 2;
- break;
- case REG_NM:
- rn = (nibs[n] & 0xc) >> 2;
- rm = (nibs[n] & 0x3);
- break;
- case REG_B:
- rb = nibs[n] & 0x07;
- break;
- case SDT_REG_N:
- /* sh-dsp: single data transfer. */
- rn = nibs[n];
- if ((rn & 0xc) != 4)
- goto fail;
- rn = rn & 0x3;
- rn |= (!(rn & 2)) << 2;
- break;
- case PPI:
- case REPEAT:
- goto fail;
- default:
- abort ();
- }
- }
-
- ok:
- /* sh2a has D_REG but not X_REG. We don't know the pattern
- doesn't match unless we check the output args to see if they
- make sense. */
- if (target_arch == arch_sh2a
- && ((op->arg[0] == DX_REG_M && (rm & 1) != 0)
- || (op->arg[1] == DX_REG_N && (rn & 1) != 0)))
- goto fail;
-
- fprintf_fn (stream, "%s\t", op->name);
- disp_pc = 0;
- for (n = 0; n < 3 && op->arg[n] != A_END; n++)
- {
- if (n && op->arg[1] != A_END)
- fprintf_fn (stream, ",");
- switch (op->arg[n])
- {
- case A_IMM:
- fprintf_fn (stream, "#%d", imm);
- break;
- case A_R0:
- fprintf_fn (stream, "r0");
- break;
- case A_REG_N:
- fprintf_fn (stream, "r%d", rn);
- break;
- case A_INC_N:
- case AS_INC_N:
- fprintf_fn (stream, "@r%d+", rn);
- break;
- case A_DEC_N:
- case AS_DEC_N:
- fprintf_fn (stream, "@-r%d", rn);
- break;
- case A_IND_N:
- case AS_IND_N:
- fprintf_fn (stream, "@r%d", rn);
- break;
- case A_DISP_REG_N:
- fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rn);
- break;
- case AS_PMOD_N:
- fprintf_fn (stream, "@r%d+r8", rn);
- break;
- case A_REG_M:
- fprintf_fn (stream, "r%d", rm);
- break;
- case A_INC_M:
- fprintf_fn (stream, "@r%d+", rm);
- break;
- case A_DEC_M:
- fprintf_fn (stream, "@-r%d", rm);
- break;
- case A_IND_M:
- fprintf_fn (stream, "@r%d", rm);
- break;
- case A_DISP_REG_M:
- fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rm);
- break;
- case A_REG_B:
- fprintf_fn (stream, "r%d_bank", rb);
- break;
- case A_DISP_PC:
- disp_pc = 1;
- disp_pc_addr = imm + 4 + (memaddr & relmask);
- (*info->print_address_func) (disp_pc_addr, info);
- break;
- case A_IND_R0_REG_N:
- fprintf_fn (stream, "@(r0,r%d)", rn);
- break;
- case A_IND_R0_REG_M:
- fprintf_fn (stream, "@(r0,r%d)", rm);
- break;
- case A_DISP_GBR:
- fprintf_fn (stream, "@(%d,gbr)", has_disp?disp:imm);
- break;
- case A_TBR:
- fprintf_fn (stream, "tbr");
- break;
- case A_DISP2_TBR:
- fprintf_fn (stream, "@@(%d,tbr)", has_disp?disp:imm);
- break;
- case A_INC_R15:
- fprintf_fn (stream, "@r15+");
- break;
- case A_DEC_R15:
- fprintf_fn (stream, "@-r15");
- break;
- case A_R0_GBR:
- fprintf_fn (stream, "@(r0,gbr)");
- break;
- case A_BDISP12:
- case A_BDISP8:
- {
- bfd_vma addr;
- addr = imm + memaddr;
- (*info->print_address_func) (addr, info);
- }
- break;
- case A_SR:
- fprintf_fn (stream, "sr");
- break;
- case A_GBR:
- fprintf_fn (stream, "gbr");
- break;
- case A_VBR:
- fprintf_fn (stream, "vbr");
- break;
- case A_DSR:
- fprintf_fn (stream, "dsr");
- break;
- case A_MOD:
- fprintf_fn (stream, "mod");
- break;
- case A_RE:
- fprintf_fn (stream, "re");
- break;
- case A_RS:
- fprintf_fn (stream, "rs");
- break;
- case A_A0:
- fprintf_fn (stream, "a0");
- break;
- case A_X0:
- fprintf_fn (stream, "x0");
- break;
- case A_X1:
- fprintf_fn (stream, "x1");
- break;
- case A_Y0:
- fprintf_fn (stream, "y0");
- break;
- case A_Y1:
- fprintf_fn (stream, "y1");
- break;
- case DSP_REG_M:
- print_dsp_reg (rm, fprintf_fn, stream);
- break;
- case A_SSR:
- fprintf_fn (stream, "ssr");
- break;
- case A_SPC:
- fprintf_fn (stream, "spc");
- break;
- case A_MACH:
- fprintf_fn (stream, "mach");
- break;
- case A_MACL:
- fprintf_fn (stream, "macl");
- break;
- case A_PR:
- fprintf_fn (stream, "pr");
- break;
- case A_SGR:
- fprintf_fn (stream, "sgr");
- break;
- case A_DBR:
- fprintf_fn (stream, "dbr");
- break;
- case F_REG_N:
- fprintf_fn (stream, "fr%d", rn);
- break;
- case F_REG_M:
- fprintf_fn (stream, "fr%d", rm);
- break;
- case DX_REG_N:
- if (rn & 1)
- {
- fprintf_fn (stream, "xd%d", rn & ~1);
- break;
- }
- case D_REG_N:
- fprintf_fn (stream, "dr%d", rn);
- break;
- case DX_REG_M:
- if (rm & 1)
- {
- fprintf_fn (stream, "xd%d", rm & ~1);
- break;
- }
- case D_REG_M:
- fprintf_fn (stream, "dr%d", rm);
- break;
- case FPSCR_M:
- case FPSCR_N:
- fprintf_fn (stream, "fpscr");
- break;
- case FPUL_M:
- case FPUL_N:
- fprintf_fn (stream, "fpul");
- break;
- case F_FR0:
- fprintf_fn (stream, "fr0");
- break;
- case V_REG_N:
- fprintf_fn (stream, "fv%d", rn * 4);
- break;
- case V_REG_M:
- fprintf_fn (stream, "fv%d", rm * 4);
- break;
- case XMTRX_M4:
- fprintf_fn (stream, "xmtrx");
- break;
- default:
- abort ();
- }
- }
-
-#if 0
- /* This code prints instructions in delay slots on the same line
- as the instruction which needs the delay slots. This can be
- confusing, since other disassembler don't work this way, and
- it means that the instructions are not all in a line. So I
- disabled it. Ian. */
- if (!(info->flags & 1)
- && (op->name[0] == 'j'
- || (op->name[0] == 'b'
- && (op->name[1] == 'r'
- || op->name[1] == 's'))
- || (op->name[0] == 'r' && op->name[1] == 't')
- || (op->name[0] == 'b' && op->name[2] == '.')))
- {
- info->flags |= 1;
- fprintf_fn (stream, "\t(slot ");
- print_insn_sh (memaddr + 2, info);
- info->flags &= ~1;
- fprintf_fn (stream, ")");
- return 4;
- }
-#endif
-
- if (disp_pc && strcmp (op->name, "mova") != 0)
- {
- int size;
- bfd_byte bytes[4];
-
- if (relmask == ~(bfd_vma) 1)
- size = 2;
- else
- size = 4;
- status = info->read_memory_func (disp_pc_addr, bytes, size, info);
- if (status == 0)
- {
- unsigned int val;
-
- if (size == 2)
- {
- if (info->endian == BFD_ENDIAN_LITTLE)
- val = bfd_getl16 (bytes);
- else
- val = bfd_getb16 (bytes);
- }
- else
- {
- if (info->endian == BFD_ENDIAN_LITTLE)
- val = bfd_getl32 (bytes);
- else
- val = bfd_getb32 (bytes);
- }
- if ((*info->symbol_at_address_func) (val, info))
- {
- fprintf_fn (stream, "\t! 0x");
- (*info->print_address_func) (val, info);
- }
- else
- fprintf_fn (stream, "\t! 0x%x", val);
- }
- }
-
- return SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 4 : 2;
- fail:
- ;
-
- }
- fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]);
- return 2;
-}
diff --git a/shaper.c b/shaper.c
new file mode 100644
index 0000000..83e5aea
--- /dev/null
+++ b/shaper.c
@@ -0,0 +1,593 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "shaper.h"
+#include "vl.h"
+#include <stdlib.h>
+
+#define SHAPER_CLOCK rt_clock
+#define SHAPER_CLOCK_UNIT 1000.
+
+static int
+_packet_is_internal( const uint8_t* data, size_t size )
+{
+ const uint8_t* end = data + size;
+
+ /* must have room for Mac + IP header */
+ if (data + 40 > end)
+ return 0;
+
+ if (data[12] != 0x08 || data[13] != 0x00 )
+ return 0;
+
+ /* must have valid IP header */
+ data += 14;
+ if ((data[0] >> 4) != 4 || (data[0] & 15) < 5)
+ return 0;
+
+ /* internal if both source and dest addresses are in 10.x.x.x */
+ return ( data[12] == 10 && data[16] == 10);
+}
+
+/* here's how we implement network shaping. we want to limit the network
+ * rate to a given constant MAX_RATE expressed as bits/second. this means
+ * that it takes 1/MAX_RATE seconds to send a single bit, and count*8/MAX_RATE
+ * seconds to send 'count' bytes.
+ *
+ * we're going to implement a scheme where, when we send a packet of
+ * 'count' bytes, no other packet will go through in the same direction for
+ * at least 'count*8/MAX_RATE' seconds. any successive packet that is "sent"
+ * in this interval is placed in a queue, associated to a timer
+ *
+ * there are different (queue/timer/rate) values for the input and output
+ * direction of the user vlan.
+ */
+typedef struct QueuedPacketRec_ {
+ int64_t expiration;
+ struct QueuedPacketRec_* next;
+ size_t size;
+ void* opaque;
+ void* data;
+} QueuedPacketRec, *QueuedPacket;
+
+
+static QueuedPacket
+queued_packet_create( const void* data,
+ size_t size,
+ void* opaque,
+ int do_copy )
+{
+ QueuedPacket packet;
+ size_t packet_size = sizeof(*packet);
+
+ if (do_copy)
+ packet_size += size;
+
+ packet = qemu_malloc(packet_size);
+ packet->next = NULL;
+ packet->expiration = 0;
+ packet->size = (size_t)size;
+ packet->opaque = opaque;
+
+ if (do_copy) {
+ packet->data = (void*)(packet+1);
+ memcpy( (char*)packet->data, (char*)data, packet->size );
+ } else {
+ packet->data = (void*)data;
+ }
+ return packet;
+}
+
+static void
+queued_packet_free( QueuedPacket packet )
+{
+ if (packet) {
+ qemu_free( packet );
+ }
+}
+
+typedef struct NetShaperRec_ {
+ QueuedPacket packets; /* list of queued packets, ordered by expiration date */
+ int num_packets;
+ int active; /* is this shaper active ? */
+ int64_t block_until;
+ double max_rate; /* max rate expressed in bytes/second */
+ double inv_rate; /* inverse of max rate */
+ QEMUTimer* timer; /* QEMU timer */
+
+ int do_copy;
+ NetShaperSendFunc send_func;
+
+} NetShaperRec;
+
+
+void
+netshaper_destroy( NetShaper shaper )
+{
+ if (shaper) {
+ shaper->active = 0;
+
+ while (shaper->packets) {
+ QueuedPacket packet = shaper->packets;
+ shaper->packets = packet->next;
+ packet->next = NULL;
+ queued_packet_free(packet);
+ }
+
+ qemu_del_timer(shaper->timer);
+ qemu_free_timer(shaper->timer);
+ shaper->timer = NULL;
+ qemu_free(shaper);
+ }
+}
+
+/* this function is called when the shaper's timer expires */
+static void
+netshaper_expires( NetShaper shaper )
+{
+ QueuedPacket packet;
+
+ while ((packet = shaper->packets) != NULL) {
+ int64_t now = qemu_get_clock( SHAPER_CLOCK );
+
+ if (packet->expiration > now)
+ break;
+
+ shaper->packets = packet->next;
+ shaper->send_func( packet->data, packet->size, packet->opaque );
+ queued_packet_free(packet);
+ shaper->num_packets--;
+ }
+
+ /* reprogram timer if needed */
+ if (shaper->packets) {
+ shaper->block_until = shaper->packets->expiration;
+ qemu_mod_timer( shaper->timer, shaper->block_until );
+ } else {
+ shaper->block_until = -1;
+ }
+}
+
+
+NetShaper
+netshaper_create( int do_copy,
+ NetShaperSendFunc send_func )
+{
+ NetShaper shaper = qemu_malloc(sizeof(*shaper));
+
+ init_timers();
+
+ shaper->active = 0;
+ shaper->packets = NULL;
+ shaper->num_packets = 0;
+ shaper->timer = qemu_new_timer( SHAPER_CLOCK,
+ (QEMUTimerCB*) netshaper_expires,
+ shaper );
+ shaper->send_func = send_func;
+ shaper->max_rate = 1e6;
+ shaper->inv_rate = 0.;
+
+ shaper->block_until = -1; /* magic value, means to not block */
+
+ return shaper;
+}
+
+void
+netshaper_set_rate( NetShaper shaper,
+ double rate )
+{
+ /* send all current packets when changing the rate */
+ while (shaper->packets) {
+ QueuedPacket packet = shaper->packets;
+ shaper->packets = packet->next;
+ shaper->send_func(packet->data, packet->size, packet->opaque);
+ qemu_free(packet);
+ shaper->num_packets = 0;
+ }
+
+ shaper->max_rate = rate;
+ if (rate > 1.) {
+ shaper->inv_rate = (8.*SHAPER_CLOCK_UNIT)/rate; /* qemu_get_clock returns time in ms */
+ shaper->active = 1; /* for the real-time clock */
+ } else {
+ shaper->active = 0;
+ }
+
+ shaper->block_until = -1;
+}
+
+void
+netshaper_send_aux( NetShaper shaper,
+ void* data,
+ size_t size,
+ void* opaque )
+{
+ int64_t now;
+
+ if (!shaper->active || _packet_is_internal(data, size)) {
+ shaper->send_func( data, size, opaque );
+ return;
+ }
+
+ now = qemu_get_clock( SHAPER_CLOCK );
+ if (now >= shaper->block_until) {
+ shaper->send_func( data, size, opaque );
+ shaper->block_until = now + size*shaper->inv_rate;
+ //fprintf(stderr, "NETSHAPER: block for %.2fms\n", (shaper->block_until - now)*1.0 );
+ return;
+ }
+
+ /* create new packet, add it to the queue */
+ {
+ QueuedPacket packet;
+
+ packet = queued_packet_create( data, size, opaque, shaper->do_copy );
+
+ packet->expiration = shaper->block_until;
+
+ {
+ QueuedPacket *pnode, node;
+
+ pnode = &shaper->packets;
+ for (;;) {
+ node = *pnode;
+ if (node == NULL || node->expiration > packet->expiration )
+ break;
+ pnode = &node->next;
+ }
+ packet->next = *pnode;
+ *pnode = packet;
+
+ if (packet == shaper->packets)
+ qemu_mod_timer( shaper->timer, packet->expiration );
+ }
+ shaper->num_packets += 1;
+ }
+ shaper->block_until += size*shaper->inv_rate;
+ //fprintf(stderr, "NETSHAPER: block2 for %.2fms\n", (shaper->block_until - now)*1.0 );
+}
+
+void
+netshaper_send( NetShaper shaper,
+ void* data,
+ size_t size )
+{
+ netshaper_send_aux(shaper, data, size, NULL);
+}
+
+
+int
+netshaper_can_send( NetShaper shaper )
+{
+ int64_t now;
+
+ if (!shaper->active || shaper->block_until < 0)
+ return 1;
+
+ if (shaper->packets)
+ return 0;
+
+ now = qemu_get_clock( SHAPER_CLOCK );
+ return (now >= shaper->block_until);
+}
+
+
+
+
+
+
+/* this type is used to model a session connection/state
+ * if session->packet is != NULL, then the connection is delayed
+ */
+typedef struct SessionRec_ {
+ int64_t expiration;
+ struct SessionRec_* next;
+ unsigned src_ip;
+ unsigned dst_ip;
+ unsigned short src_port;
+ unsigned short dst_port;
+ uint8_t protocol;
+ QueuedPacket packet;
+
+} SessionRec, *Session;
+
+#define _PROTOCOL_TCP 6
+#define _PROTOCOL_UDP 17
+
+
+
+static void
+session_free( Session session )
+{
+ if (session) {
+ if (session->packet) {
+ queued_packet_free(session->packet);
+ session->packet = NULL;
+ }
+ qemu_free( session );
+ }
+}
+
+
+#if 0 /* useful for debugging */
+static const char*
+session_to_string( Session session )
+{
+ static char temp[256];
+ const char* format = (session->protocol == _PROTOCOL_TCP) ? "TCP" : "UDP";
+ sprintf( temp, "%s[%d.%d.%d.%d:%d / %d.%d.%d.%d:%d]", format,
+ (session->src_ip >> 24) & 255, (session->src_ip >> 16) & 255,
+ (session->src_ip >> 8) & 255, (session->src_ip) & 255, session->src_port,
+ (session->dst_ip >> 24) & 255, (session->dst_ip >> 16) & 255,
+ (session->dst_ip >> 8) & 255, (session->dst_ip) & 255, session->dst_port);
+
+ return temp;
+}
+#endif
+
+/* returns TRUE if this corresponds to a SYN packet */
+int
+_packet_SYN_flags( const void* _data, size_t size, Session info )
+{
+ const uint8_t* data = (const uint8_t*)_data;
+ const uint8_t* end = data + size;
+
+ /* enough room for a Ethernet MAC packet ? */
+ if (data + 14 > end - 4)
+ return 0;
+
+ /* is it an IP packet ? */
+ if (data[12] != 0x8 || data[13] != 0)
+ return 0;
+
+ data += 14;
+ end -= 4;
+
+ if (data + 20 > end)
+ return 0;
+
+ /* IP version must be 4, and the header length in words at least 5 */
+ if ((data[0] & 0xF) < 5 || (data[0] >> 4) != 4)
+ return 0;
+
+ /* time-to-live must be > 0 */
+ if (data[8] == 0)
+ return 0;
+
+ /* must be TCP or UDP packet */
+ if (data[9] != _PROTOCOL_TCP && data[9] != _PROTOCOL_UDP)
+ return 0;
+
+ info->protocol = data[9];
+ info->src_ip = (data[12] << 24) | (data[13] << 16) | (data[14] << 8) | data[15];
+ info->dst_ip = (data[16] << 24) | (data[17] << 16) | (data[18] << 8) | data[19];
+
+ data += 4*(data[0] & 15);
+ if (data + 20 > end)
+ return 0;
+
+ info->src_port = (unsigned short)((data[0] << 8) | data[1]);
+ info->dst_port = (unsigned short)((data[2] << 8) | data[3]);
+
+ return (data[13] & 0x1f);
+}
+
+
+typedef struct NetDelayRec_
+{
+ Session sessions;
+ int num_sessions;
+ QEMUTimer* timer;
+ int active;
+ int min_ms;
+ int max_ms;
+
+ NetShaperSendFunc send_func;
+
+} NetDelayRec;
+
+
+static Session*
+netdelay_lookup_session( NetDelay delay, Session info )
+{
+ Session* pnode = &delay->sessions;
+ Session node;
+
+ for (;;) {
+ node = *pnode;
+ if (node == NULL)
+ break;
+
+ if (node->src_ip == info->src_ip &&
+ node->dst_ip == info->dst_ip &&
+ node->src_port == info->src_port &&
+ node->dst_port == info->dst_port &&
+ node->protocol == info->protocol )
+ break;
+
+ pnode = &node->next;
+ }
+ return pnode;
+}
+
+
+
+/* called by the delay's timer on expiration */
+static void
+netdelay_expires( NetDelay delay )
+{
+ Session session;
+ int64_t now = qemu_get_clock( SHAPER_CLOCK );
+ int rearm = 0;
+ int64_t rearm_time = 0;
+
+ for (session = delay->sessions; session != NULL; session = session->next)
+ {
+ QueuedPacket packet = session->packet;
+
+ if (packet == NULL)
+ continue;
+
+ if (session->expiration <= now) {
+ /* send the SYN packet now */
+ //fprintf(stderr, "NetDelay:RST: sending creation for %s\n", session_to_string(session) );
+ delay->send_func( packet->data, packet->size, packet->opaque );
+ session->packet = NULL;
+ queued_packet_free( packet );
+ } else {
+ if (!rearm) {
+ rearm = 1;
+ rearm_time = session->expiration;
+ }
+ else if ( session->expiration < rearm_time )
+ rearm_time = session->expiration;
+ }
+ }
+
+ if (rearm)
+ qemu_mod_timer( delay->timer, rearm_time );
+}
+
+
+NetDelay
+netdelay_create( NetShaperSendFunc send_func )
+{
+ NetDelay delay = qemu_malloc(sizeof(*delay));
+
+ init_timers();
+
+ delay->sessions = NULL;
+ delay->num_sessions = 0;
+ delay->timer = qemu_new_timer( SHAPER_CLOCK,
+ (QEMUTimerCB*) netdelay_expires,
+ delay );
+ delay->active = 0;
+ delay->min_ms = 0;
+ delay->max_ms = 0;
+
+ delay->send_func = send_func;
+
+ return delay;
+}
+
+
+void
+netdelay_set_latency( NetDelay delay, int min_ms, int max_ms )
+{
+ /* when changing the latency, accept all sessions */
+ while (delay->sessions) {
+ Session session = delay->sessions;
+ delay->sessions = session->next;
+ session->next = NULL;
+ if (session->packet) {
+ QueuedPacket packet = session->packet;
+ delay->send_func( packet->data, packet->size, packet->opaque );
+ }
+ session_free(session);
+ delay->num_sessions--;
+ }
+
+ delay->min_ms = min_ms;
+ delay->max_ms = max_ms;
+ delay->active = (min_ms <= max_ms) && min_ms > 0;
+}
+
+void
+netdelay_send( NetDelay delay, const void* data, size_t size )
+{
+ netdelay_send_aux(delay, data, size, NULL);
+}
+
+
+void
+netdelay_send_aux( NetDelay delay, const void* data, size_t size, void* opaque )
+{
+ if (delay->active && !_packet_is_internal(data, size)) {
+ SessionRec info[1];
+ int flags;
+
+ flags = _packet_SYN_flags( data, size, info );
+ if ((flags & 0x05) != 0)
+ { /* FIN or RST: drop connection */
+ Session* lookup = netdelay_lookup_session( delay, info );
+ Session session = *lookup;
+ if (session != NULL) {
+ //fprintf(stderr, "NetDelay:RST: dropping %s\n", session_to_string(info) );
+
+ *lookup = session->next;
+ session_free( session );
+ delay->num_sessions -= 1;
+ }
+ }
+ else if ((flags & 0x12) == 0x02)
+ {
+ /* SYN: create connection */
+ Session* lookup = netdelay_lookup_session( delay, info );
+ Session session = *lookup;
+
+ if (session != NULL) {
+ if (session->packet != NULL) {
+ /* this is a SYN re-transmission, since we didn't
+ * send the original SYN packet yet, just eat this one
+ */
+ //fprintf(stderr, "NetDelay:RST: swallow SYN re-send for %s\n", session_to_string(info) );
+ return;
+ }
+ } else {
+ /* establish a new session slightly in the future */
+ int latency = delay->min_ms;
+ int range = delay->max_ms - delay->min_ms;
+
+ if (delay > 0)
+ latency += rand() % range;
+
+ //fprintf(stderr, "NetDelay:RST: delay creation for %s\n", session_to_string(info) );
+ session = qemu_malloc( sizeof(*session) );
+
+ session->next = delay->sessions;
+ delay->sessions = session;
+ delay->num_sessions += 1;
+
+ session->expiration = qemu_get_clock( SHAPER_CLOCK ) + latency;
+
+ session->src_ip = info->src_ip;
+ session->dst_ip = info->dst_ip;
+ session->src_port = info->src_port;
+ session->dst_port = info->dst_port;
+ session->protocol = info->protocol;
+
+ session->packet = queued_packet_create( data, size, opaque, 1 );
+
+ netdelay_expires(delay);
+ return;
+ }
+ }
+ }
+
+ delay->send_func( (void*)data, size, opaque );
+}
+
+
+void
+netdelay_destroy( NetDelay delay )
+{
+ if (delay) {
+ while (delay->sessions) {
+ Session session = delay->sessions;
+ delay->sessions = session->next;
+ session_free(session);
+ delay->num_sessions -= 1;
+ }
+ delay->active = 0;
+ qemu_free( delay );
+ }
+}
+
diff --git a/shaper.h b/shaper.h
new file mode 100644
index 0000000..263e19f
--- /dev/null
+++ b/shaper.h
@@ -0,0 +1,51 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _SLIRP_SHAPER_H_
+#define _SLIRP_SHAPER_H_
+
+#include "vl.h"
+
+/* a NetShaper object is used to limit the throughput of data packets
+ * at a fixed rate expressed in bits/seconds
+ */
+typedef struct NetShaperRec_* NetShaper;
+typedef void (*NetShaperSendFunc)( void* data, size_t size, void* opaque);
+
+NetShaper netshaper_create ( int do_copy,
+ NetShaperSendFunc send_func );
+
+void netshaper_set_rate(NetShaper shaper, double rate );
+
+void netshaper_send( NetShaper shaper, void* data, size_t size );
+
+void netshaper_send_aux( NetShaper shaper, void* data, size_t size, void* opaque );
+
+int netshaper_can_send( NetShaper shaper );
+
+void netshaper_destroy (NetShaper shaper);
+
+/* a NetDelay object is used to simulate network connection latencies */
+typedef struct NetDelayRec_* NetDelay;
+
+NetDelay netdelay_create( NetShaperSendFunc send_func );
+void netdelay_set_latency( NetDelay delay, int min_ms, int max_ms );
+void netdelay_send( NetDelay delay, const void* data, size_t size );
+void netdelay_send_aux( NetDelay delay, const void* data, size_t size, void* opaque );
+void netdelay_destroy( NetDelay delay );
+
+/** in vl.c */
+/* network traffic shaper and delayer */
+extern NetShaper slirp_shaper_in;
+extern NetShaper slirp_shaper_out;
+extern NetDelay slirp_delay_in;
+
+#endif /* _SLIRP_SHAPER_H_ */
diff --git a/skins/skin_argb.h b/skins/skin_argb.h
new file mode 100644
index 0000000..c39b4ef
--- /dev/null
+++ b/skins/skin_argb.h
@@ -0,0 +1,856 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+/* this file contains template code and may be included multiple times */
+
+#ifndef ARGB_T_DEFINED
+#define ARGB_T_DEFINED
+
+#if USE_MMX
+#include <mmintrin.h>
+
+typedef __m64 mmx_t;
+typedef mmx_t argb_t;
+
+static inline mmx_t
+mmx_load8888( unsigned value, mmx_t zero )
+{
+ return _mm_unpacklo_pi8( _mm_cvtsi32_si64 (value), zero);
+}
+
+static inline unsigned
+mmx_save8888( mmx_t argb, mmx_t zero )
+{
+ return (unsigned) _mm_cvtsi64_si32( _mm_packs_pu16( argb, zero ) );
+}
+
+static inline mmx_t
+mmx_expand16( int value )
+{
+ mmx_t t1 = _mm_cvtsi32_si64( value );
+ return _mm_packs_pi32( t1, t1 );
+}
+
+static inline int
+mmx_makescale( double s )
+{
+ return (int)(s*(1 << 16));
+}
+
+static inline mmx_t
+mmx_mulshift( mmx_t argb, int multiplier, int rshift, mmx_t zero )
+{
+ mmx_t ar = _mm_unpackhi_pi16(argb, zero );
+ mmx_t gb = _mm_unpacklo_pi16(argb, zero );
+ mmx_t mult = mmx_expand16(multiplier);
+
+ ar = _mm_srli_pi32( _mm_madd_pi16( ar, mult ), rshift );
+ gb = _mm_srli_pi32( _mm_madd_pi16( gb, mult ), rshift );
+
+ return _mm_packs_pi32( gb, ar );
+}
+
+static inline mmx_t
+mmx_interp255( mmx_t m1, mmx_t m2, mmx_t zero, int alpha )
+{
+ mmx_t mult, mult2, t1, t2, r1, r2;
+
+ // m1 = [ a1 | r1 | g1 | b1 ]
+ // m2 = [ a2 | r2 | g2 | b2 ]
+ alpha = (alpha << 16) | (alpha ^ 255);
+ mult = _mm_cvtsi32_si64( alpha ); // mult = [ 0 | 0 | a | 1-a ]
+ mult2 = _mm_slli_si64( mult, 32 ); // mult2 = [ a | 1-a | 0 | 0 ]
+ mult = _mm_or_si64( mult, mult2 ); // mults = [ a | 1-a | a | 1-a ]
+
+ t1 = _mm_unpackhi_pi16( m1, m2 ); // t1 = [ a2 | a1 | r2 | r1 ]
+ r1 = _mm_madd_pi16( t1, mult ); // r1 = [ ra | rr ]
+
+ t2 = _mm_unpacklo_pi16( m1, m2 ); // t1 = [ g2 | g1 | b2 | b1 ]
+ r2 = _mm_madd_pi16( t2, mult ); // r2 = [ rg | rb ]
+
+ r1 = _mm_srli_pi32( r1, 8 );
+ r2 = _mm_srli_pi32( r2, 8 );
+
+ return _mm_packs_pi32( r2, r1 );
+}
+
+#define ARGB_DECL_ZERO() mmx_t _zero = _mm_setzero_si64()
+#define ARGB_DECL(x) mmx_t x
+#define ARGB_DECL2(x1,x2) mmx_t x1, x2
+#define ARGB_ZERO(x) x = _zero
+#define ARGB_UNPACK(x,v) x = mmx_load8888((v), _zero)
+#define ARGB_PACK(x) mmx_save8888(x, _zero)
+#define ARGB_COPY(x,y) x = y
+#define ARGB_SUM(x1,x2,x3) x1 = _mm_add_si64(x2, x3)
+#define ARGB_REDUCE(x,red) \
+ ({ \
+ int _red = (red) >> 8; \
+ if (_red < 256) \
+ x = mmx_mulshift( x, _red, 8, _zero ); \
+ })
+
+#define ARGB_INTERP255(x1,x2,x3,alpha) \
+ x1 = mmx_interp255( x2, x3, _zero, (alpha))
+
+#define ARGB_ADDW_11(x1,x2,x3) \
+ ARGB_SUM(x1,x2,x3)
+
+#define ARGB_ADDW_31(x1,x2,x3) \
+ ({ \
+ mmx_t _t1 = _mm_add_pi16(x2, x3); \
+ mmx_t _t2 = _mm_slli_pi16(x2, 1); \
+ x1 = _mm_add_pi16(_t1, _t2); \
+ })
+
+#define ARGB_ADDW_13(x1,x2,x3) \
+ ({ \
+ mmx_t _t1 = _mm_add_pi16(x2, x3); \
+ mmx_t _t2 = _mm_slli_pi16(x3, 1); \
+ x1 = _mm_add_pi16(_t1, _t2); \
+ })
+
+#define ARGB_SHR(x1,x2,s) \
+ x1 = _mm_srli_pi16(x2, s)
+
+
+#define ARGB_MULSHIFT(x1,x2,v,s) \
+ x1 = mmx_mulshift(x2, v, s, _zero)
+
+#define ARGB_DONE _mm_empty()
+
+#define ARGB_RESCALE_SHIFT 10
+#define ARGB_DECL_SCALE(s2,s) int s2 = (int)((s)*(s)*(1 << ARGB_RESCALE_SHIFT))
+#define ARGB_RESCALE(x,s2) x = mmx_mulshift( x, s2, ARGB_RESCALE_SHIFT, _zero )
+
+#else /* !USE_MMX */
+
+typedef uint32_t argb_t;
+
+#define ARGB_DECL_ZERO() argb_t _zero = 0
+#define ARGB_DECL(x) argb_t x##_ag, x##_rb
+#define ARGB_DECL2(x1,x2) argb_t x1##_ag, x1##_rb, x2##_ag, x2##_rb
+#define ARGB_ZERO(x) (x##_ag = x##_rb = 0)
+#define ARGB_COPY(x,y) (x##_ag = y##_ag, x##_rb = y##_rb)
+
+#define ARGB_UNPACK(x,v) \
+ ({ \
+ argb_t _v = (argb_t)(v); \
+ x##_ag = (_v >> 8) & 0xff00ff; \
+ x##_rb = (_v) & 0xff00ff; \
+ })
+
+#define ARGB_PACK(x) (uint32_t)(((x##_ag) << 8) | x##_rb)
+
+#define ARGB_SUM(x1,x2,x3) \
+ ({ \
+ x1##_ag = x2##_ag + x3##_ag; \
+ x1##_rb = x2##_rb + x3##_rb; \
+ })
+
+#define ARGB_REDUCE(x,red) \
+ ({ \
+ int _red = (red) >> 8; \
+ if (_red < 256) { \
+ x##_ag = ((x##_ag*_red) >> 8) & 0xff00ff; \
+ x##_rb = ((x##_rb*_red) >> 8) & 0xff00ff; \
+ } \
+ })
+
+#define ARGB_INTERP255(x1,x2,x3,alpha) \
+ ({ \
+ int _alpha = (alpha); \
+ int _ialpha; \
+ _alpha += _alpha >> 8; \
+ _ialpha = 256 - _alpha; \
+ x1##_ag = ((x2##_ag*_ialpha + x3##_ag*_alpha) >> 8) & 0xff00ff; \
+ x1##_rb = ((x2##_rb*_ialpha + x3##_rb*_alpha) >> 8) & 0xff00ff; \
+ })
+
+#define ARGB_ADDW_11(x1,x2,x3) \
+ ({ \
+ x1##_ag = (x2##_ag + x3##_ag); \
+ x1##_rb = (x2##_rb + x3##_rb); \
+ })
+
+#define ARGB_ADDW_31(x1,x2,x3) \
+ ({ \
+ x1##_ag = (3*x2##_ag + x3##_ag); \
+ x1##_rb = (3*x2##_rb + x3##_rb); \
+ })
+
+#define ARGB_ADDW_13(x1,x2,x3) \
+ ({ \
+ x1##_ag = (x2##_ag + 3*x3##_ag); \
+ x1##_rb = (x2##_rb + 3*x3##_rb); \
+ })
+
+#define ARGB_MULSHIFT(x1,x2,v,s) \
+ ({ \
+ unsigned _vv = (v); \
+ x1##_ag = ((x2##_ag * _vv) >> (s)) & 0xff00ff; \
+ x1##_rb = ((x2##_rb * _vv) >> (s)) & 0xff00ff; \
+ })
+
+#define ARGB_SHR(x1,x2,s) \
+ ({ \
+ int _s = (s); \
+ x1##_ag = (x2##_ag >> _s) & 0xff00ff; \
+ x1##_rb = (x2##_rb >> _s) & 0xff00ff; \
+ })
+
+#define ARGB_DONE ((void)0)
+
+#define ARGB_RESCALE_SHIFT 8
+#define ARGB_DECL_SCALE(s2,s) int s2 = (int)((s)*(s)*(1 << ARGB_RESCALE_SHIFT))
+#define ARGB_RESCALE(x,scale2) ARGB_MULSHIFT(x,x,scale2,ARGB_RESCALE_SHIFT)
+
+#endif /* !USE_MMX */
+
+#define ARGB_ADD(x1,x2) ARGB_SUM(x1,x1,x2)
+#define ARGB_READ(x,p) ARGB_UNPACK(x,*(uint32_t*)(p))
+#define ARGB_WRITE(x,p) *(uint32_t*)(p) = ARGB_PACK(x)
+
+#endif /* !ARGB_T_DEFINED */
+
+
+
+#ifdef ARGB_SCALE_GENERIC
+static void
+ARGB_SCALE_GENERIC( ScaleOp* op )
+{
+ int dst_pitch = op->dst_pitch;
+ int src_pitch = op->src_pitch;
+ uint8_t* dst_line = op->dst_line;
+ uint8_t* src_line = op->src_line;
+ ARGB_DECL_SCALE(scale2, op->scale);
+ int h;
+ int sx = op->sx;
+ int sy = op->sy;
+ int ix = op->ix;
+ int iy = op->iy;
+
+ src_line += (sx >> 16)*4 + (sy >> 16)*src_pitch;
+ sx &= 0xffff;
+ sy &= 0xffff;
+
+ for ( h = op->rd.h; h > 0; h-- ) {
+ uint8_t* dst = dst_line;
+ uint8_t* src = src_line;
+ uint8_t* dst_end = dst + 4*op->rd.w;
+ int sx1 = sx;
+ int sy1 = sy;
+
+ for ( ; dst < dst_end; ) {
+ int sx2 = sx1 + ix;
+ int sy2 = sy1 + iy;
+
+ ARGB_DECL_ZERO();
+ ARGB_DECL(spix);
+ ARGB_DECL(pix);
+ ARGB_ZERO(pix);
+
+ /* the current destination pixel maps to the (sx1,sy1)-(sx2,sy2)
+ * source square, we're going to compute the sum of its pixels'
+ * colors... simple box filtering
+ */
+ {
+ int gsy, gsx;
+ for ( gsy = 0; gsy < sy2; gsy += 65536 ) {
+ for ( gsx = 0; gsx < sx2; gsx += 65536 ) {
+ uint8_t* s = src + (gsx >> 16)*4 + (gsy >> 16)*src_pitch;
+ int xmin = gsx, xmax = gsx + 65536, ymin = gsy, ymax = gsy + 65536;
+ unsigned ww, hh;
+ unsigned red;
+
+ if (xmin < sx1) xmin = sx1;
+ if (xmax > sx2) xmax = sx2;
+ if (ymin < sy1) ymin = sy1;
+ if (ymax > sy2) ymax = sy2;
+
+ ww = (unsigned)(xmax-xmin);
+ red = ww;
+
+ hh = (unsigned)(ymax-ymin);
+ red = (hh < 65536) ? (red*hh >> 16U) : red;
+
+ ARGB_READ(spix,s);
+ ARGB_REDUCE(spix,red);
+ ARGB_ADD(pix,spix);
+ }
+ }
+ }
+
+ ARGB_RESCALE(pix,scale2);
+ ARGB_WRITE(pix,dst);
+
+ sx1 = sx2;
+ src += (sx1 >> 16)*4;
+ sx1 &= 0xffff;
+ dst += 4;
+ }
+
+ sy += iy;
+ src_line += (sy >> 16)*src_pitch;
+ sy &= 0xffff;
+
+ dst_line += dst_pitch;
+ }
+ ARGB_DONE;
+}
+#endif
+#undef ARGB_SCALE_GENERIC
+
+
+#ifdef ARGB_SCALE_05_TO_10
+static inline int cross( int x, int y ) {
+ if (x == 65536 && y == 65536)
+ return 65536;
+
+ return (int)((unsigned)x * (unsigned)y >> 16U);
+}
+
+static void
+scale_05_to_10( ScaleOp* op )
+{
+ int dst_pitch = op->dst_pitch;
+ int src_pitch = op->src_pitch;
+ uint8_t* dst_line = op->dst_line;
+ uint8_t* src_line = op->src_line;
+ ARGB_DECL_SCALE(scale2, op->scale);
+ int h;
+ int sx = op->sx;
+ int sy = op->sy;
+ int ix = op->ix;
+ int iy = op->iy;
+
+ src_line += (sx >> 16)*4 + (sy >> 16)*src_pitch;
+ sx &= 0xffff;
+ sy &= 0xffff;
+
+ for ( h = op->rd.h; h > 0; h-- ) {
+ uint8_t* dst = dst_line;
+ uint8_t* src = src_line;
+ uint8_t* dst_end = dst + 4*op->rd.w;
+ int sx1 = sx;
+ int sy1 = sy;
+
+ for ( ; dst < dst_end; ) {
+ int sx2 = sx1 + ix;
+ int sy2 = sy1 + iy;
+
+ ARGB_DECL_ZERO();
+ ARGB_DECL2(spix, pix);
+
+ int off = src_pitch;
+ int fx1 = sx1 & 0xffff;
+ int fx2 = sx2 & 0xffff;
+ int fy1 = sy1 & 0xffff;
+ int fy2 = sy2 & 0xffff;
+
+ int center_x = ((sx1 >> 16) + 1) < ((sx2-1) >> 16);
+ int center_y = ((sy1 >> 16) + 1) < ((sy2-1) >> 16);
+
+ ARGB_ZERO(pix);
+
+ if (fx2 == 0) {
+ fx2 = 65536;
+ }
+ if (fy2 == 0) {
+ fy2 = 65536;
+ }
+ fx1 = 65536 - fx1;
+ fy1 = 65536 - fy1;
+
+ /** TOP BAND
+ **/
+
+ /* top-left pixel */
+ ARGB_READ(spix,src);
+ ARGB_REDUCE(spix,cross(fx1,fy1));
+ ARGB_ADD(pix,spix);
+
+ /* top-center pixel, if any */
+ ARGB_READ(spix,src + 4);
+ if (center_x) {
+ ARGB_REDUCE(spix,fy1);
+ ARGB_ADD(pix,spix);
+ ARGB_READ(spix,src + 8);
+ }
+
+ /* top-right pixel */
+ ARGB_REDUCE(spix,cross(fx2,fy1));
+ ARGB_ADD(pix,spix);
+
+ /** MIDDLE BAND, IF ANY
+ **/
+ if (center_y) {
+ /* left-middle pixel */
+ ARGB_READ(spix,src + off);
+ ARGB_REDUCE(spix,fx1);
+ ARGB_ADD(pix,spix);
+
+ /* center pixel, if any */
+ ARGB_READ(spix,src + off + 4);
+ if (center_x) {
+ ARGB_ADD(pix,spix);
+ ARGB_READ(spix,src + off + 8);
+ }
+
+ /* right-middle pixel */
+ ARGB_REDUCE(spix,fx2);
+ ARGB_ADD(pix,spix);
+
+ off += src_pitch;
+ }
+
+ /** BOTTOM BAND
+ **/
+ /* left-bottom pixel */
+ ARGB_READ(spix,src + off);
+ ARGB_REDUCE(spix,cross(fx1,fy2));
+ ARGB_ADD(pix,spix);
+
+ /* center-bottom, if any */
+ ARGB_READ(spix,src + off + 4);
+ if (center_x) {
+ ARGB_REDUCE(spix,fy2);
+ ARGB_ADD(pix,spix);
+ ARGB_READ(spix,src + off + 8);
+ }
+
+ /* right-bottom pixel */
+ ARGB_REDUCE(spix,cross(fx2,fy2));
+ ARGB_ADD(pix,spix);
+
+ /** WRITE IT
+ **/
+ ARGB_RESCALE(pix,scale2);
+ ARGB_WRITE(pix,dst);
+
+ sx1 = sx2;
+ src += (sx1 >> 16)*4;
+ sx1 &= 0xffff;
+ dst += 4;
+ }
+
+ sy += iy;
+ src_line += (sy >> 16)*src_pitch;
+ sy &= 0xffff;
+
+ dst_line += dst_pitch;
+ }
+ ARGB_DONE;
+}
+#endif
+#undef ARGB_SCALE_05_TO_10
+
+
+#ifdef ARGB_SCALE_UP_BILINEAR
+static void
+scale_up_bilinear( ScaleOp* op )
+{
+ int dst_pitch = op->dst_pitch;
+ int src_pitch = op->src_pitch;
+ uint8_t* dst_line = op->dst_line;
+ uint8_t* src_line = op->src_line;
+ int sx = op->sx;
+ int sy = op->sy;
+ int ix = op->ix;
+ int iy = op->iy;
+ int xlimit, ylimit;
+ int h, sx0;
+
+ /* the center pixel is at (sx+ix/2, sy+iy/2), we then want to get */
+ /* the four nearest source pixels, which are at (0.5,0.5) offsets */
+
+ sx = sx + ix/2 - 32768;
+ sy = sy + iy/2 - 32768;
+
+ xlimit = (op->src_w-1);
+ ylimit = (op->src_h-1);
+
+ sx0 = sx;
+
+ for ( h = op->rd.h; h > 0; h-- ) {
+ uint8_t* dst = dst_line;
+ uint8_t* dst_end = dst + 4*op->rd.w;
+
+ sx = sx0;
+ for ( ; dst < dst_end; ) {
+ int ex1, ex2, ey1, ey2, alpha;
+ uint8_t* s;
+
+ ARGB_DECL_ZERO();
+ ARGB_DECL2(spix1,spix2);
+ ARGB_DECL2(pix3,pix4);
+ ARGB_DECL(pix);
+
+ /* find the four neighbours */
+ ex1 = (sx >> 16);
+ ey1 = (sy >> 16);
+ ex2 = (sx+65535) >> 16;
+ ey2 = (sy+65535) >> 16;
+
+ if (ex1 < 0) ex1 = 0; else if (ex1 > xlimit) ex1 = xlimit;
+ if (ey1 < 0) ey1 = 0; else if (ey1 > ylimit) ey1 = ylimit;
+ if (ex2 < 0) ex2 = 0; else if (ex2 > xlimit) ex2 = xlimit;
+ if (ey2 < 0) ey2 = 0; else if (ey2 > ylimit) ey2 = ylimit;
+
+ ex2 = (ex2-ex1)*4;
+ ey2 = (ey2-ey1)*src_pitch;
+
+ /* interpolate */
+ s = src_line + ex1*4 + ey1*src_pitch;
+ ARGB_READ(spix1, s);
+ ARGB_READ(spix2, s+ex2);
+
+ alpha = (sx >> 8) & 0xff;
+ ARGB_INTERP255(pix3,spix1,spix2,alpha);
+
+ s += ey2;
+ ARGB_READ(spix1, s);
+ ARGB_READ(spix2, s+ex2);
+
+ ARGB_INTERP255(pix4,spix1,spix2,alpha);
+
+ alpha = (sy >> 8) & 0xff;
+ ARGB_INTERP255(pix,pix3,pix4,alpha);
+
+ ARGB_WRITE(pix,dst);
+
+ sx += ix;
+ dst += 4;
+ }
+
+ sy += iy;
+ dst_line += dst_pitch;
+ }
+ ARGB_DONE;
+}
+#endif
+#undef ARGB_SCALE_UP_BILINEAR
+
+#ifdef ARGB_SCALE_UP_QUICK_4x4
+static void
+ARGB_SCALE_UP_QUICK_4x4( ScaleOp* op )
+{
+ int dst_pitch = op->dst_pitch;
+ int src_pitch = op->src_pitch;
+ uint8_t* dst_line = op->dst_line;
+ uint8_t* src_line = op->src_line;
+ int sx = op->sx;
+ int sy = op->sy;
+ int ix = op->ix;
+ int iy = op->iy;
+ int xlimit, ylimit;
+ int h, sx0;
+
+ /* the center pixel is at (sx+ix/2, sy+iy/2), we then want to get */
+ /* the four nearest source pixels, which are at (0.5,0.5) offsets */
+
+ sx = sx + ix/2 - 32768;
+ sy = sy + iy/2 - 32768;
+
+ xlimit = (op->src_w-1);
+ ylimit = (op->src_h-1);
+
+ sx0 = sx;
+
+ for ( h = op->rd.h; h > 0; h-- ) {
+ uint8_t* dst = dst_line;
+ uint8_t* dst_end = dst + 4*op->rd.w;
+
+ sx = sx0;
+ for ( ; dst < dst_end; ) {
+ int ex1, ex2, ey1, ey2;
+ uint8_t* p;
+ ARGB_DECL_ZERO();
+ ARGB_DECL(pix);
+ ARGB_DECL2(spix1, spix2);
+ ARGB_DECL2(pix3, pix4);
+
+ /* find the four neighbours */
+ ex1 = (sx >> 16);
+ ey1 = (sy >> 16);
+ ex2 = (sx+65535) >> 16;
+ ey2 = (sy+65535) >> 16;
+
+ if (ex1 < 0) ex1 = 0; else if (ex1 > xlimit) ex1 = xlimit;
+ if (ey1 < 0) ey1 = 0; else if (ey1 > ylimit) ey1 = ylimit;
+ if (ex2 < 0) ex2 = 0; else if (ex2 > xlimit) ex2 = xlimit;
+ if (ey2 < 0) ey2 = 0; else if (ey2 > ylimit) ey2 = ylimit;
+
+ /* interpolate */
+ p = (src_line + ex1*4 + ey1*src_pitch);
+
+ ex2 = (ex2-ex1)*4;
+ ey2 = (ey2-ey1)*src_pitch;
+
+ switch (((sx >> 14) & 3) | ((sy >> 12) & 12)) {
+ case 0:
+ *(uint32_t*)dst = *(uint32_t*)p;
+ break;
+
+ /* top-line is easy */
+ case 1:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix,spix1,spix2);
+ ARGB_SHR(pix,pix,2);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ case 2:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix, spix1, spix2);
+ ARGB_SHR(pix,pix,1);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ case 3:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix,spix1,spix2);
+ ARGB_SHR(pix,pix,2);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ /* second line is harder */
+ case 4:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ey2);
+ ARGB_ADDW_31(pix,spix1,spix2);
+ ARGB_SHR(pix,pix,2);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ case 5:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix4,spix1,spix2);
+
+ ARGB_ADDW_31(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,4);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ case 6:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix4,spix1,spix2);
+
+ ARGB_ADDW_31(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,3);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ case 7:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix4,spix1,spix2);
+
+ ARGB_ADDW_31(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,4);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ /* third line */
+ case 8:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ey2);
+ ARGB_ADDW_11(pix,spix1,spix2);
+ ARGB_SHR(pix,pix,1);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ case 9:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix4,spix1,spix2);
+
+ ARGB_ADDW_11(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,3);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ case 10:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix4,spix1,spix2);
+
+ ARGB_ADDW_11(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,2);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ case 11:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix4,spix1,spix2);
+
+ ARGB_ADDW_11(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,3);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ /* last line */
+ case 12:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ey2);
+ ARGB_ADDW_13(pix,spix1,spix2);
+ ARGB_SHR(pix,pix,2);
+ ARGB_WRITE(pix, dst);
+ break;
+
+ case 13:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_31(pix4,spix1,spix2);
+
+ ARGB_ADDW_13(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,4);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ case 14:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_11(pix4,spix1,spix2);
+
+ ARGB_ADDW_13(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,3);
+ ARGB_WRITE(pix,dst);
+ break;
+
+ default:
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix3,spix1,spix2);
+ p += ey2;
+ ARGB_READ(spix1, p);
+ ARGB_READ(spix2, p+ex2);
+ ARGB_ADDW_13(pix4,spix1,spix2);
+
+ ARGB_ADDW_13(pix,pix3,pix4);
+ ARGB_SHR(pix,pix,4);
+ ARGB_WRITE(pix,dst);
+ }
+ sx += ix;
+ dst += 4;
+ }
+
+ sy += iy;
+ dst_line += dst_pitch;
+ }
+ ARGB_DONE;
+}
+#endif
+#undef ARGB_SCALE_UP_QUICK_4x4
+
+
+#ifdef ARGB_SCALE_NEAREST
+/* this version scales up with nearest neighbours - looks crap */
+static void
+ARGB_SCALE_NEAREST( ScaleOp* op )
+{
+ int dst_pitch = op->dst_pitch;
+ int src_pitch = op->src_pitch;
+ uint8_t* dst_line = op->dst_line;
+ uint8_t* src_line = op->src_line;
+ int sx = op->sx;
+ int sy = op->sy;
+ int ix = op->ix;
+ int iy = op->iy;
+ int xlimit, ylimit;
+ int h, sx0;
+
+ /* the center pixel is at (sx+ix/2, sy+iy/2), we then want to get */
+ /* the four nearest source pixels, which are at (0.5,0.5) offsets */
+
+ sx = sx + ix/2 - 32768;
+ sy = sy + iy/2 - 32768;
+
+ xlimit = (op->src_w-1);
+ ylimit = (op->src_h-1);
+
+ sx0 = sx;
+
+ for ( h = op->rd.h; h > 0; h-- ) {
+ uint8_t* dst = dst_line;
+ uint8_t* dst_end = dst + 4*op->rd.w;
+
+ sx = sx0;
+ for ( ; dst < dst_end; ) {
+ int ex1, ex2, ey1, ey2;
+ unsigned* p;
+
+ /* find the top-left neighbour */
+ ex1 = (sx >> 16);
+ ey1 = (sy >> 16);
+ ex2 = ex1+1;
+ ey2 = ey1+1;
+
+ if (ex1 < 0) ex1 = 0; else if (ex1 > xlimit) ex1 = xlimit;
+ if (ey1 < 0) ey1 = 0; else if (ey1 > ylimit) ey1 = ylimit;
+ if (ex2 < 0) ex2 = 0; else if (ex2 > xlimit) ex2 = xlimit;
+ if (ey2 < 0) ey2 = 0; else if (ey2 > ylimit) ey2 = ylimit;
+
+ p = (unsigned*)(src_line + ex1*4 + ey1*src_pitch);
+ if ((sx & 0xffff) >= 32768)
+ p += (ex2-ex1);
+ if ((sy & 0xffff) >= 32768)
+ p = (unsigned*)((char*)p + (ey2-ey1)*src_pitch);
+
+ *(unsigned*)dst = p[0];
+
+ sx += ix;
+ dst += 4;
+ }
+
+ sy += iy;
+ dst_line += dst_pitch;
+ }
+}
+#endif
+#undef ARGB_SCALE_NEAREST
diff --git a/skins/skin_composer.c b/skins/skin_composer.c
new file mode 100644
index 0000000..87cf20f
--- /dev/null
+++ b/skins/skin_composer.c
@@ -0,0 +1,398 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skin_composer.h"
+#include <stddef.h>
+#include "osdep.h"
+
+/* forwards */
+static void skin_plate_get_region ( SkinPlate* p, SkinRegion *pregion );
+static void skin_plate_get_opaque_region( SkinPlate* p, SkinRegion *pregion );
+
+/* recompute region if needed */
+static void
+skin_plate_ensure_region( SkinPlate* p )
+{
+ if (p->any.type == SKIN_PLATE_SURFACE || p->group.hasRegion)
+ return;
+ else {
+ int n, count = qvector_len( p->group.children );
+
+ skin_region_reset(p->any.region);
+
+ for (n = 0; n < count; n++) {
+ SkinRegion r[1];
+ SkinPlate* child = qvector_get( p->group.children, n );
+
+ skin_plate_get_region( child, r );
+ skin_region_translate( r, child->any.pos.x, child->any.pos.y );
+ skin_region_union( p->any.region, r );
+ }
+
+ p->group.hasRegion = 1;
+ }
+}
+
+/* return region in 'region' */
+static void
+skin_plate_get_region( SkinPlate* p, SkinRegion* region )
+{
+ if ( p->any.type != SKIN_PLATE_SURFACE && !p->group.hasRegion ) {
+ skin_plate_ensure_region(p);
+ }
+ skin_region_init_copy( region, p->any.region );
+}
+
+
+/* recompute opaque region is needed */
+static void
+skin_plate_ensure_opaque_region( SkinPlate* p )
+{
+ if (p->any.type != SKIN_PLATE_SURFACE && !p->group.hasOpaqueRegion) {
+ int n, count = qvector_len( p->group.children );
+
+ skin_region_reset(p->group.opaqueRegion);
+
+ for (n = 0; n < count; n++) {
+ SkinRegion r[1];
+ SkinPlate* child = qvector_get( p->group.children, n );
+
+ skin_plate_get_opaque_region(child, r);
+ skin_region_translate(r, child->any.pos.x, child->any.pos.y);
+ skin_region_union( p->group.opaqueRegion, r);
+ }
+
+ p->group.hasOpaqueRegion = 1;
+ }
+}
+
+
+/* return opaque pixels region */
+static void
+skin_plate_get_opaque_region( SkinPlate* p, SkinRegion *pregion )
+{
+ if ( p->any.type == SKIN_PLATE_SURFACE ) {
+ if (p->any.isOpaque)
+ skin_region_init_copy(pregion, p->any.region);
+ else
+ skin_region_reset(pregion);
+ } else {
+ skin_plate_ensure_opaque_region(p);
+ skin_region_init_copy(pregion, p->group.opaqueRegion);
+ }
+}
+
+
+/* invalidate region in parent groups */
+static void
+skin_plate_invalidate_parent( SkinPlate* p )
+{
+ if (!p->any.isVisible)
+ return;
+
+ while (p) {
+ if (p->any.type != SKIN_PLATE_SURFACE) {
+ p->group.hasRegion = 0;
+ p->group.hasOpaqueRegion = 0;
+ }
+ p = p->any.parent;
+ }
+}
+
+
+static void
+skin_plate_invalidate_( SkinPlate* p, SkinRegion* r, SkinPlate* child )
+{
+ if (p->any.type != SKIN_PLATE_SURFACE) {
+ int n = qvector_len( p->group.children );
+ if (child != NULL) {
+ n = qvector_index( p->group.children, child );
+ }
+ while (n > 0) {
+ n -= 1;
+ child = qvector_get( p->group.children, n );
+ skin_region_translate( r, child->any.pos.x, child->any.pos.y );
+ skin_plate_invalidate_( p, r, NULL );
+ skin_region_translate( r, -child->any.pos.x, -child->any.pos.y );
+ if (skin_region_is_empty(r))
+ return;
+ }
+ if (p->any.type != SKIN_PLATE_SPACE) {
+ SkinPlate* parent = p->any.parent;
+ skin_region_translate(r, parent->any.pos.x, parent->any.pos.y );
+ skin_plate_invalidate_(parent, r, p);
+ } else {
+ /* send to viewports */
+ int n, count = qvector_len( p->space.viewports );
+ for (n = 0; n < count; n++) {
+ SkinViewport* v = qvector_get( p->space.viewports, n );
+ skin_viewport_invalidate(v, r);
+ }
+ }
+ }
+}
+
+static void
+skin_plate_invalidate_region( SkinPlate* p )
+{
+ SkinRegion r[1];
+
+ skin_plate_get_region( p, r );
+ skin_plate_invalidate_(p->any.parent, r, p);
+ skin_region_reset(r);
+}
+
+/* change visibility */
+void
+skin_plate_set_visible( SkinPlate* p, int isVisible )
+{
+ isVisible = !!isVisible;
+ if (isVisible == p->any.isVisible)
+ return;
+
+ skin_plate_invalidate_parent(p);
+ skin_plate_invalidate_region(p);
+ p->any.isVisible = isVisible;
+}
+
+void
+skin_plate_set_opaque( SkinPlate* p, int isOpaque )
+{
+ isOpaque = !!isOpaque;
+ if (isOpaque == p->any.isOpaque)
+ return;
+
+ skin_plate_invalidate_parent(p);
+ skin_plate_invalidate_region(p);
+ p->any.isOpaque = isOpaque;
+}
+
+
+
+extern SkinPlate*
+skin_plate_surface( SkinPlate* parent,
+ SkinPos* pos,
+ SkinRegion* region,
+ void* surface,
+ SkinPlateDrawFunc draw,
+ SkinPlateDoneFunc done )
+{
+ SkinPlate* p = qemu_mallocz(sizeof(*p));
+
+ p->any.type = SKIN_PLATE_SURFACE;
+ p->any.parent = parent;
+ p->any.pos.x = pos->x;
+ p->any.pos.y = pos->y;
+ p->any.isVisible = 1;
+ p->any.isOpaque = 1;
+
+ skin_region_init_copy( p->any.region, region );
+ return p;
+}
+
+
+SkinPlate*
+skin_plate_group( SkinPlate* parent, SkinPos* pos )
+{
+ SkinRegion r[1];
+ SkinPlate* p;
+
+ skin_region_reset(r);
+ p = skin_plate_surface( parent, pos, r, NULL, NULL, NULL );
+ p->any.type = SKIN_PLATE_GROUP;
+ p->group.hasOpaqueRegion = 0;
+ skin_region_init_empty( p->group.opaqueRegion );
+
+ qvector_init( p->group.children );
+ return p;
+}
+
+
+SkinPlate*
+skin_plate_space( void )
+{
+ SkinPos pos;
+ SkinPlate* p;
+
+ pos.x = pos.y = 0;
+ p = skin_plate_group( NULL, &pos );
+ p->any.type = SKIN_PLATE_SPACE;
+ qvector_init( p->space.viewports );
+ return p;
+}
+
+
+extern void
+skin_plate_free( SkinPlate* p )
+{
+ if (p->any.type >= SKIN_PLATE_SPACE) {
+ while ( qvector_len( p->space.viewports ) )
+ skin_viewport_free( qvector_get( p->space.viewports, 0 ) );
+ }
+ if (p->any.type >= SKIN_PLATE_GROUP) {
+ skin_region_reset( p->group.opaqueRegion );
+ p->group.hasOpaqueRegion = 0;
+ p->group.hasRegion = 0;
+
+ while ( qvector_len( p->group.children ) )
+ skin_plate_free( qvector_get( p->group.children, 0 ) );
+ }
+ if (p->any.type == SKIN_PLATE_SURFACE) {
+ if (p->surface.done)
+ p->surface.done( p->surface.user );
+ }
+
+ skin_region_reset( p->any.region );
+
+ if (p->any.parent) {
+ qvector_del( p->any.parent->group.children, p );
+ }
+}
+
+void
+skin_plate_invalidate( SkinPlate* plate, SkinRegion* region )
+{
+ SkinRegion r[1];
+ skin_region_init_copy( r, region );
+}
+
+
+/* we use two regions to manage the front-to-back composition here
+ *
+ * 'updated' initially contains the update region, in parent coordinates
+ *
+ * 'drawn' is initially empty, and will be filled with the region of translucent
+ * pixels that have been
+ *
+ * for a given surface plate, we translate the regions to plate coordinates,
+ * then we do an opaque blit of 'intersection(updated,region)', then removing it from 'updated'
+ *
+ * after that, we make a DSTOVER blit of 'intersection(drawn,region)'
+ * if the plate is not opaque, we add this intersection to 'drawn'
+ *
+ */
+static void
+skin_plate_redraw( SkinPlate* plate, SkinRegion* updated, SkinRegion* drawn, SkinPos* apos, SkinViewport* viewport )
+{
+ SkinPos pos = plate->any.pos;
+
+ if (!plate->any.isVisible)
+ return;
+
+ if (skin_region_is_empty(updated) && skin_region_is_empty(drawn))
+ return;
+
+ /* translate regions to plate coordinates */
+ skin_region_translate( updated, pos.x, pos.y );
+ skin_region_translate( drawn, pos.y, pos.y );
+ apos->x += pos.x;
+ apos->y += pos.y;
+
+ if (plate->any.type == SKIN_PLATE_SURFACE) {
+ SkinRegion r[1];
+
+ /* inter(updated,region) => opaque blit + remove 'region' from 'updated'*/
+ skin_plate_get_region(plate, r);
+ skin_region_intersect(r, updated);
+ if (!skin_region_is_empty(r)) {
+ plate->surface.draw( plate->surface.user, r, apos, viewport, 1 );
+ skin_region_substract(updated, r);
+ skin_region_reset(r);
+ }
+
+ /* inter(drawn,region) => DSTOVER blit + if non-opaque add it to 'drawn' */
+ skin_plate_get_region(plate, r);
+ skin_region_intersect(r, drawn);
+ if (!skin_region_is_empty(r)) {
+ plate->surface.draw( plate->surface.user, r, apos, viewport, 0);
+ if (!plate->any.isOpaque)
+ skin_region_union(drawn, r);
+ skin_region_reset(r);
+ }
+
+ } else {
+ int n, count = qvector_len(plate->group.children);
+ for (n = 0; n < count; n++) {
+ SkinPos pos;
+
+ pos.x = apos->x + plate->any.pos.x;
+ pos.y = apos->y + plate->any.pos.y;
+
+ skin_plate_redraw( qvector_get(plate->group.children, n ), updated, drawn, &pos, viewport );
+ if (skin_region_is_empty(updated) && skin_region_is_empty(drawn))
+ break;
+ }
+ }
+
+ /* convert back to parent coordinates */
+ apos->x -= pos.x;
+ apos->y -= pos.y;
+ skin_region_translate( updated, -pos.x, -pos.y );
+ skin_region_translate( drawn, -pos.x, -pos.y );
+}
+
+
+extern SkinViewport*
+skin_viewport( SkinPlate* space, SkinRect* rect, void* surface, int sx, int sy )
+{
+ SkinViewport* v = qemu_mallocz(sizeof(*v));
+ v->space = space;
+ v->rect = rect[0];
+ v->spos.x = sx;
+ v->spos.y = sy;
+ v->surface = surface;
+
+ skin_region_init_empty( v->update );
+ return v;
+}
+
+extern void
+skin_viewport_free( SkinViewport* v )
+{
+ SkinPlate* space = v->space;
+ if (space != NULL) {
+ qvector_del( space->space.viewports, v );
+ v->space = NULL;
+ }
+ skin_region_reset( v->update );
+ qemu_free(v);
+}
+
+extern void
+skin_viewport_invalidate( SkinViewport* v, SkinRegion* region )
+{
+ SkinRegion r[1];
+ skin_region_init_copy(r,region);
+ skin_region_translate(r, -v->spos.x, -v->spos.y);
+ skin_region_intersect_rect(r,&v->rect);
+ skin_region_union( v->update, r );
+ skin_region_reset(r);
+}
+
+extern void
+skin_viewport_redraw( SkinViewport* v )
+{
+ if (v->space && !skin_region_is_empty(v->update)) {
+ SkinRegion update[1];
+ SkinRegion drawn[1];
+ SkinPos apos;
+
+ skin_region_copy(update, v->update);
+ skin_region_reset(drawn);
+ skin_region_reset( v->update );
+
+ apos.x = apos.y = 0;
+ skin_plate_redraw( v->space, update, drawn, &apos, v );
+
+ skin_region_reset(update);
+ skin_region_reset(drawn);
+ }
+}
diff --git a/skins/skin_composer.h b/skins/skin_composer.h
new file mode 100644
index 0000000..d13339b
--- /dev/null
+++ b/skins/skin_composer.h
@@ -0,0 +1,102 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_SKIN_COMPOSER_H
+#define _ANDROID_SKIN_COMPOSER_H
+
+#include "skin_rect.h"
+#include "skin_region.h"
+#include "android_utils.h"
+
+/* the composer displays stacked surfaces on a target window/SDL_Surface */
+
+typedef enum {
+ SKIN_PLATE_SURFACE = 0,
+ SKIN_PLATE_GROUP,
+ SKIN_PLATE_SPACE
+} SkinPlateType;
+
+typedef union SkinPlate SkinPlate;
+typedef struct SkinViewport SkinViewport;
+
+struct SkinPlateAny {
+ SkinPlateType type; /* class pointer */
+ SkinPlate* parent; /* parent container */
+ SkinPos pos; /* position relative to parent */
+ SkinRegion region[1]; /* the plate's region */
+ char isVisible; /* flag: TRUE iff the region is visible */
+ char isOpaque; /* flag: TRUE iff the region is opaque */
+};
+
+
+typedef void (*SkinPlateDrawFunc)( void* user, SkinRegion* region, SkinPos* apos, SkinViewport* viewport, int opaque );
+typedef void (*SkinPlateDoneFunc)( void* user );
+
+struct SkinPlateSurface {
+ struct SkinPlateAny any;
+ void* user;
+ SkinPlateDrawFunc draw;
+ SkinPlateDoneFunc done;
+};
+
+struct SkinPlateGroup {
+ struct SkinPlateAny any;
+ char hasRegion;
+ char hasOpaqueRegion;
+ SkinRegion opaqueRegion[1];
+ qvector_t children[1];
+};
+
+struct SkinPlateSpace {
+ struct SkinPlateGroup group;
+ qvector_t viewports[1];
+};
+
+
+union SkinPlate {
+ struct SkinPlateAny any;
+ struct SkinPlateSurface surface;
+ struct SkinPlateGroup group;
+ struct SkinPlateSpace space;
+};
+
+
+extern SkinPlate* skin_plate_surface( SkinPlate* parent,
+ SkinPos* pos,
+ SkinRegion* region,
+ void* user,
+ SkinPlateDrawFunc draw,
+ SkinPlateDoneFunc done );
+
+extern SkinPlate* skin_plate_group( SkinPlate* parent, SkinPos* pos );
+
+extern SkinPlate* skin_plate_space( void );
+
+extern void skin_plate_free( SkinPlate* plate );
+extern void skin_plate_invalidate( SkinPlate* plate, SkinRegion* region );
+extern void skin_plate_set_pos( SkinPlate* plate, int x, int y );
+extern void skin_plate_set_visible( SkinPlate* plate, int isVisible );
+extern void skin_plate_set_opaque( SkinPlate* plate, int isOpaque );
+
+struct SkinViewport {
+ SkinPlate* space;
+ SkinRect rect;
+ void* surface;
+ SkinPos spos;
+ SkinRegion update[1];
+};
+
+extern SkinViewport* skin_viewport( SkinPlate* space, SkinRect* rect, void* surface, int sx, int sy );
+extern void skin_viewport_free( SkinViewport* v );
+extern void skin_viewport_invalidate( SkinViewport* v, SkinRegion* r );
+extern void skin_viewport_redraw( SkinViewport* v );
+
+#endif /* _ANDROID_SKIN_COMPOSER_H */
diff --git a/skins/skin_default.h b/skins/skin_default.h
new file mode 100644
index 0000000..8ab0c01
--- /dev/null
+++ b/skins/skin_default.h
@@ -0,0 +1,7414 @@
+/* automatically generated, do not touch */
+
+
+static const unsigned char _data_arrow_down_png[3438] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 98, 0, 0, 0, 31, 16, 6, 0, 0, 0, 76,137,196,
+ 82, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 2,
+ 153, 73, 68, 65, 84,120,218,236,156, 59, 75,195, 80, 24,134,163,
+ 184,104,113, 18, 20, 68,135, 90,169,163, 93,189, 45, 90,156, 26,
+ 208,165, 46, 29,252, 13,222, 6, 23, 69, 71, 47,163,179, 66, 39,
+ 65,112,238,170, 80, 71, 69, 23,171, 78,186, 40, 56,137, 56,198,
+ 225,203, 43, 36,161,164,177, 39,151,230,188,207,242,129, 96, 27,
+ 206,121,159,156,227,151, 99,186, 44,203,178, 44,203, 48,102,231,
+ 170,213,151,103, 35, 38, 6, 22,157,149,232,201,103,205, 89,163,
+ 227,250,170, 82,201,141, 27, 70, 79, 50, 6, 98,189,223, 22,162,
+ 159,161,208, 90, 8,123,254,183, 99,187,130,238,120, 7, 96, 97,
+ 139, 43, 3,241,238, 20,144, 11,109,132,232,173, 74, 45,237, 48,
+ 4,196, 11,114,129,156,164, 94,136,242,152,212,190, 42, 39,159,
+ 120, 65, 46,144,147,212, 10, 49,242, 33,117,250,158,147, 78,252,
+ 65, 78,144,155,212, 9,177, 50,206, 73, 38, 73,206, 77, 68, 66,
+ 20, 10, 82,243, 7,156, 92, 18, 28,228, 6, 57,234,120, 33,202,
+ 57, 78, 42,233,132, 28,133, 44,132, 57, 44,149,109, 85,162, 2,
+ 228, 8,185,234, 24, 33,112,225,243, 79,156, 68,162, 30,228, 74,
+ 253,141, 54,164, 39,213,165, 93,169,186,180, 85,207, 95,164,190,
+ 14,198,123, 29,163, 31,122,108, 81,145, 43,228,236,172,150, 80,
+ 33,242,135, 82,117,107,171,226, 65,210,209,183,212,183,136,197,
+ 64, 91,178,148,177,127,160,201,141, 8, 57,171,219,185,107,108,
+ 36,108,203,100,238,233,185,132,227,142,181,158,113, 6, 52, 42,
+ 17,240,189,186, 62,232, 84,151, 59, 69, 66, 76, 61,216, 43,132,
+ 230,109,213,168,196,160, 8,174,157,201,129, 51,135,177, 9,129,
+ 179, 38, 38,207, 36, 69, 34, 6, 69,240, 89, 41,218, 62, 3,213,
+ 166, 16, 69,158, 86,141, 68, 12,138,208, 26,200, 97,113, 43, 98,
+ 33,240,197, 60,173, 26,174, 24, 20,161,189, 38, 71,240, 27,245,
+ 63,133, 40,243, 76, 82,168, 98, 80, 4, 53, 4,207,105, 64, 33,
+ 208, 86, 45, 76,114,176,195, 16,131, 34,168, 5, 57, 69,110,149,
+ 11,193,149, 33, 92, 49, 40, 66,220, 43, 69,139, 66,160,157, 53,
+ 250,206,193, 13, 83, 12,138, 16, 14,200,173,127, 91,214, 71, 8,
+ 180,175,202, 89, 14, 42, 73,193, 74,145,117,230,218,139,207,209,
+ 13,115,215,190,115,125,115, 48, 73,122, 86, 98,211,126,144,119,
+ 222,234, 10,241,247,246,131, 77, 14, 34, 73, 31,200,181,183, 45,
+ 219, 68,136,213, 27, 14, 26, 73, 63,222,156,187,182, 76,104, 79,
+ 229,249,194, 48,162, 1, 56, 3,149,255,146,218,216,112,173, 16,
+ 171,117, 14, 18,209,112,165,168, 55,217, 50,237, 47, 75, 61,157,
+ 145,122,123,199,193, 34,233, 3,185, 70,206,145,123,207,150,233,
+ 167, 34, 21,194,184, 23, 12,108,169, 38,142,165,142, 44, 73, 69,
+ 159,151,135,252, 72,156,224, 37,201,175, 67, 82,223, 46,165, 62,
+ 174, 97, 75,228,250,133, 19,159,191, 33,252,192, 7, 54,154,125,
+ 224,133, 83, 28, 0,129, 8, 81, 1, 2,238,206,101, 83, 90,254,
+ 79,186, 95, 0, 0, 0,255,255, 3, 0,243,175,157,107, 47,151,
+ 202,243, 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_arrow_left_png[4122] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 47, 0, 0, 0, 87, 16, 6, 0, 0, 0,196,198,192,
+ 67, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 5,
+ 69, 73, 68, 65, 84,120,218,236, 93, 61, 76, 20, 65, 20, 62, 47,
+ 52,136,216,144, 0, 49, 88, 32, 8,141,198, 43, 5,172, 60, 67,
+ 37,137,132,228,108,136,208, 25, 40, 1, 41,140, 9,168, 9, 5,
+ 63,150, 98, 9, 66, 35,137,129, 4, 42, 5, 59, 14, 74,136, 54,
+ 30,160,197, 17,140, 38, 52,138, 71,107, 49,243,173,238,122,199,
+ 238,236,205,223,238,204,215, 12,176,100,127,190,121,251,189,247,
+ 102,222,204,158,235,184,181,176,176,191,151, 48, 4, 53,157,164,
+ 77,127, 33,109,126,133,180, 91,215,100,223, 73, 69,188,137,110,
+ 153, 38,109,215, 51,250,123,143,251,120,161,145,180, 59,139,164,
+ 61,237,181,196,135, 66, 42, 69,218, 76, 19,181,240,106,122, 96,
+ 170,248,255,159,167,132,119,209,227, 75,210,238, 52, 25, 15,139,
+ 30,190, 72,218,129, 1,183,164, 4, 69,250, 17,105, 27,126, 88,
+ 226,139,162,146, 90,104, 95,150, 18, 78, 45,186,101,138,207,249,
+ 239, 55, 91,226,139, 74,200, 68, 55,105,219, 63, 10,122,131,166,
+ 220,215, 51,142,120, 88,118,166,217, 45, 33,208,100,209,128,143,
+ 48,134,120,104,243,240, 5,183,246,170,186,143,174, 75, 49, 39,
+ 30, 78,237,201, 50,105, 47,127,215,227,190,110,239,185,223,192,
+ 216,132,147,109,159, 72,219,191,172,167,228, 65,218, 50,215, 73,
+ 59, 31,117,139,119, 8,223,140,134,115,135, 51, 71,248, 26, 57,
+ 226,163, 70,184, 23,200,128, 35, 67,124,212, 9,247,134,155,120,
+ 30,109,137,135,211,140, 58,225,255, 89,254, 88,185, 78, 87, 16,
+ 241, 78, 88, 88,149,136, 37,240,124,119, 70, 53, 35,126, 96, 80,
+ 110,194,163, 58,220,100, 29, 27,226, 78, 60, 50, 77, 93,226,112,
+ 105,225,102,179, 34,226, 49,182,161, 42,211, 84,141,212, 13,214,
+ 112,179, 76,226,157,209,194,205,132, 5,147,229,151, 73,124,215,
+ 184, 25, 90, 30, 20,144, 88,255,112, 51, 36,241, 8, 19, 77,149,
+ 22, 95,203,111,244, 11, 55, 67, 18, 47,111,194, 32,218, 78,183,
+ 116,184,201, 72, 60,156, 7,175, 25,159,184,227,238, 88,169,112,
+ 147,145,120,126, 99, 21,102,161,127,219,251,151, 10, 70, 75,175,
+ 182, 36,134, 1, 20,162,229, 23,105,115, 35, 1, 45, 30, 5, 64,
+ 22,101, 90,254, 86, 64,139,135, 54, 33, 65,176, 40, 15, 78, 37,
+ 91, 83, 69,176,140,212,130, 13, 5, 90,145,150,163,225,246,225,
+ 138,251,120,126,200,135,248,244, 1,253,161,201,146,121, 22,178,
+ 116,106,112,131,134,217,135,126,163,178, 35, 21,103, 39, 72, 53,
+ 203,150,212,179,136, 94,163,153,251,241, 67,214, 51,148, 32,190,
+ 117,218, 90,122, 49,233,152,157,165, 18,210, 94,238, 25, 75, 68,
+ 53,169, 87,150,236, 68, 34,145,200,215,145,246,241, 50,194, 64,
+ 94,103, 78,158, 29,119,154, 78,248,204, 9,105,249,151,111, 39,
+ 139, 39, 74,166, 75,138, 56,194, 75, 16,223,250, 34, 26,196, 28,
+ 191, 19,115,126,104,184,248, 5, 10, 30,226, 27,238,105,110,137,
+ 191, 41,241,239,249,158,127,103,151,183,134, 51, 18,175,219,132,
+ 134,151,240,195, 90, 49,215, 89,218,151,253,100, 73, 61,157,170,
+ 44,194, 17,143,139,146, 46,230,168, 38,238,132, 3,187,131,170,
+ 158, 52,169, 71, 52, 35,155,112, 71,219,119, 20, 19,111, 26,225,
+ 57,229,115,197, 73,179, 8,119, 18,164, 90,195,136, 87, 77, 56,
+ 112, 90, 48,140,120, 36, 40,135,202, 45,206, 48,226, 81,105, 85,
+ 185,104,137,151, 10, 84, 90, 97, 85,159,185, 29,160,200,185,170,
+ 238,128,150, 19, 67,137, 87,221, 1, 13,223, 52, 33, 62, 95,111,
+ 86, 7, 96, 76, 74,222,166, 17, 37,136,151,183, 79,139, 94, 29,
+ 144,222, 87, 76,188,147, 88,212,153,213, 1,168, 23,146,239,228,
+ 61,196,203, 31,165, 83,219, 1,206, 70, 65,227,138,137,247, 22,
+ 222,104,219, 1,175, 57, 75,142,234,141,130, 62, 15,233, 29,253,
+ 162, 3, 68, 45,110,235,207,202,146, 30,175,198,215, 39,140, 6,
+ 58, 20, 29, 32,141,120, 68, 55,186, 56, 89, 85,128,211,237, 19,
+ 246, 6,148, 72,160,228, 77,250,234, 13,236,218, 1,223,194,190,
+ 144,152,145,248,108,214,146, 94, 76,130,176,145, 81,122, 84, 16,
+ 241, 24,182,213, 45,188, 84, 13,103, 37, 55,173, 41,157,232,113,
+ 119, 68,112, 73,242, 41,211, 70,189, 73,186,211,146, 94, 12,144,
+ 158, 12,253, 61, 67, 39,120,114,116, 31,204, 28,149, 40,204,120,
+ 97, 34,168,240,192,135,248,141, 43,148,120,203, 49, 19,156, 53,
+ 79, 37,142,175,165,124,136,135,212,228,182,221, 39,180, 8, 7,
+ 88,252,122, 85,192, 97, 97,235,108,249, 96,233, 43,194,246,128,
+ 196, 99,155,111,235,108,195, 1,121,209,223,237,210, 25, 39, 66,
+ 86,159, 90, 18, 67, 89,250,126,192,112,210, 90, 62, 31,160, 54,
+ 243,255,132, 52,228,212,223, 92,155, 37, 53,136, 19,197,226,180,
+ 192, 9,148, 31,208,131,136,243, 45,220,248,112,213, 79, 25,202,
+ 156,236,134,118, 21,122, 45,217,255, 18,189, 62, 25,114,200,128,
+ 245, 66,107,214,233, 18, 67, 60, 64,184, 40,152,120, 39,195,157,
+ 52, 91,122, 80,125, 28,188,236,155,115, 93,205, 92,187,153, 81,
+ 207, 27,230,106, 5,206,196,227, 21,123, 57,107,134,246, 35, 92,
+ 100, 47,194, 21, 84, 73,134, 27, 65,138, 28,215,112,113, 41,244,
+ 62, 62,130, 75,248,144,112,193,233,196, 45, 92, 12, 95, 8, 38,
+ 169,118, 18,206, 23,175,102,212,195,197,213,163,114,207, 36,185,
+ 104,117,190, 61,218, 29,192, 47, 99, 87, 84, 45,140, 14,136,138,
+ 4, 33, 92, 20,190,123,135, 44, 64,130,230, 58, 52,183,244,155,
+ 188,207,168,201, 71, 22,225,132,243,180,132, 14, 27,254,171, 94,
+ 226,191, 65,103,220,142,185, 87, 21,107,182,178, 27, 97,168,179,
+ 49,143,162,245,168, 8, 23, 87,199, 69, 93, 65,211, 79,206, 33,
+ 76,155,249, 73, 90,217, 99, 65,184,158,180,253,106,116, 5,194,
+ 183,231,221, 98,223, 4, 76,209,109, 76,138,126,162,136,125, 86,
+ 20, 82,132, 55, 1, 78,153,215,208,132,188,237, 83, 34,254, 33,
+ 93, 56,101,248, 4, 72, 4,107, 71, 40,223, 40, 40,170,128, 22,
+ 67,146,188, 29,225, 55, 90, 42,127,163,160,152,126, 44,221,233,
+ 8,248,136,183,164, 77,209,132,173,141, 38,112, 88, 1,115,124,
+ 36,251, 14,255, 12, 0,112,186,137,242,235,201, 20,157, 0, 0,
+ 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_arrow_right_png[4147] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 47, 0, 0, 0, 87, 16, 6, 0, 0, 0,196,198,192,
+ 67, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 5,
+ 94, 73, 68, 65, 84,120,218,236,157, 59, 76, 20, 65, 24,199,199,
+ 11,141,248,104, 72,208, 24, 40, 4, 61, 26,141,103, 39,167,149,
+ 24, 43, 72, 32, 38,216,144,120,157,129, 22,206,194,168,128, 38,
+ 22, 60, 44,197, 18,149, 70, 18,131, 9, 84, 42,118,128,229, 33,
+ 52,242,178,128, 96, 48,161, 81, 30,173,197,204,127,143,221,123,
+ 176,183, 59,175,221,153,175,249, 2, 7,251,248,125,179,223, 99,
+ 118,230,187, 19, 55,111,189,127,191,182, 74, 20, 73,243, 50,213,
+ 245,237, 84,207, 54, 80,189,251,153,196, 92,170,212,156,246,228,
+ 4,213,157, 23,169,174,206, 82,221,194, 62, 95,249, 78,245,244,
+ 51,246,115,159, 5,207, 69,218, 6, 24,240,253,226,159, 39,135,
+ 169,238,101, 63,239,222,163,122,114,157,234, 92, 46,234,224, 19,
+ 114, 79, 87,115,151,141,236,108,176,255,235,238,102, 6, 57,203,
+ 12, 52, 98,193,251,146,204,119, 62,199,113,158,136, 51, 84, 63,
+ 152,119,187, 48, 11,158, 73, 42,229, 6,198, 91,210, 75, 84,191,
+ 236,112,159,207,120,240,157,141,114,206, 83, 61,225,118, 73,157,
+ 151,116,125, 18, 4,131,111,187,224,246,209,178, 5,177,164,247,
+ 180,218,235,144, 6, 30, 35,236,246,170, 30,183, 89,191, 67,245,
+ 147, 41,170,235,254,196, 20,124,103,131,251,209,215, 69,112, 61,
+ 79,167,220, 5, 92,228,193, 35,189, 67,176,211, 93, 50,115,170,
+ 12,192, 25,124,219,243,104,102,213,242, 13,192,169,114,197, 5,
+ 39,231,162, 93, 79,194, 0,132,221,207,194, 21, 77, 71, 60,130,
+ 104, 91, 63,137,149,192, 0,226,130,112, 72,240,119, 30,233,150,
+ 166,241,149,222, 83,162,238, 47, 32,120, 92,136, 46,233,162,240,
+ 130,172, 71, 19,240,168, 8,171, 39,136, 17,130, 58, 0,247, 45,
+ 29, 60,210,197,212, 53, 98,164,160, 18, 14, 63, 23,148, 8, 54,
+ 210, 77,151, 7,115,238,228, 66, 24,120,231, 21,221,142,133,126,
+ 212,197,226,133, 14,119,240,222, 87,116, 86,138,187,158,202,211,
+ 206,132,191,116,209,148, 32, 26, 84,238, 95,226, 4, 30,233, 98,
+ 107,191,133,234, 43,233, 24,118, 39, 31,129,193,243,122, 69,103,
+ 154,248,159,171,170, 42,158, 46, 38,207, 88,136,161, 70,254, 63,
+ 170, 75, 47, 75,241,140,248,204,130,133,199, 37,232,110,248,116,
+ 53, 45, 49,159,115,145, 45, 40, 48, 75,243,100,224, 55,107,169,
+ 158, 25,116,235,220, 34,213, 7, 93, 22,102, 16, 73, 47, 31,227,
+ 227,225,139, 86,188,159,191,118,107,228,171, 45,107,236,192, 75,
+ 22,110,217,194,179,153,234,233,143, 33,167, 12,182,216,147,241,
+ 54, 77,245, 99,118,192,249,171, 22,114,185,180,188,176,192, 10,
+ 57, 31,143, 85,189, 48,196,232, 63,235,154,138, 73,211, 8,103,
+ 240, 94,129,203,122,204,222,226,111,158,179,208, 9, 33, 36,245,
+ 70, 48,120,200, 33, 27,241,163,123,214, 0, 71,243,123,225,224,
+ 75, 25,192,116, 23,148,159, 82,144,180,118, 18, 6, 24, 27, 19,
+ 115,124,196, 26,221, 13,219,244, 74, 50,120,111, 12,224,157, 5,
+ 237,126, 97, 79,214,190,222, 6,168,107, 87, 4, 30, 50, 51, 32,
+ 230,184, 72,119,117, 53, 64,126,122, 93, 17,120,184, 6, 81,249,
+ 191,174, 6,200, 7,217,132,218, 11, 89,236, 17,123,124,125,159,
+ 0,197,224,101,109, 34,211,205, 0,201,145,132, 30,246, 95,201,
+ 154,102, 0, 77,192, 99,118, 84,150,168, 55,128, 38,224, 15, 15,
+ 212,156, 87,157, 1, 52, 1,175, 90, 96, 0, 81, 5, 94,161, 84,
+ 89,232,132, 28, 89, 63,196, 54,169,145, 29, 59,226,165, 0,199,
+ 174, 64,121, 43,229, 52, 1,159,220, 51, 5,184,102,224,235,126,
+ 155, 2, 92, 19,240,120, 37, 38,122,137,160, 62,192, 89,250,124,
+ 94, 49,120,188, 52, 55, 5,184,147, 62,119, 41, 2, 15, 32,162,
+ 54, 56,232, 10, 60,255, 38, 78, 81, 58,233,172, 66,222, 55, 3,
+ 56, 36,223,242, 75, 50,120,248,244,214, 41,206,192,223, 49,224,
+ 68, 79,224, 78,161,246, 73, 50,120,140,196,204,188,152,227, 71,
+ 101,167,138, 51, 39,181, 45,201,199, 3,184,233, 91,121,126,246,
+ 9, 30,241, 78, 9,206,186,120,164, 12, 95,234,135,160,122,216,
+ 46, 8,188,211,180, 13,193,205,174,173, 36,132, 20, 91, 39,207,
+ 201,213, 96,153, 55, 26,241,216,221,129,110,153, 47,136,109, 21,
+ 142,120,184,144,244, 15, 6,156,245,129,172, 65,207, 49,187, 73,
+ 173,104,250,184,245,176, 4,120,167,116,127,231, 46,225,235,217,
+ 239, 49,137,149, 68,222,221,232,209, 86,138, 10,246, 23, 20, 10,
+ 3,127, 61,197,242,107,236,242,235,182,208,120, 8,122, 37,147,
+ 181, 18, 62,254,235, 16,213,118,121, 53,167, 96,154,245, 86,170,
+ 37,192, 99,109,227,228, 47, 11, 77, 76, 48, 61, 38,171, 65, 43,
+ 40, 89,203, 45,226, 26, 76,143,111,169, 85, 34,157, 68,251,112,
+ 43,149,201,244,160,223,191, 76,148, 79,248,237,222, 38,222, 35,
+ 221,103, 1,133, 85,189, 54,232,150,151,241,230, 74,255, 35,225,
+ 207,146,223, 46, 91,184,229,242,244,202,191,209,193,231,148, 1,
+ 210,205,248,127,119,135, 63,129, 7,152, 12,252,234,210, 39,120,
+ 39,221, 92,183,208, 9,201,239,124, 15, 62, 16, 43,156, 36,195,
+ 178,106, 83,211, 77,184,150,217,161,176, 71, 10, 56, 59,249, 97,
+ 205, 44,224, 24,217,227,105, 94, 71, 12, 8, 30,139, 60, 77, 73,
+ 55, 95,143,185, 93,174, 50,240,144,201,141,120,167,155,227, 55,
+ 221, 3,141,159,132, 4,143, 17, 16,183,116, 19, 73,132,182,221,
+ 180,157, 82,121, 59, 30,233, 38, 92,103,248,224, 41, 9,124,240,
+ 10, 78, 47,224,111,211,178,206, 40,168,123, 71, 84,210, 77,228,
+ 227,242,128, 11, 2,239,140,252, 27,209, 8,154,112,145,242, 69,
+ 16,120,248,250,217, 97, 61, 64, 35,235, 66, 35, 35,113, 65, 83,
+ 49,120, 39,232, 14,168, 77, 55,225,242,208,184, 72,159,175, 39,
+ 149,212,175,102,102, 80,238,109,225,124,163,127,121, 23, 62, 17,
+ 1, 15, 65,122, 38,170, 83, 19, 70,246,139, 14,213,190, 91, 51,
+ 240, 78, 97,194,105,142, 7,174, 11, 65, 18, 35,123,171,150, 68,
+ 68, 36,175,143,135,143,205,177,174, 29,126,119,132, 28,120, 42,
+ 228,175,167,116,117, 33,154,130,247,142,252, 82,224,157,119,152,
+ 11, 30,208,112, 33,145,159, 27, 82, 4, 30, 96,103, 88, 11, 88,
+ 180,140, 90, 96,235, 81, 10,218,169,196,110, 18,238,255, 0, 9,
+ 225,144,193,153,103,176,249, 0, 0, 0, 0, 73, 69, 78, 68,174,
+ 66, 96,130
+};
+
+static const unsigned char _data_arrow_up_png[3493] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 98, 0, 0, 0, 31, 16, 6, 0, 0, 0, 76,137,196,
+ 82, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 2,
+ 208, 73, 68, 65, 84,120,218,236,156,189, 79,219, 80, 20,197, 93,
+ 43, 75, 17,116,161,130,165,153,160,233, 2,123, 9, 48, 85,160,
+ 142,176, 91, 85,214,238,237, 86,137, 34,161, 14, 41,255, 0, 27,
+ 66, 89,200, 2, 18, 12,136,143, 46,109,194,154, 74, 93, 26, 1,
+ 75,171, 74, 84,101, 65, 5, 70, 51,188,123, 2, 54,114, 18,219,
+ 239,197, 78,114,126,203,145,162,248, 35,215,231,216,126,247,217,
+ 121,228,186,174,235,186,150, 53, 51, 91, 42,157,158, 88,154,121,
+ 246, 87,233,192,134,247,243,225,215, 74,159,206, 91,132, 4,242,
+ 111, 95,233,197,158,247,243,235, 55, 74,127,143,232,218,210,183,
+ 175,142, 51, 54,110, 89,153,112,139, 61, 46, 41,125,177,170, 52,
+ 43,134,207,253, 23,163,207,137,194,232, 91,162, 67,190, 21, 85,
+ 68,151,120,208, 73, 19, 42, 1,254,129,175,214, 36, 48, 8,206,
+ 129,210,250,160,210, 95, 18,152,159,239,148,222, 56,173, 54,152,
+ 105,126,102,207,231,197,240, 8,192,185,124,225, 45,143, 21, 73,
+ 15, 56, 1, 67,115,254, 47, 92, 73, 64,182, 37, 48, 18,144,106,
+ 213,127,165,241, 5,226,131, 44,144, 69, 2,223,139,158,179,232,
+ 164,251,193, 9, 61, 43,190,126,181,229, 13,202,202,130,237, 93,
+ 224,104,156, 69, 35,253,199,157,239,125,129, 56,158,144,196,140,
+ 178, 72,164,247,129,207,225,251, 7,129, 0,229, 19, 22,139,244,
+ 62, 15,125, 30, 16, 8, 12, 58,106,223, 89, 52,210,123,192,215,
+ 240,121,203, 64,248, 19,116,237,176,136,164,251,129,143,131,239,
+ 128, 90, 4, 2,253,221, 47,207, 89, 76,210,253,192,199,240,117,
+ 232, 64,128,195, 98,171, 21, 17,146, 94,224, 91,248, 56,152, 54,
+ 3,129, 25,190,157,101, 22,215, 4,235,211, 94, 37,122,129,111,
+ 35,207, 84, 7,129,246, 84,254,137,210,220,103, 22, 91, 71, 16,
+ 238,218,126,194, 15, 37,133, 10,107, 20,135,186, 76,192, 29, 95,
+ 182,187,132, 29,109, 67,155,108,203,154, 9,130,239,196,195, 43,
+ 70, 60,194,251, 52, 98, 32,240,236, 71,117,146, 69,215, 25, 4,
+ 6, 67, 15,240,101,248,167, 97,237,120, 27, 46,159, 41,101, 91,
+ 86,111, 16, 24,140,104, 52,218,170,103, 81,215, 16, 51, 16, 24,
+ 164,176, 45,107, 38, 8, 12, 70, 56,224,195, 27, 39,161, 64, 52,
+ 70,241,127,148,178, 45,107, 38, 8, 12, 70,115,224, 59,248, 48,
+ 58,182,222, 29, 43,159, 50, 8, 38,131,192, 96,152,246,157,230,
+ 64,212,106, 74,209,238, 98, 16, 24, 12,147,192,103,240, 93,124,
+ 50,134, 12,242, 82,233,167, 62, 57, 48,152, 47, 40,172, 37,188,
+ 35,125, 54,111, 1,159, 89,218,110,213,109, 51, 59,138,123,186,
+ 35, 78,220, 17, 3,192, 87,250,199,172,182,217, 29,223,249,168,
+ 148,109, 89,162, 3,248, 8,190,210,143,225, 64,160,253,181,203,
+ 103,160,136, 6,118,219,126, 38, 41,165,129,104, 92,226,248,180,
+ 44,209,113, 11, 94, 52,189, 37,187,179, 63,108,125,138, 7,151,
+ 164,217, 55, 29, 14, 4, 95, 77, 37, 97, 8,126,213,179, 71, 2,
+ 1,248, 39, 6, 36,157, 62, 73, 40, 16,184, 39,228, 96,155, 52,
+ 27, 60,119,126,204,105, 39,251,195,241, 74, 31,219,178,228,190,
+ 15, 14,139, 73,237, 65, 38,217, 2,160,125,182,226,251,111, 78,
+ 210,159, 92, 44,138, 47, 18,235, 70,222, 2, 0, 0,255,255, 3,
+ 0,166,247,214, 91, 44,122,150,205, 0, 0, 0, 0, 73, 69, 78,
+ 68,174, 66, 96,130
+};
+
+static const unsigned char _data_back_png[3564] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 46, 0, 0, 0, 47, 16, 6, 0, 0, 0,204,117, 36,
+ 209, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 23, 73, 68, 65, 84,120,218,236,155, 59,108, 19, 65, 16,134, 23,
+ 43, 13, 78, 66, 67, 20, 40,156, 34,194,144, 6,228,107, 19, 83,
+ 97,100,165,177,196, 67, 10,141, 37,232, 34,187, 4, 76,129, 16,
+ 226,209,133,164,141, 41, 19,146, 42,141,145,160, 66, 28, 93, 28,
+ 74, 35,165,193, 9,105, 28,129,176,148, 6,129,211, 82,236,252,
+ 129, 59,251,228,123,236,173,207,246,252,205, 40,241,227,124,223,
+ 206,254, 59,123,119,115, 42,125,117, 99, 99,127, 79, 68, 92,151,
+ 150,189,189,191,113, 94,198,227,124,212,206,100,164,183,135, 63,
+ 189, 41,163, 97, 16,216, 95, 50,206,172,200,120, 54,235,243,139,
+ 255,200,208,162, 88, 47, 81, 28,147,177, 86,147,241,232,195,128,
+ 3, 71,166,102, 14, 8, 52, 1, 17,219,182, 55,102,213, 28, 47,
+ 142, 1, 77, 81,164,255, 47, 92,160, 1,248, 44, 99,181, 42,227,
+ 206,229, 62, 7, 14,192,185, 23,244,247, 56,189,144,138,136, 85,
+ 189,162, 72, 3,158,187, 45,227,214, 55,235, 76, 80,167, 88, 56,
+ 22,177,144,148,241,193,184,245,196,162, 46, 88, 88,161, 64,191,
+ 255, 76, 64,107, 11, 11,120,162, 73, 63,144, 60, 50, 83, 18, 3,
+ 33, 36,202,147,138,117,173,233, 25,240, 19,208,163, 50, 78,253,
+ 20, 3, 41,172, 5,200,252,217, 93,205, 30,142,145, 46, 84,196,
+ 80,234, 30, 22,249, 93,175,139,109,204, 95, 70,223,221, 22,172,
+ 255,192,187,207,120,151,192,177, 24,194, 58, 48,197, 88, 86,240,
+ 72,200,192,192,139, 69, 6,237,138, 83,193,154,160,158,129, 99,
+ 170,244, 75, 89, 23,149,178, 50,247,204, 35,240,147,122,122,154,
+ 33,250, 17,202,226,118,139,113, 0,126,253, 17, 91,136, 10,221,
+ 73,186, 4,126,109,143, 97,169,220, 56,253,219,169,198, 58,123,
+ 54,103,182, 98,139, 57,112, 0,110,172, 50,156, 48,100,164, 28,
+ 128,115, 53, 18,110,245,146,104, 18,112, 92, 70,101, 43, 9, 87,
+ 51,203, 4,124,170,201, 48,116, 40,113, 35,198,153,173, 83, 19,
+ 243,176,148,223, 12, 67, 75,134,255,136, 49, 4,157,138,111, 50,
+ 112,205, 98,224, 12,124, 40,128, 55, 38, 25,133, 14,213, 75, 4,
+ 252,232, 22,195,208,161, 86,158, 51, 92,171, 14,223, 18,240,250,
+ 67,134,161, 67, 95,239,219, 30,147,168,125,145,209, 72, 49, 28,
+ 181, 86, 66,137, 61,106,171, 82,106, 69,134, 19,134,144,200,109,
+ 101, 33, 30, 94,108,229, 25,146, 74,153, 73, 7,224,120,128,253,
+ 211, 69,134,164,166, 12,164,197,114,178,203,198,231,227, 18,103,
+ 186, 10,189,123,234,114,167,137, 76,127,255,156,161, 5,241,236,
+ 246,234,175,203,214,222,164, 76,111,156, 99,136, 94,170,145,181,
+ 185, 46, 91,251,110, 42,175,178,197,184,209,122,218,234, 16,190,
+ 129,163,249,168, 92,102,168,157, 4,235,237,222,162,226,241,106,
+ 33, 60,105, 45,205,144,133, 16,162,122,133, 22,199,239,110, 63,
+ 225,243,242, 44, 30, 64, 31, 86,240, 38, 61, 78,178, 62,231,245,
+ 147, 1,175,135, 3,252,203,155,195,225,241, 72,176,173,125,191,
+ 223,160,232, 6, 4, 10,251,199, 21,251, 86,182,191,133,234, 12,
+ 9, 21,188,143, 83,113,159, 38, 86,103,172,173,232, 5, 66, 35,
+ 170,186,246,187,112,203, 58, 44,130,230,162,234, 35,132,220, 24,
+ 139, 85, 27,113,150, 78, 36, 67, 83,178,215, 93,111,168,190, 76,
+ 74,136, 42,205,208,227,165,176,142,168,185,245, 27, 83,114, 71,
+ 88, 51, 30, 51,193,120, 45,163,234,103, 28, 97, 13,168,178,208,
+ 234,125,184,168,123,136, 71, 34,146, 97,136,120,129, 64,160,131,
+ 32,254,134, 6,104, 94,198,137,108,103, 43,176,223,185,114,188,
+ 177,210,179, 59, 92,127, 7, 0,162,170,196, 84,182,147,226,216,
+ 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_end_png[3562] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 46, 0, 0, 0, 47, 16, 6, 0, 0, 0,204,117, 36,
+ 209, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 21, 73, 68, 65, 84,120,218,236,156, 61, 72, 91, 81, 20,199, 95,
+ 31, 89,140,208, 69,209, 82,226,208,150,218,197,162, 99,243,236,
+ 166,136,131, 1, 69,112, 10,146,173,152,177,126, 76,173, 70, 40,
+ 29,172,174,149,110, 17, 51, 9,146,130, 29, 74, 81, 55,147,142,
+ 79,236,162,141,237,160,180, 24,234, 98, 75,178, 58,220,115,132,
+ 119,227,235,251,186,247,230, 37, 57,255,229,228,227,230, 37,249,
+ 221,115,207, 61,231,230,222,220, 25,124,190,185, 89,250,174,133,
+ 92, 29, 35, 86,107,167,202, 52,179,231, 93, 97,253, 38,145,112,
+ 124,140,129, 1,102,123,255,129, 93,101,182,231,194,227,133,242,
+ 96, 63, 48,115,214, 13, 22, 58,224,228, 46,179,166,201,108, 53,
+ 217,228,192, 99,101,102,135, 74, 0,186,159,217,104,142,107,120,
+ 33,230,253,176,195,208, 26,220,243,102,154,217,189,135,208, 33,
+ 115, 13, 14, 28, 67, 64,234, 43,120,110,158,107,112, 84,231,145,
+ 5, 29, 14, 3,236,102, 4,236, 44,202,234, 0, 73,192, 19,247,
+ 153, 29,155,132, 7, 38,181,134, 80,239, 59,102,103,185, 17,144,
+ 53, 68,133,160,136, 88, 79,158, 73,251,140,189, 33, 21,142,128,
+ 183, 19,204,174,149,131, 78,202,186,152,152,252, 42,223, 92,160,
+ 121,225, 28,243, 26,190,103,252,155, 98,224, 8,122,182,221,102,
+ 210,107,114,165, 14,252,130,215, 9,180, 90,240, 46,129,183, 1,
+ 216,244, 12,129,190, 77, 83, 15,172, 14, 25, 24,120,170,224,174,
+ 210,107, 85, 69, 57,135,108,203,249, 4,142, 21, 32,206,214, 36,
+ 119,217, 90, 34,227, 17, 56,246,208,212, 35,130,232, 71, 67,243,
+ 118, 17,193, 6,248,240, 2,133, 16, 17, 26,203,184, 4, 30,143,
+ 19, 44, 17, 50,142,120,199,213,111,143,217,228,217,130, 67,204,
+ 15, 27,224,253,239, 9,142,204, 37,130, 90, 15,167,108, 68,106,
+ 246, 18, 43,235,214,132,157, 10, 26,185,122,178,170,227, 13,130,
+ 161, 66,177,113,157, 60, 91,165, 58, 71, 1, 56,254,150, 72,146,
+ 236,225,191,117,130,160, 82,209, 28, 1, 87, 44, 2, 78,192, 91,
+ 2,248, 89, 23,161, 80,161,147,121, 0, 94,173, 16, 12, 21,170,
+ 36, 1,248,241, 75,130,161, 66,231, 31, 1,184,252, 45, 94, 36,
+ 230,216,220, 70, 32,243,144, 89, 90,196, 18, 29, 74,192,177,219,
+ 185, 44, 5,183,118,145,196, 10, 29,185, 38, 45,196,109,188,149,
+ 36, 65, 18,169, 98, 1,111,113, 33, 5, 55, 43,154,208,192, 32,
+ 86, 1,211, 64,176, 87, 14,133,207,167, 12,121,186, 8,225,182,
+ 103,199, 74,243,242, 11,179,251,143, 9, 90, 32,207,158,243, 88,
+ 218,239,252,130, 74,180,155, 32,122,201, 70,178,207, 28, 74,123,
+ 39,225,134,116, 10, 49,255,215,214, 79,107,132,240, 13, 28, 55,
+ 160,227, 5, 73, 86,237,193,201,137, 98,159, 83, 75,143,171,133,
+ 120,193,236, 32, 65,214, 52, 77, 43, 60, 5, 71, 44,185,125,133,
+ 207,229,217, 86, 7,143,160, 55, 60,231,205, 1,215,195, 17,252,
+ 250,122,107,196,248,173, 83,191,160, 5, 1,231, 43,212, 55, 19,
+ 214,180,168,209,133,147,223,218, 95,136,213, 43, 65,175, 24,145,
+ 244, 1,225,126, 28, 66, 78, 98,137,217,176,239, 89,196, 17,138,
+ 245,199,238,138,181, 2, 15, 46,201, 7, 99, 49,228, 20,177, 3,
+ 150,195,213, 1, 53,128,225,236, 82, 21,234, 15, 77,120,136, 84,
+ 124,244,155,239,128, 24,196,126, 3, 98,162,239, 51,246, 46, 71,
+ 222, 49,156,120, 61,132, 85, 81,243, 5,215, 80,250, 28, 84,231,
+ 63, 55,184,201,239,241,129,113,235,243,216, 1,184, 51,172,199,
+ 225,208,210, 31, 0,123,249, 25, 42,228,123,224,177,219,208, 96,
+ 187,222, 65,235,122, 0,217,217,201, 30, 62,205,111,211, 0, 0,
+ 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_home_png[3578] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 46, 0, 0, 0, 47, 16, 6, 0, 0, 0,204,117, 36,
+ 209, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 37, 73, 68, 65, 84,120,218,236,155, 61,108, 19, 49, 20,199,143,
+ 136, 5, 10, 12,128,130,144,154, 1, 40, 97, 41, 52, 43, 41, 19,
+ 65,136, 1,164, 10,164,176, 68,148, 13,114,107, 10, 27, 95, 18,
+ 83, 18,214, 68,108,169,218, 41, 75,145,202,128, 42,194,150,118,
+ 228, 16, 44,164,133,165, 21, 31, 17,217, 10, 93, 25,252, 94, 42,
+ 91,181,236,107,206,190, 75,238,253,151,167,228, 46,185,228,231,
+ 231,191,159,239,236, 3,211, 87, 22, 22, 54,214,157,136,234,208,
+ 34,139,169, 95,254, 62,215,153,139,234, 63, 58, 24,238,229, 79,
+ 92,103, 49,147, 97, 49,189, 13,177,194,226, 97, 0,238, 28,245,
+ 249,197,175, 89,232,173,176,248,181, 4, 13,113,140, 69,207, 99,
+ 113,167, 48,226,192, 47,127, 97, 49,155, 5,176,119, 36, 39, 46,
+ 6,219,160,217,207, 16,133,227,158,203, 98,235,172,173,158, 97,
+ 24, 56,102,110,254, 28, 0,104,195,129, 74, 52, 58,120,102, 10,
+ 162,195,247,128,229,167,166, 26, 32, 97,198, 34, 74,240,195,139,
+ 69,254,253,168, 11,173,172, 4, 22,150,159,224,199,146,200,100,
+ 56,102,242,236,146,224,189, 67,174,220, 35,104,136, 35, 44, 54,
+ 186, 44,110, 37, 67,202,112,244,100,204,228, 81, 1, 45, 42,245,
+ 27, 50,127,140,197,241,174,101,224, 8,250,126,219,137,149, 48,
+ 161,158, 44,241, 61,219, 24,240,184,130,150,105,182,237, 55,227,
+ 53,129,227, 23, 18,232,189, 51, 30,173, 70, 61,184, 38,244,102,
+ 122,110,145,224,234,128,119,221, 1,129,223,122, 62, 92,101, 93,
+ 84,202, 74,180, 94,109,224,104, 33, 88, 22,145,252, 41,127, 70,
+ 102, 49, 18,224,119, 39, 8, 90, 16, 22,115,237,177, 2, 56, 90,
+ 71,186, 66,208,130,208,213,117, 5,240,220,119,130,100, 34,211,
+ 119, 61, 93, 0,142, 55,115, 72,193, 42, 83, 19,128,227, 32, 73,
+ 213,136, 33,224, 83, 2,240, 11, 85,130, 98,165,108,172, 98,134,
+ 207, 16, 12, 27, 74,117, 1,248,201, 27, 4,195,206, 32,138, 25,
+ 254,147, 96, 88,177,148,237, 4, 95,190,144, 76, 43, 65, 8, 8,
+ 120, 28,128,255, 43, 16, 10,171,192,183, 78, 19, 10, 27,218, 76,
+ 82,134, 91, 85,239, 54,102,248, 27,130, 97, 53,195, 63,122, 4,
+ 195,134, 58,115,152,225, 73,178, 22,147,242, 62, 73,202,194,221,
+ 3,164, 64,129,187, 18,224, 45,122,180, 22,168,208, 49,188,190,
+ 101, 11,107, 11,209, 90,112, 21, 41, 61,106, 27, 76, 31,206,179,
+ 184,243, 67, 49,211,196,229,186,164,193, 50,251,125, 89,115,106,
+ 143,235,162,201,211,247,167,183, 47, 32,179, 11,154,192, 81,141,
+ 44, 85, 47,190,234,236, 83, 48, 22,150, 21, 83,123,153,176,133,
+ 230,167, 9,166,142,133,212,107,170, 51, 53,239, 22,226, 40,139,
+ 93,133,196,171, 94,135,169,251,138,234, 76,159, 59, 32,150, 97,
+ 180, 61,126,145, 69,220,172, 20, 87, 53,160,231,119, 38,117, 63,
+ 177,207,251,225,243,224,237,173, 74,188, 65,175, 77,250,253,228,
+ 128,123,124,154, 27, 48, 88,192, 15, 24,213,245,227,232,209,175,
+ 254,242,243, 21,255, 10,104, 83, 21,182,244, 38, 46,220, 95,101,
+ 17,247,198, 12,237,148, 28,202,226,198,152,172,204, 11, 9,184,
+ 56, 83,125, 9,175,115,176,122,244,230, 51, 22,163,254,176, 26,
+ 7,189,230, 55, 97, 74, 94, 11,234, 10,134, 55,198, 98, 61,186,
+ 122, 9, 6, 89,248, 35, 57,136, 97, 47,173,235,215,205,112, 15,
+ 105,237,129,233, 43, 90,218,250,141, 93,177,229,240,113, 28,202,
+ 169,254, 86,240,170, 25, 43,234,192,198, 2,239, 33,159,185,234,
+ 50,110, 72,129,171, 44,168,137,111,204,240,199,211,194,154,199,
+ 84,119,111,107,250, 3,224,122,239, 96,144,187, 39, 25,220,202,
+ 97,155,214,255, 1, 0,168,120,199,110, 67,179,158,126, 0, 0,
+ 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_key_png[2857] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 35, 0, 0, 0, 34, 16, 6, 0, 0, 0,133, 21,188,
+ 191, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 0,
+ 84, 73, 68, 65, 84,120,218,236,208, 49, 1, 0, 16, 16, 0, 64,
+ 212,250,112,212, 48,107, 32,207, 23,177,153,101,112, 23,225,106,
+ 236,117,114,142, 94,120, 52, 5, 98,196,136, 17, 35, 70,140, 24,
+ 49, 98,196,136, 65,140, 24, 49, 98,196,136, 17, 35, 70,140, 24,
+ 49,136, 17, 35, 70,140, 24, 49, 98,196,136, 17,243,159, 11, 0,
+ 0,255,255, 3, 0, 56,171, 5, 65,131,211,234, 11, 0, 0, 0,
+ 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_layout[7714] = {
+ 112, 97,114,116,115, 32,123, 10, 32, 32, 32, 32,100,101,118,105,
+ 99,101, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98, 97, 99,
+ 107,103,114,111,117,110,100, 32,123, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32, 32,100,101,
+ 118,105, 99,101, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32,100,105,115,112,108,
+ 97,121, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,119,105,100,116,104, 32, 32, 32, 51, 50, 48, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,104,101,105,103,104,116, 32,
+ 32, 52, 56, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,120, 32, 32, 32, 32, 32, 32, 32, 51, 49, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 32, 32, 32, 32, 32, 32,
+ 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 98,117,116,116,111,110,115, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,115,111,102,116,
+ 45,108,101,102,116, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32,109,101,110,117, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120,
+ 32, 49, 52, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 53, 53, 53, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,104,111,109,101, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32,104,111,109,101, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,120, 32, 52, 56, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 53, 57, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 98, 97, 99,107, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 98, 97, 99,107, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32,
+ 50, 56, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 53, 57, 48, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,100,112, 97,100, 45,117,112, 32,
+ 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 97,114,114,111,
+ 119, 95,117,112, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49,
+ 52, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,121, 32, 53, 57, 53, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,100,112, 97,100, 45,100,111,119,110,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 97,114,114,
+ 111,119, 95,100,111,119,110, 46,112,110,103, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 120, 32, 49, 52, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 54, 53, 54, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,100,112, 97,100, 45,108,
+ 101,102,116, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32,
+ 97,114,114,111,119, 95,108,101,102,116, 46,112,110,103, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 49, 49, 49, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 53,
+ 57, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,100,112, 97,
+ 100, 45,114,105,103,104,116, 32,123, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109,
+ 97,103,101, 32, 97,114,114,111,119, 95,114,105,103,104,116, 46,
+ 112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 50, 50, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,121, 32, 53, 57, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,100,112, 97,100, 45, 99,101,110,116,101,114, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32,115,101,108,101, 99,116,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 52, 50, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,121, 32, 54, 50, 54, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,112,104,111,110,101, 45,100,105, 97,108, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32,115,101,110,100, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,120, 32, 52, 56, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 54, 52, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 112,104,111,110,101, 45,104, 97,110,103,117,112, 32,123, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32,101,110,100, 46,112,110,103,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,120, 32, 50, 56, 54, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121,
+ 32, 54, 52, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 112,111,119,101,114, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32,112,111,119,101,114, 46,112,110,103, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 120, 32, 45, 51, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 53, 50, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,118,111,108,117,109,101,
+ 45,117,112, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32,
+ 118,111,108,117,109,101, 95,117,112, 46,112,110,103, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 51, 54, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 50, 54,
+ 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,118,111,108,
+ 117,109,101, 45,100,111,119,110, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,
+ 109, 97,103,101, 32,118,111,108,117,109,101, 95,100,111,119,110,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 51, 54, 50, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,121, 32, 51, 49, 48, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 32, 32, 32, 32,125, 10, 10, 32, 32, 32, 32,107,101,121, 98,
+ 111, 97,114,100, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98,
+ 97, 99,107,103,114,111,117,110,100, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32, 32,
+ 107,101,121, 98,111, 97,114,100, 46,112,110,103, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 98,
+ 117,116,116,111,110,115, 32,123, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 49, 32,123, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,
+ 107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 32, 48, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 32,
+ 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 50, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120,
+ 32, 51, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,121, 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 51, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,120, 32, 55, 52, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 48, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 52, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 49, 49,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 53,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,
+ 103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 49, 52, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 48, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 54, 32,123, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32,
+ 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 56, 53, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121,
+ 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 55, 32,123,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 120, 32, 50, 50, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,121, 32, 48, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 56, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,
+ 101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 53, 57, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 48,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 57, 32,123, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,
+ 109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32,
+ 50, 57, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,121, 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 48, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,120, 32, 51, 51, 51, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 48, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,113, 32,123, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109,
+ 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 32,
+ 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,121, 32, 32, 51, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,119, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,120, 32, 51, 55, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 51, 54, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,101, 32,123, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,
+ 103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 55, 52,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 51, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 114, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 49, 49, 49, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 51, 54, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,116, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 52, 56,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 51, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 49, 56, 53, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 51, 54, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,117, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 50, 50,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 51, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 105, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 50, 53, 57, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 51, 54, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,111, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 57, 54,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 51, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 112, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 51, 51, 51, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 51, 54, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 97, 32,123, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,
+ 103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 32, 48,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 32, 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,115, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,
+ 112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,120, 32, 51, 55, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 55, 50, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,100, 32,123, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,
+ 101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 55, 52, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,102,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,
+ 103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 49, 49, 49, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 55, 50, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,103, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 52, 56, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,104,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,
+ 103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 49, 56, 53, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 55, 50, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,106, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 50, 50, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,107,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,
+ 103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 50, 53, 57, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 55, 50, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,108, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 57, 54, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 55, 50, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 68,
+ 69, 76, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,
+ 112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,120, 32, 51, 51, 51, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 55, 50, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 67, 65, 80, 32,123, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120,
+ 32, 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,121, 32, 32, 49, 48, 56, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,122, 32,123, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,
+ 107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 51, 55, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49,
+ 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32,123,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 120, 32, 55, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,121, 32, 49, 48, 56, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 99, 32,123, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,
+ 107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 49, 49, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32,
+ 49, 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,118, 32,
+ 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,103,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,120, 32, 49, 52, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,121, 32, 49, 48, 56, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 98, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 56, 53, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 49, 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 110, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 50, 50, 50, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49, 48, 56, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,109, 32,123, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,
+ 103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 53,
+ 57, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,121, 32, 49, 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 80, 69, 82, 73, 79, 68, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101,
+ 32, 32,107,101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 50, 57, 54, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 121, 32, 49, 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 69, 78, 84, 69, 82, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,
+ 101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,120, 32, 51, 51, 51, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49,
+ 48, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 65, 76,
+ 84, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,
+ 110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,120, 32, 32, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 32, 49, 52, 52, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 83, 89, 77, 32,123, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,
+ 109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32,
+ 51, 55, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,121, 32, 49, 52, 52, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 65, 84, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,
+ 101,121, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,120, 32, 55, 52, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49, 52,
+ 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 83, 80, 65, 67,
+ 69, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,105,109, 97,103,101, 32, 32,115,112, 97, 99,101,
+ 98, 97,114, 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 49, 49, 49, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32,
+ 49, 52, 52, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 125, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 83, 76,
+ 65, 83, 72, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121,
+ 46,112,110,103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,120, 32, 50, 53, 57, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49, 52, 52,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 67, 79, 77, 77, 65,
+ 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32,105,109, 97,103,101, 32, 32,107,101,121, 46,112,110,
+ 103, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32,120, 32, 50, 57, 54, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,121, 32, 49, 52, 52, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 65, 76, 84, 50, 32,123, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,105,
+ 109, 97,103,101, 32, 32,107,101,121, 46,112,110,103, 10, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32,
+ 51, 51, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,121, 32, 49, 52, 52, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,125, 10, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32,125, 10, 32, 32, 32, 32,125, 10,125, 10, 10,108, 97,121,111,
+ 117,116,115, 32,123, 10, 32, 32, 32, 32,112,111,114,116,114, 97,
+ 105,116, 32,123, 10, 32, 32, 32, 32, 32, 32, 32, 32,119,105,100,
+ 116,104, 32, 32, 32, 32, 32, 57, 48, 48, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32,104,101,105,103,104,116, 32, 32, 32, 32, 55, 51, 48,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 99,111,108,111,114, 32, 32,
+ 32, 32, 32, 48,120,101, 48,101, 48,101, 48, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32,101,118,101,110,116, 32, 32, 32, 32, 32, 69, 86,
+ 95, 83, 87, 58, 48, 58, 49, 10, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32,112, 97,114,116, 49, 32,123, 10, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32,110, 97,109,101, 32, 32, 32, 32,100,101,118,
+ 105, 99,101, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 120, 32, 32, 32, 32, 32, 32, 32, 52, 48, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32,121, 32, 32, 32, 32, 32, 32, 32, 45,
+ 49, 56, 10, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32,112, 97,114,116, 50, 32,123, 10, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32,110, 97,109,101, 32, 32, 32,
+ 32,107,101,121, 98,111, 97,114,100, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32,120, 32, 32, 32, 32, 32, 32, 32, 52, 56,
+ 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,121, 32,
+ 32, 32, 32, 32, 32, 32, 50, 48, 48, 10, 32, 32, 32, 32, 32, 32,
+ 32, 32,125, 10, 32, 32, 32, 32,125, 10, 10, 32, 32, 32, 32,108,
+ 97,110,100,115, 99, 97,112,101, 32,123, 10, 32, 32, 32, 32, 32,
+ 32, 32, 32,119,105,100,116,104, 32, 32, 32, 32, 32, 57, 48, 48,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32,104,101,105,103,104,116, 32,
+ 32, 32, 32, 54, 55, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 99,
+ 111,108,111,114, 32, 32, 32, 32, 32, 48,120,101, 48,101, 48,101,
+ 48, 10, 32, 32, 32, 32, 32, 32, 32, 32,101,118,101,110,116, 32,
+ 32, 32, 32, 32, 69, 86, 95, 83, 87, 58, 48, 58, 48, 10, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32,112, 97,114,116, 49, 32,123, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,110, 97,109,101, 32,
+ 32, 32, 32, 32, 32,100,101,118,105, 99,101, 10, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 53, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32,121, 32, 32, 32, 32, 32, 32, 32, 32, 32, 52, 52, 48, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,114,111,116, 97,116,
+ 105,111,110, 32, 32, 51, 10, 32, 32, 32, 32, 32, 32, 32, 32,125,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32,112, 97,114,116, 50, 32,123,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,110, 97,109,
+ 101, 32, 32, 32, 32, 32,107,101,121, 98,111, 97,114,100, 10, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,120, 32, 32, 32, 32,
+ 32, 32, 32, 32, 50, 53, 48, 10, 32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32,121, 32, 32, 32, 32, 32, 32, 32, 32, 52, 55, 48,
+ 10, 32, 32, 32, 32, 32, 32, 32, 32,125, 10, 32, 32, 32, 32,125,
+ 10,125, 10, 10,107,101,121, 98,111, 97,114,100, 32,123, 10, 32,
+ 32, 32, 32, 99,104, 97,114,109, 97,112, 32,113,119,101,114,116,
+ 121, 50, 10,125, 10, 10,110,101,116,119,111,114,107, 32,123, 10,
+ 32, 32, 32, 32,115,112,101,101,100, 32, 32,102,117,108,108, 10,
+ 32, 32, 32, 32,100,101,108, 97,121, 32, 32,110,111,110,101, 10,
+ 125, 10
+};
+
+static const unsigned char _data_menu_png[3079] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 84, 0, 0, 0, 34, 16, 6, 0, 0, 0,145,128, 34,
+ 94, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 1,
+ 50, 73, 68, 65, 84,120,218,236,220,161, 78,195, 80, 20,128, 97,
+ 70, 48, 44, 72, 50, 5, 10,130, 6, 75,192,162,120,132, 62,193,
+ 44, 40, 12, 15, 64,176,224, 73, 61,104, 44, 4, 11,154, 48, 53,
+ 12, 36, 56,194,228, 69,220, 94,193, 72, 89, 41, 91, 90,146,239,
+ 51, 39, 89,167, 78,254,220,110,230,118, 66, 8, 33,132, 57,104,
+ 165,121, 43,160,205, 22,198, 63,216,217,205,243,193, 83,217,215,
+ 87, 94,227,220,218,180, 58,234,187,127,136,243,185, 55,254,228,
+ 246, 38,203,214,214,127, 8,244,171,197, 60,206,131,165, 56, 87,
+ 47,139, 7,199,150, 76,125,251, 69, 71,195,171, 56, 79,223,227,
+ 28,101,191,124,197,247,251, 69,152, 47,150,202,244,165,174, 82,
+ 103,149,127,131,166, 87,249,198,137, 37, 50,123,169,179,212,221,
+ 196, 64,187, 23,150, 70, 3, 39,106,213, 64,161, 9,203,123, 2,
+ 229, 95, 17, 40, 2, 5,129, 34, 80, 16, 40, 8, 20,129,130, 64,
+ 17, 40, 8, 20, 4,138, 64, 65,160, 8, 20, 4, 10, 2, 69,160,
+ 32, 80, 4, 10, 13,251,200, 4, 74,139, 13,123, 21, 3,125, 60,
+ 140,243,237,218,210,152,189,212, 89,234,174,242, 9,122,118, 94,
+ 118,244,194,244, 94,233,169,179,239, 38,220,205,148, 46,119, 58,
+ 42,238,104,218, 30,196,217,205, 45,151,191,135,121, 87,220,209,
+ 52, 42, 61, 0, 59,238, 7,197,191,120,168,233, 19, 0, 0,255,
+ 255, 3, 0, 6, 52, 60,111, 44, 61, 74,153, 0, 0, 0, 0, 73,
+ 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_power_png[3782] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 58, 0, 0, 0, 67, 16, 6, 0, 0, 0,157, 6,202,
+ 98, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 241, 73, 68, 65, 84,120,218,236, 93, 63, 76, 83, 65, 28, 46,196,
+ 5, 84, 22,140, 70, 3,139,104, 93, 76, 90,199, 86, 93,108, 36,
+ 14,152, 72, 76,152, 72, 96, 51,178, 22, 54, 19, 37, 49, 14, 10,
+ 107,113,172,166, 19,137,209,164, 14, 6,197, 77,234, 38, 68, 22,
+ 234, 31, 6,136, 9, 70, 28, 20,203, 88,135,187,175,205, 93,251,
+ 120,175,237, 81, 30,119,223,183,252,104, 31,247,238,253,238,235,
+ 239,254,126,247,174,163, 92, 46,151,203,229, 8, 97, 9,142,224,
+ 143, 43, 87,115,185,111, 95, 89, 32, 42,250,126, 10,123, 97, 70,
+ 216,238, 92,107,247, 43,141, 10,187, 54, 41,236,230,201,125, 35,
+ 212,109,244, 14, 10,155,250, 46,108, 98, 69, 35,112, 64,218,251,
+ 134, 50,124, 41, 9,254, 39,108, 33, 38,236,226, 89, 97,183, 23,
+ 72,104, 83,184,121, 70,216,161,219,218,133, 92,123,242,199, 15,
+ 38, 53, 37,173,252,254,245,170,176,249, 31, 36,116, 79,116,201,
+ 2, 76, 31, 19,182,127, 43,156,207, 57, 36,107,130,216, 41, 97,
+ 103,119,132,221, 29,245, 75,217,233, 86, 91,248,104, 56,220, 68,
+ 234,192,115,226,185,225,135,179,132, 34, 34,199,151,204,116,106,
+ 14, 10,221,154, 31, 93, 57, 71, 9, 69, 1, 28,150,136, 12, 26,
+ 177,240,203, 25, 66,227,113,105, 99,150,250, 23, 83,253,180,158,
+ 208,145, 1, 55,250, 6,181,126, 90, 70,104,116, 70, 29, 87,186,
+ 50,126,134,223,214, 17, 26,127,234,230,120,186,234,183,165, 17,
+ 234, 26,172,141, 80, 91,122,179,205,251,221, 25, 33,172, 2, 9,
+ 181,172,234, 37,161,140, 80,130,132, 18, 36,148, 8, 21,161,174,
+ 142, 7,173, 35, 52,221, 35,237,113, 97,199,150, 88,196,135,154,
+ 208,232, 19,245,243,137, 27, 44, 98,182,161, 4, 9, 37,154, 36,
+ 20,210,135, 49, 95, 41,196,222, 72,172,182,150,158,240, 66, 64,
+ 213, 31,196, 73,233,163,194, 66,227,242,123, 90,216,124,131,189,
+ 223,241, 15,194, 66,127,154,145,247, 55, 47, 60,102,132, 6, 34,
+ 18,184,246,165,177,236, 32,100, 6,176, 64,139,251,251,171,218,
+ 136,150, 8,157,184, 91,159,200, 13,169, 23,125, 56,220, 88,118,
+ 249, 7,106,122, 64, 87,181, 17,134, 9, 69, 27,167, 75, 57, 54,
+ 52,225,111,163,146,125, 84,169, 94,233,177,174,135,252, 9, 67,
+ 132,166, 60,182, 45,205,203,239,253, 21,220,123, 3,233,243,211,
+ 245,175,199, 51,164,198, 40,161,250,202, 63, 34,179, 56,105, 54,
+ 251,194,197,250,145,106,171,252,178,237,132,122,205,193,154, 38,
+ 82,199,246, 91, 82,209,214,113,232,110, 41, 32, 49, 11, 44,210,
+ 80,141, 67, 43,132,104,219,235,162, 59,193,110,151,153, 19,246,
+ 82, 92,216, 79,104,139,125,198,151, 93,207,229, 31, 91,164,196,
+ 104,132,130,208,146,214,233,193,164,187,159,128, 25,189, 88,236,
+ 107,244,155, 40,192,253,188,218,108,194, 80,149, 91,240,232,148,
+ 140,156, 51,155,253,248,199,250,223,175, 76,144, 26,163,132, 98,
+ 107,184, 30,169,232,125,182,186,206,137,244,250,114, 27,242,123,
+ 247,152,212, 24, 37, 20, 85,239,252,122,253,235,201,207,194, 98,
+ 65,187,118, 23,148,246, 67,144,215,239,189, 82,211,215,140,115,
+ 215,205,140,115,217, 41,242, 25, 39,246,203,170, 22,239, 2,208,
+ 219,214,104,208,252, 60, 58, 61,217,203,106,126,196, 62, 15, 91,
+ 48, 67, 52, 55,103,102,120,130,244,179,127, 73,100, 91, 35, 84,
+ 199,242,178,106, 19,114,234, 46,250, 71, 88, 47,201,201,175, 55,
+ 106,103, 7,233, 35, 47, 72,193,129, 18,234, 85, 37, 23,252,254,
+ 49,201,162, 14, 85,149, 75,144, 80,130,132, 18, 36,148, 32,161,
+ 36,148, 32,161, 4, 9, 37, 72, 40,161,163, 56, 73, 66, 25,161,
+ 97,134,171,154,166,170,223,150, 17,186,150,118,147,208,170,223,
+ 150, 17, 90,236,113,180,237,236,177,148, 80,172,254,148, 28, 81,
+ 60,192,207,234,122,178,165,157,162,247,231,221, 32,180,214, 79,
+ 75, 9,133,140,212, 86, 57, 40,252,170, 61, 6,196,242, 97, 75,
+ 54,105, 87, 21, 12, 63,178, 73, 71, 39, 22, 32,244,246, 82, 47,
+ 30, 54,192, 15,111, 1,187, 35, 7,241,160,211,176, 27, 23,118,
+ 76,190, 18, 32,236,199,126, 32, 34,159, 73, 85,228,242, 29,199,
+ 38, 22,252, 0,113, 26,118,158, 23,167, 66, 58, 12,153, 82,159,
+ 179, 34,170,243,133,163,103,159, 85,100,164,242,115, 66, 70, 0,
+ 54, 58,183,251,205,216,232,228, 44, 74,253,115, 65,170, 40, 35,
+ 13,207,124,241,116, 66,165, 74,134,122, 17, 47,239,192, 46,186,
+ 190, 91,106, 21,221,123, 93,218,193, 96, 85,230,230,105,245,115,
+ 81,158,189,102,254,216,201, 14, 30, 8,107, 23, 72,168,101,248,
+ 63, 0,179,160, 16,217,188,199, 69, 53, 0, 0, 0, 0, 73, 69,
+ 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_select_png[3374] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 98, 0, 0, 0, 33, 16, 6, 0, 0, 0,114,249,162,
+ 143, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 2,
+ 89, 73, 68, 65, 84,120,218,236,156, 59, 79,219, 96, 20,134, 67,
+ 196, 2, 20,150, 86, 97, 33, 83, 43,179, 80, 53, 43,208,141,170,
+ 98,233, 90,150, 72,229, 55,132,203,136, 84,196, 68,163,142,204,
+ 69,176, 20, 9, 21, 41, 75, 85, 53, 35, 9, 99, 16, 83,211,192,
+ 18,166, 8,150,150,203,202,112,206, 73, 20, 87, 86, 76,108, 82,
+ 98, 63,207,242,202, 78,236, 47, 58, 62,175,191,139,227, 51, 48,
+ 251,122,103,167,246, 59,241, 64, 60,125, 43,234,124, 86,253, 35,
+ 250,108,190,253,123,206,167, 4, 64,147,234, 74,251,246,197,119,
+ 221, 63,166,154, 19,189,252, 17,118,203, 3,225, 26,194,201,139,
+ 190, 91, 39,209,161,119,198, 41,172,233,246,114,208, 51, 14, 6,
+ 59,124,162, 33,186,240, 66, 13, 48,170, 31, 96, 4,232, 1,118,
+ 195, 93, 74,180,247, 32, 95,107,162,231,169, 30,245, 16,115,171,
+ 162,239,159,115, 81,224,241,178,119, 42, 90,220,244,123, 68,242,
+ 126, 13,124, 40, 97, 4,232, 31, 44, 79, 45,111, 67, 51,132,157,
+ 112,230,132, 32, 67,255, 97,121,219,217, 24, 73,127, 67, 35,140,
+ 0, 81, 50,134,229,181,111, 67,216,114, 41, 67, 35,136,242, 80,
+ 202, 22,133, 58, 26, 98,241,136,160, 65,244,177,213,209, 22,174,
+ 101, 87,123,142,208, 92, 62, 5,136, 48,182,108,235,252, 21,173,
+ 46,187,122,136,185, 51,130, 4,241,163,149,247,218, 67, 12,237,
+ 138,102,174, 9, 14,196,143,204, 43,243,129,246, 16,147,121,130,
+ 2, 48,153, 87, 67,164, 27, 4, 3, 32,221, 80, 67, 56, 87, 4,
+ 3,192,185, 74, 18, 4,128, 22, 24, 2, 0, 67, 0, 96, 8, 0,
+ 191,134,168,167, 8, 5, 64, 61,101,134, 56, 32, 24, 0,245, 3,
+ 53,132,189,180, 13, 16,103,170, 57, 53,132, 85, 47,112, 87, 59,
+ 0,136,133, 17, 86,204, 7,174, 73,117,169, 68,112, 32,126,180,
+ 242,222,101,136,242,148,142,165,198, 9, 18, 68, 31, 27, 25, 89,
+ 222,123, 46,187,238,213, 8, 22, 68,159, 47,211,238, 61, 30,134,
+ 176,130, 79, 69,234, 43, 65, 4,177,188,254,183,176, 89,135, 7,
+ 115,214, 83, 48,217,134, 40, 77,158,189, 71, 64, 62,159, 84,111,
+ 109, 49,183,128,254,197,242,214,242,216, 27,159,165, 44,111,179,
+ 162, 27,186, 77,157, 38,232, 7, 74, 47, 69,183,103,252, 30,209,
+ 101,109, 87,107,224, 56,163, 6, 57, 20, 29,222,229, 34,192,255,
+ 227, 70,111,220,219,179,162,149,202,125,207, 16,176,216,177, 53,
+ 248,235,155,232,155,143,162,211, 58,123,183,250, 78, 0, 15, 65,
+ 115,217,180, 44,250,115, 68, 71, 52,149,110,207, 56, 24,206, 15,
+ 179, 33, 85, 65,183, 11,251,162, 25, 45, 54,107,111,228,217,171,
+ 170,148,201,135,110, 38,195,246, 39,212,234, 19,143, 30, 32, 27,
+ 180,165, 59, 0, 0, 0,255,255, 3, 0, 97,168,142, 82, 14,236,
+ 17,113, 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_send_png[3561] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 46, 0, 0, 0, 47, 16, 6, 0, 0, 0,204,117, 36,
+ 209, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 20, 73, 68, 65, 84,120,218,236,156, 61,108,211, 64, 20,199, 15,
+ 171, 75,194,199, 66, 21, 22, 60, 32,192, 93, 64,201, 72, 93,182,
+ 34,196,208, 74, 32,164, 78, 29,186, 33, 58, 66,202, 80, 33, 8,
+ 31, 98, 32,201, 74,214, 64, 59, 69,170,130,212, 76, 72, 97,107,
+ 186, 6,193, 66, 40, 48, 36,226,163, 18, 75, 33,237,202,112,239,
+ 165,178, 19,247, 92,251,238,156,212,239,191,188,184, 57,217,201,
+ 239,222, 61,191,119,125,206,177,169,171, 43, 43, 91, 95,216,144,
+ 235,236, 54,183,201, 55, 7,143,251,243,206,105,135, 79, 99,209,
+ 94, 62,177,202,109, 38,195,173,181,195,173, 9,128,205,223, 48,
+ 176, 10,246,164,224,132,183,157,182,125,134,219, 86, 22,236, 9,
+ 110,155,205,152, 0,183, 10,220, 78,127, 3,208, 93,120, 99, 67,
+ 205,245,112,194,204, 37,184, 46,252,125,119, 30,192,127,224,182,
+ 126,129,219, 78,106,196,129, 35,224,217,167,112,140, 30,154,142,
+ 118,101, 37, 97,101,217,112,108,127,132, 21,112,138,219,242, 21,
+ 85,161,105, 76, 77,136, 88,104,128, 7, 35,224, 60, 27, 9, 89,
+ 240, 57, 95,192,113,237, 19,183,235, 63,134, 12, 56,222,212,238,
+ 31, 7, 15,234,178, 35,161,153,199,176, 32,225, 94, 80,122, 21,
+ 214,243, 67, 2,159, 4, 15, 88,168,178, 35, 45,188, 23, 60,132,
+ 239, 89,236, 6,141,249, 70, 72,208, 27, 44, 86,194,216,143, 43,
+ 25, 87,182, 50,224,113, 5, 45, 15,188, 79,224,120,194,185,115,
+ 140, 52, 0,252,226, 93,103,210, 16, 24,120,194,117,194,228, 42,
+ 65, 30,164,211,215,157,217, 89, 96,224,179, 57,231, 9, 73, 7,
+ 43,147,118, 86,206,190,129, 35,224,233, 37,130, 24, 68,115,231,
+ 189, 66,140, 7,240,153, 28, 65,147, 17, 98,174, 61, 16, 0,199,
+ 129, 88,234,146, 66,214, 41,147, 2,224,184,169, 68,146,235,233,
+ 251, 49,221, 24, 28,244, 73,146, 61,221,118, 1,199, 60,155,178,
+ 17, 53,178,242, 46,224, 19, 5,130,162,163, 64,178, 10,232,225,
+ 55, 9,138, 14,153,219, 0,124,252, 6,193,208,227,233,232,225,
+ 63, 9,134,150, 88,254,207,112,198, 24,146,106, 25,132,128,128,
+ 19,112,146,116,224, 45,218, 21,212,162,118, 10,128, 99, 99, 12,
+ 73,173,246,118, 1,120,231, 45,193,208,161,207,247, 12,124, 65,
+ 48,116,168,149,197, 24,158,165,208,162, 82,216,195,216,151,165,
+ 236,191, 65,146, 10,124,209, 3,248,102,131,224,200, 84,175, 75,
+ 183,233, 1,188,215, 71, 77,105,162,212, 80,178, 55, 47, 40,124,
+ 214, 31, 17, 44, 25,158, 93,203,249,172, 52,201,211,195,233,253,
+ 69,110,251,187,108, 5,165, 61, 54,166, 83,246,226,179,146,132,
+ 182,102,239,126,114, 1,112,156,161,202,119,130,233, 39,132,148,
+ 109,209, 72,159,155, 87,155,151,184,173,231, 9,238, 32,161, 67,
+ 138,251,197, 15,185, 91, 88,217,226,182,113,153, 32, 51,198, 88,
+ 121,202,233,144, 98, 5,220,158,125,109,199, 27,252,225, 65,135,
+ 4,238, 6, 95,249, 26,143, 24, 93, 42, 5, 5, 45, 9, 56,170,
+ 254,146,219,226, 95,175,116,104, 52,133,105,241,243, 91,238,138,
+ 49, 98,224,238,252,253, 25,124,192,218,147,209, 74, 43,209, 81,
+ 48,100, 20,119,100, 59,144,162,127,177, 97, 41,139,249,232,114,
+ 117, 56, 39,192, 13,120,121, 45,108,200, 16, 73,211,163,223,189,
+ 9,192,173, 3,120, 24, 9,187, 74,211,240,252,227, 68,145, 91,
+ 217, 61,142,238,103,238, 27,176, 73,215,185, 3, 3,214,116, 77,
+ 113,196, 63,110,128, 49,177,233, 42, 24, 18, 16,146,204, 95, 48,
+ 1,208, 25, 54, 46,152,136,118,202,185,130, 16,112,159, 82, 81,
+ 125,227,255, 3, 0,233,237,207,153, 62,209, 88,144, 0, 0, 0,
+ 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_spacebar_png[2916] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0,145, 0, 0, 0, 34, 16, 6, 0, 0, 0, 15, 22,231,
+ 187, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 0,
+ 143, 73, 68, 65, 84,120,218,236,212, 49, 1, 0, 32, 12,192, 48,
+ 192,214,196,129, 13,110, 28,160,103, 70,248,144,177, 39,145,208,
+ 163, 61,238,121,185,215,108, 0, 69,134, 4,128, 17, 1, 70, 36,
+ 1, 96, 68,128, 17, 73, 0, 24, 17, 96, 68, 18, 0, 70, 4, 24,
+ 145, 4,128, 17, 1, 70, 36, 1, 96, 68,128, 17, 73, 0, 24, 17,
+ 96, 68, 18, 0, 70, 4, 24,145, 4,128, 17, 1, 70, 36, 1, 96,
+ 68,128, 17, 73, 0, 24, 17, 96, 68, 18, 0, 70, 4, 24,145, 4,
+ 128, 17, 1, 70, 36, 1, 96, 68,128, 17, 73, 0, 24, 17, 96, 68,
+ 18, 0, 70, 4, 24,145, 4, 64,181, 15, 0, 0,255,255, 3, 0,
+ 87,196, 5, 65, 55,106, 37, 28, 0, 0, 0, 0, 73, 69, 78, 68,
+ 174, 66, 96,130
+};
+
+static const unsigned char _data_volume_down_png[3586] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 67, 0, 0, 0, 49, 16, 6, 0, 0, 0,209,176,200,
+ 250, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 3,
+ 45, 73, 68, 65, 84,120,218,236,157,191,111,211, 64, 20,199, 13,
+ 234, 82, 68,197, 64, 21, 33,148, 12, 80, 4, 11,136,172,117, 97,
+ 138,132, 24, 26, 9,150,178, 88, 34, 27,136, 17, 8,107, 11, 35,
+ 16,254,134, 84,242, 66, 36, 36,134, 14,168, 82, 38,136, 25, 88,
+ 140,202,210,136, 76,141, 16, 32,178, 80, 53,108,152,225,222,139,
+ 100,171,174,206,241, 97,159,115,223,239,242,106,183,138,239,221,
+ 125,242,238,221, 15, 95,143, 5, 65, 16, 4,129,101, 93,187,238,
+ 186,131,175,150, 98,205,187,194, 86,190, 11,123,233, 85,186,207,
+ 219,125, 40,236,222, 25, 97,255, 56, 22,100, 89,150,101,125,120,
+ 239, 56, 75, 23,212,125,222,156, 90, 0,170, 85, 97,107,132, 88,
+ 229, 7,253,193, 2,217,245,116,207, 89,229, 31, 14, 8,144,183,
+ 194,118,169, 74,124, 31,192,104, 1,198,242, 23, 97,215,206, 9,
+ 123,194,205,182,248, 12, 94,131,236,152,128,232, 80,185, 62, 94,
+ 70, 19,103, 2, 6, 71,134,134, 71, 17,162, 71,191,232,233,225,
+ 14,131,217,160,235,234, 3, 97,219, 54, 34, 73, 50, 29, 79, 6,
+ 196,163,147, 84,225, 87,139,225, 30,151,147,203, 61,239,162,201,
+ 149,128, 17, 5, 98,146, 51, 20, 76, 92,110, 0,162, 8,140,250,
+ 70,177,129,136, 3,132,253,130, 18,230, 24, 23, 95,210,232, 98,
+ 97, 54,221,174, 53,105, 20,179, 47,108,255, 49, 80,144,138, 24,
+ 245,103,102,184,111,138,159,169,193, 40,255,164,136,241,194, 12,
+ 247,217, 79,246, 27,138, 1,195,182,205,172, 6, 83,253,150, 6,
+ 163, 98,232, 55,135,115, 42, 40, 6, 12, 83,186,144,184,209, 10,
+ 36, 57, 92,133, 0, 6,132, 46, 5, 96,196,118, 41, 57,231, 88,
+ 188, 40, 89, 63, 11, 48,180,210, 94, 41, 95, 32, 26, 61, 93,106,
+ 2, 96,104, 17, 33,244, 1,130, 53,135,198,201, 67,119,105,219,
+ 130,221,211,181,132,136, 24,249, 0,177,163,123, 73, 17, 49, 82,
+ 73, 54, 73, 44,223, 18,182,186,163, 22,176,197,155,194,182,126,
+ 3, 12,173,180,186,158,237,243,120, 79,237, 36,226,208,132,228,
+ 242,138,176,234,182, 50,162, 43, 41,148,120,179,115,191, 25,190,
+ 175,126,173, 7, 96, 20, 82,158, 23,190, 86,191,148, 1, 48, 10,
+ 169,209, 59,140, 74,160, 67, 20,157,161, 29, 59, 0,195,104,241,
+ 38,230,218, 32,124, 63,154,115, 0, 12,211, 34, 5,189,234,121,
+ 250, 70,248,126,247, 60,134,171, 90,169,181,159, 44,244,175, 45,
+ 165,123, 30,111, 90,110,211, 84,250, 34, 1,210,255, 6, 48,180,
+ 146,236,238,242, 62,231, 2,138,214, 70,254,255,171,151,232, 74,
+ 50, 21, 55,104,123, 69,247,146, 2,140, 92, 1,225,174,104,236,
+ 0, 12,232,144,174,168,117,160, 27, 32, 0, 67, 11, 13, 75, 97,
+ 64,126,109,231, 93, 34, 36,159, 33,157,122,162, 7, 32, 67, 68,
+ 12,189,244,233, 47,234, 0, 96, 64,242, 96,168,159, 90, 45, 72,
+ 18,216, 4, 10, 71,130,225,223, 55,179, 26, 76,245, 91, 30, 12,
+ 223, 80, 48,124,160,112, 36, 24, 35, 26, 38,121, 87,204,112,159,
+ 253, 28,109, 3, 5,169,228,115,107, 67,216,241,140,158,114,199,
+ 126,177,159,144, 36, 24,252, 13,218,122, 58,155,110,179, 95,136,
+ 20, 83, 14, 87,187,207,103,171,107, 97, 63,216, 47,104, 74, 48,
+ 88,155,118,177, 1,225,114,111,226,228, 28,181, 96, 68, 1,233,
+ 12,138,213,101, 0,136,164,154,114,173,132, 67,241, 46,237, 76,
+ 186, 67,135,188,231,125, 34, 15, 79, 84,189,166, 67,238,135,247,
+ 208,196,153,130,193,154,172, 10,210,117,249,182,176,252, 2, 12,
+ 31,217, 28,221,163,152, 86,156, 52,250,159,169,171,240, 34, 32,
+ 148,208,180,185,130, 17, 7, 74,135,174, 59,252, 31, 80,222, 80,
+ 68, 73,121, 98, 77,236, 86, 58,128,160, 88,255, 6, 0,161,232,
+ 198,240, 68,249,103, 76, 0, 0, 0, 0, 73, 69, 78, 68,174, 66,
+ 96,130
+};
+
+static const unsigned char _data_volume_up_png[3856] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 0, 67, 0, 0, 0, 49, 16, 6, 0, 0, 0,209,176,200,
+ 250, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 10, 79,105, 67, 67, 80, 80,104,
+ 111,116,111,115,104,111,112, 32, 73, 67, 67, 32,112,114,111,102,
+ 105,108,101, 0, 0,120,218,157, 83,103, 84, 83,233, 22, 61,247,
+ 222,244, 66, 75,136,128,148, 75,111, 82, 21, 8, 32, 82, 66,139,
+ 128, 20,145, 38, 42, 33, 9, 16, 74,136, 33,161,217, 21, 81,193,
+ 17, 69, 69, 4, 27,200,160,136, 3,142,142,128,140, 21, 81, 44,
+ 12,138, 10,216, 7,228, 33,162,142,131,163,136,138,202,251,225,
+ 123,163,107,214,188,247,230,205,254,181,215, 62,231,172,243,157,
+ 179,207, 7,192, 8, 12,150, 72, 51, 81, 53,128, 12,169, 66, 30,
+ 17,224,131,199,196,198,225,228, 46, 64,129, 10, 36,112, 0, 16,
+ 8,179,100, 33,115,253, 35, 1, 0,248,126, 60, 60, 43, 34,192,
+ 7,190, 0, 1,120,211, 11, 8, 0,192, 77,155,192, 48, 28,135,
+ 255, 15,234, 66,153, 92, 1,128,132, 1,192,116,145, 56, 75, 8,
+ 128, 20, 0, 64,122,142, 66,166, 0, 64, 70, 1,128,157,152, 38,
+ 83, 0,160, 4, 0, 96,203, 99, 98,227, 0, 80, 45, 0, 96, 39,
+ 127,230,211, 0,128,157,248,153,123, 1, 0, 91,148, 33, 21, 1,
+ 160,145, 0, 32, 19,101,136, 68, 0,104, 59, 0,172,207, 86,138,
+ 69, 0, 88, 48, 0, 20,102, 75,196, 57, 0,216, 45, 0, 48, 73,
+ 87,102, 72, 0,176,183, 0,192,206, 16, 11,178, 0, 8, 12, 0,
+ 48, 81,136,133, 41, 0, 4,123, 0, 96,200, 35, 35,120, 0,132,
+ 153, 0, 20, 70,242, 87, 60,241, 43,174, 16,231, 42, 0, 0,120,
+ 153,178, 60,185, 36, 57, 69,129, 91, 8, 45,113, 7, 87, 87, 46,
+ 30, 40,206, 73, 23, 43, 20, 54, 97, 2, 97,154, 64, 46,194,121,
+ 153, 25, 50,129, 52, 15,224,243,204, 0, 0,160,145, 21, 17,224,
+ 131,243,253,120,206, 14,174,206,206, 54,142,182, 14, 95, 45,234,
+ 191, 6,255, 34, 98, 98,227,254,229,207,171,112, 64, 0, 0,225,
+ 116,126,209,254, 44, 47,179, 26,128, 59, 6,128,109,254,162, 37,
+ 238, 4,104, 94, 11,160,117,247,139,102,178, 15, 64,181, 0,160,
+ 233,218, 87,243,112,248,126, 60, 60, 69,161,144,185,217,217,229,
+ 228,228,216, 74,196, 66, 91, 97,202, 87,125,254,103,194, 95,192,
+ 87,253,108,249,126, 60,252,247,245,224,190,226, 36,129, 50, 93,
+ 129, 71, 4,248,224,194,204,244, 76,165, 28,207,146, 9,132, 98,
+ 220,230,143, 71,252,183, 11,255,252, 29,211, 34,196, 73, 98,185,
+ 88, 42, 20,227, 81, 18,113,142, 68,154,140,243, 50,165, 34,137,
+ 66,146, 41,197, 37,210,255,100,226,223, 44,251, 3, 62,223, 53,
+ 0,176,106, 62, 1,123,145, 45,168, 93, 99, 3,246, 75, 39, 16,
+ 88,116,192,226,247, 0, 0,242,187,111,193,212, 40, 8, 3,128,
+ 104,131,225,207,119,255,239, 63,253, 71,160, 37, 0,128,102, 73,
+ 146,113, 0, 0, 94, 68, 36, 46, 84,202,179, 63,199, 8, 0, 0,
+ 68,160,129, 42,176, 65, 27,244,193, 24, 44,192, 6, 28,193, 5,
+ 220,193, 11,252, 96, 54,132, 66, 36,196,194, 66, 16, 66, 10,100,
+ 128, 28,114, 96, 41,172,130, 66, 40,134,205,176, 29, 42, 96, 47,
+ 212, 64, 29, 52,192, 81,104,134,147,112, 14, 46,194, 85,184, 14,
+ 61,112, 15,250, 97, 8,158,193, 40,188,129, 9, 4, 65,200, 8,
+ 19, 97, 33,218,136, 1, 98,138, 88, 35,142, 8, 23,153,133,248,
+ 33,193, 72, 4, 18,139, 36, 32,201,136, 20, 81, 34, 75,145, 53,
+ 72, 49, 82,138, 84, 32, 85, 72, 29,242, 61,114, 2, 57,135, 92,
+ 70,186,145, 59,200, 0, 50,130,252,134,188, 71, 49,148,129,178,
+ 81, 61,212, 12,181, 67,185,168, 55, 26,132, 70,162, 11,208,100,
+ 116, 49,154,143, 22,160,155,208,114,180, 26, 61,140, 54,161,231,
+ 208,171,104, 15,218,143, 62, 67,199, 48,192,232, 24, 7, 51,196,
+ 108, 48, 46,198,195, 66,177, 56, 44, 9,147, 99,203,177, 34,172,
+ 12,171,198, 26,176, 86,172, 3,187,137,245, 99,207,177,119, 4,
+ 18,129, 69,192, 9, 54, 4,119, 66, 32, 97, 30, 65, 72, 88, 76,
+ 88, 78,216, 72,168, 32, 28, 36, 52, 17,218, 9, 55, 9, 3,132,
+ 81,194, 39, 34,147,168, 75,180, 38,186, 17,249,196, 24, 98, 50,
+ 49,135, 88, 72, 44, 35,214, 18,143, 19, 47, 16,123,136, 67,196,
+ 55, 36, 18,137, 67, 50, 39,185,144, 2, 73,177,164, 84,210, 18,
+ 210, 70,210,110, 82, 35,233, 44,169,155, 52, 72, 26, 35,147,201,
+ 218,100,107,178, 7, 57,148, 44, 32, 43,200,133,228,157,228,195,
+ 228, 51,228, 27,228, 33,242, 91, 10,157, 98, 64,113,164,248, 83,
+ 226, 40, 82,202,106, 74, 25,229, 16,229, 52,229, 6,101,152, 50,
+ 65, 85,163,154, 82,221,168,161, 84, 17, 53,143, 90, 66,173,161,
+ 182, 82,175, 81,135,168, 19, 52,117,154, 57,205,131, 22, 73, 75,
+ 165,173,162,149,211, 26,104, 23,104,247,105,175,232,116,186, 17,
+ 221,149, 30, 78,151,208, 87,210,203,233, 71,232,151,232, 3,244,
+ 119, 12, 13,134, 21,131,199,136,103, 40, 25,155, 24, 7, 24,103,
+ 25,119, 24,175,152, 76,166, 25,211,139, 25,199, 84, 48, 55, 49,
+ 235,152,231,153, 15,153,111, 85, 88, 42,182, 42,124, 21,145,202,
+ 10,149, 74,149, 38,149, 27, 42, 47, 84,169,170,166,170,222,170,
+ 11, 85,243, 85,203, 84,143,169, 94, 83,125,174, 70, 85, 51, 83,
+ 227,169, 9,212,150,171, 85,170,157, 80,235, 83, 27, 83,103,169,
+ 59,168,135,170,103,168,111, 84, 63,164,126, 89,253,137, 6, 89,
+ 195, 76,195, 79, 67,164, 81,160,177, 95,227,188,198, 32, 11, 99,
+ 25,179,120, 44, 33,107, 13,171,134,117,129, 53,196, 38,177,205,
+ 217,124,118, 42,187,152,253, 29,187,139, 61,170,169,161, 57, 67,
+ 51, 74, 51, 87,179, 82,243,148,102, 63, 7,227,152,113,248,156,
+ 116, 78, 9,231, 40,167,151,243,126,138,222, 20,239, 41,226, 41,
+ 27,166, 52, 76,185, 49,101, 92,107,170,150,151,150, 88,171, 72,
+ 171, 81,171, 71,235,189, 54,174,237,167,157,166,189, 69,187, 89,
+ 251,129, 14, 65,199, 74, 39, 92, 39, 71,103,143,206, 5,157,231,
+ 83,217, 83,221,167, 10,167, 22, 77, 61, 58,245,174, 46,170,107,
+ 165, 27,161,187, 68,119,191,110,167,238,152,158,190, 94,128,158,
+ 76,111,167,222,121,189,231,250, 28,125, 47,253, 84,253,109,250,
+ 167,245, 71, 12, 88, 6,179, 12, 36, 6,219, 12,206, 24, 60,197,
+ 53,113,111, 60, 29, 47,199,219,241, 81, 67, 93,195, 64, 67,165,
+ 97,149, 97,151,225,132,145,185,209, 60,163,213, 70,141, 70, 15,
+ 140,105,198, 92,227, 36,227,109,198,109,198,163, 38, 6, 38, 33,
+ 38, 75, 77,234, 77,238,154, 82, 77,185,166, 41,166, 59, 76, 59,
+ 76,199,205,204,205,162,205,214,153, 53,155, 61, 49,215, 50,231,
+ 155,231,155,215,155,223,183, 96, 90,120, 90, 44,182,168,182,184,
+ 101, 73,178,228, 90,166, 89,238,182,188,110,133, 90, 57, 89,165,
+ 88, 85, 90, 93,179, 70,173,157,173, 37,214,187,173,187,167, 17,
+ 167,185, 78,147, 78,171,158,214,103,195,176,241,182,201,182,169,
+ 183, 25,176,229,216, 6,219,174,182,109,182,125, 97,103, 98, 23,
+ 103,183,197,174,195,238,147,189,147,125,186,125,141,253, 61, 7,
+ 13,135,217, 14,171, 29, 90, 29,126,115,180,114, 20, 58, 86, 58,
+ 222,154,206,156,238, 63,125,197,244,150,233, 47,103, 88,207, 16,
+ 207,216, 51,227,182, 19,203, 41,196,105,157, 83,155,211, 71,103,
+ 23,103,185,115,131,243,136,139,137, 75,130,203, 46,151, 62, 46,
+ 155, 27,198,221,200,189,228, 74,116,245,113, 93,225,122,210,245,
+ 157,155,179,155,194,237,168,219,175,238, 54,238,105,238,135,220,
+ 159,204, 52,159, 41,158, 89, 51,115,208,195,200, 67,224, 81,229,
+ 209, 63, 11,159,149, 48,107,223,172,126, 79, 67, 79,129,103,181,
+ 231, 35, 47, 99, 47,145, 87,173,215,176,183,165,119,170,247, 97,
+ 239, 23, 62,246, 62,114,159,227, 62,227, 60, 55,222, 50,222, 89,
+ 95,204, 55,192,183,200,183,203, 79,195,111,158, 95,133,223, 67,
+ 127, 35,255,100,255,122,255,209, 0,167,128, 37, 1,103, 3,137,
+ 129, 65,129, 91, 2,251,248,122,124, 33,191,142, 63, 58,219,101,
+ 246,178,217,237, 65,140,160,185, 65, 21, 65,143,130,173,130,229,
+ 193,173, 33,104,200,236,144,173, 33,247,231,152,206,145,206,105,
+ 14,133, 80,126,232,214,208, 7, 97,230, 97,139,195,126, 12, 39,
+ 133,135,133, 87,134, 63,142,112,136, 88, 26,209, 49,151, 53,119,
+ 209,220, 67,115,223, 68,250, 68,150, 68,222,155,103, 49, 79, 57,
+ 175, 45, 74, 53, 42, 62,170, 46,106, 60,218, 55,186, 52,186, 63,
+ 198, 46,102, 89,204,213, 88,157, 88, 73,108, 75, 28, 57, 46, 42,
+ 174, 54,110,108,190,223,252,237,243,135,226,157,226, 11,227,123,
+ 23,152, 47,200, 93,112,121,161,206,194,244,133,167, 22,169, 46,
+ 18, 44, 58,150, 64, 76,136, 78, 56,148,240, 65, 16, 42,168, 22,
+ 140, 37,242, 19,119, 37,142, 10,121,194, 29,194,103, 34, 47,209,
+ 54,209,136,216, 67, 92, 42, 30, 78,242, 72, 42, 77,122,146,236,
+ 145,188, 53,121, 36,197, 51,165, 44,229,185,132, 39,169,144,188,
+ 76, 13, 76,221,155, 58,158, 22,154,118, 32,109, 50, 61, 58,189,
+ 49,131,146,145,144,113, 66,170, 33, 77,147,182,103,234,103,230,
+ 102,118,203,172,101,133,178,254,197,110,139,183, 47, 30,149, 7,
+ 201,107,179,144,172, 5, 89, 45, 10,182, 66,166,232, 84, 90, 40,
+ 215, 42, 7,178,103,101, 87,102,191,205,137,202, 57,150,171,158,
+ 43,205,237,204,179,202,219,144, 55,156,239,159,255,237, 18,194,
+ 18,225,146,182,165,134, 75, 87, 45, 29, 88,230,189,172,106, 57,
+ 178, 60,113,121,219, 10,227, 21, 5, 43,134, 86, 6,172, 60,184,
+ 138,182, 42,109,213, 79,171,237, 87,151,174,126,189, 38,122, 77,
+ 107,129, 94,193,202,130,193,181, 1,107,235, 11, 85, 10,229,133,
+ 125,235,220,215,237, 93, 79, 88, 47, 89,223,181, 97,250,134,157,
+ 27, 62, 21,137,138,174, 20,219, 23,151, 21,127,216, 40,220,120,
+ 229, 27,135,111,202,191,153,220,148,180,169,171,196,185,100,207,
+ 102,210,102,233,230,222, 45,158, 91, 14,150,170,151,230,151, 14,
+ 110, 13,217,218,180, 13,223, 86,180,237,245,246, 69,219, 47,151,
+ 205, 40,219,187,131,182, 67,185,163,191, 60,184,188,101,167,201,
+ 206,205, 59, 63, 84,164, 84,244, 84,250, 84, 54,238,210,221,181,
+ 97,215,248,110,209,238, 27,123,188,246, 52,236,213,219, 91,188,
+ 247,253, 62,201,190,219, 85, 1, 85, 77,213,102,213,101,251, 73,
+ 251,179,247, 63,174,137,170,233,248,150,251,109, 93,173, 78,109,
+ 113,237,199, 3,210, 3,253, 7, 35, 14,182,215,185,212,213, 29,
+ 210, 61, 84, 82,143,214, 43,235, 71, 14,199, 31,190,254,157,239,
+ 119, 45, 13, 54, 13, 85,141,156,198,226, 35,112, 68,121,228,233,
+ 247, 9,223,247, 30, 13, 58,218,118,140,123,172,225, 7,211, 31,
+ 118, 29,103, 29, 47,106, 66,154,242,154, 70,155, 83,154,251, 91,
+ 98, 91,186, 79,204, 62,209,214,234,222,122,252, 71,219, 31, 15,
+ 156, 52, 60, 89,121, 74,243, 84,201,105,218,233,130,211,147,103,
+ 242,207,140,157,149,157,125,126, 46,249,220, 96,219,162,182,123,
+ 231, 99,206,223,106, 15,111,239,186, 16,116,225,210, 69,255,139,
+ 231, 59,188, 59,206, 92,242,184,116,242,178,219,229, 19, 87,184,
+ 87,154,175, 58, 95,109,234,116,234, 60,254,147,211, 79,199,187,
+ 156,187,154,174,185, 92,107,185,238,122,189,181,123,102,247,233,
+ 27,158, 55,206,221,244,189,121,241, 22,255,214,213,158, 57, 61,
+ 221,189,243,122,111,247,197,247,245,223, 22,221,126,114, 39,253,
+ 206,203,187,217,119, 39,238,173,188, 79,188, 95,244, 64,237, 65,
+ 217, 67,221,135,213, 63, 91,254,220,216,239,220,127,106,192,119,
+ 160,243,209,220, 71,247, 6,133,131,207,254,145,245,143, 15, 67,
+ 5,143,153,143,203,134, 13,134,235,158, 56, 62, 57, 57,226, 63,
+ 114,253,233,252,167, 67,207,100,207, 38,158, 23,254,162,254,203,
+ 174, 23, 22, 47,126,248,213,235,215,206,209,152,209,161,151,242,
+ 151,147,191,109,124,165,253,234,192,235, 25,175,219,198,194,198,
+ 30,190,201,120, 51, 49, 94,244, 86,251,237,193,119,220,119, 29,
+ 239,163,223, 15, 79,228,124, 32,127, 40,255,104,249,177,245, 83,
+ 208,167,251,147, 25,147,147,255, 4, 3,152,243,252, 99, 51, 45,
+ 219, 0, 0, 0, 32, 99, 72, 82, 77, 0, 0,122, 37, 0, 0,128,
+ 131, 0, 0,249,255, 0, 0,128,233, 0, 0,117, 48, 0, 0,234,
+ 96, 0, 0, 58,152, 0, 0, 23,111,146, 95,197, 70, 0, 0, 4,
+ 59, 73, 68, 65, 84,120,218,236,157, 61, 76, 20, 65, 20,199, 87,
+ 67,163, 6, 27, 8, 24,195, 53, 66,176, 17,185, 82, 78,109,196,
+ 24, 11, 76, 52, 36, 84, 68,175,195,163,148,143, 82,161,177, 16,
+ 177, 4,236, 78,115, 21,141,197, 81,153, 80, 41,123,150,103,176,
+ 1, 65, 11,136, 2,209, 6,149, 43,207, 98,222,255,200, 12,187,
+ 183,115,183,115, 31,187,251,254,205,228,150,185,189,121, 55,191,
+ 155,247,222,124, 44,167,138,197, 98,177, 88,180,172, 27, 55, 51,
+ 153,237, 45,171,198,234,125,233,239,253,155,147, 22,171,166,250,
+ 248, 97,116,180,187,199,178, 90,204,222,182,237,142, 40, 7,191,
+ 201, 32,196,246, 13,125,192,107, 81,236,116,202,160,172, 94, 18,
+ 229,239,247,220,181,102,212, 98, 6,132,228, 39, 2, 97, 88,169,
+ 176, 95,155,102, 3,180,216, 20,129,136, 17,133,218,145,190,198,
+ 160, 52, 4,140,193,105, 81,142,116,211,133,225,230, 48,167,119,
+ 78,148,207,233,245,114,156, 70,148, 23,220,213,149,233,116,101,
+ 213, 31,217, 10, 16, 77, 46,180, 19,237,102, 25, 6, 3, 95,108,
+ 98, 61,152,102,162,221, 12,136, 33, 48,224, 50,130, 10,132, 27,
+ 32,176,139, 85, 33, 24, 8, 42,135,158,133,211,108,216, 5, 59,
+ 89,154, 96, 12,205,136,242,108, 38,156,102,195, 46,216,201,242,
+ 0, 3,191,160,176,184, 14, 93,215,194, 35,135, 7, 24,241,120,
+ 52,191,134,168,218,173, 15,198, 82, 68,193, 88, 98, 20,202,130,
+ 209,245, 51,154, 95, 3, 38,198, 88, 46, 96,132, 53,216,100, 25,
+ 202, 74,162,170,174,131,112,219,165, 31, 75, 49, 24,242,136,249,
+ 182, 57, 58,112,224,139,217,251, 77,156, 19,101, 42,165,251, 3,
+ 96, 48,154,234, 23,141, 14,108, 55,148, 62, 23, 70,157,175,143,
+ 19, 32,103, 50, 12,134,150, 98, 7,141, 5,194,111,140,167,142,
+ 56,216,118,176,184, 40,215,195,188,205,237,105, 6, 67, 75, 59,
+ 29,245,249, 28,116,156,105, 32,112,191,228, 26,101, 91,180, 81,
+ 10, 27,154,236, 62,249,125,183,190,186,141, 28, 12, 70, 93, 5,
+ 32,208,113,166,178, 64,140, 12,133,135,242,245,100, 78,126,189,
+ 50,227,156,133,158, 12, 74, 91,184,179,252, 72,119, 15, 43, 92,
+ 212,200,154, 89,192, 16,139,100, 41,150, 72, 83,123, 38, 20,151,
+ 49, 48, 43,202,220, 21, 81,230,123, 8,136,126, 81, 38, 18,244,
+ 119, 6,195,140, 38, 90, 53, 43,182,154, 5, 17, 35,142, 69,171,
+ 196, 27,127,100,151,177,121,158,234,211,196, 93,124, 65,238,248,
+ 252, 56, 93, 95,147,235, 89, 99,236, 74,130, 25, 3, 93,144, 93,
+ 7,132,205,215, 80,254,177, 2,212,156, 94, 44,117,156,198, 50,
+ 24,129, 18,210,207,213,238,202, 58, 30,177, 4,130,204, 93, 23,
+ 48,142,231,113, 24,140, 80,100, 79,106, 16,139,145,229, 68,172,
+ 179,167,251, 9, 12, 70, 32,213,118,215, 35,216,221, 43,159,189,
+ 48, 24, 33, 21,178, 8,104,115,170,252, 8,162,130,225,189, 49,
+ 137,193, 8,148, 48,223,160,198, 20,182,178,251,189,127, 65,113,
+ 45,157,206,233,179,170,227, 35,160,156,174,250,210,202,172, 94,
+ 189,174,251,242,188, 65,181,202,231, 9, 4,154,193,108, 39,151,
+ 146, 59,148, 71, 2,117,107,102,206, 13,156,117,103,112, 24, 12,
+ 159,202,254,208,172, 72, 29, 97,234,124,206,155,132,243,117, 28,
+ 21,197,201,192, 35,202, 98,236,119,114, 86, 82, 2,116, 93, 29,
+ 41, 24,140,134,168,212,161,134, 15,112,149, 92, 76,202,121, 68,
+ 43,208, 17,205,123, 23, 41, 6,249, 39,215,195,161,112,107,139,
+ 99, 12,231,104,254,160,190,128,232,186, 34, 93, 23,147,190, 46,
+ 187, 26,156,217,133,139,193,162, 89, 41, 54,233,115,203, 86,120,
+ 196, 40, 59, 63, 80, 47, 87,244,139, 58, 52,233,115, 45, 5,107,
+ 33,202,218,153,149, 26,151,179, 21,184,152,149, 7,110,119, 98,
+ 48,154, 66,232, 80, 11,139, 99,134,238,235,246,124,146,229,239,
+ 94,243, 26, 12,134,164, 35, 44, 91, 79, 54, 24, 16, 67, 66, 80,
+ 153, 38,224, 98,148, 29,229,198,188,222,201, 96, 72,218,237, 8,
+ 167, 93,110, 46,198, 93, 28,124,178,116,192, 56, 57,209, 17,145,
+ 160,179,147, 81, 40, 11, 70, 84,159,138,199, 79, 3,244, 0,195,
+ 142,232, 19,103,108,126,210, 78,121, 48, 16,124,169,171,117,161,
+ 29, 41,166,194, 29,116, 26, 3, 3,202, 62,141,134,249, 81,177,
+ 211, 24, 24,165, 7,171,134,244, 20, 56,236,226,216,162,202,116,
+ 53, 59, 19,174,168, 29,118,192, 46, 86,149, 96, 96,243,233,252,
+ 223, 96, 3,130,118,195, 14,183, 51,157, 44, 77, 48,220, 0,201,
+ 127, 14, 86,112,201, 64,212, 8, 12, 21,144, 69,218,120,178,188,
+ 45,202,163, 38,249,194,209, 14,180,107,254,144,129,168, 78, 62,
+ 215, 74,176,222,111, 95, 21,101,130, 58,100,128,246, 27,196,246,
+ 107,219,124,184, 8,108, 93,195, 78,165, 2, 63, 59,188,177, 96,
+ 168, 35,201,170, 37,151,216, 32,130,242,242, 43,127,159,179,241,
+ 68,148, 88, 46,230,255, 46, 80, 43,253, 31, 0,165, 77, 46,225,
+ 17, 27,221, 39, 0, 0, 0, 0, 73, 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_device_png[45511] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 1,149, 0, 0, 3, 34, 8, 2, 0, 0, 0, 41,105,201,
+ 136, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 0, 7,116, 73, 77, 69, 7,216,
+ 1, 30, 13, 5, 29,169,182, 54, 49, 0, 0, 32, 0, 73, 68, 65,
+ 84,120,218,236,189, 89,112,100, 87,122,231,247,157,115,111,174,
+ 88, 10, 40, 84, 21,139,100, 85,145, 44,146, 93,100, 55, 91,205,
+ 110,182,122,139,222,212,148,186, 37,185,229,112, 43, 36,217,150,
+ 34, 70,114,132,165,152,241,131, 61,178,159,198, 49,143, 19,158,
+ 183,113,204,219,196,232,101,244, 48, 19, 99, 43, 28,154,113,104,
+ 108,105, 70,106,141,130, 82,111, 86,179, 91, 18,155,108, 54,151,
+ 34,107, 97, 85,161, 10, 64, 1,185,220,229, 44,159, 31,238,118,
+ 238,205, 4,144, 0, 18,185, 0,255, 31, 73, 48,145,184,153,121,
+ 51,145,249,195,255,251,238,185,231,136,183,223,185, 78, 0,140,
+ 1, 30,121, 75,129, 23, 11,140, 5, 31, 47,193,137,209, 7, 51,
+ 49, 91,230,170, 83,152, 89, 41,165,148,178,150,247,208, 13, 51,
+ 71, 81,212,237,118,149, 82, 7,213, 20,239,103,177,122,189,190,
+ 184,184,216,104, 52,132,216, 75, 94, 66,136, 90,173, 94,171,213,
+ 164, 20,131, 63,147, 66,208,222,183,135, 58,225, 47, 48, 21,251,
+ 88,203,204,169,110,180,209, 42,142,141,177, 68,100,173, 9,130,
+ 160,215,235, 25, 99,146, 77,181,214,253, 94,175, 31, 4,198,232,
+ 92, 26,177, 82, 58,140, 60,102,203,182, 98, 18,107,237,114,171,
+ 85,243,188, 76,109,187, 6,165,154,239,175, 46, 44,202, 97,110,
+ 28,118,113,168, 21,134,171, 76, 17, 95,239,245,148,209,187, 27,
+ 36,217, 90, 40,163, 59, 81, 40,165, 28,212,151,149,162,214,108,
+ 214,234,245,252, 74,207,243,218,237,246, 66,123,193,243,189,244,
+ 13,237,251,237,118,187,213,106,121,158, 71, 68, 82,202,122,189,
+ 238,251, 62, 9, 65, 68, 82, 8, 33, 68,114,249,224, 38,131,251,
+ 102, 14,129,250,241,216,210, 80,138, 49, 38,142, 99,109,140, 53,
+ 38, 8,130,126,175,175,141,214, 90,247,251,253,126,191,111,140,
+ 49,198,132,253,126,141,200, 38,194, 98,219,170,213,219,245, 6,
+ 103, 2, 88,104, 52, 23,155,205,226, 35, 78,180,208,108, 46, 54,
+ 91,156,185, 68, 12, 81, 13, 15, 10,136,121,224, 35, 40,178,228,
+ 54,112,181,171,172, 34,224,141, 94, 65, 86,247,131,247, 80,128,
+ 16,130,119, 83,227,174,185, 46,189, 69, 47, 10,123, 81,228, 94,
+ 223,139,162,228,154,228,193, 2, 21,135, 70, 11, 33,137,200,147,
+ 82,123,178,217,110,123,158,151,184,175,221,110,251,190,159, 91,
+ 79,122,158,239,121,245,122,221,243, 60, 33, 68,146,249,136, 68,
+ 190,227, 2,178,131,191, 78,134,155,140,177,113, 28, 41,173, 85,
+ 28,119, 58,157, 40,138,162, 40,218,217,217,137,227, 56, 12, 3,
+ 161, 12, 89,107,217,122, 66,158,105,183, 83, 19, 53,155, 11,141,
+ 102,230,160,214, 98,171, 85,124,104,139,255,115,102, 16, 30, 30,
+ 130,202, 91, 14, 90,131,137,197, 96, 86,202,237,197,251, 60,185,
+ 210,157,187, 15,199, 44, 70,214, 23,237,225,163,106, 9,200,123,
+ 239, 18, 31,224,237, 44, 10,167, 11,226, 93,238, 34,255,206,117,
+ 95, 47,138,250,113,122,185, 19,133,134, 88, 10, 73, 82,138,102,
+ 189,217,108,213,235,245,229,229,229, 70,163,209,104, 52,150,150,
+ 150,106,181,122,173,230,215,235,117,233,121,105,166, 27, 48,156,
+ 128,224,224,175, 41, 26,202, 88,107,180,142,227, 56, 12,195, 78,
+ 167,211,235,245,146,196,212,235,245,132,214,100,173, 49,230,220,
+ 210,114,242,121,121,100,117, 53,185,221,197,213,179,197, 71, 87,
+ 164,159,149,146,137,184,144, 78, 38, 32, 87, 67,188,107,118,201,
+ 220, 52,236, 74, 55, 55,177,123,189,112,219, 99,195,101, 48,164,
+ 17, 54,240, 19,222, 87, 74,213, 29,216,199, 51, 98, 4, 43,241,
+ 208,102, 23, 15,127, 92, 49,228,233,141,214, 43,227,234, 19, 24,
+ 242, 35,102,190,223,221, 73,174,186,223,237, 36, 27,110, 6,125,
+ 207,243,132,231,137, 70,125, 97, 97,161,213,110, 47, 44, 44, 44,
+ 44, 44, 44, 45, 45, 53,154,205,122,173,238,251,158,148, 94,214,
+ 203, 19, 21,119, 9,216, 13,254, 58,154,164,200, 90,163,181, 14,
+ 195,176,219,237,118,187,221, 78,167,211,235,118,183,183,183,235,
+ 68, 74,233, 86,173,214,110, 52,137,248,145,213,179,196,188,216,
+ 106, 45, 54, 91,236,124, 74,133, 83, 92, 17,231, 63,201, 63, 74,
+ 69,213,198,196,185,167, 74,185,137,185,242,109,238, 29,102, 46,
+ 55,158,184,106,146,129,107,134,110, 86,242, 14,243,222, 42, 24,
+ 182, 25,237, 91, 63,138,189, 67, 20, 15,126,126,197,174,162, 97,
+ 222,213, 59, 98,151,155, 15,181,149,112, 30,125,183, 31, 21,226,
+ 203, 54,221, 93,121,188,223,149,189, 56,173, 91,239,119, 59,130,
+ 40, 80, 42,178,218,247,107,166, 94, 59,115,230,204,162, 67,179,
+ 217,244,253, 90, 18,221,134,239, 19,212, 6,127,185,111, 51,107,
+ 173, 82, 42,241,212,195, 12, 82,138,141,109,214,106,237, 70, 99,
+ 177,217, 90,104, 54, 27,181,218,217,165,229,236,131,202, 68,130,
+ 28,137,184, 98, 74,138,169,212, 79,133,151,184,164, 39,215, 77,
+ 204,101,211,229,183,229,146, 99,184, 26,202,220,123,168,214,140,
+ 21,247, 81,249, 81,134, 74,118,223, 78, 22,243, 64,206,226,145,
+ 162,215, 40,149,158, 99,135,146, 40,134, 89, 99,200,167, 88, 12,
+ 223, 94, 36, 79,177,116,231, 98,247,199, 21,187,238,149,168, 62,
+ 82,169, 8, 29, 8, 80,206, 37,167,106,173,100,232,236,133,121,
+ 24,244,149,214,189, 56, 14, 84, 28,104, 21, 91, 35,253,154,215,
+ 106,174,172,174,158, 57,115,102,101,101, 37,241, 90,173, 86,147,
+ 82,150,119, 82,140,150,218, 4,252,117,114, 84,213,239, 7,157,
+ 206,206,195,135, 15, 55, 54, 54, 58,219,219, 62,115,221,247, 23,
+ 26,205,133,102,115,177,213, 58,187,180, 92,247,125,215, 11, 84,
+ 169,188,242,203, 37,239,148, 37,149, 27,138,157,219,231, 55, 41,
+ 93, 40, 4,151, 89,136,221,138,176, 48,102,122, 57,251,105,245,
+ 178,107, 52, 46,212,199, 60,216,185,114, 36, 85,190,135, 61,234,
+ 193,193,155,140,104,174, 81,219, 83,187,186, 67,236, 37, 50, 87,
+ 49, 98,136,190,242,123,174, 4, 52,231, 74,225,124,250,179,221,
+ 112,182,174,228, 32,177,187, 4,157, 99,151,156,109,195,196, 69,
+ 142, 27,144, 32, 19,103, 7, 40,200,253,146,108,175,140,121, 24,
+ 244,123,113, 20, 40, 21,106,165,152,185, 81, 95, 94, 89, 89, 91,
+ 91, 59,115,102,101,121,121,169,221,110, 39, 82, 27,216, 35, 49,
+ 66, 94, 19,240,215, 76,219,202, 24, 27, 69, 97,183,219,221,216,
+ 216,216,220,220,220,220,220,240, 13,215, 61,175,221,104,156, 93,
+ 90,174,215,252,139,171,107,121, 84, 17,206,199,184,106,168,178,
+ 110, 50,215,148, 37,149, 93,200,111, 91,186, 80,140,127, 56,200,
+ 173,156, 58,145,203,138, 44, 41,111, 80,100,217, 13,135,199,186,
+ 129,166, 91,165,167,182, 71,147,107,247, 10,148,119,251,108,140,
+ 244, 41, 17,229,207,218,208, 44, 86,232,108,160, 29,238, 72,167,
+ 106,171,172,125,158,109,146, 29, 50,204,190, 21,149,252,149, 59,
+ 72,228,251, 36,202,114,204, 4, 38,202,138, 20,101,163,186, 30,
+ 20, 69, 95,111,184,139, 69,222,161, 19,110, 93, 91,241, 90,254,
+ 18,223,239,117,149,214,219, 97, 16, 26,173,136, 68,163,190,178,
+ 182,118,254,252,249,179,103,215,150,150, 22, 27,141,134,231,121,
+ 238,179, 28, 89,106, 2,254,154,102, 91, 61, 86,170,215,237,222,
+ 191,127,255,222,189,123,219, 91, 91,210,218,165,102,107,161,217,
+ 60,187,188,188,182,180, 92,243,125, 81,201, 26,185, 92, 92, 73,
+ 37, 67, 57, 19, 95,176,165,194, 27, 54, 21,141,107, 25,203,142,
+ 206,242, 13,153, 42, 55, 73,175, 76, 15, 79,146,107, 52,203,185,
+ 215,152,152,172,107,180,226, 2,115,177, 99,121, 76,203,246,194,
+ 186,165,107, 85,115,236, 20,168, 21, 59,239,110,180,161, 86,114,
+ 111,184,119,231, 75, 12,205,109,187, 21,133, 21, 49,149, 5, 82,
+ 114,217, 96, 2,114,135,107, 13,202,168, 16, 77,201, 50, 34,137,
+ 85,206,205,156,156,149, 95, 46, 76,148,222,133,112, 30,216, 29,
+ 46,155, 63,174, 40, 30, 37,185,151,194,128,162, 16,100,250, 20,
+ 132, 72,235,218,194,116, 92,186,156,121,173,168,241,139, 2,148,
+ 216,141,211, 68,177, 49,219, 65,176, 29, 5,129, 86,129, 49,178,
+ 213, 92, 89, 91,187,112,225,194,249,243, 23, 22, 23, 23,106,181,
+ 122,113,160, 64, 12,171,117, 79,162,209,102,220, 95,204,204,113,
+ 28,239,236,116,214,215,239,221,186,117, 75,245,251,237, 90,189,
+ 221,104, 92, 60,187,118,118,121,185,238,215,200,173,188, 28, 53,
+ 148,180,101, 45, 19,101,198,201,174, 79, 68,145,248, 34,253,202,
+ 185,152,216, 50, 37,222, 98,231, 38,217,215,193, 11,213,159, 22,
+ 119, 69,108,237,128,212, 50, 7, 13, 83,103,177,217,174, 25,205,
+ 113, 49,187,250,226, 82, 95,172, 92,150, 14,145,218, 80,175,237,
+ 114,229,208,177,102,163, 84,140,149, 2, 80,148,107, 49, 81,201,
+ 47,174, 32, 92, 69,185,201, 72,148,243, 85, 58,122, 65, 20,121,
+ 73, 56,242,202, 77,147,125, 83,186, 38,151, 86,225, 65, 81,186,
+ 57, 13, 92,147,252, 39, 75,119, 91,185,183,178,245,178,125, 22,
+ 206,147,116, 29,231,170, 37,201, 99,217,229,244, 53,207, 74,212,
+ 138,209,152, 40,214,122, 59, 10, 55,250,189,200,152, 88, 80,251,
+ 236,202,165,199, 47,157,191,240,200,242,242, 82,189, 94,207, 6,
+ 175,237, 98,180, 19,161,179, 25,244, 23,107,173, 59,157,238,221,
+ 187,119,110,220,184,145, 8,107,101,113,241,236,242,153, 71,207,
+ 174, 13, 85, 85,242,201, 31, 34, 20,235, 58, 37, 75, 73,201, 56,
+ 247,252,250,204, 86,204,214,221,158,152,147, 17,241,197, 64,212,
+ 244, 91,170,108, 89,217, 44, 55, 87,246,136,214,121,136,170,230,
+ 202,215,228, 10, 43, 5, 58, 87,199, 60,172,218,229, 97,141,185,
+ 189,155,104, 60,228,176,230,240,107,152,246, 75, 89,251,246,185,
+ 68,165,232,162,161, 1,106, 96,195, 82,149,151,121,161,148,170,
+ 210,248, 51,196, 77, 85, 79,165,114, 41,162,147, 16, 85, 85, 57,
+ 1, 45, 27,207, 37,164,115, 71, 66, 86,239,202,185, 67, 33,179,
+ 8, 39, 68,105, 63, 51,205, 13, 23,101,245, 66,201,226, 36,170,
+ 7, 37, 72,136,226,119, 34, 68,209,131,205,255,130, 17, 61,232,
+ 247,118,162,176,171, 98, 37, 69,123,117,245,242,149, 43, 23, 47,
+ 94, 92, 90, 90,242,125,223,121,225, 69, 53,242,206,173,206,102,
+ 194, 95,204, 28,199,209,131, 7, 15,110,221,186,117,239,206,157,
+ 166,244,206,180,219, 23,215,206, 61,186,182, 86, 42,178,114,103,
+ 229, 95, 43, 2,226,236,202,196, 26, 92,182, 76, 98,174,212, 35,
+ 169,131,138, 45, 45, 91,107,137,243,109,138,123,200,110,232,126,
+ 101,103,203,236,202, 92,142,249,206,100,143, 80, 85, 94, 98, 40,
+ 215,113,101,153,230,230, 74,246,161,200,137,142,197,156, 38,157,
+ 83, 84, 38, 42,119, 43,202,234, 49, 80,183,215, 50, 36,142,141,
+ 82, 99,238,253,182, 22, 67,251, 86, 67,107, 64, 81,237,181,187,
+ 193,101, 72,245, 87,117, 83, 57, 34,185, 22,203, 21, 67, 36,164,
+ 44, 46,184,186,145,194,181, 76,113,101, 73,112, 14, 50, 81, 88,
+ 182,181,112, 12, 85, 92, 87,186, 9, 13,123,172,106,124, 19,162,
+ 178,231, 78,137,234,244, 10, 69, 54,212,163,120,125, 57, 55, 90,
+ 126,188, 60, 63,166,147,252, 34, 55,250,189,141,176, 31, 88,195,
+ 173,230,197,199, 31,191,244,248,165,181,115,107,217, 89,168,135,
+ 208,153,128,191,138, 15,135, 82,234,193,131, 7,215,223,125,247,
+ 193,250,250, 98,189,241,200,217,179,143,158, 93, 91,108,181,137,
+ 170, 29,116,102, 75,182, 28,118, 42,194,178, 54,119, 4, 91,155,
+ 41, 35,221,192, 90, 75, 37,133,101,150, 73,111,101, 51,121,177,
+ 181,150,172,181,169, 89,216, 26, 91,186,243,252,230,165,123, 96,
+ 102,203,198,114, 69,118,217,157,184,254, 26,154,221, 92, 5, 23,
+ 249,142, 6,116,198,165,230,218, 94,205,126,167, 85,230,182,224,
+ 121,216,224, 47, 30,126,210,207,190,103,100, 31, 96,164,196,110,
+ 209, 76, 8,177,107,139,166,170,179,129,246, 86, 94, 48, 58,230,
+ 26, 76, 73, 37,161, 56,238, 16, 50,191, 94,230, 95, 40,243,148,
+ 227, 44, 33,132, 36,231,178,115,129,132,144,233, 13,147,155, 12,
+ 220, 48,125,208,202,198,249,163, 16,145,115, 19, 26,178,219, 89,
+ 53,234, 22,167,187, 27,141,179,226,147,139, 97,124,156, 29,254,
+ 225,158,138, 55,195,224, 97, 28,233,122,237,194,165,199,159,122,
+ 234,169,115,231,206,213,106,181,188, 39,184,107,177, 57,195, 46,
+ 155,176,191,216, 90,238,245,186,215,175, 95,127,255,189,247,234,
+ 36, 46,157, 63,255,216,185,243,201,105, 52,121, 7,138, 42,129,
+ 101,184,116,152,172, 45,164,195,108, 19,173,152,138, 98,172, 53,
+ 214,241,148,181, 54,251,169,205,175,201, 54, 54,229,111,243,203,
+ 249, 77, 56,191, 55, 46,174,103,107,179,157, 25,180,103,113,185,
+ 146,212,156,203,238,177,203,129, 60, 53, 80,250,237,209,204, 58,
+ 160,105,120,215,111, 70,127,251, 28,250,237, 44, 14,252,131, 1,
+ 235, 85, 71, 19,184,253, 44, 55,232,229, 81,173,154,215,100,166,
+ 188, 84, 53,101, 1,201,226,130,116,180, 85,124, 21, 50,255, 81,
+ 105,179, 98, 99, 41,203,130, 19, 66,122, 50,243,154, 99,183,236,
+ 135,249,110, 16,145, 24, 80, 91,226, 95,114, 52, 77,197,209,135,
+ 188, 77, 86,209, 89,250,215, 45, 63, 32,149,188,223,122, 42,222,
+ 140,194,205, 56,146, 75, 11, 79, 94,125,250,169,171, 79, 45, 44,
+ 44, 56,227,206,118,143,102, 51,230,178,201,248,139,173,181, 91,
+ 91, 91,111,188,241,198,195, 7, 15, 86,218,237,103, 47, 63,177,
+ 182,188, 92, 77, 19,238, 71,189, 82,178, 25, 91,146, 84, 69, 61,
+ 201,101,227, 92,105, 74, 63,181,198, 36,247,105,173,101, 99,202,
+ 215, 23,146, 42,127,107,115, 33,218,129,135,179, 21,169, 89,155,
+ 164,188,129, 2,147,220, 10,177, 84,241,177,155,154, 70, 27, 89,
+ 186,183,128, 14,245,123, 57,202,143,197, 17, 36,117,244,219,236,
+ 54, 80,108,143, 59, 25,140,126,110,172, 27,108,135,185, 53,160,
+ 168, 90, 70, 74, 47,243,139, 39, 11, 85,201,221, 47, 75, 33,165,
+ 20, 66, 14, 94,206,197, 39,115,247,165, 63,173,154,148,156,244,
+ 71,133,127,243, 98, 83,148,189,150,232, 76, 20,127, 6,201,105,
+ 177, 80,250, 22,222, 81,209,221,160, 23,249,222,133, 39, 46, 63,
+ 247,220,243,171,171,171,201,212, 29,123,230,178,221,106, 76,113,
+ 162,252,101,173,125,248,112,235,245,215, 95,223, 92, 95,191,114,
+ 225,145, 39, 31,125,116,177,213, 46, 26, 58,110,255,200,173,209,
+ 74,202, 48,105,170,178,156, 94,206,124,148,234, 38,253, 90,136,
+ 41,149, 84,118,125,113,193, 14,217,222, 26,147, 61,156,177, 38,
+ 123,196,108, 7,108,217,131,105,254, 42,165,194,162, 75,197,165,
+ 145, 16,187,142,255,228,145,181,194, 71,212, 18,211,172, 35, 14,
+ 255,150,223, 55,249,137,145,196, 39,118,219,184,146,242,132,219,
+ 128,207,186,105, 78, 85, 88,216, 45,245,154,148,169,143,178,175,
+ 66, 10, 41,189,226, 74, 79, 58,194,114,190, 77,172,231,201,146,
+ 212,156, 12, 40,165,164, 97,106,171, 30, 88, 16, 84,209, 89,114,
+ 122, 91,222, 75,206, 44,150,254,229,181,108,251, 74, 61,136,195,
+ 109,193,143, 60,245,228,135, 63,252,225,149,149,149, 60,145, 13,
+ 186,108,191, 80, 38,230,216, 95, 76, 28, 6,193,155,111,190,121,
+ 253,157,119,174, 62,114,241,201,199, 30, 91,108,181,203,206,114,
+ 242, 75,102,156, 60, 58,185, 57, 40,245,139, 49,169, 86, 82, 49,
+ 177, 53, 58,117, 80,162, 45, 99,172,179,153,209,154,141,181,214,
+ 88, 99,178,205,210,111,243, 59,201,228,149, 92, 40,197,177,172,
+ 243,101,171, 45,170,193,154,142,246,152,247,133, 71,116, 8, 31,
+ 202, 53,135,171, 25,231,232,200,248,161,243,155, 24, 73,124, 98,
+ 223, 15, 92,165,133, 39,134, 9,206, 61,168, 90, 4,185,212,108,
+ 110, 33,233,196, 49,175,240,154,244, 50,163,121, 82, 74,207,181,
+ 152,244, 60, 87,127,123, 8, 46, 79,115,148, 94, 40,106,210,172,
+ 137, 38,243, 3,184,204,197, 16,179,124, 88, 99,214,196, 77,255,
+ 208,247,181,218, 80,209,118,205,123,230, 35, 31,190,118,237, 90,
+ 171,213,114,250,253, 21,149, 85, 67,153, 16, 19, 21,217,152,253,
+ 197,108, 55, 55, 55,255,250,123,223,171,147,120,225,233,167,215,
+ 206,172, 84, 14,225, 85,138,178,212, 32,198,186,122, 42, 89, 38,
+ 189,172,109,241,213, 88,157,125,171,141,181,198,106, 51,240,173,
+ 177, 38,187,144, 95, 83,122,184,129, 10,212, 61, 2,232,182,198,
+ 75,126, 25, 41,217,240,168, 17,139,199,250, 55,227,164, 72,107,
+ 172,247, 39,142,176,145,216,175, 44,221, 67,112,238,103,221,237,
+ 194,201,244, 24,130,148, 78,225,153, 75, 45,215, 89,122,193,243,
+ 164, 87,254,182,162,182,228,130, 87, 14,122,110, 73, 43, 4,101,
+ 241,144,178, 35,176,238, 65,128,124, 16, 70,214,181,205,106, 21,
+ 107,181, 49, 93,163,239,153,184,241,200,249,159,254,236,103,207,
+ 158, 61, 91,137, 99,101,147,149, 69, 54,169, 68, 54, 54,127, 89,
+ 107,110,221,186,245, 55,175,190,122,113,245,236, 79, 61,243,108,
+ 221,247,147,126,188, 91, 9,218,193, 36,101,140,209,169,107, 56,
+ 19,141,209,186,176, 79, 98, 37, 99,172,214, 70, 39,230,202,182,
+ 209,218,106, 99, 76,118,165,123,219,226,223,114, 93,233, 30, 58,
+ 28,108, 69,237,217,126,218, 55, 37, 29, 78, 73, 39, 53, 62,205,
+ 161, 7,247,158,217,122, 88, 64,219, 83,112,165, 22,248, 64,106,
+ 43,186,242,233,144,142, 82, 11, 44, 79, 91,137,161,164,231,101,
+ 255,166, 49, 77,122,158,148,158,244,188, 92,124,153,203,188,193,
+ 188,150, 29, 70,112,142, 84, 8, 73,162, 24, 69,156,157, 36,146,
+ 156, 0, 98,211,201,163,108, 50,183,166,137,140,185,103, 84,124,
+ 102,241,165,207,125,246,210,165,203,217,180, 25, 3,199, 75,134,
+ 38,178,221, 78,111,154, 29,127, 49,219,251,247,239,127,231,175,
+ 254,234,218,229, 43,215,158,120,210, 29, 28,144,215,101, 73, 8,
+ 50,131,162, 73, 28, 84,185,172,181,213,218,100,194, 50,217,183,
+ 182,122, 77,106, 46,199, 89, 78, 69, 89, 58, 26,152, 31,120, 33,
+ 103, 6, 7, 30, 93, 79, 60,178,103,224,163,147,237, 59,177,235,
+ 20,178,123, 53,247,134,122,109, 31,169,149, 15, 89, 74, 41, 7,
+ 228, 37,165,231, 73,223,247,188,220, 95,158,244,189,220,101,137,
+ 239, 6, 75, 81,183,176,117,206, 16,160,188, 45,146, 30,147,226,
+ 36, 93, 24,109,180,214,198, 24,179, 73,166,187,178,244,249,159,
+ 125,249,194,249, 11, 89,251,207, 21,217,224,209,223, 99,183,216,
+ 17,253,197, 65, 16,188,242, 23,127,113,182,213,254,228, 71, 94,
+ 200, 14, 35,166,135,231,172, 49,108,147, 23, 32,247,145, 54,170,
+ 226, 35,109,148,182,233,245,202, 42, 99,180,114,174,209, 70,169,
+ 210,246,201,205,147, 56,150, 23,131, 69,191,204, 29, 17,234,230,
+ 41,222,187,178, 27, 49, 58,193, 77,112,220, 33,236, 54,108,242,
+ 177,170,215,134, 74, 45,183,129, 59,170, 67, 10, 33, 60, 79, 10,
+ 81,142,102, 82,122,158,231,121,210,247,165, 39, 61,207,151, 94,
+ 234, 50, 47,151, 90, 97, 52,175,148,203,178,222,127,158, 20,211,
+ 166, 88,122, 4, 43,249, 4, 27,173,149,210,218, 24,179,238,139,
+ 198,213, 43, 95,252,202, 87, 90,173,118, 90, 14,151,162, 36, 13,
+ 251, 58,180, 59, 38,166,233, 47,107,237, 27,111,188,254,193,245,
+ 235,159,249,232,199,150,218,109,119,152,123,210,141, 50, 73,158,
+ 82,202,104,173,149, 50, 42,249,154,252,171,139,175, 90,155, 56,
+ 46,174,209,233, 6,201,198, 73, 34, 51, 74, 23,133,100,126,108,
+ 177, 24,169,192, 92, 58,213,153, 15, 45, 41, 24, 10, 28,143,221,
+ 196,158,199, 7,246,144, 90,213,104,162, 66,214, 64,171, 84,154,
+ 158,231, 75, 79,122,190, 47,253,228,178,231,249,158,244,156,176,
+ 230,121, 89, 91, 77,150,134,170,101, 3, 47,138,118,152, 49,198,
+ 24,173,181,210, 90, 41,165,180,138,152, 31, 44, 53, 95,248,242,
+ 23,175, 61,247,188,231, 57,227,212,168,116,226,131,107,177,210,
+ 137,251,227,179,216,225,252,197,113, 28,255,233,127,252,143,207,
+ 95,186,242,212,227,143,167, 51,249,185,230, 82,218,106,173,149,
+ 54, 42,214, 74,233, 56,249, 55,185, 28,155,228,114,172,140,138,
+ 77,172,180, 82, 38, 86, 90,197, 70,105, 19, 43,163, 84, 17,193,
+ 116,214,146, 55,206,192,174, 52, 91,101,211,212, 12,158,125,188,
+ 159,136, 32, 41, 48, 35,106, 27,172,171,196,176,164, 38,134,101,
+ 180,161, 58,115,143,108,230,170,242, 60,223,243,147, 74,211,243,
+ 124, 63, 19, 89, 22,208, 60, 95,122,178,200,101,249, 64,217,196,
+ 98,201,216,162,180,142, 74, 21, 22, 43, 21, 43,213,175,251,244,
+ 252,211, 63,247,139,191,152,157, 43, 94, 29,111,187, 71,105, 57,
+ 174,138,242, 16,254,226,173,173,173, 87,254,252,207,191,252,241,
+ 151,150, 22, 22,136, 40, 29,119,154, 55,182,148, 74,157, 21,197,
+ 58,142, 84, 28,235, 40,214,113,172,162, 88, 69, 81,114, 65,199,
+ 177,137,227, 68,106, 38,142,203,129, 43,105,105, 25,174,180,177,
+ 156,105,101,170, 11, 88,192, 83,224,228, 74, 77,136,225, 58,171,
+ 4,180,138,206,210,227, 0,206, 65, 0,207, 79, 83,152,231,251,
+ 137,209, 60,223,175,232,204,243, 60,247, 56,102, 50, 7, 70,242,
+ 1, 52,214,106,163,181,210, 74,235, 88,197,113,172, 98, 21,199,
+ 68,219, 79, 60,250,213, 95,249,229,124,176,216, 32, 35, 91, 76,
+ 28,187,191,152,248,198,251,239, 95,127,253,141,207,124,244,167,
+ 234,181,154,200, 78, 69, 76, 14, 20, 38, 1, 74,199,177,142, 99,
+ 21, 70, 42, 10, 85, 24,199, 81,168,194, 72, 69, 81,250, 53,138,
+ 18,139,233, 40, 54, 74,101,129, 75, 27,109,138, 33, 93,110, 39,
+ 139,120,248, 28, 47, 80, 21, 56, 53, 82,115, 63,230, 98, 96,162,
+ 124, 55,157, 9, 18,123,187,204, 75, 19, 89, 26,196, 82,151,213,
+ 252,204,101,190,231,229,135, 8,100,118,154,122, 58, 94,219, 24,
+ 109,140,209, 74,199, 74,197, 42,142,149,138,162, 40,102,219,121,
+ 100,237, 51,191,250,141,203,151, 47,167,227,220,134,121,108,224,
+ 112,229,174,167,129, 29,151,191,152,237,107,175,189,182,125,231,
+ 238,231,126,234, 99,148,159,172,103, 44, 91,155,116,181,116, 20,
+ 167,158, 10,195, 56, 8,227, 48,140,131, 64,133, 81, 28,134,113,
+ 24,230,254, 74, 4,151, 52,188, 74, 45,173, 98, 10, 7, 34,226,
+ 253, 58, 89, 0,156, 82,163, 13,213,217, 96,177, 57,232,178,236,
+ 196, 39, 41, 18,145, 73,233,101, 69,165, 95,243, 61,207,247, 19,
+ 145, 37,245,166, 87,196,177,188,150, 76,122, 97, 74,171, 56, 86,
+ 113, 28, 71,113, 28,169, 56,138,227,238, 99,231, 63,250, 75,191,
+ 240,252,135, 63,236, 73, 47, 59,111, 93, 10, 57, 74, 28, 59, 82,
+ 16, 27,213, 95,204,246,123,223,251,222, 50,211,135,174, 60,145,
+ 62, 66, 50, 74, 36, 57, 38,168,148, 10, 67, 21, 69,113, 16,196,
+ 253, 48,238,247,163,126, 16, 5, 65, 28, 4,137,200, 84, 24,170,
+ 40, 86,113,164,227,172,127,111, 12, 59,227,221, 43, 67, 70,161,
+ 42, 0, 14,173, 51,215,101,110,247, 92,150,102,199, 72, 90,101,
+ 194,203,154,250,190,239,123,190,159,126,117, 69,150, 40, 44,233,
+ 235,103, 41, 76,169,204, 95,113, 28,197,113, 24, 71,209,217,149,
+ 167,190,241,139,159,120,233,165,100,233,223, 52,244,185,231,141,
+ 86,210,216,240, 6,255,193, 20,230,143, 38, 47,126,237,181,215,
+ 150, 12, 63,115,229, 74,209,173, 55, 54, 25,168,165,163, 56, 14,
+ 66, 21, 4, 81, 16, 68,189,126,212,235, 71,253, 94,212, 15,162,
+ 94, 63, 14,195, 56, 8,211,216,165,148,206,142, 39,186,141,173,
+ 161,163,177, 0, 0,251, 86, 30,217, 50, 34,238,100, 71,217,105,
+ 219,196,197,100,174,156,207,179,207,130, 51,145, 25,147, 72, 70,
+ 107,157,100, 49,157,212,150,169,196, 10,151,165, 69,101, 62,248,
+ 158,173,176,236, 49,249, 36, 44, 9,195,100,152,124, 38,117,103,
+ 253,237, 63,248,247,126,173,246,209, 23, 94,144,158,199,150,133,
+ 20, 44, 89,112,114,211,100, 61, 96,145, 75, 53, 23, 46, 39,203,
+ 155, 48,113,145,200,120, 68,133,249, 35,188,100,124,227,198,251,
+ 15,111,127,240,233, 15,127,132,242,179,215,147,110,189, 82, 42,
+ 138, 84, 16,196,253, 32,234,245,194,110, 47,236,246,194, 94, 47,
+ 234,245,163, 32,136,250,129, 10,195, 36,104, 22,227,182, 6, 3,
+ 23, 0,224,200, 58,219,195,101,233, 44,135, 68,194, 21, 25, 9,
+ 193,198,178, 16, 66, 88,107,165,144, 70,106, 41,165,167, 61,157,
+ 228,174, 76,100,190,163,176,164,150, 20,150,133,101,201,228, 17,
+ 249, 66, 24, 34,159,201,183,172,111,221,125,237,255,252,119, 11,
+ 11, 11, 79, 62,249,164,148, 82,178,100,102, 41,153, 89, 72, 41,
+ 89,144,116, 39, 99,115,151,124, 74,213,197,204, 7, 83,216,190,
+ 254,226,173,205,205,183,255,246,239, 62,255,209,159,202,229, 69,
+ 214, 90,173, 77,172, 84, 24,170,126, 16,245,131,176,211, 13,187,
+ 221,176,219, 13, 58,221,168,223,143,250, 65, 28,132,113, 20,169,
+ 56, 50, 74,235,108,124,124,113,226,206, 1, 39,138, 1, 0, 28,
+ 218,101,204,105,113,198,196,105,129,153,137, 76, 16, 11, 22, 44,
+ 132, 37, 43, 88, 74,107,211, 1, 95,210,120, 90, 26,207, 55,190,
+ 103,124,223,243, 18,139,121, 73,123,139,136,200, 90,193, 86, 50,
+ 121, 76, 73, 22,171,145,208, 66,154,235, 55,191,245,111,255, 96,
+ 233,191,255,239, 86,207,158,245,164,199,146, 89,178,148,169,200,
+ 178, 18, 86, 74,105,157,234,150,184,112,216,193, 20,230,253,143,
+ 255,211, 63,220,227, 53,137,227,248, 79,255,159,255,247, 43, 47,
+ 126, 60, 61, 93,221, 90, 50,198, 42,109,162, 88, 7, 97,220,235,
+ 71,157,110,184,179, 19,108,239, 4,219,219,253,237, 78,208,233,
+ 132,157,110,212,235,199, 65, 16,135,161,138, 99,163, 84,118,122,
+ 35,115,101,185, 86, 48,153,119, 54,179, 37, 50,217,192, 57, 49,
+ 116, 29,198,108, 54, 2,195,108,152,147,191,221, 98,151, 51, 2,
+ 45,167,155,101,127,132,134,111,152, 28, 66,206,142,203,236,241,
+ 184, 35,237, 30, 24, 83,203, 76, 56,225, 44, 17, 71,218,117,206,
+ 150, 96,160,129, 9, 23,210,137,249, 40,155, 51,134,146,182,143,
+ 97, 74,102,142, 49,150,181,177,198, 48,145,101,226,245,141,183,
+ 59, 15,159,254,200,135,165, 20,233,212,137,229, 79,124,117, 73,
+ 60, 42, 45,102, 55,228,108,240, 67,229, 47,182,214,254,167, 63,
+ 249,147,207, 61,247, 97,107,173, 76, 15,162,178,213,218,102,201,
+ 43,236,246,194, 78, 39,216,233, 4,157, 78,208,233,134,189, 94,
+ 212, 79,181,165,149, 74, 99,151,205,231,231,152,155,105,169, 78,
+ 144,185,200,176, 13,140,238, 25, 21, 26, 67, 68, 13,207, 91,244,
+ 106, 45,207,247,202, 11,145, 25,230,200,152,174, 86,129,213,150,
+ 185, 38,229,130, 87,107,123,126,178, 24,180,235,154,200,218,158,
+ 86,125,163, 52,179, 39, 68,219,243, 23,252, 90, 93,122, 94,121,
+ 51,197,182,175,117,207,168,216, 90, 73,212,244,252, 5,191,214,
+ 148,222,224,227, 6, 70,119,181, 10,141, 38,162,134,244, 22,252,
+ 90,203,243,124, 33, 97,177,241,230,178,106,129,201, 34, 47, 45,
+ 147, 56, 38, 4, 49,147, 48,134,165,100, 33, 44,179, 21, 50,153,
+ 25,207, 26,207,250,214, 26,227, 39, 3, 47,146, 9, 45, 44,147,
+ 101, 73,228, 17,121, 68,190,148, 62,179, 47,217,176, 53,175,190,
+ 246,103, 23,254,248,231,126,225, 23,253, 26,123, 82,178,244,216,
+ 115, 22,173,145, 44, 73, 74, 65,182, 88,125, 32, 95, 49, 47,111,
+ 135, 9, 22,249, 76, 63,226,160,254, 98, 38,122,227,141, 55,174,
+ 174,174,181, 27,117, 50,217,250, 99,198,152, 88,153, 40, 82,253,
+ 126,212,233,133,157, 78,176,189,147,248, 43,236,245,195, 36,115,
+ 69,177,214,202, 24, 99,141, 53,214,112,121, 73, 8,200,107,146,
+ 24,182,219, 42,190, 19,246, 54,226,112, 51,142, 60, 33, 26,158,
+ 119,181,189,124,174,209, 92,244,235,126,246, 7,208, 50,247,180,
+ 186, 23,246,215,163, 96, 83,133,150,185, 38,189, 71,155,237, 71,
+ 155, 11, 43,181,122, 67,122,233, 42,211,204,161, 53,247,163,224,
+ 78,208,219, 80, 81,108,141, 47,228, 90,189,113,185,181,180, 90,
+ 111,180, 60, 63, 55,157, 98,187, 25,135, 31, 4,253,141, 56,232,
+ 106,237, 9,177, 84,171, 61,209, 90, 90,107,180, 22, 60,223,203,
+ 30,215, 48,239,168,248,110,216,187, 31, 5,155, 42,146, 36, 26,
+ 158,247, 68,123,233, 92,189,185, 92,171,215, 8, 10, 59, 46,145,
+ 57,139,184,164,245,100,201, 98,214,178, 16, 44, 4, 39,195, 87,
+ 61,201,238,217,129,214,114, 58, 82,159, 18,133, 9,102,143,200,
+ 19,210,151,214,103,161,133,148, 97,188,253,202,119,223,188,122,
+ 245, 67,215,174, 89,207,243, 60,246, 88,178,231,177, 27,197, 4,
+ 137,108, 77, 21, 34,153,239,154,171, 48,218,175,144,244,119,123,
+ 166, 65,191,255,254, 27, 63,254,252,135, 95, 32, 99, 57,153,247,
+ 44, 57,107, 58,140,226,126, 16,117,187,225, 78, 42,175,126,167,
+ 147, 37,175, 40,142, 99,173,149,209,198,102,230,130,188,166, 88,
+ 54,134,214,220,139,250,215,251, 59, 55,131, 94,100, 77,114,253,
+ 205,160,251,213, 11,151,155, 73, 4, 35, 65, 68,202,218,205, 56,
+ 188, 25,116,223,233,237,116,141, 74, 54,123,167,183,243,169,213,
+ 11,139,203,103,107, 68,146, 73, 8, 50,204,219, 42,250, 32,232,
+ 253,164,247,112, 35,142,146,205,222,234,209, 67, 21,127,246,236,
+ 197,186, 76, 75,206,196,134,119,195,254,187,189,237,219, 81,223,
+ 102,111,128, 59, 97,255,203,231, 30,111,121,158, 71,156,124, 98,
+ 34,163,215,163,254,205,160,251,118,111,199,221,189,207,157,189,
+ 184,224,215,124, 65,176,215,241,137,172, 20,199, 6, 44,150,188,
+ 127, 88,202,236, 4,227,108,206, 97,203,108, 45,121, 54, 57, 5,
+ 156,152, 5,179, 96,146, 68,158, 16,158,144,190, 96, 95, 90,205,
+ 66,221,223,250,193, 31,255,167,199, 30,123,108, 97, 97,145, 45,
+ 179, 39, 37,179,231,121,196,204,228,229, 41,140,136,164,144,148,
+ 182,195,100, 69, 97,251,246,194,228,208,103,103, 45,127,243, 79,
+ 255,244,167,159,126,150,141, 33,107,217,104,214,218,196,202,132,
+ 145,234, 7,113,175, 23,117,186, 97,167, 27,118, 58, 97,167, 19,
+ 117,123, 73,195, 94,197,145, 78,166,139,176, 38, 25, 32, 65,144,
+ 215,244,176,196, 61,173, 58, 42,190, 17,116,115, 59, 16, 81, 71,
+ 171,255,252,224,131,154, 40, 10,195,200,154,109, 21,223, 14,123,
+ 185,188,136, 72,179,253,235,135,235,145, 53, 50,139, 75,138,237,
+ 142, 82,247,162,126, 46,175,132, 31,119, 31,222,137,250,126, 86,
+ 24,106,182, 93,173, 54,227,232, 3, 71, 94, 68,116, 47, 10, 94,
+ 239,108,122, 89, 97,200,196,129, 49, 59, 42,126,199,145, 87,178,
+ 123,127,181,121,183, 38,164, 32,129, 99, 60,199,106,177, 98,122,
+ 115,202, 87,106, 78, 47, 91,102, 75,156,204,185,110,172,213,214,
+ 170, 98, 46,157,164, 57,164,141,214, 73, 34, 19,196,201, 34, 75,
+ 94,250,175, 76, 46,200, 55,222,121,229,155,223, 76, 50, 77,178,
+ 189, 78,102,226, 73,166,237, 75, 7, 35,216,124,233,136,172,209,
+ 84, 44,103, 89, 89,170,116, 20,127, 17, 17,221,189,123,231,188,
+ 95,247,132, 32,203,172, 13, 43, 99, 99,101,227, 88, 7,161, 10,
+ 130,184,219,139, 58,221,112,167, 19,238,116,195, 94, 63, 31, 39,
+ 161,149, 74,167, 72,205, 23,251, 26,120,165,192, 4,139, 71, 86,
+ 214,238,104, 21, 91, 91,249,209, 70, 28,238, 8,235,249,126,242,
+ 6, 73,122,231, 15,226,176,178, 89,108,237,219, 65,167,214,168,
+ 39,198,177,233,102,209,224, 99,253,168,187, 85,111, 54,211,129,
+ 218, 76,134,121, 83, 69,102, 64, 63,127,183,179,217,168,215,165,
+ 231, 37,159, 25,205,182,111,116,232,200, 43,161,171,213,186,137,
+ 189,154,143,242,113,194, 22,203, 39,243, 76,215,122, 38, 78,142,
+ 213, 20, 34, 75,228, 99,141,214,201, 60,162, 38, 25, 14, 37, 4,
+ 73, 18,146, 74, 10, 35, 99,182,190,255,183,119,239,222, 81,201,
+ 180, 21,249, 36, 90,153,192,114,139,241, 16,133, 13, 91, 90,121,
+ 63,127, 49, 17, 25, 99,191,243,151,127,249,204, 35, 23,147,163,
+ 141,108, 12,107,109,226, 88,135,145, 10,130,184,215,143,186,189,
+ 100,192, 68,212,239,199,253, 64, 69,145,202,202, 70, 99,109,101,
+ 158, 64,152,107, 90, 72, 18, 53, 41, 3,171,135,219,205,247,252,
+ 122, 45,155, 29, 93,216, 93,126, 81, 94,173,230, 55, 82,227, 72,
+ 33,106, 82,122,195,164, 34,165, 87,107, 54,164,239, 39, 45,216,
+ 154,148, 53, 57,252, 79,227, 29,171,252, 90, 45, 89,147,218, 43,
+ 141, 2, 42,241,129, 10,235,141,134,220,229, 78,192, 49, 89,172,
+ 48, 87, 42,175,116, 22,157, 68, 97, 58, 61,207,185, 80, 88, 62,
+ 171,113,242,123, 79, 78,152,244, 10,139, 9,186,125,239,187,255,
+ 249, 47,162, 40, 82, 90,105,149,228, 54,157, 26, 76,167, 45,242,
+ 1,133, 13,134,176, 93, 87,123,144, 21,121, 49,209,173, 91, 55,
+ 47, 47, 46, 91, 99, 41, 57,155, 90,235, 52,124,133,161, 10,194,
+ 184,219,139,186,189,168,215,143,123,253, 56,200,228,165,180, 53,
+ 198, 50,228, 53, 67,120, 66, 46,250,181,203,173,197,225,141,207,
+ 90, 93,250,105,205,215,144,242,145, 70,123,248,157,248,190, 95,
+ 171, 37,135,182,125, 33,151,252,225,161, 72, 72,233,213,211,152,
+ 230, 9,185,224,213, 26,210, 27,122,135,207,158,127, 68,250, 30,
+ 9,146, 68, 45,207,111,123,195,143, 32, 61,115,238,130, 87,175,
+ 145, 68, 0,155,116, 95,140,156, 37,253,152,210,225, 20, 54, 11,
+ 233,198,178,225,108,250,119,107,147,252,197,249,192, 23, 74, 21,
+ 150,254, 75,194, 19, 34,250,241,219,183,111,223, 86,177, 82, 42,
+ 171, 60,181,214, 38,115, 88,118,164,207, 81,152, 45, 2,152,179,
+ 234,233,208, 42,178,250,247,205, 26,251,215,223,254,206,149,149,
+ 179,233,200, 14,109, 56,153,198, 43,138,117, 24,169,126, 63,238,
+ 7,113,175, 23,247,251,113, 16,170, 48, 82,113,108,180, 54, 69,
+ 240, 98,198,201, 64,179,129, 16,212,242,252,103, 23, 87,150,252,
+ 90,229, 71,143, 46,157,121,250,220,133,252,247, 84,151,222,106,
+ 189,241,161,197,149,202,102, 77,191,246,201, 75, 79,230, 17,222,
+ 23,242, 76,173,241,226,202,185,193,199,250,252,147, 79, 39,237,
+ 86, 34,242,132, 88,244,107, 31, 59,179, 86, 31, 80,216, 75,143,
+ 93, 17,158, 76,198, 22, 9, 33,154,158,127,109,105,117,173,222,
+ 172,108,182,218,106, 63,189,118, 33, 89, 52, 15,191,199,153, 80,
+ 88,210, 17, 99, 54,233, 74, 22, 54, 93, 26,167, 88, 89, 62,121,
+ 203, 37,107, 31, 9, 73, 34, 91,167,151,104,125,227, 7,223,250,
+ 118, 28, 71,233,228,135, 74,107,173, 76,230,176,244,140,112, 71,
+ 97, 92, 14, 97, 89, 25, 57,124,192,123, 62,126, 53,141, 75, 31,
+ 124,112, 91, 60,216, 90,110,182, 4,179,176, 76,214,178,214, 54,
+ 138,211,206,125,183, 31,118,187, 97,183, 23,246,250, 81, 16,196,
+ 201, 56, 47,227, 62,178, 51,234, 23,111,135,233, 43, 76, 52,164,
+ 255,196,210,202,123,253, 78,100,210, 66,242,177,229,149, 95,251,
+ 169, 79, 54,153,162,126,223, 40,149,111,246,228,226,153,187,113,
+ 184,157,181,183,154,181,218,127,253,177, 79, 62,214, 94,140,186,
+ 61, 29,199,105, 97,232,121,143,180, 22,164,231,221,236,117,242,
+ 71,249,194, 83,207,126,238,210,147, 81,175,175,194, 40, 85,152,
+ 148, 75,181,250,249,246,226,123,189, 29,205,105,247,237,233,181,
+ 243,191,242,209, 79,112, 24,199,253,192, 90,155, 20,164, 13,207,
+ 191,180,184,124, 55,238,247, 84,122,232, 96,181,189,240,247, 94,
+ 250,108,147, 41,236,245,140, 82,248, 37, 78,231,157,147,126,117,
+ 230, 76, 21,165, 63,141,206,114, 29,233,117,201,231,221, 50,167,
+ 181,103, 54, 22,218, 18,199, 65,112,230,233, 39,219,237,118,101,
+ 122,198,236,159, 98,225,224,252,254,203,139, 13, 87,150, 8, 41,
+ 30, 54,159,127, 34, 61,236,248,127,255,187, 63,252,233,179, 23,
+ 132, 16, 30, 9,201, 44,172,101,165, 77, 20,171, 32,136, 58,221,
+ 96,167,211,127,184,221,223,217, 9,186,189, 40, 8,162, 40, 82,
+ 74,233, 34, 68, 22,254,130,188,102,165, 11,230,121,126,189, 86,
+ 111,181,110, 71,193,142, 81,107, 11,139, 79,173,174,197, 65, 16,
+ 236,116,226, 94,223,102,173,125, 33,165, 95,171,213,154,205, 77,
+ 214,247,163, 96,109,113,233,209,165, 51,190,181,193, 78, 39,234,
+ 246,140,214,185, 16,165,239,213, 26,205,192, 19, 15, 84, 36,125,
+ 239,177,229,149,229, 90, 61,236,116,131,157, 78,162,185,228,157,
+ 41, 60, 89,107, 52,108,163,182,161,227, 29, 21, 63,190,178,122,
+ 113, 97, 41,234,245,251, 59, 59, 42, 8,243, 63,166,210,243,252,
+ 90,173,222,106,221,142,251, 59, 70,175, 45, 44, 94, 93, 61, 23,
+ 7, 65,176,179, 19, 57,187, 7,166,171, 48,145,157,186,232,101,
+ 199, 25,125, 41, 61, 33,124,233,249, 66,120,153, 88, 44,179,102,
+ 171,172,141,172, 9,141, 9,141, 9,173, 14,141,137,172,105,253,
+ 204,231,190,244,179, 47,215,106, 53,223,247,125, 63,253,127, 54,
+ 229, 69, 58, 67,172, 39,179,127,210, 89,100,221, 89, 43, 6,166,
+ 220, 73,218, 32,110,248,234,247,123,173, 72, 25, 99,124,145, 78,
+ 77,200,198,218, 88,153, 40, 54, 97,164,195, 72, 39, 51,225,132,
+ 81, 50, 25,180,209, 38, 63,191, 0,242,154,209,138,192, 90, 29,
+ 43, 34,122,180,209,184,220, 94, 36, 33,186, 27,155, 42, 8,117,
+ 28,187,118, 72, 38,113, 35,162,213, 70,253,252,210,170,144,210,
+ 236,116,194, 40,210, 81,156,203, 43, 9,241, 86, 27, 77, 81,171,
+ 209,120,170,181, 40, 61,143,195,184,187,221, 85, 81,228,102, 37,
+ 38,174, 62, 35,195, 0, 0, 32, 0, 73, 68, 65, 84, 38,107,117,
+ 28,251, 68,143, 54, 26,151,154, 11,100,168,243, 96, 83,133,161,
+ 86,202,173, 4,172,177,154,146,221,107, 94,110,215, 72,136,206,
+ 198, 70,242, 6,131,188,166, 94, 75,138,236, 76,239,100,230, 10,
+ 98,178,130, 4,145, 37, 50,108,133,240, 44, 91, 75, 50, 27,126,
+ 90,204, 60,150, 86,145, 73,168, 34, 18, 68, 59,111,191,219,253,
+ 244,167, 22,151,150,242, 37,117,138, 97,104,162,136,122,121, 36,
+ 147, 76,204,146,178, 19, 54,147,193,105, 34,249, 82,236,157, 59,
+ 126,149,249,205, 55,223,124,116, 97,137,141, 97, 33,153,217, 26,
+ 75,218,216, 56, 54,113,164,163, 72, 71,145, 10, 28,121, 37,171,
+ 162, 57, 29,123,136,107, 22,223,133,204,108, 76, 28, 88, 21,197,
+ 201,225,188,228,136,209,224,150,214, 90, 27, 69, 90, 41, 33,250,
+ 66,136,100, 9,173,193,223, 41, 51, 39,163,252,226, 32, 72,122,
+ 94,156,117,112, 43,155, 37, 51,142,168, 48, 20,178, 24,192, 61,
+ 68,176,198,196,198,170,120,159,221, 3, 83, 84, 88,113,214, 36,
+ 177,205, 78,182,182,214, 90, 41, 13, 89, 33,146, 65,244,249,218,
+ 222,148,205,146, 35,164, 72,207,162, 16,247, 55,223,123,239,189,
+ 107,207, 61,231,188,161,156,117,116,139, 10,178,152,120,145,136,
+ 165,180,204,210, 45, 90, 43,227, 88,253,108,166, 83,178,204,239,
+ 189,245,214,139, 75,171,172, 13, 11,203, 76,100, 12, 39,107,106,
+ 36,147,217,135, 81, 50,147,189,206,103,124,182, 54,159, 8,199,
+ 61, 4, 11,102,209, 99,150,205, 8, 94, 72, 15,134,143,166,197,
+ 145, 54, 75, 78,251, 31,211,238,129, 41,137, 44,201, 97,204, 44,
+ 88,144, 77, 38,174, 32,178,204,146,132, 77,198,239,151,187, 87,
+ 233,140,209, 89,175,140,251,193,141,183,222,126,234,234, 85, 87,
+ 16,197,242,228,130,132, 32, 35,132, 48,133,201,152,137, 89, 50,
+ 115,169,225, 85, 12,202,103, 34, 81,228,175, 48, 8, 90,177,177,
+ 218, 72,201,150, 4, 49, 11, 99, 88,105,171,148, 73,150,219,200,
+ 102,127, 54, 74, 39, 3,236, 43,167, 7, 65, 94, 0,156,200, 8,
+ 86,104, 76, 16, 23, 99, 92,133, 37,182,130, 5,145, 76,227, 87,
+ 113,114, 82,218, 50,163,108, 97, 73, 18,225, 7,119,251,189,158,
+ 88,204, 58,246,238,146,145,105,209,153,152,204, 80,102,192,228,
+ 4, 76, 34, 33, 68,126, 84,176, 52,126,199,207, 42, 81,254,224,
+ 131, 15,150,125,159, 77, 22,169, 44,179, 49,156, 44,215,152, 68,
+ 48, 85, 76,253, 92,156,222,152,141,209,192,152, 9, 0, 78, 65,
+ 21, 89,138, 96,146, 68, 30,193,178,179,237, 83, 15, 8, 55, 97,
+ 37,183,220,233,222,191,127,191,209,104, 8,167,192, 44, 45,206,
+ 43,132,169, 76,150,111,147, 42, 50, 31, 97,150,252, 87, 68, 48,
+ 63,139,239,244,238,187,239, 94,246,235,108, 12, 91,145,204, 81,
+ 72,218,176,214, 54, 89,155, 67,101, 10, 43,102,197,169,154, 11,
+ 2, 3,224, 68,167,176,116, 90,155, 44,130,165,218,226,100,134,
+ 196,116,213,219, 66, 4, 69,253,152,124,187,221,185,115,231,206,
+ 35,143, 60,146, 23,153, 84,158, 24, 63,185, 96,203, 10, 75,207,
+ 202,100, 73,201,212,215,229, 8,230,115,218,244,176, 59,119,239,
+ 25,191, 37,165,180, 66, 8, 38, 97, 44,165,245,163,182, 74, 89,
+ 149,230,175,116,204,218, 96,233, 8, 0, 56,233, 22, 75,211, 78,
+ 110,177,116,250, 73, 33, 69, 90,231, 57,155, 59, 3,184, 50,187,
+ 109,221,254, 32,254,200, 71, 74, 11,238,138,116,180,126,178,244,
+ 154, 16, 82, 72, 43,140, 21,233, 37, 43,178, 53, 40, 69, 62, 72,
+ 150,178,163,145, 68,126,178, 83, 81, 20,214, 99,109,133, 73,211,
+ 32,179,180,150,180,177, 90, 25,165,141, 54,201,130,216,233,114,
+ 103,197,128,219,188,103, 15,149, 1,112, 58, 34,152, 51, 41, 23,
+ 23,115, 87, 8,206, 38, 12, 41, 90, 96,197,188,132,169,217,212,
+ 230,195, 48, 8,220,133,213,146,149,144,210,139, 82,202,124,197,
+ 34, 43,172,176, 66,138,100, 46,178,124, 18,223,172, 17,150, 30,
+ 136,244,147,129,249, 59, 59, 59,181,164,225,101,217, 10, 18, 54,
+ 173, 31,109,178,172,172,214,214,232,114,229,232,156,228,200, 40,
+ 30, 1, 56, 53, 17,140,137, 69,222, 59, 18,201, 92,227,110, 9,
+ 57,128,115, 0, 32,138,186,221,110,189, 94,151,114,112,149,112,
+ 45,117,234, 48, 35,165,176, 54, 49,152, 16,130, 57,139, 96,194,
+ 105,132, 9,230,236,248, 35,111,111,111, 55,153,172,214, 86, 74,
+ 73,194,218, 60,127, 25, 78, 44,150, 45, 52,203,214,157,163, 7,
+ 226, 2,224,180, 69,176,172,207,149, 76,202, 75, 34, 85, 75, 50,
+ 45,229,192,108,247,238,205, 57,136,186,221,238,242,242,114,186,
+ 72,119, 58,208, 94,107,153, 99,146,175, 54, 41, 30,237, 64, 21,
+ 41, 68,145,240,152,252, 36, 4,110,111,111, 11,107,153, 12,219,
+ 108,135,146, 56,102,138,245,177,173,201, 7,124,237, 54,155, 5,
+ 0,224,180,120,204,169, 31,211,238, 23, 21,163, 28,134,247,148,
+ 216,152, 94,175,103,180,214, 89,240,210,217,127, 58, 79, 97,158,
+ 148, 86, 74,107,172,149,210, 10, 43,109, 54,143,117, 81, 69,230,
+ 231,101,250,137, 75,123,221,110, 75, 91, 43,201, 74,182, 36, 4,
+ 179,181, 76, 73,224, 74,102,209,201, 87,156,117, 98, 23, 38, 38,
+ 4,224, 52,218,139,243,229,139, 6,230, 40,101, 26,218, 79, 74,
+ 167,169, 14,163, 32, 8,180, 49, 66,235,188,112,212, 73,234, 50,
+ 198, 24, 35,165,244,140,177, 73, 12,179,198, 90, 41,172,149, 66,
+ 90, 81,116,193,210,168, 71,130, 4,167,227,239,149, 82,117,163,
+ 211, 69, 66,146, 54,156,205,230,255,178, 38, 89,109,155, 77,113,
+ 98, 7, 15,238, 27, 0,224,116, 68, 47,166,124,184,106,178,188,
+ 119,238, 52,225,142,165, 42, 47,166,155,126, 81, 74, 25,173,147,
+ 243,179,141, 54, 58,215,151,244,140, 52, 82, 74, 99,140,148,158,
+ 148,214, 74,107,173,149, 86,102, 17, 44, 31, 75,145, 87,145,194,
+ 15,131,208, 24, 19,132,161,191,211, 37,207, 99, 41, 89, 72,203,
+ 36,172, 37, 99,141,214, 42,138, 84, 24,170, 40, 82,177, 50,198,
+ 36, 19, 99,179, 59,103, 54, 97, 81, 71, 0, 78,143,194, 4, 9,
+ 182,156, 24,196, 18, 9,178,146,132, 37, 41,211,249,194,152,117,
+ 54,223, 97, 50, 45,141,205,230,212, 55,204,183,127,242,214,135,
+ 158,125, 86, 74, 45,141,212, 82, 75,147, 4,175,100, 86,124,233,
+ 25,207, 24,227,121,198,218, 76, 96,108,165, 77, 86,242,206,102,
+ 23, 44,202, 85,146, 16, 15, 0, 96,146,100,190,210,102, 24,214,
+ 38,157,246,124,105, 15,107,243, 73, 18, 75, 75,154, 49, 49, 29,
+ 98,126,113,232, 14, 0,112,120, 15,232, 76, 84,195,236,149,253,
+ 196, 49, 24,103,255, 12, 42,204,159,254,179, 1, 0,204, 15, 71,
+ 95,146,192, 24, 99, 60, 79, 26,227, 73, 89,137, 94, 38, 29,234,
+ 96,173,177,214, 75, 87, 86,179,108, 37,203,228,107, 62,248, 33,
+ 169, 32,177,190, 11, 0, 96,162,228,227,177,202, 17,204,154,252,
+ 202, 84, 96,121, 4,115,167,197, 39,119,153,141,195,251, 11,129,
+ 11, 0,112, 24,127,229, 20,101,162, 77,150, 4, 49,214, 21, 87,
+ 190,184,109, 33, 48,114,231,189, 25, 99,253,184,135,227,138,200,
+ 135, 95, 29, 0, 51, 94, 24,102, 83,204,139,177, 74,160,116, 13,
+ 115,197, 90, 89,227, 62,187,170,176, 23, 39, 11,170, 89,206,142,
+ 64, 82, 62,221,179,115,254,208,120, 35,151,187,126, 47, 51, 91,
+ 34,194, 57,146, 0,204,188,188,146, 57, 3,179,213, 58, 74,179,
+ 223,140, 57,127, 21, 10, 51,214,122,133,182, 76, 41,146,113, 58,
+ 108,190,188,168, 26,165,249, 75,112, 58,127, 14,149,150, 92, 43,
+ 205, 49,125, 96,231, 48, 81, 50,208, 67,179, 53,201, 72,144,116,
+ 9, 57, 0,192, 76, 43, 44, 89,128,182, 70,194, 23,194, 23,210,
+ 203,102,175, 31,115, 89, 86, 10, 96, 92,201, 93,249,144,137,108,
+ 101, 5,206,214,180, 45, 41, 44,249,215,207,229,149, 72,199, 79,
+ 43,203,253,246,121, 23, 27, 37,139,190,105,203, 49,155,136,109,
+ 192, 28, 18, 43, 98,131,119, 7, 0, 51, 47, 48, 65,228,179,168,
+ 147,104,145,108, 17, 55, 73,214, 73,202,100,125,142,113,231, 47,
+ 78, 7,184, 22, 2,227,106,223, 43, 95,145,187,218,187,207, 91,
+ 96, 62,101,211,244,252,248,238,237,165, 70,243,234,218,121, 95,
+ 212,188, 67, 41,215, 18, 27,203,138,109, 96, 77,151,109,135,108,
+ 143,108,223,218,190,142, 35,165,176, 64, 17, 0,115, 16,193,132,
+ 88,240,235,171,245,198,178,231, 47,177,183, 36,185, 65,146,132,
+ 28,163,194,210,252,149,228,171,226, 2, 59,253,250,108,212,106,
+ 222,253, 42,250,247,228,158,115,233, 39,123,237,121,222,139, 79,
+ 61, 29, 71,209,255,247,222, 59, 31,191,244,196, 90,171,125,192,
+ 154,145,153,200, 48,199,108, 3,107,182,217,108,145,125,104,212,
+ 253,238,206,189,157,109,188, 45, 0,152, 59, 46, 47,175, 60,187,
+ 124,150, 69,125,153, 68,147, 88,236, 82, 72, 30, 34,146,228,139,
+ 233,101,181, 97, 58,200, 43, 13, 92,153,171, 42,227, 38,184,114,
+ 0,146,136,136,100,190, 20,136,244,188,165,197,197,207, 62,115,
+ 237,221,205, 7, 94,189,126,208,178,215, 50,107,203,161, 53, 15,
+ 217,108,144,189, 27, 7, 63,190,123, 27,242, 2, 96, 78,185,185,
+ 243,240,149, 15,222,187, 21,246,250,108,227,221,103,245, 58,100,
+ 254,114,200,131, 88,170,178,162,109,239,110, 66, 78,221,152,223,
+ 73, 54,254,203, 90,171,162, 72,133,145, 71,226, 76,171,189, 19,
+ 71, 94,163, 62,226,193,135,164,147,150,132,175, 46,217,109,178,
+ 247,194,254,219,247,238,104, 44,231, 7,192, 60,163,172,253,214,
+ 221,155,239,245,119, 20,179, 41, 4,198,123,202,224,128, 6,203,
+ 60,229,246,186, 6,114, 87, 46,175,116, 41,202,252,252, 33,153,
+ 11, 40,189, 35,226,229,122, 67, 25, 45,253,154,244, 61,177,255,
+ 40, 16, 38, 78, 14, 56,218,144,237, 14,217, 45,163,222,185,127,
+ 23,191,123, 0, 78, 6,223, 90,191,253, 80, 69, 78, 24, 57,234,
+ 1, 73,102,215, 97, 84, 57,186,104,135, 92,202,167,186, 41,214,
+ 59, 75,238,196, 47,221,105,186,168, 7,179,177, 66, 10, 33, 37,
+ 141, 80,242, 38,119,170,136,251,100, 67, 98, 87, 94, 88,162, 8,
+ 128,249, 37,111, 34,253,233,221, 27,127,239,137,107,201, 85, 71,
+ 175, 35,243, 6, 86,222,207, 34, 30, 38, 48, 71,113,101,125,229,
+ 67, 40,200, 31, 22,167, 92,239,136, 81,130, 34, 51, 25,230,136,
+ 248, 65,208, 15,148,202,175,255,111,254,219,223,192,155, 0,128,
+ 57,229,255,248,183,255, 38,185,208,209,241, 91,157,135, 47,172,
+ 156, 99,107,199, 50, 48,127,160, 29,191, 23,228, 12,188,119, 87,
+ 202,102, 30,223,249,219,134,200, 16,109,245,187,248,173, 3,112,
+ 242,184, 30,246,252,122,221,243,253,253,234,177,145,228, 85,186,
+ 92, 17, 25,185,230,202,100, 71,217, 90,103,217, 63,201,247, 99,
+ 243, 87,114,135, 91, 65, 31,191,105, 0, 78, 30, 55,123, 59,245,
+ 86, 83,214,252, 97, 53,217,193,207,210, 41,157, 13,148,213,124,
+ 89,159,158,202, 35, 85,211,172,149,231,175,172,103, 69, 52,190,
+ 252, 37,136, 36,145,194, 49, 71, 0, 78, 34,161,209, 94,173,230,
+ 121,222, 56,206, 39,114,231,197,207,207,150,166,114, 49,153,127,
+ 239,230,175,234,173,229, 88,246,161,112, 24, 0,224,132, 34,199,
+ 116, 42,145,123,252, 49, 43, 10,211,132,149,127,235,172, 35,233,
+ 230,175,124,201,141,244, 58,204, 95, 8, 0, 24,177,200, 18, 36,
+ 199, 52, 39, 69, 49,141,170,155,191,138,111, 41,147, 85,166,181,
+ 114,106,226,163,231, 47, 0,192, 41,134,143,176, 49,151, 47, 23,
+ 51,122, 21,249,139,156,252, 85,174, 31,115,225,141,216,191,199,
+ 32, 46, 0,192,152,237,150,159,198,232,204,104, 95,228,175,202,
+ 189,184,103,110, 31,186,255, 5,145, 1, 0,142,170, 7,174,244,
+ 226,121,200, 72,119,103,168,132,187,100,135,243, 32, 99, 61,254,
+ 8, 0, 0, 7,151,222, 80,113, 21,134,202,199,122, 13,249, 57,
+ 252, 5, 0,152,116,252,218,237,218, 98, 97, 90,230,161, 61,178,
+ 129,219,202,169, 60, 1, 0, 0, 98, 87,217, 28,124,136, 25, 78,
+ 145,191, 0, 0,199,144, 94, 14, 21,199,170,147,244, 48, 13,255,
+ 22,254, 2, 0,204,180, 15,247,200, 99, 24,255, 5, 0, 24,107,
+ 226, 26,255, 77,121, 88, 50, 67,254, 2, 0,204,150, 7,249, 80,
+ 150,147,163, 63, 0, 0, 0,236,235, 9, 62,228,237,118,253,158,
+ 119,223, 82, 30,249,177, 0, 0,167,202, 82, 7, 80,192,168,135,
+ 20,249,144, 63, 66,253, 8, 0, 24,123,124, 25,126, 80,113,236,
+ 15, 10,127, 1, 0,166, 46,195, 67, 26, 14,254, 2, 0, 76, 51,
+ 170, 29, 5,248, 11, 0, 48,175, 28,216, 95,104,223, 3, 0,102,
+ 36,162, 73, 40, 10, 0, 48,187, 37, 34,234, 71, 0,192, 73,210,
+ 22,252, 5, 0,152,123, 70,247, 23,170, 74, 0,192,108,229, 52,
+ 57,243,123, 8, 0, 0,168, 31, 1, 0,240, 23, 0, 0,192, 95,
+ 0,128,211,194,113,244,154,228,108,238, 22, 0, 96,222,221, 52,
+ 1, 51,200,202,227, 57, 11,128,192, 75, 0,128,185,169, 31, 75,
+ 11, 74,138, 81,108,123,244,243,199, 1, 0, 39,168, 24,228,201,
+ 22,105,178,188,128, 55, 51,115, 47,142,132,148,194,243,246,118,
+ 24, 0, 0,204, 68,254, 98,182,198,178,101,102,162, 7,221,206,
+ 165, 71, 31, 21,158, 71,101,129, 33, 97, 1, 0,102,206, 95,204,
+ 204,150,147,142,215,223,220,124,255,201,199, 30,175, 53,155,100,
+ 45, 91,139, 23, 8, 0, 48,179,248, 68, 68, 36,132, 16,111,222,
+ 189, 45,132,120,254,234,213,167,159,120,146,163,216,104,205,214,
+ 50,241, 40,211, 93, 35,154, 1, 0,166,227, 47, 33,200,243,188,
+ 151,158,251,240,153,179,171,205,102,211, 42,173,131,208, 42,197,
+ 204, 48, 19, 0, 96,118,253, 37,136, 4, 9, 33, 37,179, 85, 65,
+ 72,177, 18, 74,115, 20,179,214,100, 45, 97, 20, 5, 0, 96,182,
+ 235, 71,178,214,170, 32, 12,180, 49,210,247,137,132,177,194, 88,
+ 184, 11, 0, 48,235,254,226,180,133,111,173, 54, 70,178, 32,225,
+ 113,178,202, 27, 4, 6, 0,152,249,252, 69,217,224, 47,178,123,
+ 15, 93,133,209, 0, 0,179,194,168,231, 63,242, 48,125, 65,102,
+ 0,128,195, 27,100,236,254,130,146, 0, 0,135,246,211,140,230,
+ 47, 0, 0,152,215,250, 17, 0, 0, 78,136,191, 80,102, 2, 0,
+ 144,191, 0, 0, 0,254, 2, 0, 28, 59,179, 85,122,201,121,220,
+ 105, 0, 0, 64,254, 2, 0,156, 28,127, 49,114, 23, 0, 0,249,
+ 11, 0,112, 74,153, 88,238,129,191, 0, 0, 39, 44,127, 29,216,
+ 159, 40, 52, 1, 64,210,162, 9,207, 24,136,252, 5, 0,152,215,
+ 168, 34,231,253, 9, 0, 0, 80, 63,194, 76, 0,128,185,246, 23,
+ 210, 22, 0, 96,126, 74, 76,244,191, 0, 0, 51, 43,168,113,249,
+ 11, 49, 12, 0, 48, 99, 82,144, 39,227,105, 0, 0, 78, 33,168,
+ 31, 1, 0,167,214, 95,200, 94, 0,128,185,243, 23,196, 5, 0,
+ 152,174, 9, 80, 63, 2, 0, 78,109,253,136, 36, 6, 0,152,146,
+ 40,144,191, 0, 0,227,150,210,164, 50, 13,252, 5, 0, 56,205,
+ 245, 35, 0, 0,169,107, 98, 69, 35,252, 5, 0,152,188,204,224,
+ 47, 0,192,188,168,234,216,205, 38,103,107,119, 0, 0, 39,211,
+ 122,199, 34, 15,121,200,157, 1, 0,128,105,115, 32,127,193, 92,
+ 0,128,153,247, 23,143,228, 45,232, 12, 0, 48, 55,249, 11, 0,
+ 0,118, 79, 47, 19,143, 52,242, 24,158, 4, 0,224, 52,137,140,
+ 247, 42,218,142,213, 17, 18,110, 2, 0,140, 51,149, 77,208, 28,
+ 168, 31, 1, 0,135,169,182,120, 6, 34, 15,252, 5, 0, 56, 70,
+ 205, 77,218, 95,140,130, 18, 0, 48, 15, 32,127, 1, 0, 78,142,
+ 191, 70, 27,251,133, 84, 6, 0,152, 29,127,241, 81,189, 4,145,
+ 1, 0, 80, 63, 2, 0, 0,252, 5, 0, 24, 31, 51, 87, 99,201,
+ 185,127, 6, 0,128,169,123,109, 74, 94,144,135, 85, 21, 60, 6,
+ 0,152,178, 19, 80, 63, 2, 0,230, 21,248, 11, 0, 0,127, 1,
+ 0, 0,252, 5, 0,152, 11,120,191,150,215,113,183,196,224, 47,
+ 0,192, 97,220,133,252, 5, 0,128,213,142,201, 95, 60,123,190,
+ 5, 0, 32,140, 13,245, 23,214,233, 0, 0,204, 71,233,136,250,
+ 17, 0, 48,215, 28,213, 95,200,102, 0,128,121,243, 23,188, 5,
+ 0,152,182, 40,228, 12,238, 19, 0,224, 4,120,107, 2,158, 64,
+ 255, 11, 0,112,210,234, 71, 68, 44, 0,192,188,250, 11,213, 36,
+ 0, 96,214, 63,245,114,196, 61,101,104, 10, 0,112, 88,197, 29,
+ 147, 62,208,255, 2, 0,204,107, 36,131,191, 0, 0,243, 10,252,
+ 5, 0,128,191, 0, 0, 40, 20, 39, 91, 98, 74,154,157,125, 1,
+ 0,128,177,248,107, 20, 59,193, 96, 0,128,249,171, 31, 43,230,
+ 98,152, 12, 0, 48, 7,254,130,170, 0, 0,179, 33, 10,121,168,
+ 93,129,195, 0, 0,211, 87, 26,142, 63, 2, 0,230, 49,123,193,
+ 95, 0,128,121, 70,238,237, 76,158,154, 88, 1, 0,224, 72,249,
+ 11,182, 2, 0,204,171,191, 96, 53, 0,192, 17, 57, 70, 97,160,
+ 255, 5, 0,152,148,151,198,173, 50,185,207,131, 32,107, 1, 0,
+ 102,181, 42, 67,254, 2, 0,204, 43,251,251, 11, 9, 12, 0, 48,
+ 175,254,154,233,248, 8, 0,128,191,160, 33, 0,192,220, 37, 21,
+ 244,191, 0, 0, 39,188,126, 68, 44, 3, 0,204,156, 12,228, 9,
+ 125, 94, 0,128,147,175, 55, 57, 31,187, 9, 0, 64,242, 58,162,
+ 191,224, 44, 0,192,236,248, 66,206,218, 14, 1, 0,224,168, 99,
+ 175, 31, 1, 0,128,166, 58,203, 22,252, 5, 0,152, 87,142,230,
+ 47,148,147, 0,160, 92,156, 45,127,193, 74, 0,128,113,155,237,
+ 56,188, 34,199,178,103, 0, 0, 88,139, 39,174, 15,121, 60, 79,
+ 4, 0, 0,166, 82, 63, 2, 0,192, 60, 36, 25,248, 11, 0,112,
+ 220, 22, 59, 46,167,193, 95, 0, 0,212,143, 0, 0, 84,135,147,
+ 237,131,195, 95, 0,128,227,113, 25,252, 5, 0,152,109, 99, 77,
+ 211, 98,240, 23, 0, 96, 62,211,215,110,254,226, 3,239, 52, 70,
+ 127, 1, 0,102, 58,127,241, 46,170,130,188, 0, 0,168, 31, 1,
+ 0, 0,254, 2, 0,204, 10,199, 86,161,201, 81, 31, 9, 53, 34,
+ 0, 96, 90,162, 66,254, 2, 0,156, 48,129,201,153,221, 51, 0,
+ 0,140, 54,186,191, 32, 40, 0,192, 24,165,116,236, 74,145, 71,
+ 120,112,248, 14, 0,176,191, 11,142,207, 20, 18, 90, 2, 0, 28,
+ 78, 82, 83,119, 5,250,247, 0,128,227, 83,221,241, 42, 78, 34,
+ 123, 1, 0,230,148, 35,230, 47,248, 14, 0,128,250, 17, 0,112,
+ 82,138, 70,248, 11, 0, 0,165, 29,206, 95,168, 11, 1, 0, 7,
+ 181,210,196,189, 33,247,219, 73,134,208, 0, 0,123,122,106,106,
+ 122, 56,106,253,200, 60, 19, 79, 3, 0,112,218,138,199,163,248,
+ 139,225, 44, 0,192,116, 65,255, 30, 0, 48,111,185,235, 48,254,
+ 66,210, 2, 0,204,146, 12,144,191, 0, 0,243, 42,179, 49,248,
+ 139,145,203, 0, 0,211,245, 23, 44, 4, 0,152,175, 74, 82,206,
+ 250, 14, 2, 0,192,120,235, 71, 40, 13, 0, 48,117, 63,200,185,
+ 216, 75, 0, 0, 12, 54,102,127, 1, 0, 96,168,249,171, 31, 1,
+ 0,208,215,212,109, 38, 71,182, 43,138, 69, 0,192,108, 33, 15,
+ 161, 40,152, 12, 0, 48,155,245, 35, 38,148, 0, 0,140,189,194,
+ 156,108,253, 56,115,123, 10, 0, 0,199,225, 47, 0, 0, 34,213,
+ 228, 51,142,220,247, 49,144,173, 0, 0,200, 95, 0, 0, 48, 25,
+ 127, 33,119, 1, 0,102,161,246, 28, 87,254,130,211, 0, 0,179,
+ 99, 4,121,168,253,133,199, 0, 0,211, 23,158, 68,210, 2, 0,
+ 204, 41,232,223, 3, 0, 78,149,191,152,136,145,208, 0, 0, 83,
+ 174,217,144,191, 0, 0,135,215, 20, 59, 77,241,201, 27, 76,142,
+ 79,168, 8,100, 0,156,218,160, 53,157,143, 63,242, 23, 0, 96,
+ 94,139, 75, 57,197,199, 6, 0, 64, 85,199,236, 47,216, 11, 0,
+ 48,147,160,126, 4, 0,156, 76,127, 33,122, 1, 0,102,182,124,
+ 60, 68,254,130,211, 0, 0,179,225, 9, 57, 75, 59, 3, 0, 0,
+ 71,240, 23, 68, 5, 0,152,151, 24, 38, 15,186, 19, 16, 28, 0,
+ 96, 70,202, 53, 57, 15, 59, 9, 0, 56, 45,166, 99, 62,128,102,
+ 48,126, 2, 0, 48, 99, 33,140, 71, 93,138, 3,254, 2, 0, 76,
+ 208, 90,214, 10,107,247,220, 62, 61, 19,156,247,200,104,217, 87,
+ 57,206, 61, 3, 0, 64, 85,123,210,221,220,218,185,183,110,226,
+ 184, 90, 40, 14,150,142, 67, 31,138, 75, 9, 77, 78,247,201, 0,
+ 0, 78, 21, 70,233,173, 15,238, 60,184,123,143, 43,206,170, 76,
+ 77,191, 71, 1,201,168, 31, 1, 0, 83, 66,133, 81,208,237,106,
+ 165, 6,211, 23, 87, 4,198,187, 6, 48,248, 11, 0, 48,133, 66,
+ 147,217, 90, 99,114,127,241,176, 57, 17,147,237,216, 17, 88, 69,
+ 97,188,187,191, 80, 11, 2, 0,142,160,168,125,183, 31, 24, 37,
+ 193,238,143,216,153,214,149,147, 18,147,243,105,235,157, 76,198,
+ 200, 95, 0,128,169,186,142, 51, 41, 49, 15,241,217,158, 51, 84,
+ 203,131, 62, 22, 0, 0,238, 57,186, 32,152,136,221, 24,198,204,
+ 165, 92,150,100, 45,222,251, 97,228,193,172, 5,157, 1, 0,198,
+ 105, 68,174,120,133, 19,136,220,194, 49,181, 27, 85, 15, 83, 30,
+ 168,126,100,196, 52, 0,192,120, 62,245,236, 4,175, 36,119,113,
+ 169, 13,150,133, 48,206, 47, 19, 23, 87,237,239, 47, 72, 9, 0,
+ 112,108,138,168,180,240,139,241, 19,204,133,216,156, 77,185, 52,
+ 198,226,176,227, 87,161, 53, 0,192,193,229, 48,112, 86, 99, 86,
+ 41,150, 58,243, 89, 31, 44, 43, 30,147,139,149,250, 49,147,153,
+ 28,199,126, 1, 0,224,172, 67,222, 44,209, 83,214,247, 26,158,
+ 191,168,168, 46,243,240,133,241, 19, 0,128, 25, 83, 96,145,191,
+ 56,207, 95,249,113,201, 92,111, 35,244,191, 0, 0,224,184,170,
+ 50, 46, 37,174,226, 59, 38,231,248, 99,145,185,242,248,229, 22,
+ 155,240, 23, 0, 96,170,146, 99, 87, 81, 89,205,152, 23,149,213,
+ 1, 21,165, 83, 34,229,100,247, 20, 0, 0, 40, 23, 22,231,195,
+ 86,179, 14,189,147,196,200, 29,209,202,121,242, 98,206, 7, 81,
+ 32,127, 1, 0,142, 39,196,240,104,219, 22,199, 22,179, 33,171,
+ 78, 81, 73,229,102, 88,105,152,197,208,254, 61, 82, 20, 0,224,
+ 232,101, 22,143, 82, 54,114, 81, 45,150, 2, 87,222,183,119, 11,
+ 202,242, 16,138, 49,212,143,144, 29, 0, 48,216,225,182,100, 71,
+ 97, 92,118,150,107, 43,167,161, 79,149, 30, 62,234, 71, 0,192,
+ 180, 11,205,226, 20, 34,119,198, 47,118,126,144,119,249,157, 67,
+ 147, 71,245, 23, 35,132, 1,128,216,117,120, 15,184, 67,240,221,
+ 163,141, 69,225,200,249, 68, 21,204, 85,235, 29,201, 95,124,196,
+ 93, 7, 0,204,169,196,248,232, 38, 99,118,143, 45, 14, 76,105,
+ 152, 70,176,242,144,251,242,232,175, 67,143,191,135,174, 0, 0,
+ 7,242, 4,239,187,101,249, 68, 34,103,192,106,218, 23,203, 92,
+ 135,254, 23, 0, 96,122,133, 39, 87,199, 70, 12,157, 98,149, 43,
+ 167, 64,186,163, 87,247,152,255, 30, 89, 12, 0,112,140, 31,122,
+ 75,236,249, 62, 13,214,143,206,192, 47,103, 10,252,234, 50, 68,
+ 121, 65,233, 31,101,223, 97, 46, 0,192,129,229, 37, 37,147,240,
+ 107, 53, 30,168, 31,157, 62, 24,231,229, 36,149,230,211, 57,220,
+ 248, 47, 70,246, 2, 0, 28,197, 3, 76, 68, 36,132,105,212,151,
+ 207,174,142,120, 23, 3, 43, 63,150, 78,129, 68,255, 11, 0, 48,
+ 57,180, 39,253,133,246,218,185,115,153,131,156,163,144, 78, 14,
+ 43, 29,105,220,101,137,110, 66,255, 30, 0, 48, 73, 22,151,151,
+ 159,188,122, 85,122, 94, 85, 73,110,217, 72, 84,140,100,101, 26,
+ 178,138,109,214, 0,147,251, 5,190, 17, 98, 29, 0, 0,149,226,
+ 94, 55, 40,110, 86,171,213,242,228,229,108,197,213,107, 10,151,
+ 85, 87,246,112, 55,144, 7,218, 79, 72, 11, 0,112,172,122,228,
+ 189,162, 84,181, 27, 38, 71,185, 71, 0, 0,152, 65, 23,200,221,
+ 247, 18,226, 2, 0,204,180,233,208,191, 7, 0,140, 93, 91, 99,
+ 23,152, 32, 65, 68, 98,119,127, 29,117, 25, 36, 0,192,169,118,
+ 215,193, 92, 32, 68,245,178, 16,162,170,168,244, 10, 33, 6,212,
+ 37,136, 72,200,209,118, 12, 0, 0,142, 43,225, 8,114,178, 85,
+ 234, 53,145, 74,203, 53, 87,126, 57,187, 1,234, 71, 0,192,100,
+ 41, 5, 47, 33,210,240,149, 5,173, 68, 93,130,138, 44, 38, 92,
+ 107,149,130,216,232,254,226, 61, 60,138,132, 6, 0, 2,214,161,
+ 74,199, 65,167,149, 5, 55,100,195, 60,169, 33,127, 1, 0,198,
+ 171,179,145,125, 54,208,210, 18,165,122, 81, 8,202, 26, 98, 34,
+ 41, 39, 7,110,115,120,127, 33,115, 1, 0, 14,233,129,164,104,
+ 204, 11, 67,145,235, 73,164,174, 18, 37,117,185,213,165,219, 17,
+ 147,199,184,139, 0, 0,176, 91,236, 74, 13,150,246,191, 74, 71,
+ 30, 69,185,210, 20, 67, 74,199, 68, 98,168, 31, 1, 0,179,145,
+ 204,146,204,149,143,165, 72,123,248,162, 20,208,168,100, 59,121,
+ 192, 71, 67, 20, 3, 0, 28, 77, 5, 66, 84,142, 36, 38,122, 18,
+ 110, 40, 75, 55, 40,140,230, 30,164,204,111,135,252, 5, 0,152,
+ 140,183, 74, 53,100, 81, 61,230,122,114,242,151, 40,231,175, 36,
+ 113,137,178,190,170,227,191, 24,241, 10, 0, 48, 9,165,137,234,
+ 248,251,114,254, 42,174,205, 75, 73,167,109,150, 15,108, 69,254,
+ 2, 0, 76,212,105, 98,160,142, 20,229,252,149,199, 50, 81,202,
+ 95,121,215, 94,228,135, 32,229, 65, 45,202,149, 45,121,220,193,
+ 18, 0,112,130,107, 72, 81, 58,207, 49, 27, 40, 81,228, 47,225,
+ 6,180,180, 49,150,253,143,156,250, 81, 84,253, 5, 0, 0,199,
+ 107, 54, 81, 36,169,210,120,137,188,233, 69,194,233,125, 81,254,
+ 95,233, 86, 89,252, 58, 72,255, 30,241, 10, 0, 48,220, 11,135,
+ 178, 67,169, 80, 44,138, 73,119,252, 68,169,144,204, 15, 74,230,
+ 213,166,132,165, 0, 0,147,211,157,210, 30, 17, 49,139, 74, 77,
+ 89, 20,147, 84,252, 47,111,119, 21,195,243, 75,179, 85,200,177,
+ 101, 45,136, 15, 0, 20,142,251,209,221,218,218,124,255,134,142,
+ 162,162,126,116, 38,255, 34,183,137, 79,197, 76, 20,162,226, 49,
+ 66,255, 11, 0, 48,113,145,177,181,157, 7,155, 27,119,239,209,
+ 192,176,213,226,248, 98, 49, 84,162,116, 38,209, 81,230,207, 1,
+ 0,128, 49,160,226, 40, 10, 2, 21, 69,228, 28, 75,172,158, 3,
+ 233, 76, 0, 54, 48, 45,107,225,181,113,248, 11,149, 35, 0, 8,
+ 93, 7,249, 49, 51, 91,107,135,110,155, 87,137,110, 59, 95,148,
+ 206,249, 70,254, 2, 0, 76, 47,183, 48, 15,206, 18, 86,204,178,
+ 58,100,122, 67,162,210,184,175,108, 83,248, 11, 0, 48, 5, 42,
+ 115,228,208,144,217, 9,135,174,217, 81, 2,254, 2, 0, 76, 54,
+ 125,141, 15, 57, 79, 59, 11, 0,128,219,246,244, 23, 79,120, 15,
+ 0, 0,115, 37, 38, 30,139,181,156,181,110,139,147,170,121,239,
+ 187,100,212,143, 0,128,153,148, 35,103,146,218,101, 5, 16,199,
+ 158,217,166,114, 79,193, 29,227,114,224, 0, 0, 48,204, 82,156,
+ 184, 44,213, 21,179,235, 54, 46,203, 8,249, 11, 0, 48,253,138,
+ 148,139,255,101,166,202,190,101,230,114,130,226,124,166, 85,121,
+ 248,199, 4, 0,160,228, 59,194,141,153,185,156,175, 82, 49, 57,
+ 105,139, 7,165,229, 62,166,132,166, 0, 0,147,201, 89,123, 89,
+ 144,217, 41, 24, 57, 29,224,154,248,141,179,186,145, 29,101,242,
+ 81,234, 71,184, 13, 0, 48, 62,187, 49, 57,214, 42, 76, 86,241,
+ 86,209,255,226, 61,242, 23,195, 80, 0,128,227,118, 86, 6,229,
+ 133,164,155,191,146, 43,243,252,149,111, 64, 89,149,201,232,223,
+ 3, 0,166, 82,119,241, 46,249, 43,119, 23,229,233,171,232,228,
+ 59,149, 36, 13, 25, 63,177,231,195, 48, 42, 71, 0,192, 24, 5,
+ 86, 84,140, 92, 50, 83, 58, 12,172,240, 89,186,101, 81, 26,238,
+ 223,255,130,170, 0, 0,199,150,207,152,203,227, 35,156,244,149,
+ 151,149,121, 51, 44,203, 95, 78, 5,137,241, 95, 0,128,169,248,
+ 141,203, 38,115, 7, 82,176, 51,156,130,139,178, 50,223, 52,171,
+ 40,209,255, 2, 0, 28,147,166,246, 15, 99,121,208, 42,242, 87,
+ 238,177,188, 7, 86, 12,113,205,227, 87,254, 40,242, 0,187,131,
+ 170, 18, 0, 48, 54,201, 49,187, 23,135,228,175,210,129,199,180,
+ 251, 94, 26, 27,193, 71,205, 95,144, 25, 0,168, 2,199,104,180,
+ 161,249,203, 41, 32,217, 61,211, 72, 30,249, 9, 64,100, 0,128,
+ 131, 97,139,161,170, 69,253,200, 67,149, 86, 46, 24,185,184,158,
+ 9,253,123, 0,192, 68,146,154,139,176, 68,181, 70,195,233,201,
+ 115, 49,192,190, 24, 1,230, 28,108,116, 79,140,116,206,138,148,
+ 227,219, 39, 0, 0, 74,200,221,174, 46,190,183,190, 71,158, 39,
+ 165,228,161,245, 99, 41, 99,185, 18, 27, 50,254, 84,142,229, 25,
+ 0, 0,192, 40,158, 96, 41, 85,221, 95, 89, 59,187,215,102,123,
+ 217,209, 45, 34, 15,232, 47, 40, 11, 0,112, 20,140, 39, 87, 46,
+ 92, 88, 93, 91,203, 35, 23,187, 85, 97,105,214, 9,114,103, 45,
+ 36, 26,109,254, 28, 30, 89, 96, 12,185, 1, 0, 14,194,153,149,
+ 149, 11, 23, 46, 12,243,138, 83, 54,230, 62, 43,213,147,206,229,
+ 236, 6, 99,232,223,195, 91, 0,128, 17, 77, 32,164, 40,123,202,
+ 185, 92,157,104,149,157, 51,187,135,246,211,134,143,255,130,145,
+ 0, 0, 7, 22,214,120, 22, 38,218,237, 78,134,205,234, 37,247,
+ 221, 65,200, 12, 0, 48,155,213, 25,198,127, 1, 0,102,223, 84,
+ 163,248, 11, 89, 11, 0, 48, 61, 67, 9, 34,177,219, 79, 4,149,
+ 126, 40,144,191, 0, 0,147, 38,115,144,112,101, 36,170,215, 20,
+ 54, 19,201, 79,134,121, 77,200,125, 92,139, 68, 6, 0, 24,191,
+ 189, 74,223, 10, 87, 94, 66, 20,129, 75, 36,255, 23,165, 16,150,
+ 221, 76, 32,127, 1, 0,198, 91,100,238,159,121,202,201, 75, 8,
+ 71, 74, 66,228,215, 21,181,164, 24,144, 93,134, 60,210,158, 2,
+ 0,160,172, 35,167, 48,218,181,237, 53,208,241,114, 91,100, 98,
+ 52,127, 65, 84, 0,128,221,189,192,135, 51,135, 24,200,101, 34,
+ 253,146,212,138,217,191,201,149,194, 41, 42,199,145,191,224, 55,
+ 0, 32,177, 67,109, 35,132,219,243, 18, 66,184,215, 84,234,199,
+ 244, 39,213, 66, 82, 28,201, 95,144, 22, 0,224, 16,228,210,202,
+ 84, 85, 26, 25, 81, 42, 24, 69,233,192,163, 24, 56,120,137,254,
+ 61, 0, 96, 54,114, 90,154,187,146,255,220,146, 49,189,222,209,
+ 222, 81,199,127,241,200, 59, 5, 0, 56, 45, 54, 26,237, 28,110,
+ 33, 74,255,119,234,199,114, 66, 43,108,229, 14, 3, 43, 54, 20,
+ 242,160, 59, 10, 99, 1, 0,142, 92, 67,102,101,163, 91, 63, 22,
+ 201, 43,203, 95,169,173,132,200, 47,149,238,227, 32,249,139,247,
+ 250, 17,180, 6, 0,234,192, 67,230, 28,167,127,239,182,187,132,
+ 27,204,242,186, 81,100,199, 38,105,108,253, 47,232, 11, 0, 80,
+ 81,194,110,171,119,148,235,200, 82,254,114, 19, 24,149,251, 95,
+ 197,224, 9,113,136,254, 23, 20, 5, 0, 56,122,229, 72, 36,220,
+ 241, 18,194,137, 90,228, 94,147,187,140,242, 77,168,122, 18,247,
+ 40,254, 98,232, 11, 0, 48, 62,129,149, 37, 84, 68, 45,167, 41,
+ 70,131, 61, 50,145,107, 46, 63, 50,137,241, 19, 0,128, 3, 22,
+ 134, 71,140, 95,142,184,114, 69,229, 22, 19,229,250,209, 57, 70,
+ 89,154,140, 34,249, 71, 78,243,169, 0, 0, 78,161,238, 68,121,
+ 188,132,147,191,168, 84, 46,186, 99,193,178,252, 85, 30,131, 47,
+ 15, 40, 39,134,195, 0, 0, 71,214,153, 24,146,191,178,110,151,
+ 91, 46,186, 35,238,171, 7, 40, 49,254, 30, 0,112,244, 68,117,
+ 196,233, 2, 69,245,160,164, 27,185, 10,203, 81,249,100,110,248,
+ 11, 0, 48,105,245, 13, 52,182, 74,165, 34, 21, 51, 24,150,103,
+ 93, 21,206, 20,210,217, 88, 48,248, 11, 0, 48, 89,156, 89,113,
+ 132,123, 58,163, 40,231, 47, 42,242,151,211, 35,115, 34,155, 24,
+ 115,254, 66, 47, 12, 0, 48,220, 6,251, 77, 6,230, 12,140, 24,
+ 200, 95,162, 80, 86,214, 1,195,250, 29, 0,128,137,184,107,152,
+ 175, 92,113, 21, 93,124, 39,163, 81, 54,249,189, 16,228,134, 52,
+ 167,171, 15,127, 1, 0,166, 84, 69,102, 30, 43,159,149,237, 12,
+ 254,162, 34,146,149,234,199,236, 6,163,250,171,124, 54, 19,234,
+ 68, 0,144,177, 14, 43, 46,103, 98, 85, 49,112,220,177,216,170,
+ 152,243,107,215,217,241,145,191, 0, 0, 99,212,215,126,147,209,
+ 8, 55,124,229,151, 7,214,127, 28, 50,235,234,144,197,109,225,
+ 47, 0,192,100,211,152, 16,131, 82, 27,108,135,229,162, 19,206,
+ 156, 19,229, 1,248,229,241, 19, 40, 11, 1, 0, 19, 70,236,178,
+ 168,109,105,252,151,168, 46,164,134,249,239, 1, 0, 83,241,213,
+ 174,169, 76, 84,214,241, 16,131,183, 17,168, 31, 1, 0,147, 44,
+ 26,121, 87,141,137, 93, 22,215, 22,187,155,111,232,252, 95, 40,
+ 30, 1, 0, 19,204, 97, 98,255,107,118,141, 95, 2,227, 87, 1,
+ 0, 51, 88, 76,138, 33,139,213, 14,187,149,216,219, 95, 72,100,
+ 0,128, 99, 44, 43,119,183,154, 24,205,117,200, 95, 0,128,105,
+ 9, 76,236, 91, 86,138, 61,111, 47,199,188, 63, 0,128,211,102,
+ 166,233,233, 1,249, 11, 0, 48,175,192, 95, 0,128,201, 85,140,
+ 240, 23, 0, 0,236,230, 47, 70,187, 11, 0, 48,135,254,226,209,
+ 66, 34, 4, 7, 0,152,122, 77, 41,103,115,183, 0, 0, 51, 40,
+ 36,158, 49, 29,200,131,237, 62, 92, 6, 0,152,217,250,241,192,
+ 118,130,192, 0, 64, 97,184,123, 62, 59, 86, 69,224,248, 35, 0,
+ 224,232,101,228, 76,228, 47,164, 41, 0,192,161,172, 54, 13,121,
+ 72,148,133, 0,128,113,149,144,227,191,209,184,235, 71, 44, 67,
+ 4, 0,152,146,177, 14,234, 47, 72, 10, 0, 48,155, 72,200, 11,
+ 0, 48, 71,153,235,136,245, 35, 28, 7, 0,152,135,252, 5, 0,
+ 0,115,225, 47, 30, 53, 83, 49, 2, 24, 0,224, 0,182,224,227,
+ 17, 5,242, 23, 0,224,224,166,226,153, 8, 47,114, 20,153, 34,
+ 96, 1, 0,142,150,195, 38,228,175,253,246, 2, 50, 3, 0,204,
+ 134, 17,228, 33,119, 10, 22, 3, 0,240,148,155,225,242, 32,187,
+ 10,113, 1, 0,102, 8,121,104,115, 66,100, 0,128,153,241, 23,
+ 68, 5, 0,152,111,127, 29,214, 86,176, 28, 0, 39,155, 25,252,
+ 140,203,121,221,113, 0,192,169,151, 29,198,175, 2, 0,230, 53,
+ 144, 73,100, 46, 0,192,156, 34, 15,166, 87, 72, 13, 0, 48, 31,
+ 254, 2, 0,128, 25,174, 36,225, 47, 0,192, 49,232,107, 34, 74,
+ 147, 99,217,105,148,149, 0, 0,228, 47, 0, 0,152,128,191, 16,
+ 186, 0, 64,173,136,252, 5, 0, 56,201,174, 59, 54,231,201, 17,
+ 13,203,152, 52, 26, 0, 48,170,178,120,119, 87,140, 83, 29,114,
+ 140,251, 13,165, 1, 0, 38, 89,114,202,163, 61, 52,148, 5, 0,
+ 152, 26, 7,205, 95, 12,139, 1, 0,230,200, 95,208, 19, 0, 96,
+ 22,189,128,227,143, 0,128,121,116, 23,252, 5, 0, 56,201,245,
+ 35,106, 71, 0,192,188,250, 11, 0, 0,224, 47, 0,192, 9, 99,
+ 234,229,153, 60, 41, 79, 4, 0, 48,123, 94, 59,102, 49,200,227,
+ 216,103, 0,192,169,119,215, 36,132, 32,199,183,187, 0,128,211,
+ 84, 50,242, 97,111, 56, 17,127, 49, 15, 60,250,177,159, 78, 14,
+ 0, 0,211,168, 31, 1, 0,200,101, 19,173,207,224, 47, 0,192,
+ 49, 75, 12,254, 2, 0, 64, 95, 99,240, 23,163, 1, 6, 0,152,
+ 1,144,191, 0, 0,227, 13, 95,147,139, 55,240, 23, 0,224,120,
+ 140,118,252, 30,131,191, 0, 0, 71,203, 91,243, 81, 63,162,233,
+ 5, 0,152, 37,228, 80, 65,141,106, 42,172,217, 1, 0,152, 94,
+ 214,145,179,181, 59, 0,128,121,119,215, 4,109,129,254, 23, 0,
+ 96, 54,211,213, 56,252,133,232, 5, 0,152, 77, 14,148,191,120,
+ 215,239, 25,170, 3,224, 20, 37,175, 25,249,172, 75,100, 45, 0,
+ 192,152,170,199, 73, 27, 68,162,120, 4, 0,204,125,253, 8, 85,
+ 1, 0,142, 24,200,120,228, 31, 29, 75,254,226,221,247, 15,130,
+ 3, 0,204,104,254, 26, 67,241, 11, 0, 0,179,236, 47, 24, 13,
+ 0, 48,191,254,130,175, 0, 0, 39, 37,127, 1, 0, 78, 45,211,
+ 141, 51, 18, 81, 11, 0,112,234,242, 23,220, 6, 0, 72, 93, 48,
+ 37, 29,160,126, 4, 0,204,107,177, 41, 17,175, 0, 0, 99,183,
+ 19, 79, 68, 39,200, 95, 0,128, 99, 76, 81,199,154,132,224, 47,
+ 0,192,204, 21,134,135,247, 23, 42, 71, 0,192, 92,128,252, 5,
+ 0,152,215, 12, 38,103, 44, 15, 2, 0,160, 45,228, 47, 0,192,
+ 201,182,215,232,254, 66, 30, 3, 0,204,154, 27,144,191, 0, 0,
+ 243,106, 57,248, 11, 0, 48,175,192, 95, 0, 0,248, 11, 0,112,
+ 226, 75,192, 25,107,132,203,113, 60, 39, 0,192,105,178,216,124,
+ 251,139, 33, 49, 0,224,176,131,223, 98,220,166, 64,253, 8, 0,
+ 152, 87, 14,238, 47,100, 45, 0,192, 76,250, 11,114, 2, 0,140,
+ 152,100,120,234,222,144, 72, 88, 0,128, 83, 83, 63,162,172, 4,
+ 224,212, 70,174, 25,179,129, 60,194,174, 67, 89, 0,128,105, 26,
+ 76, 30,112,167, 24,238, 2, 0,204,136, 6,228,193,118, 9,218,
+ 2, 0,186, 58,144, 10,248, 24, 13, 34, 71,122,120,222,115,167,
+ 32, 53, 0, 96,180,105,152, 0,227, 87, 1, 0,243, 10,252, 5,
+ 0,152, 72, 60,155,156,191,184,252,101,194, 59, 5, 0, 56, 65,
+ 174, 58, 62, 99,200,163,237, 24, 0, 0, 76, 45,147,201,163,237,
+ 3,212, 6, 0,152, 26, 18, 57, 11, 0, 48,163,249,234,152,242,
+ 23, 0, 0,236,165,175,137,120, 12,254, 2, 0,204,107, 0,147,
+ 227,216, 17, 20,158, 0,192, 81, 83,240,130,132,148, 0, 0,115,
+ 10,234, 71, 0,192,188,214,145,114,223, 7,102,100, 51, 0,192,
+ 12,216,106,172,249,139, 97, 50, 0,192,190, 26, 59,198, 67,146,
+ 242,104,123, 6, 0, 0, 83, 83, 5,250, 95, 0,128,121,168, 21,
+ 15,225, 47,222,115,119, 81, 65, 2, 0,133, 77, 81,238,183,167,
+ 75, 0, 0, 32, 0, 73, 68, 65, 84, 1,242,160,126,133,174, 0,
+ 0,179,159,191, 14,100, 42,104, 13, 0, 48, 99,245, 35, 0, 0,
+ 192, 95, 0, 0,112,220,254,226,161,223, 50,138, 68, 0,192, 62,
+ 76,124,182,102,121,132, 61, 3, 0,156,118, 65,237,189, 2,209,
+ 113,107, 3,245, 35, 0,224, 72, 17,107,150,234,199, 35, 61, 33,
+ 132, 52, 0, 32,178, 41,249, 11, 35, 38, 0, 0,199, 80, 87,162,
+ 126, 4, 0, 0,248, 11, 0,112,250,252,133,138, 17, 0, 48, 75,
+ 66,144,187,237, 13,100, 5, 0,152,179,252, 53,130,182, 96, 54,
+ 0,192, 92,213,143,144, 22, 0, 96, 84, 89, 76,106, 21, 72,244,
+ 239, 1, 0, 39, 61,127, 1, 0, 0,252, 5, 0, 56,169,117,227,
+ 28,251, 11, 45, 50, 0,192, 48, 37, 28,155, 27, 36,244, 3, 0,
+ 152,211, 84, 38,103,119,215, 0, 0,224,160,254,194,124, 18, 0,
+ 128,121,245, 23, 0, 0,192, 95, 0, 0,144, 21,115,199, 80,206,
+ 193, 95, 0,128,211,145,191,208, 15, 3, 0,204,142, 40,228,252,
+ 237, 50, 0,224, 20,184, 9,245, 35, 0, 96,114, 86,155,188,218,
+ 228,248,118, 30, 0,112,138, 18, 24,207,192,167, 95,142,255,105,
+ 1, 0, 80, 77,162,126, 4, 0,204,129,178,248,144,183,131,191,
+ 0, 0, 51, 33,174,169, 36, 49,121, 92,207, 12, 0,128, 82,114,
+ 6,253, 5, 89, 1, 0,102, 1, 9, 71, 1, 0, 78,152,191, 0,
+ 0, 96,214,235, 72, 57,251,187, 8, 0,128,178, 14,236,175, 97,
+ 11,218, 66, 92, 0, 0,212,143, 0, 0, 36, 50,248, 11, 0,112,
+ 250,106, 71,248, 11, 0, 48, 86,117, 77,216,102,240, 23, 0, 96,
+ 94, 67,154, 60,194, 46,160,151, 15, 0,152,102,101,233, 31,118,
+ 39, 74, 87, 11, 65,130,132,192,111, 12, 0, 48,119,245,163, 32,
+ 18, 68,146, 96, 48, 0, 78,174, 44,228,225,117,113, 76, 89, 76,
+ 30,102, 71,120, 80, 94,194, 39, 81, 39,225, 11, 52,212, 0, 56,
+ 129, 52,253,154,231,251, 98,255, 42,107,162,109,165,145,116,179,
+ 239, 44, 25, 66, 80, 77,136, 22,137, 71, 90,109,252,166, 1, 56,
+ 121, 60,125,238,188,244, 61,158,186,177,142,167,126, 20, 53, 18,
+ 109, 33, 47,183, 22,241,155, 6,224,228,241,161,181, 11,196,196,
+ 198, 28,229, 78,198,110, 58,191,122,247, 98,191,114,113,184,191,
+ 200,147,178, 97,237,179,237,229,215,182, 55,186, 90, 37,215,175,
+ 175,223,195, 47, 30,128,121,231,236,194,226,103,158,185,214,121,
+ 176,161,149,158,170,175,246,246,215,190,143,207,187,215,149,204,
+ 190,148, 45,182, 95, 90,123,244, 63,220,187,145, 92,249,231,223,
+ 252, 51,252,238, 1,152,119,190,241,209,143,235, 56,142,250,125,
+ 163, 20, 51, 19, 51,137,153, 24,111, 48,230,118,187,239,249, 79,
+ 180,151,126,246,194, 37,252,202, 1, 56, 25,252,202, 39, 62,117,
+ 237,209,199,251,219, 59,113, 16,176,181,135,136, 86,199, 23,195,
+ 252,163,221,188,180, 99,204, 44,152,165,231,125,100,245,188, 95,
+ 175,255,249,157, 27,145,209,248,245, 3, 48,167,180, 27,141,255,
+ 226, 35, 47,126,250,234, 51,157, 7, 27,253,237, 29, 29,103,225,
+ 107,102,240,199,123,119,214, 90, 18, 66, 18,191,176,118,225,202,
+ 202,217,239,109,220,253,225,157, 91,120, 31, 0, 48,119,124,234,
+ 234, 51, 63,243,236,243,231, 22,150, 58, 15, 54, 58, 27,155,113,
+ 24, 88,107,118,151,215,144,222,249,204,248,235, 32, 43, 38, 89,
+ 99,116, 76, 66,136, 51,173,214,215,159,126,254,231,174, 94,123,
+ 235,225,131,157, 56,222,137,194,135, 97,128,183,197,145,254, 60,
+ 48,199,108,243,195, 35, 68,116,161,181,192,108,217, 50, 94,135,
+ 83,248, 58,140, 23, 65,180,210, 94, 88,105,181, 86, 90,237, 23,
+ 46, 93, 89,108, 52,195,110,111,235,206,221, 96,103, 39, 14, 35,
+ 107, 44,113,106, 47, 49,145,218,240,248,242,215,222,109,125, 98,
+ 99, 84, 24, 89,109,140, 82,181, 86,235,163,107,143,212, 27, 77,
+ 175,230, 75,207, 19, 82, 10,156,104,116, 88,250, 70,223,143,195,
+ 87,119, 54,242,107,126,253,153, 23, 84, 28,233, 40,198,235,112,
+ 10, 95,135, 99,249,219, 96,140, 53, 70,245,194,141,251,155, 81,
+ 175,167,194, 72, 43,197,108,201,142, 94, 55, 78,110,174, 83,127,
+ 255, 44,120,240,221, 96, 34,182,150,149, 50,198,196, 65, 24,214,
+ 106, 94,205,247,124, 63,145,151,144,240,215, 33,233,106,125, 47,
+ 234,223,120,120, 63,191,102,107,241,156, 10, 35, 21,133,120, 29,
+ 78,225,235, 48, 70, 82, 57, 49, 39,254,210, 74, 89,173,173, 54,
+ 156,113,208, 10,109,150,243,215,136,175, 8,179, 49,108,173, 49,
+ 70,132, 68, 34, 9, 94,144,215,225,233,104,181, 21,246,214,183,
+ 214,139, 79,242,197, 45, 21,134,113, 16,226,117, 56,133,175,195,
+ 113,125,110,211,175, 76, 76,204, 51, 93,146, 31,222, 95, 60,154,
+ 120,147, 3, 22, 76, 36, 4, 49,228, 53,142,108,175,181, 46, 93,
+ 163,141, 61,218,168,104,188, 14, 96,152,195,142,226,133, 9, 37,
+ 50,127,176,242, 59,166,136,148, 88, 29,111,141,163, 70,218, 74,
+ 152, 79,255, 62, 48, 94,135, 83,248, 58,204,192,111, 98,202, 5,
+ 21,166,139,152,187,247,203,192,247,140,215,129,240,199,241,116,
+ 34, 15,249,126, 1, 0,128, 81,254,174,204, 76,254,130,196, 0,
+ 0,115,152,191, 0, 0, 96, 78,253,197,136,100, 0,128, 3,124,
+ 244, 39,162, 6,228, 47, 0,192, 73,202, 95,140, 96, 5, 0, 56,
+ 57,245, 35,152,155,216,142,215, 1,156, 30,124,188, 53, 0, 17,
+ 173, 92,185,244,137,223,248, 85, 34,122,229,159,255, 11,213, 15,
+ 136,232,133,111,124,253,194,115,207,110,189,127,235, 7,255,230,
+ 15,146,109,190,242,143,126, 55,223,254,250, 95,126,231,250, 43,
+ 223, 38,162,143,255,250,175,174, 62,113,233,214,171,127,243,147,
+ 63,249,102,242, 45, 17,185, 55,201,239, 33,217,242,155,255,244,
+ 127,199,171, 13,142,213, 95,176,216,169,163,222,110, 95,120,254,
+ 26, 17, 93,122,233,197, 68, 76, 79,125,254, 51, 11,231,207,185,
+ 219, 92,120,254, 90,220,235, 63,188,113,211,189,114,245,137, 75,
+ 23,158,191,182,114,229,242,245, 87,190,173,250,193,234, 19,151,
+ 42, 55,169,108,137,151, 26, 28,191,191, 38, 55, 1, 6,152, 33,
+ 226, 94,255,252,115,207, 94,127,229,219, 43, 87, 46, 45,156, 63,
+ 183,245,254,205,202, 91, 96,235,198,205, 63, 47, 7, 40, 38,234,
+ 221,127,176,112,254,220,181,175,189,252,218, 31,254,209, 30, 51,
+ 197,225,221,132, 82,127,146,249,107,191, 29,153,244, 80, 91,176,
+ 199,171, 60,158, 23,255,214,171, 63,188,244,137, 23,191, 71,191,
+ 127,233,165, 23,183,222,191, 25,247,251,149, 59, 95,189,114,249,
+ 103,254,209,239, 18,209, 15,254,245, 31,228, 65,172,251, 96,227,
+ 222,143,127,242,161,175,126,229,205, 63,249,179, 93,246,135,199,
+ 190,171, 60,241,143, 10,200, 16, 99,249, 85,141, 5,121,228,119,
+ 14,222, 49, 39,135,251, 63,126,171,190,208, 94,185,114,249,241,
+ 79,124,236,250, 95,126,123,244, 27,254,232, 15,255, 67,125,161,
+ 125,237,107, 47,227, 53, 60,213,127, 92,121,210,127, 81,124,188,
+ 232, 32,167,119,127, 99,235,253,155, 31,250,218, 87, 86,159,184,
+ 252,221,223,251,253,199, 63,241, 49, 26, 82, 63,254,179, 33, 55,
+ 124,240,224,221, 87,190,245,161,175,126,165,247, 96, 35, 75,109,
+ 0, 85,194,177,227,143, 92, 30,130, 83,241, 94, 89,127,227, 39,
+ 215,126,254,229,238,253, 7,149, 62,125,194,194,185,181, 23,190,
+ 241, 75,201,102,235, 63,126,179, 18,193,174,126,225,115,245,133,
+ 246,189, 55,138,235,111,125,255,135,151, 94,122,241,227,191,254,
+ 107, 68,244,200,243,215,110,125,255,135, 39,224, 51, 3,102, 7,
+ 127,212, 55, 1,227,237,115, 42, 28,118,251,213,191,185,246,243,
+ 47,223,254,254,223, 12,109,188, 47,158, 63,247,194, 55,190, 78,
+ 68,175,209, 31,173, 59,158, 34,166,222,253, 7,239,190,242,173,
+ 171, 95,248,156,123,147,239,254,222,239, 19,209,181,159,127, 57,
+ 113,217,119,127,239,247,143,247,125,130, 55,225, 4, 16,123,188,
+ 250,147,158, 12, 76,252,237,223,190,166,141,249,230, 55,255,172,
+ 241,253,215,106, 82,214,164,172,145,144, 76,194, 90, 50,214,104,
+ 165,194, 40, 10,130,160,215,239,119, 59, 97, 24, 25,182,134, 57,
+ 249,215, 18, 91,102, 78,103, 95,194,123,231,216,233, 24,117, 43,
+ 232,255,197,214,221,252,154,255,229, 99,159,137,131, 80, 5, 1,
+ 94,135, 83,248, 58, 76,201, 95, 66, 16, 9, 34, 41,132, 36, 33,
+ 133,240,132,240,132,240,133, 16, 36,136,200, 18,107,102,109,173,
+ 98, 27, 89, 19, 25, 19, 88, 19, 26, 19, 90, 19, 90,211,191,112,
+ 246, 67, 47,126,204,247,125,223,247, 61,207,175,213,124,223,247,
+ 107,181, 90,173,158,210,104, 52,234,141, 70,179,209, 72, 46, 52,
+ 234,141, 90,189, 94,175,215,106,181,122,173,230,167, 55,240,124,
+ 207,247, 60,233, 73,252,241, 2,243,249, 33,194,107,112,146,251,
+ 24, 35,130,243,135,230, 43,185,139, 90,121,245, 38, 41,229, 41,
+ 252, 36, 75, 18, 53, 33,241, 58,128,253,252, 53,254,129, 59,224,
+ 240,212,165, 60,227,215,243,111,155,190,239,215,235,167,112, 73,
+ 167,154,148,203,126,205, 85,216,233,124, 29,166,155,180,248, 64,
+ 91, 79,204, 95,208,212,236,126,110,133, 60, 91,111,188,124,225,
+ 82,195,243,155,126,237, 23,174,189, 64, 66, 48,219,211,249, 58,
+ 124,241,252, 99,201,235,240,141,143,188, 40, 78,229,235, 0, 48,
+ 254,107,174,234, 71, 33,106,158,255,209,165, 71, 62,245,212, 51,
+ 181,102,211, 26, 29,236,116,140,210,120, 29,130,157,174,209, 26,
+ 239,144,233, 36,177,249,242, 23,207,226, 19, 57, 53,239, 24,107,
+ 85, 24, 89, 99,165,215, 73,215, 73, 62,149,139, 30, 14,121, 29,
+ 52, 22,127, 60,117, 82, 67,254,154,175,183, 6, 51,179,177,214,
+ 40,133,215, 1,175,195,212,252, 36,102, 69, 96, 56,254, 8, 0,
+ 152, 87, 14,153,191, 6,231,158, 64, 1, 9,192,105, 96,164,163,
+ 188,147,210, 1,242, 23, 0, 96,156,197,229, 36,145,179,180, 51,
+ 0, 0,112, 60,249, 11, 50, 3, 0,204,148, 17, 36,132, 5, 0,
+ 152, 83,124,216, 10,127, 26,231, 2,156, 28, 52, 83,239,174, 25,
+ 249,117, 96,252,215, 73,240, 20,151,103, 48, 74,191, 61,113,242,
+ 18,217,167, 38, 57, 85, 59,249, 22, 94, 59,205, 54,131,191,230,
+ 216, 89,204,196,196, 76,148, 92,216,209, 74, 89,203, 68,129,213,
+ 193, 9, 26,148,223,146, 94,211,243, 4, 81, 77,202, 37,191, 46,
+ 136, 4,147, 32, 33, 4, 11, 74, 46,192,101,167,190,126, 28,177,
+ 18, 65,153, 57, 69,109,185,206,138,173,221,136,195, 29,173, 54,
+ 85, 20, 90, 19, 26,115,102,237,172,223,168, 17, 81,123,233, 76,
+ 107, 97,129,153,231,127, 78, 73,182,214,110,117,123, 97,191, 79,
+ 68, 42,142,187,247,239, 55, 61,175, 41,189,149, 90,125,201,175,
+ 173,213, 26, 53,233, 73, 38,153, 78,170,151,186, 12, 34, 59, 37,
+ 165, 36,242,215,156,164, 45,102, 75,100,153,183,117,124, 59,236,
+ 109,170, 56,242,196,133,199, 30, 91, 57,183,246,177,139, 23,155,
+ 237,118,115,161,173,148, 82, 74, 89,107,173,181, 74, 41,173,181,
+ 181,115, 63, 37, 3, 51, 75, 41,107,181,154,231,121,201, 53, 97,
+ 191,223,239,118, 31,222,127,112,123,123,231,245,141, 7, 77,166,
+ 85,191,241,104,179,117,198,175, 75, 33, 36, 11, 41, 72,166,179,
+ 132, 34,145, 77,255,173, 59,125,127, 49,226,215, 84, 3,151, 37,
+ 238,104,117, 35,232,174,199, 97,115,117,229,234, 39, 95,124,238,
+ 226,197,133, 51,203, 81, 20,245,251,253, 94,175,119,239,214, 70,
+ 175,215, 11,130, 32,142, 99, 99,140, 49, 70,107,109,172, 97, 59,
+ 223,191, 47, 33,132, 16,194,243, 60,223,247,189,140, 70,163,209,
+ 108, 54,151, 46,156, 63,127,229,178,239,251,253,157,206,246,198,
+ 198,107,183, 63,176, 59, 91,231,234,141,203,173,133, 69,175,230,
+ 37, 83, 27, 35,142, 77,215, 83,199,191,156, 26,242,215,172,155,
+ 235,118,216,191, 25,116,227, 86,227,185,159,254,248,199,158,120,
+ 194,107,212,187,157,206,131,173,173,159,188,251,206,246,246,118,
+ 183,219,237,247,251,169,185,230, 95, 88,251, 34,165, 76, 20,214,
+ 202,104,183,219, 11,103,150,159,185,248,136, 81,234,225,250,253,
+ 239,223,188,213, 54,252,120,179,253,104,163,237, 9,225,145,144,
+ 68,176,216, 73,197, 63,200,103, 10, 76,212, 92,111,247,118,110,
+ 134,189, 51,143, 94,252,228,207,125,105,229,252,185,157,157,157,
+ 219,119,239,220,187,119,111, 99, 99, 99,123,123,187, 31, 4, 42,
+ 142, 43, 45, 46,113,210, 63,164,204,172,181,214, 90,247,122, 61,
+ 18, 66, 10, 81,175,215,219,237,246,226,210,226,210,210,242,226,
+ 242,210,213, 79,188, 24,116, 58,239,221,184,245,206,230,189,199,
+ 155,237,167,218,139,158,144,176,216,108,100,179,241, 59,196, 31,
+ 242,120,248, 13, 79, 81, 94,204,134,248,131,176,127, 35,232,158,
+ 125,246,233,159,255,244, 79, 75,223,223,216,216,248,193, 15,126,
+ 112,231,206,157,205,205,205,126,191,175,181,182,156, 29,132, 20,
+ 167,239,143,139,243,254,180,204, 97, 20, 69, 81,244,240,225,195,
+ 68,100,203,203,203,203,203,203,143, 94,123,214, 42,189,126,227,
+ 230,131,237, 7,143, 55, 22, 30,107,166, 89,204, 59, 13,142,159,
+ 206, 59, 87, 76, 37,238,248, 71,221,109, 48,190,216,101,153, 54,
+ 85,244,126,208,181,231, 86, 63,249,213, 47, 45,173,174,222,189,
+ 123,247,198,141, 27,119,239,222,125,248,240, 97, 24,134,121, 63,
+ 94,208,240,255,159,222, 23,144, 57,138,162, 56,142,119, 58,157,
+ 214,198,198,210,210,210,210,210,210,226,197, 11,102,229,204,187,
+ 247,214, 55, 58,155,151,154, 11,103,107, 13, 22, 66,146,148, 8,
+ 98, 99, 23,214,148,114,143, 15, 65,205, 78,236,250,113,119,251,
+ 150,137, 62,245,229, 47, 61,126,245,169,245,245,245, 87, 95,125,
+ 245,198,141, 27, 91, 91, 91, 74,169,164, 78,116,163, 3,187,255,
+ 63,109,191, 39,225,252, 87,198, 26,147, 28,202,216,222,222, 94,
+ 90, 90, 58,115,230,204,234, 19,151,131,135,219, 63,184,123,239,
+ 241,122,235,217,246,114, 77, 18,130,216,113, 36,174,169,224,143,
+ 229,153,204, 26,159,254,237,223, 92,255,241, 79,174,191,242,237,
+ 121,120, 31,164,177,235,189,160,235, 95,186,248,141,159,125,185,
+ 219,235,189,246,218,107,215,175, 95,127,240,224, 65, 24,134,150,
+ 237,208,151,184, 20,189,240, 65, 44,191, 52,150, 57, 12, 67,165,
+ 84,191,223, 95, 90, 94, 94, 92, 88, 56,123,245,201,245, 59,247,
+ 162,238,214,229, 52,136, 73,143, 72,138, 98, 76,255, 76, 81,111,
+ 183, 63,255, 15,255,254,234,149,203,255,215,223,255,221,185,177,
+ 215, 52,148,230, 31,241, 89,204, 32,159,254,237,223,188,250,197,
+ 207, 93,253,226,231,136,104,150, 21,150,213,140,252, 94,208,125,
+ 43,238,127,234,203, 95,122,244,169, 39,111,221,190,253,214, 91,
+ 111,221,190,125,187,215,235, 25, 99, 40, 57, 75, 70,236,246,226,
+ 159,226,121, 35,119,143, 96, 57,198,152,126,191, 31,199,113,208,
+ 239, 47, 45, 45,181, 46,156,235,118,186,175,110,108, 62,211, 90,
+ 186,210, 90,168,145,244, 72,204, 96, 45, 89,111,183,191,242,191,
+ 254,207,171, 79, 92,158,219,100, 54, 87,249,107, 6,229, 21,247,
+ 250,245,133,246,103,126,231,183,102, 86, 97,156, 14, 73,229, 55,
+ 186,219,235, 62,125,245, 87,126, 89,248,254,235, 63,250,209,219,
+ 111,191,189,177,177, 17,171,152, 56,173,111,118,243,148,115, 10,
+ 224,124,255,189, 25, 22, 42,143,120, 47, 37, 31,105,173,187,221,
+ 110, 28,199, 11,139,139,173,102,179,113,126,237,237, 7,155,161,
+ 209,207, 46,156,169, 73,233, 39,115,176,204, 82, 45,249,233,223,
+ 249,205, 89,150,215,144,152,197,196, 83,122,249, 78,148,191,114,
+ 121,125,243,159,254,179,149, 43,151, 62,243, 59,191, 53,155, 10,
+ 203, 27, 94,127,215,217,234, 45,182,126,241,151,255,171,173,135,
+ 15,223,252,209,143,222,123,239,189, 78,167, 83, 25, 52, 63,232,
+ 169, 67, 39,175,147, 89,101,238,171, 30, 33,146,238,190, 49, 70,
+ 43,213,106,181,234,231,215,110,111,108,169,238,195,231, 23,207,
+ 176,240,124, 73, 30,207,138,194, 62,253,219,191,121,233,165, 23,
+ 183,222,191, 73, 68,115, 17,193,166,251, 71, 81,142, 99,175,102,
+ 226,239,186, 43,175,173,247,111, 94,127,229,219,223,249,151,255,
+ 138,136, 62,243, 59,191,245,212, 23, 62, 59,155,242,106, 60,117,
+ 229,107,191,246, 43,247,214,215,127,248,195, 31,190,253,246,219,
+ 59,157,157, 68, 94, 34, 29,121, 46,132, 24, 82,220,136,242, 6,
+ 46, 36, 78,226,129, 53,177,219,211, 77,158,243, 48,163, 13,219,
+ 32, 41, 39,123,189,158, 97,246,215, 86,239, 9,243, 70,119, 59,
+ 102,163,173, 53, 52, 19,103,139, 38,239,225,173,247,111,126,243,
+ 127,251,103,113,191, 79,224,216,242,215,108,213, 34, 21,121, 37,
+ 87, 38,177,107,166, 82,152, 43,175,250, 83,151, 63,241,197,207,
+ 95,191,126,253,141, 55,222,184,123,247,110, 28,151,107,198,236,
+ 211, 36,136,168,114,216,113,247, 15, 90,105,126,153,211,195, 30,
+ 209,169,220, 62, 52,198, 4, 97, 96,173,109, 52,155,220,106,222,
+ 233,246,185,251,240,185,133, 21, 34, 34, 41,167,155,194,146,247,
+ 112,247,254, 3, 87, 94, 47,252,242, 47,173,191,241,166,234, 7,
+ 249,187,122,198, 75,201, 57,170, 31,121, 70, 84, 54, 84, 94, 51,
+ 168,176,170,188,190,240,249,247,222,123,239, 71,175,191,190,126,
+ 239,158, 78,214,142, 22, 34,113,147,235,172,234, 8,251, 97,122,
+ 58, 1, 19, 77,140,179, 96,220,101,155,244,111,131,229, 40,138,
+ 152,185, 94,175,115,187,121,167, 31, 80,111,250, 10,203,223,195,
+ 127,249,207,255,133,155,188, 62,250,141,175,211, 55,190,158, 92,
+ 190,245,253, 31, 94,127,229,219,183,190,255,195,185,248, 45,241,
+ 76,249,107,102, 63, 31,123,200,107,166, 20,150, 30,109, 76,228,
+ 245,228,229, 79,124,225,243,239,223,184,241,250,235,175,223, 95,
+ 95,215,217, 92, 93,185,155, 74,249,107,132,240,133,145, 76,123,
+ 188, 8,213,235,133, 32, 34,165, 20, 17, 53, 26, 13,221,108,220,
+ 238, 5,212,123,248,252,226, 10, 89, 18, 82,202,137, 39,216,161,
+ 239,225, 31,252,235, 63, 88, 56,183,182,242,196,101, 34,186,240,
+ 220,179,171, 87, 46, 95,122,233,197,164, 53,246,221,223,251,253,
+ 153,140, 99,115,149,191,120, 6,236,182,175,188,102, 73, 97,108,
+ 153,223,232,110,119, 23,154, 63,251,197,207,223,188,121,243,141,
+ 215, 95,191,127,255,190,214,122, 80, 91, 67, 69, 54, 52,124,141,
+ 148,188,230,103, 38, 25,206,158,213,209, 83,216,224,207, 75,127,
+ 9,152,181,214, 66, 8,207,247, 2, 79,220,137, 67,191,183,243,
+ 161,133,101,193,194,159,236,184,176,221,222,195, 91,239,223,220,
+ 122,255,166,155,182,158,250,194,103,175,125,237,229,213, 39, 46,
+ 255,252, 63,249,199,223,249,151,255,106, 46,134, 55, 30, 55,242,
+ 128,166,154,167,228, 85, 81,216, 20,219,249,201, 32,213,247,130,
+ 238,186, 71, 95,254, 47,191,126,247,238,221, 55,223,124,115,125,
+ 125, 61,249, 8,229,159, 43,145,181,158, 93, 97,237,209,200, 39,
+ 218,171,175,237, 54,176,211, 65, 78, 98,166,201,159,252,136, 79,
+ 106,239, 23, 99,240,234,202,183,204,172,148, 54,218,212,235,245,
+ 190,239,221,138,250, 55,130,158,178,214,112, 58, 73,228,100,222,
+ 27,235, 63,254, 9, 17,213, 23,218, 43, 87, 46,237,251, 30,254,
+ 227,127,252, 79,254,238, 15,255, 40,121, 27, 95,120,254, 67,240,
+ 151,247, 15,254,193,255, 96,153,175, 95,191,238,221, 89,247,132,
+ 244,132,144, 66, 72, 34,145,142, 80,178,214,104,163,181, 86, 74,
+ 197,177, 49,218,230,115, 36, 20, 19, 25, 79,129, 79,252,198,175,
+ 62,251,242,151, 18,121, 45,156, 91, 91,126,236,226,206,157,187,
+ 123,108,127,237,107, 47,111,188,115,253,193,219,239, 38, 33,188,
+ 247, 96,227,225,141, 91, 19,203, 20,150,233,255,103,239, 93, 99,
+ 44,203,174,251,190,181,214, 62,231, 62,235,253,234,119,247, 76,
+ 15,103,122,154, 28,146,195,225,155,163, 33,101, 82, 50, 73, 88,
+ 68, 98,138,162, 13,136,177,101, 32,118,190,216,128, 19,125, 72,
+ 32, 27, 72, 62,200,130,191, 40,118,144, 0, 70,164, 4,145, 0,
+ 41,128, 5,135, 66, 64, 57,162, 2, 83,136, 69, 81, 36, 45,241,
+ 77,113,166,103, 56,211,211,211,239,238,170,234,122,221,215, 57,
+ 103,175,149, 15,251,236,115,246, 62,231,220,170,234, 71,245,220,
+ 234, 62,187,171,171,110,221,186, 85,117,235,220,123,126,247,255,
+ 255,239,181,215,222, 74,162, 11,189,173,143,125,238,179,163, 56,
+ 126,229,149, 87,174, 93,187,150, 36, 73,134,164, 34,182,170, 78,
+ 210,253,158,216,229, 65, 68,120,104, 6, 56,255,247,196,242, 46,
+ 72, 43, 95,237,125,234, 92, 84, 74, 9, 72,130,176, 19,141, 22,
+ 194,102,131,136,178, 25,222,131,127,122,108,188,117,165,183,186,
+ 86,126, 90,190,240,203,191,116,254,115,159,233, 46, 47,173,156,
+ 63,215, 93, 90, 68,196,225,230, 22, 0,220,122,249, 85,115,251,
+ 149,103,159,121,243,235,223,212,113,242, 54, 88,117,115,252,236,
+ 33, 37, 64, 66, 36,123,192,108, 84, 2, 44,162, 69, 18,251, 22,
+ 11,107,150,120,170,179,120,244, 40,217,161,148,121,159,143, 32,
+ 8, 84,144, 14,243,137,243, 69,251, 13,102, 32, 5,227, 78, 57,
+ 156,108,241,181,114,254, 92,166,188, 62,243,235,255, 60,234,245,
+ 119,207, 53, 95,248,210, 23,111,190,124,225, 79,127,227,127, 76,
+ 95,187,158,125,230,225,200,239,172, 78,245, 98,127,231, 29, 31,
+ 254, 64,208,106,189,242,242,203,215,174, 93, 51,249, 75,238, 19,
+ 253,229,141,178,255,240,107,247,115,236, 16, 6, 99, 89, 93,189,
+ 236,186, 9,137,136,236,106, 16,199, 95,237,191, 80,136,136,214,
+ 58, 8,130, 88, 36, 82,112,121,208,235,170,128, 8, 17, 5, 31,
+ 86,150, 95,153,111,204,157, 57,117,228,252,185, 35,231,207,101,
+ 55, 51, 79,242, 87,255,223, 63,189,248,245,111, 26,222, 61,243,
+ 153, 79,253,248,203,127, 52, 49,214,255,109,120,174, 29,214,250,
+ 213,175,254,243, 95,119, 63,109,116, 59,230,194, 39,127,237,191,
+ 113, 31,242, 31,253,225, 87, 10, 15,240,197,175,127,243,225, 6,
+ 7,194, 32,175,236,108,242,177,165, 51,231,158,185,120,241,226,
+ 149, 43, 87,134,195, 81,118, 30,185,228, 42, 99,203, 61,135,177,
+ 58, 86,222,223, 73,123, 8, 7,142,167,216,126,206,149,221,243,
+ 47,247, 19, 17, 17,145, 48, 12, 99,136,175,199,163,160,191,253,
+ 76,119,134, 4, 17, 65,193, 67, 74, 14,199, 69,180, 95,251,141,
+ 223,236, 46, 45,118,151, 23, 87,158,125,230,200,249,115,102, 97,
+ 220,149,239,124,255,199,127,248, 71, 39,223,255,252,147, 63,243,
+ 209,137,225, 87,101,226, 36, 53,191, 14,241, 48,206,113, 59,137,
+ 175, 36,163, 79,191,244, 51,183,110,221, 50, 21,246, 0, 98,242,
+ 151, 74,138,249, 32,219,243,252, 41,157,167,143,214,100,164,165,
+ 88,177,136, 68, 42, 20, 25,220,131,254, 50,151,153, 57, 8, 2,
+ 34, 26, 5,112,109,212, 63,210,104,205,135, 77, 34,194,116,129,
+ 36, 60,124,132,165,233,216,203,175,230, 47,210,157,246,147, 47,
+ 125,236,185,191,253, 11,198, 60, 70,189,254,212,242,210,252,153,
+ 83,135,100, 46, 82, 38,135, 95,147, 94,109,244,181,223,248,205,
+ 149,243,207,188,251,111,127,238,237,126,196, 82,231,248,236, 11,
+ 207, 15, 71,163, 75,111,189,181,182,182,198,204,230, 4,172,210,
+ 95,233,177,245,103,202,220, 3,190, 7,173, 42,216,117, 8,113,
+ 38,206,255,236,143,144,189,247,180,148,221,255,232,113,250,203,
+ 92,212, 90, 43,165, 18,145, 72,209,213, 97,127, 42, 8,149,228,
+ 91,180,193, 67, 71, 88,212, 43,214,223, 71,253,193,133, 63,249,
+ 218, 27, 95,255,139, 23,126,249,139,166, 61, 1, 0,156,120,255,
+ 123,223,102,126,189,173, 69,172,193, 35,197,173,201, 58, 9, 69,
+ 4,174, 13,251,219,221,230,243,231,158,121,235,173,183,178, 58,
+ 85, 87, 83,248, 20,203,213,214, 56, 9,182, 15, 49,113, 15,216,
+ 194,135, 15,168,253, 68, 96, 62,211, 65, 0,157, 4,208, 19, 97,
+ 34,178, 79, 35, 93,125,196,204, 81, 70, 36,162, 36,128,155,209,
+ 104,118, 52, 56,217,234,144, 32, 1, 10,202,195, 71, 88, 22,137,
+ 20, 70,220, 31,124,251,183,127, 23, 0, 12,194,230, 79,159,154,
+ 236,179,224, 96,185, 17,220,223,115, 79,106,162,141, 59, 72, 34,
+ 192, 34,111, 13,118,158,123,241,111,108,109,109, 93,189,122,117,
+ 48, 24,164, 82, 2, 0, 68,112,223,201,253,216, 19,178,234,226,
+ 158,130,108, 18, 76,225,254, 36,152, 20, 89, 15, 32,217, 18, 5,
+ 188,187, 39,223,126,184,111, 92,100,146, 36,163,128,110,140,250,
+ 71, 26, 45,133,164, 64, 16, 30,106,159,176, 12, 97,187,220,230,
+ 219,191,253,187,243,103, 78,205,159, 57, 21,118,218,135,194, 48,
+ 202,164,240,107, 82,135, 41,135,105,116,188, 87,173,238,226,226,
+ 219, 84, 38, 35, 2,112,117,212,167,197,249,233,133,249,139, 23,
+ 47,174,175,175,107,173, 77,236,101, 94,235, 43,201, 85,118,142,
+ 165, 83,199,171,100,242, 47,140,129, 24, 28,142, 18, 86,113,208,
+ 85,168,224,205,161,159,246,252,151,241, 57, 88,245,193,220, 93,
+ 164,186,143, 2, 17,105,165, 54,147,248,198,104,112,178,213, 85,
+ 10,201,136,191,135,120,252, 12,194,230,119,173, 8,251,238,239,
+ 255,193,167,126,237, 87,187, 75,139, 19,229, 57, 30,178,113, 11,
+ 238,230,119, 76,202,130,199,202,241,169, 95,251,213,242,149, 89,
+ 35,195,135, 79, 47, 35,190,206,127,244, 19,219,219,219,183,110,
+ 221, 26, 69, 81, 10,175,130,254,202,133, 6, 58,207, 2,207, 78,
+ 142,145, 84,233, 5,255,195, 46, 12,115,180, 15, 78, 34,183,208,
+ 119,143,230,192, 32, 8, 32, 58, 23, 50, 5, 54, 86,130,149,130,
+ 252,221,167, 34,139, 7,140,136, 68, 36, 14,212,205,104,112,164,
+ 217, 14, 4, 85, 90,251,251, 80,143,202,197,175,127,243,226,174,
+ 55,184,245,242,171,111,252,217, 95,196,143,119,155,138,224,158,
+ 158,106,147, 53,126,244,135, 95, 41, 92,211,187,189,118, 11, 94,
+ 253, 17,124,165,112,229,195, 75,190, 0,110, 69, 3,181, 56, 63,
+ 179,184,240,230,155,111,110,110,109,101,138, 32,211, 95,105,106,
+ 3,238, 82,109, 48,242,162,100, 86, 42,206, 55,239,195, 24,148,
+ 77,104,119,228,106, 55, 89,110,138,103,170, 39, 48,191, 32,146,
+ 191, 6,236,230, 30,171,181,210, 46,115, 31,133,227, 75, 68,137,
+ 162,205, 36, 94,141,134,199,154, 29,165,132, 0, 5,100,210, 14,
+ 167, 9,194,106,126, 29, 22, 82, 85,143,202, 18,152,222,234,154,
+ 59,247,252,118,136,175,222,153,247,125,168,215,235,173,174,174,
+ 70,163, 81,230, 25,119,137,189,118, 49,121,101, 85,229,128, 43,
+ 189, 8,152,214, 50, 49,155,178,217, 67, 31, 78,102,127, 99, 86,
+ 143, 15, 25,188,140,250, 42,105,176,177, 85, 20, 57, 45, 61, 10,
+ 149, 25,102, 44,164, 82, 42, 86,250,102, 52, 88,106,180, 2, 73,
+ 83,176,122,153,252,164,233,156,186,254,235,193, 63,114, 2,208,
+ 211,201, 78, 67, 45, 29, 59,122,229,202,149,205,205, 45, 95, 56,
+ 64, 86, 60, 81,157,212, 8, 8, 72,105,241, 80,122,214,185, 18,
+ 43,255, 33, 0,172, 53,107,157,232, 68,107,205,204,194, 98, 55,
+ 254, 56,172, 59,122, 34, 66,186,242,201, 89, 95,146, 47,133,178,
+ 127,152,236, 42,190, 50,167,185,191, 32, 44, 63,186, 68, 20, 7,
+ 234,206, 48,234,233,164, 65,196,136,100,148, 96,253, 20, 63,196,
+ 254,177, 30,251,146, 95,114,101,216, 59,254,212, 19,195,225,112,
+ 109,109, 61,138, 70, 89,193,151, 93,245,130, 48, 62,176,207, 88,
+ 85, 25,123,121,126, 17, 80, 64, 88,235, 40,138,162, 40, 66,196,
+ 169,110,119,170,219, 13,195, 16, 4, 26,237,150, 9,215, 36,171,
+ 65,240, 47, 76,196,235,179,184,169,125,118,127, 69, 0,132, 89,
+ 68,226,225,136,133,147, 36, 25, 70, 81, 20, 69, 74,169, 48, 12,
+ 149, 82,184,143,229,137, 34, 96,194,198,177, 49,152,163,197,202,
+ 194,214,184,200,155,163,193,116, 16, 6, 34, 10,165,210,231,214,
+ 99, 55,211, 94,243,235,208,209,139, 69,174,141,250,239, 63,125,
+ 122,123,123,123,123,123,155, 89,178, 34, 0,183, 78,181, 98,170,
+ 177,232, 31, 43, 52, 66,246, 94, 4,152,117, 20, 69,195,225,176,
+ 213,106,157, 62,121,170,213,237,184,132, 18,145, 2, 29, 38, 10,
+ 97, 30,203,220,187,237, 30, 17, 17,213, 8,145, 25,149, 82, 97,
+ 200,204, 58,142, 71,163,136, 20,101, 20, 27,107, 30,109,116,182,
+ 87, 10, 86, 93,144, 98, 22, 23, 39,138,214,226,209, 19,204, 26,
+ 137, 69,168,182,144,135, 83,127,213,101, 94,251, 60, 76, 34, 0,
+ 155, 73, 28, 76, 79,169, 70,184,121,235,230,112, 56, 44,193, 75,
+ 252, 58,213, 74,114,141, 21, 8,217, 15, 73,146,100, 56, 24, 32,
+ 209,153, 83,167,219,221, 14, 0,204,119,167,206, 46,173,156, 93,
+ 90,158,111,182, 69,235, 51,115, 11,200, 44, 6,168,249,212,246,
+ 4, 78, 34, 75, 81,138, 73,202, 49, 22,254,233,218,109, 0, 92,
+ 237,239, 92,184,117,227,213, 91, 55,110,111,109,134,141,144,147,
+ 36, 26,141,194, 70, 35, 8, 2,159, 40, 57,176,118,143,219,199,
+ 87,165,184, 22, 18,129,104, 4,122, 43,137,155,164,178,206, 43,
+ 88, 75,176,137, 9,196,106,253,245,224, 17,182, 22, 13,231,143,
+ 175,196,113,178,179,179,163,117,226,152,199, 66,242,181, 27,185,
+ 198,158, 88, 0, 34, 18, 71,113,127,208,159,157,153, 57,114,244,
+ 40, 0, 28,153,153,125,207,201,211,159,124,234, 89,142, 34, 29,
+ 69, 58,142,133,113,120,103, 67,180, 78, 85,152,100,219,116,139,
+ 147,178,165,191,216, 45,105,127,248,142, 35,223, 64,188,200, 47,
+ 17,129,147, 24, 2,192,201,169,249,247, 77, 47,200,211,207,253,
+ 63,175,191,252,157,171,111, 93,189,179,206,146,182,129, 14,195,
+ 176,236, 37,247, 76,241, 43, 41,230, 30,106,147,226, 19, 81, 66,
+ 184, 30,143, 22,194, 38,139, 72,157,128, 29, 74,253, 85,203,175,
+ 187, 48,143,112, 43, 26, 62,121,252, 88, 20,141,134,195,161, 61,
+ 145, 10,201, 87, 21,185, 82,141,180,139,191, 49,243,111, 18,199,
+ 113,191,223, 59,114,228,200,204,236, 44, 0,188,244,204,249, 95,
+ 56,255,110, 61, 24,142,238,108,232, 40,210, 73,194,137, 22,214,
+ 194, 34,194,192,226, 58, 71,215,179, 77,226,225,203, 8,109, 61,
+ 112,122, 89,196, 28,154,159, 95, 57,249,243,199,159,248,119,175,
+ 254,248,107, 63,125, 69,107,205,137,198, 46, 5,129, 74,219, 62,
+ 143,115,142, 99,143,237, 30, 41,152, 82, 42, 65,220, 78,226, 4,
+ 152,133, 88,128, 30,191,221, 81, 38, 67,105,213,250,235,224, 31,
+ 56,227, 47, 54,226,104,122, 97,254,214,173, 91,195,225,104, 76,
+ 242, 85, 69,174,252, 52,218,109,201, 94,146, 36,131,193, 96,101,
+ 101,101,122,102, 38, 84,234, 75, 31,121,233,217,185,197,209,198,
+ 102, 60, 24,234, 56, 22, 59,249,232,229, 95,238,251,137,229,151,
+ 248,255, 37,237,146, 41, 44,194, 44,194,233, 5, 0, 68,252,207,
+ 79, 62,117,118,106,230,127,251,238,183,134,113,196,219, 60, 61,
+ 59,227, 54, 43, 44, 88, 60, 83, 58,134,121,153, 89,181,255, 43,
+ 167, 96, 70,127,177,162, 94, 28,107, 17,157,234,216, 90,131, 29,
+ 190,252,171, 30,251, 37,216, 90, 52,154, 91, 94, 50,123, 62,199,
+ 113,140, 56, 54,249,170, 34,215, 30,214, 38, 73,146,225,112, 56,
+ 53, 53, 53, 53, 51, 19, 42,245, 95,127,234,179,243,168, 6, 27,
+ 155,201,112,196, 73, 98, 38,236, 64,114,120, 21, 17, 54,129,228,
+ 170, 92, 36,231,136, 47,251,102,103, 70,152, 89, 24,162,232,157,
+ 173,233,255,246,131, 31,255,245,111,254,233, 40,142,130,126,191,
+ 59, 53,101,187, 66,123,250,200, 78, 65,238,171,111,154,115,204,
+ 243, 20, 12, 17, 53,225,102, 28,181, 72,113,138, 47,168, 9, 54,
+ 33, 10, 44, 56, 4,247,241, 80, 61,114,235,241,104,230,216,177,
+ 56,142, 77, 58, 3, 78,239,151, 93, 74, 37,246,145,206,160, 8,
+ 199,113,204,154,151,150,150, 64,228,151, 63,252, 51,115, 64,195,
+ 173,237,100, 56,148, 68, 75, 42, 88,192, 65, 24, 27,231, 85,133,
+ 176,137,124, 32,197,227,186,135, 48,102, 96, 6, 97, 16, 6,102,
+ 102, 22,145, 37,162, 95,121,215, 11,191,253,195,191,236,245,251,
+ 205, 86,171,209,104, 64,177,135,199, 56,120, 57, 20, 43,177,168,
+ 92,139,175, 9,183,146,120,185,209,146,250,137,239,153,244, 67,
+ 161,191,164,102,215,126,211, 27, 17,216, 74,226,197,169, 41, 91,
+ 144, 85, 76,190,236, 52,160,236,115, 61,181,139,176, 36,209,209,
+ 104,180,178,188,196, 34, 31,126,242,169,103,103, 23, 70,155, 91,
+ 201, 96,200, 73,146, 85, 27,216,240,200,120, 46, 25, 27,222, 79,
+ 208,163, 88, 85,133, 42,249, 1, 21, 71, 75,166,115,169, 44,192,
+ 44,204, 73,162,207,119,103,127,230,228, 19,127,126,229,205,157,
+ 173,173,197,229,229,194, 26,210,253, 47, 90, 31, 23,228, 27, 11,
+ 169, 1,250, 58, 97, 16, 78,183,246,168, 35,176, 73, 1, 88,112,
+ 79,247,187, 30,227, 14,141, 36,194, 42, 8,146, 36,201,187, 77,
+ 32,250, 86,177,234,164,218,205,148, 32, 34, 48,115, 18,199,164,
+ 84,216,108, 30,153,153,253,252,115,239,139,182,123,241, 96,200,
+ 113, 92,168,249,202,135, 99, 39, 11,252,154,156,149, 69, 8, 0,
+ 192, 69,132,185, 19,145,204, 96, 18, 61, 22, 72,103, 36, 88, 88,
+ 18,150, 68, 88,115,242,217, 19, 79,190,186,190,122,171,191, 19,
+ 69, 81,179,217,130,116,186,183,170,202, 97,111,231, 87,177,206,
+ 148,136, 52, 66, 98, 66, 69,111,218,182,126,182,191,253,116,168,
+ 243,175, 7,154,126, 1,108,196,209,185,133,249,245,245,117,219,
+ 170,208,150,218,143,179,138,105,175, 9, 25,103,103,172,121,148,
+ 56, 73,102,166,166,153,249,189, 39, 78,225, 48,138,251,125,142,
+ 99, 97,206, 3,163, 76, 4, 50,155,201,199, 84, 48, 88, 59, 86,
+ 244,104,147,115, 14, 56, 34,172,184,189, 37,179,137,189,204,155,
+ 185,108,166, 87, 53,115, 34,146, 48,159,159, 95,186,213,223,233,
+ 109,111,119, 58, 29,131,238,226,161, 46, 31,228,241, 32,115, 31,
+ 168, 84,127, 33,166,250,203,217,118,171, 30, 80, 33,155, 31, 54,
+ 217,131,123,189,175,245,168,118, 60, 0,192,204,163, 81,100,246,
+ 118, 44, 39, 95, 0,126,201, 83,133, 34,171, 56,193,152,153,153,
+ 195,102,163, 25, 4, 47,157,121, 42,222,233,235, 81,196, 6,145,
+ 78,160, 38, 41,181,204,217,110,150, 64,166,225,183, 56,246,117,
+ 50, 7, 22, 67,176,244,104,102,134, 81,152, 57,101, 86,186, 49,
+ 87,204, 58, 17,121, 97, 97,229, 91, 55,174, 12,163,168,209,104,
+ 48,179,217,219,169, 64,174, 42,217,187, 27,200,242, 5,167,144,
+ 238,188,201,217,202, 38,172, 53,216,164,140,224, 0,206,100, 17,
+ 1, 51,223,204, 34,242,216,160, 79,139,172, 70,195,238,252, 92,
+ 146,232, 36,142,157,149,195,232,157, 75,166, 1,223,190, 26,113,
+ 165,223, 45, 44, 90,235, 64, 5,204,252,212,210,145,134,150,225,
+ 112,164,227,216,246,243,179, 39,187,131, 47, 73, 67,110,150,108,
+ 242, 46,151, 52, 19, 79, 46,183,139,182,145,147, 58,229, 87, 34,
+ 108,156, 99,204,156, 88,253, 21, 0,156,156,154,121,125,115, 61,
+ 138,162, 86,171,149,196,201,174, 47, 15, 99,239, 66,133,248,181,
+ 160,138, 17, 86,163, 17, 54, 80,139,132, 66,234, 81, 15,192, 12,
+ 179, 3, 36,101,122,127, 76, 42,174,131,123,133,212,216,193, 2,
+ 3,157,108, 37, 81, 79, 39, 49,243,227,163,218, 24,100, 43,137,
+ 135, 24,198,113,172, 89, 99,169,131,251,190,207,165,138,151, 4,
+ 102, 14,149,210, 90,159,156,157, 75,134, 67, 29, 69,146,232,130,
+ 211, 18, 48,188,178,240, 98,102,230,108,253, 54, 64,113, 47,144,
+ 201,129,151,140, 33, 90,206, 47,102,102,209, 41,191, 56,227, 87,
+ 156,126, 42, 75,173,246,235,155, 48,236,247,167,167,167,205,204,
+ 239,125,244,105,244, 94,116,204,131, 54, 98,189, 26, 13, 35,214,
+ 1, 81,128, 72,240,200,243, 11, 66,162,174, 10,103,130,176,165,
+ 148,154, 84,132, 5, 15,220, 47,198,172, 87,163,225,213, 81,127,
+ 53, 26,198, 34,143,143,204, 22,128,132, 57, 12,167,205, 22,244,
+ 213,103,195,189,255,116, 33,165,180,214, 79,206, 47,154, 21, 66,
+ 172, 53,218,179,223, 13,239,141,236, 98, 35, 88,220,249,187, 98,
+ 224, 52,113, 10, 12, 61,243,102, 67, 61, 22, 96,214,194, 9,139,
+ 150, 92,127, 37,204,177,131,179,149, 86, 27, 0,122,189,254,153,
+ 78,199, 76,254, 62, 56, 33, 2,134, 95,215, 71,131,213,120, 68,
+ 153,159,124,212, 7, 33,206, 4,225, 59,187,115, 10,145,198, 41,
+ 206,183,219, 72, 7,247,123,143, 74, 39, 66, 34,210,211,201, 27,
+ 131,157,190, 78,224, 49, 27, 2, 50,111,211,174, 61, 58, 21,200,
+ 126,206,104, 55,139, 65,102, 22,173, 37, 73, 52, 19,199,137,104,
+ 237,224,200, 52,156, 73,165,151,136, 88,126,177,228,107,113, 96,
+ 66, 59,128, 99,229,197, 92,127, 89,114, 89,253, 37,146,100,228,
+ 202,174,209,108, 94, 42,218,237,118,175,215, 43, 68, 96,251,191,
+ 3,227, 70, 34, 50,210, 9,242,227,149,122,221,138,134, 91, 73,
+ 252,159,173,156, 38,162,201,220,171, 39,184,111,209, 85,220,107,
+ 151, 16, 59, 42,120, 12,225,229,158, 11,105,104,176,203,241,196,
+ 187,251,161,136,200,137, 22, 17,157, 36, 76,196, 73, 34, 70,127,
+ 101,224,116,235, 38,172,225, 18,225,172,151,131, 76, 98,241,215,
+ 238, 79, 38, 83, 53, 33,137,112, 34,172,173,236,178,239, 83,138,
+ 105,243, 37,102,115,156,130, 32, 80,164,118,133,226,221, 65, 21,
+ 1, 31,231,134, 19,183,162,225,212,220,108, 52, 24, 38,209,232,
+ 238, 14,168, 60, 56, 79,247,192,243, 10,121, 31,104, 0, 0, 32,
+ 0, 73, 68, 65, 84,175, 93,238, 89,131,104,185,209, 90, 8,155,
+ 235,241,232, 49, 69,152, 25,100,170, 87,203,143,156,220,213, 73,
+ 132, 0,130, 68,136, 17,107,102,224, 68, 51, 37,150, 95, 54,248,
+ 246,249, 37, 25,190,196,246, 96,157,232, 24,210,187,119,146, 9,
+ 47, 0, 22, 51,207,232, 73, 45, 39, 5, 19, 3, 47,227, 43,205,
+ 1, 11,130, 0, 41,107, 71, 33,119,139, 44, 44, 1,236,225,109,
+ 192, 61,145,227,137,185,133,102,183, 27, 71,209, 61, 55, 41, 57,
+ 208,167, 94, 80,254, 77,114,127,247, 38, 64,154,110,168, 47,156,
+ 121,230,175, 7, 91,170,216,158,233, 81, 30, 44,178, 57, 28,220,
+ 1, 38,164,188,163,139, 61,143,156, 70, 49,120,183,103, 20, 41,
+ 82, 65,192,131,129, 22, 97,173, 89,136, 19,109,252, 35, 58,221,
+ 178,178,185, 71,157,190, 29,142, 54,248,121,113,173, 83, 86, 98,
+ 58,150,153, 63,196,211, 92,182,236,203,188,103,225,236, 54,230,
+ 149,163,217,108, 18, 17,185,125, 87,239,150, 95, 88,241,106, 52,
+ 213,104, 30,233, 76,205,180, 90, 13, 21, 4, 68,244, 56, 60,171,
+ 17, 17,241,195, 39,206,112,127, 96,158,108,111, 51,171,238, 86,
+ 127,201,125,252,229, 13,162,143, 44, 29, 11,155, 77,116, 27,155,
+ 60,202,201, 23,104,214, 87,182,183,190,183,189,102,186,215, 35,
+ 82,126, 8,241,222,142,102,122,150, 16, 82, 16, 4, 0,144, 36,
+ 201,197,181,219,167, 22,143, 49,107, 73,146, 60,249,178,213, 73,
+ 12,162, 37, 69, 24,231, 11, 32,139,143, 41,190,205,207,186,234,
+ 95, 47, 96,215,107,218,106,144,212, 60, 90,231,232,164, 96,162,
+ 133,179,191, 81, 64, 54,162, 17, 0, 44, 46, 46, 41, 82, 32,247,
+ 214, 38,181,162, 28,204,236, 26, 2, 0,221, 48,124,106,118,254,
+ 196,244,108, 39,108,180,148, 82,164, 30,125,128, 33,128, 72,188,
+ 211, 27,245,251, 58,153,208, 56, 40, 40, 61,149,240, 62,159,207,
+ 2, 2,154,147,209,136,227,100,168,122,143,137,254, 18, 0,205,
+ 50, 24,246,178,149, 67, 68,232,148,103,221, 35,196,236,206,207,
+ 24, 4, 1, 41,165,135,195,215, 87,111,189,180,120, 76, 51,107,
+ 173,109,139,153,244,189, 89,160,103,245, 23,179, 5,129, 83,120,
+ 54,225,177, 87, 90,172,102,144,148,133, 95, 58,115,139,105,224,
+ 101,213,165,243, 71,109, 68, 67, 0, 56,122,236,104,156,196,137,
+ 78,238,157, 95, 85,171, 32, 69, 68, 39,122,184,211,235,107, 16,
+ 21,196,164,212, 99, 33,192,192, 76, 4,177,214,247, 17, 64,200,
+ 195,228, 87,245,239,151,187, 71,152,137, 96,224,113, 10,241,181,
+ 72,155,101,176,189,109,214, 60,102,219,125,229,235, 98,228,174,
+ 33,150,109,229, 17,168,160,213,110,111,109,111,191,124,227, 90,
+ 252,236,123, 18,128, 88,242,130,112,247,132, 55, 20,211, 86,152,
+ 136,215,111,117,130,225, 37,158,254,202,254, 16,167,108, 34, 39,
+ 151,159,153,137, 0,172,141, 6, 0,112,250,204,153,181,181, 53,
+ 179,242,225,238,213,198,152,125,213, 0,152,153, 52, 55, 89,146,
+ 81, 20, 43,141, 68,252,120, 47,224,158,156,229, 7,245,250,199,
+ 7, 57, 66, 36, 78, 91,217,100,237,234,161,160,194,246,120,149,
+ 194,234,147, 74, 5,170,211,233, 52,130,112,117,103,251, 27, 87,
+ 47,189,119,106, 62, 78, 51,122,123,182,139, 48, 0, 91, 75,101,
+ 206,127, 55,252, 42, 76, 36,200, 4,182, 47,116,244, 87,166, 37,
+ 179,153, 71, 87,115, 21, 14,219, 91,189,237,126,146, 44,206, 47,
+ 116, 58,221, 43, 87,174,228,107,230,247,119,144,203,226, 43,123,
+ 217,128,180,158, 78, 76, 49, 58,214,173,239, 39, 34,245,170,249,
+ 117, 48,113, 1, 2,116,131, 96,184,211, 35, 34, 69,202, 84,142,
+ 230, 91,172, 34, 96,165, 10, 18,144,180,214,162,100, 97,242,109,
+ 31, 41, 12, 27,211, 51,211,107,235,235,127,254,214,197,119,191,
+ 103, 41, 65,212,206, 36,163, 43,190, 28,126, 57,251,118, 72, 85,
+ 226, 52, 73, 39, 64, 33,249,202,140,112, 82, 69, 46,112,130,255,
+ 183,122,219, 0,240,222,231,223,219,239,247,134,131,161, 51,249,
+ 136,222, 77, 81,118, 89, 33,143, 37,120, 33,166,149,255,196,210,
+ 164, 28, 94, 53,194, 38,135,111, 53,191, 30, 40,193, 16, 91,164,
+ 162,225,176, 57, 61, 21,132, 65,146, 36, 40,233,190,243,226,189,
+ 250, 75, 73,139, 75, 94, 58,230,157, 34, 89, 35, 80, 8,195, 96,
+ 97,113,113,107,107,235,226,218,237, 63,185,244,211,151,150,142,
+ 199,144,106,176, 2,182,236,101,167,239,132, 84,164,248,147, 20,
+ 179,100, 73,133,184,138,210, 53,140,133,166, 91, 25,188, 94,222,
+ 188,179, 54, 26,180, 91,173,119,190,235, 93, 23, 46,188,106,246,
+ 193, 28,243, 26, 81,121,132, 11,230,209,219, 32, 24,128, 89, 51,
+ 1,132, 68, 4,104,227,252,154, 96,247,196, 45,121, 27,249, 85,
+ 119,159,216,159,254,154, 86,225, 86,175,215,153,155, 13,195,144,
+ 211, 14, 92, 6, 95,152, 46, 39, 46, 73, 48, 41, 79,217,231, 39,
+ 88,126, 58,153,237, 14,143, 30, 59,118,249,242,229,175,189,241,
+ 234,217,153,185, 5, 84,166,158,192,203,191, 28,132,101, 68, 40,
+ 71, 96, 19, 37,189,178,254,176,118, 46, 66, 24, 64, 11,251,162,
+ 75, 4,176,112,247, 55,226,232,194,214, 58, 0,124,254, 23,127,
+ 113,115, 99,115,107,107,147,133,203,221, 62, 10,237,192,198,111,
+ 158,230,110, 82,135,136,144, 36,162,181, 38,145,182, 10,208, 86,
+ 178, 98,205,165,137, 57, 6,193,110,119, 76,118, 69, 88, 77,180,
+ 42,132,205,135,141,155, 91,219,116,138, 2, 21, 68, 24,217,189,
+ 184, 32,119,145,101, 9, 86, 37,228,202,219, 62,138, 72, 16, 4,
+ 179,179,115, 59, 91,219,119, 54, 55,254,240,181,159,252,210, 59,
+ 222,217, 64,176,179,141, 69, 9,230,216, 49,207, 62, 74, 21, 60,
+ 222,246,215,231, 66,254,229,116, 44,243,247, 11,112,198, 64,235,
+ 239,172,221, 4,128,231,223,243,222,249,249,249, 87, 94,185, 48,
+ 24, 12,210, 93,154,188,109, 32,139,237,192,138, 81,189,215, 42,
+ 199,254, 67, 52,109,215, 18,157, 4, 2,109,165, 8,144,234,198,
+ 171, 19, 54,106,255,248,128, 13,228, 76,208, 24,109,109, 34, 34,
+ 41, 34, 36, 73, 59,176,166, 77,245,196,169,100,173,120,221,144,
+ 114,132,236,157, 78, 0,208,108, 54,158, 56,251,228,232,149, 87,
+ 86,123, 59,255,247, 27, 23,254,198,137, 51, 51,168, 18, 22,102,
+ 91, 15,149,137, 47, 17,182,109, 95, 29,120,249,221,239, 39, 50,
+ 197,223, 15,230,183,226,248,251,119,110,109,199,209,177,163, 71,
+ 63,253,217,207,188,246,218,107, 27, 27,119,152,185, 96, 14,199,
+ 72,133,138, 62,171,174,246,178, 91,129, 72,146, 36, 58, 73, 90,
+ 2, 51, 65, 72,147,221, 73,166,230,215,132, 70,116,135,201, 63,
+ 34, 52,136,218,130,253,237, 29, 10, 3, 36,194,116, 97, 15, 32,
+ 216, 40, 12,100, 79,245,229, 57, 71,159, 95, 34,210,108, 54,223,
+ 253,158,247,254,240, 7,223,191,182,189,249,111, 95,253,241, 7,
+ 143,156, 56, 63,179,160, 33, 85, 97,110, 85,167, 28,170,135, 69,
+ 246,109, 87,126,186,189,249,147,205, 53, 22, 89,152,159,255, 47,
+ 254,222,223,187,122,245,234,205,155, 55,205,110, 79,222, 55,101,
+ 27, 65,250, 66,206,147,183,249, 12, 73, 74, 47,107, 30,145, 57,
+ 137,163, 8,180,110, 17, 53, 80, 17, 34, 1,214, 83,144, 19,117,
+ 254, 7, 53,150, 30,116, 4,134,115, 97,163,183,177, 57,179,178,
+ 28, 4, 1,107, 45,152, 53,177, 73,189,100, 6,179,170, 3, 46,
+ 5,229,149, 42, 2,219,181, 69, 68,180,214,173, 86,251,227,159,
+ 248,196, 15,127,240,131,235, 55,110,124,243,250,229, 43, 59, 91,
+ 231,102, 23,150, 27, 45, 45, 98,226,176, 67,251,236,151, 93,110,
+ 128, 0,183, 71,131,215,183, 55,111, 12,122, 0,240,238,231,158,
+ 251,197, 47,124,225,205, 55,223,188,124,249, 74,191, 63,200,203,
+ 238,109, 21,118,234, 28,211,233, 93,192, 10,126, 21, 95, 36,242,
+ 15,136, 81,164, 71,163,136, 88,186, 65,160, 16,149,201,239,235,
+ 103,249,225,209, 95, 82, 3,237,238,220,163, 32,161, 28,111,118,
+ 126,176,182, 54,119,244, 72, 16, 4,177,112,170,185,208, 10,177,
+ 52, 15,131, 44,209, 47, 11,178, 49,137, 76,122,182, 49,115, 20,
+ 141,130, 64,189,255, 3, 31, 88,189,189,250,151,127,249,151,151,
+ 183, 55, 47,111,111, 46,183,187,199, 58,221,217,176,185,216,104,
+ 226,164,175,217,190,139,231,149, 0,172,141,134,155,241,232,122,
+ 191,103,234, 84,195, 32,248,187,127,247,239,158, 62,115,230,181,
+ 215, 94,187,122,245,106,175,183, 99,143, 44, 88, 94,229,251,166,
+ 101, 74, 12,199,120,243,204, 51,250,230, 17,146, 36,137,162,168,
+ 5,184, 16, 54, 21, 34,161, 89,202, 93, 11,176, 58,255,122,180,
+ 35,176, 48,196,237, 81, 18,141, 40, 8,136, 40,219,253, 43,163,
+ 152, 51, 31,185,219,207, 1,172, 8,101, 50,132, 13, 6, 67, 17,
+ 88, 57,178,242,139,191,244,133, 11, 63,121,249,194,133, 87,110,
+ 15,122,183, 7,189, 71,251,240,118, 90,237, 15,127,228,195, 31,
+ 255,196, 39, 54,183,182, 94,126,249,149,219,183,111, 13, 6, 67,
+ 27,123, 65,190,211,182,117,142,206, 22,144,133,156,203, 59,182,
+ 133, 35,140,136, 73,146,140,134, 35, 78,226, 38,224, 84, 16,170,
+ 12, 94,245, 24, 99,234, 15, 31,191,106, 49, 86, 25,129,145,224,
+ 82,163,181,179,126,103,230,200, 10,145, 50,203,168,237,155, 41,
+ 200,247,138, 42,198,129,172, 60, 29,102,127,131, 65,152, 30,141,
+ 134,155,155,156, 36,201, 59,159,123,238,163, 47,190,120,253,250,
+ 181,159,190,250,234,141, 27, 55,214,238,220,121,196, 14,236,242,
+ 226,226,233,211,167,159,127,225,133,119,188,227,233,245, 59,235,
+ 111,188,113,241,246,237, 91,219, 91,219,113, 18, 23, 55, 6, 6,
+ 65,243,175,176,243,166,111, 21,161, 84, 42,225,194, 11, 0,147,
+ 68, 15, 6, 3,197, 50, 29, 52, 20,162,170,195,175,177, 16, 40,
+ 161, 76, 14, 9,191,106,138, 85, 66,135, 16, 79,182,186,223,185,
+ 117,123,246,200, 17,165,148,237, 65,159, 55,115,206,130,176,180,
+ 168,162, 12, 49,129,162,127,132, 52,125,113,202, 39, 81, 68,162,
+ 40,214,122,123, 56, 26,237,236,108, 79, 77, 77,191,248,210, 75,
+ 83,211,211,221, 78,167,209,108,154,174,229, 88,238,104, 85,245,
+ 217,196,120, 71,167,191,181,216, 99, 35,146, 36,122, 48,232,111,
+ 110,110,254,240,135, 63,216,220,220,220,217,233,197,113,204,172,
+ 237, 95,146,215, 6, 99,230, 31,205, 42, 34,255, 72, 22, 95, 21,
+ 178,216,203, 31,204, 60, 26, 13,135,195, 97, 27,112, 33,108,154,
+ 109, 44,168,198,215,225,240,143, 82,177,104,187,134,212,254, 37,
+ 24, 1, 78, 5, 65, 71,203,112,103,167, 53, 61, 69, 64,206,214,
+ 26,217,192, 10, 47,233,128, 76,178, 62,212,254,252,163,123,162,
+ 166, 15,141,112, 52, 26, 37,113,188,179,179,179,190,222,108,183,
+ 91,205,102,171,209, 8,145, 8,139,154, 99, 2,233, 85,194,150,
+ 67, 47,115,216,180,214,113, 28, 15,134,131,225, 96, 16, 69,145,
+ 214, 90,156,149,157,152, 30,180,108,122,214, 44,155,151,116,243,
+ 58, 27,185,151,253,184, 39,187, 32,109, 57,105, 70, 28,199,253,
+ 94, 95,226,120,138,130,233, 32, 12, 76,248, 85,135,247,135, 47,
+ 255,218,127,193,246, 4, 19,174,187,188, 56,181,180,100, 46,223,
+ 121,235,114,212,235, 31,180,133, 84,130,199,154,157,107,171,107,
+ 237,233, 41, 36, 18, 17, 17,146,226,216,219, 75, 22,245,151,173,
+ 0,119, 75, 58,179, 51, 86,107, 30,142,134, 81, 52, 66,220,178,
+ 137,116,206, 64,184,255,158,202, 15,135, 95,206, 94,188,146,247,
+ 149,229,236,127,245, 65, 79,191, 49, 19,182,169,121,244,177, 85,
+ 229, 25,193, 97, 23,165,101, 95,195,225,176,215,219,105, 8,204,
+ 5,141, 16, 73, 33, 41,215, 60, 62,222, 47,230,178, 63, 21, 42,
+ 19,193,175,195, 60,142,156, 63,247,228, 75, 31, 93,126,231, 51,
+ 211, 22, 94, 0, 48,234,247,191,247,123,127,240,198,159,253,197,
+ 65, 91,200, 19,173,206,155,235, 55,227,227,199,194,102,211,246,
+ 210,225, 18,194, 42,189,164, 39,196, 92,132,165, 5, 26,165,167,
+ 138,164, 69, 23, 94,169, 42, 22, 94,125, 38, 87, 60,248, 47,146,
+ 213,252,202, 86, 18,216,203, 85,155,174,217,169, 93, 44,170,215,
+ 113,158,209,113,143,100,197,215,104, 20,109,111,111, 71,131,225,
+ 34,170,229, 70, 43, 32, 12,106,243,184,219, 99,135,111,163,156,
+ 121, 4,249,213,232,118, 78,190,255,249,119,125,254, 23, 12,182,
+ 182,227,254,215,175,255,240,167,155, 87, 1, 96, 42,108,127,230,
+ 244,135, 62,242,143,126,165,119,123,237,230,203, 23, 14,212, 66,
+ 42,196,227,173,206,234,181,235,203, 79, 62, 65,100,188,141,170,
+ 66, 88,217, 75, 58,142, 50, 95,214, 13,110,253,101,254, 12,201,
+ 151,201,236,178,172, 82, 38,173,229,234, 88,140,185,251, 41, 65,
+ 190,247,155, 71,177,234,150,116, 25,255,179,248,190,202, 45, 22,
+ 235,188, 10,240, 34, 17, 30,244,251, 91,155, 91, 45,192,249,176,
+ 25, 18,165,225, 87,109, 30,239, 61,211,172,249,181,239,113,238,
+ 51, 63,247,220,231,127,161,217,233, 0,192,215,175,255,240,171,
+ 151,255,211,159, 95,255,161,123,131, 63,191,241,163,255,233,197,
+ 127,242,161,255,234,239,127,229,159,254,218,129, 90, 72, 2,124,
+ 162, 61,125,109,253,102,124,252,104,163,213,166,212,155,224, 88,
+ 132, 21,188,100,169,111, 5,238,150, 24, 85, 61,119, 76,253, 64,
+ 42, 68,196,180,143,129,251,216,214,245,225, 69, 95, 30,193,242,
+ 234, 19,219,162,162,130, 96,185, 96, 53, 69,117,228,112,203, 9,
+ 16,113, 87,120, 33,194, 96, 16,111,108,220,137, 71,195, 25, 84,
+ 199,154,237, 16, 41,176, 57, 98,205,175,253,169,176,135,250,210,
+ 24,220, 51, 49, 39,237, 21,252,228, 7,158,127,223,151,190,104,
+ 52,215, 31,191,245,237,223,185,240,199, 55,250,235,229,155,125,
+ 127,245,181,239,173,190,246,190,165,167,207,125,230,231, 46,124,
+ 245, 63, 28,160,133, 4, 8, 16,143,183, 58,215, 47, 94, 58,254,
+ 236, 51, 0, 1, 17, 2, 32, 51,102,129, 78, 17, 97, 34,206,122,
+ 201, 92, 81,164, 89, 53,186,114, 43, 91, 20,147, 63, 30,197, 94,
+ 13,232, 5,100, 89, 19,172, 73, 13,112, 10,125,202, 60, 9, 6,
+ 69, 43, 89,106,236,111, 15,187,128, 16, 82,217, 45, 86,194, 43,
+ 243,140,198, 32,106,157,236,108,111,111,108,108,118, 4,231, 27,
+ 205,144, 40,180,187,109, 63, 52,124, 29, 57,127, 14, 0, 86,206,
+ 63, 83,249,213,222,234, 90,239,246,218, 65,103,184,135,104, 60,
+ 10,250,171,209,237,124,248, 31,254,253, 83, 31,120, 95, 70,174,
+ 169,176,253,133,179, 63,251,142,217, 19,239, 91,122,250,235,215,
+ 127,248, 47,191,247,251, 59,241, 32,187,253,191,252,222,239,255,
+ 219,159,255, 31,158,251,252, 47, 28, 36,191,128,172, 4,219,220,
+ 90,235,221,217,152, 94, 92,180,243, 91,102,143, 70,220, 21, 97,
+ 48, 86,134, 21,156, 97,102,186, 42, 58,243,228,228, 50,251,160,
+ 227,196,178, 11,160, 18, 94,249,230, 74, 5, 29, 6,144,107,177,
+ 2,192,128,138,110,209, 89, 18, 84,158,106, 76,131,123, 66, 17,
+ 25, 12, 6,107,107,171,144, 36, 51, 42, 56,214,108, 55,172,248,
+ 58,232, 29,212,230,207,156,122,242,165,143, 30, 61,127,110,238,
+ 204,169,125,126, 75,127,117,237,198, 79, 46, 92,249,238,247,175,
+ 252,213,247,107,126,221,175,230,122, 27,207,137,147, 31,120,254,
+ 195,255,232, 87,154,157,206,107,155, 87,254,151, 31,255, 33, 0,
+ 252,119,239,251,229,247, 45, 61,157,221,224,165, 99,239,249,233,
+ 230,213,223,185,240,199,217, 53,207, 47, 61,189, 29,247,167, 59,
+ 157,249, 51,167,238, 92,186,124,112, 18, 76, 1, 4,136, 39, 90,
+ 221,151, 47, 95,105,207, 76, 19,181, 84, 64,132, 36,194,136, 50,
+ 70,136,101, 8,179,117,152,217,191, 98,255,174,188,184, 60, 61,
+ 219,171, 58, 91,184,226,203, 80, 12, 74,121,218,219,171,186, 42,
+ 10,117, 36,111,167, 51, 70,136, 85,244,254,201, 68, 86, 33,234,
+ 42,151,167,122,222, 49, 45, 50,193,209,104,184,190,182,190,189,
+ 185, 53, 45,176, 24, 54,155,164,140,248, 82, 7, 41,190,230,207,
+ 156,122,225, 75, 95, 52,154, 11, 0,228,198, 53,184,113, 29, 54,
+ 54,224,230,117, 24, 14, 42,190,225,204, 89,104,181,224,232,177,
+ 206, 19,103,207,126,252, 99,103, 63,254,177,222,237,213,111,253,
+ 214,239, 30, 92,152, 59,225, 89,216,225,214, 95, 47,124,233,139,
+ 207,126,230,231, 0,224,255,120,229,143,255,221, 27,255,223,175,
+ 156,251,236, 47, 61,245,179, 0,112,253,149, 11,151,254,236,155,
+ 87,190,243,125, 0,248,220,191,250,141, 47, 60,245,137,175, 94,
+ 254,246,141,254,250, 59,102, 79,252,227,231, 62,111,232,246,202,
+ 87,255,195,193,193, 43, 75,193, 20,224, 74,163,117, 39, 30,173,
+ 95,189,182,116,250, 20, 17, 82, 16, 16, 40,102, 65,100, 43,196,
+ 74, 50, 44,239, 90, 81, 4, 89, 94,239,108,150,200,152,204,204,
+ 118,217,119, 82,127, 79,124, 89, 90, 21,102,250,112, 2,159,221,
+ 226,238,231, 81,156,140,116,246,186,204,154,203, 26,245, 73,119,
+ 11, 47,114, 98, 47, 76,146,100,115, 99,227,246,237, 91, 45,128,
+ 165,176,185,220,104, 53,108,114,127,112,244,154, 63,115,234,231,
+ 254,217,175,134,157,142,188,249, 6,252,224,187,240,202, 79, 96,
+ 56, 4, 0,104,181,224,217,119,194,153, 39,225,232,177,252,214,
+ 27,119,224,230, 13,248,193,119, 97,227, 78,122,212,158,125, 39,
+ 156, 59,223,125,254,253,159,250,103,191,250,173,223,250,157, 3,
+ 157, 82,159,216, 76,233,176,242,171,209,237,188,240,203, 95, 60,
+ 251,241,143,109,199,253,127,254,159,254,247,159,110, 94,249,215,
+ 47,254,147,167,103, 79,110,175,174,126,239,247,254,192, 21,213,
+ 175,126,245,107,239,254,252,231,254,241,115,159,223,137, 7,159,
+ 61,253, 97, 67,183,191,254,191,254,232,214,193,191,100, 33, 32,
+ 33, 40,196,179,157,233, 31,173,223,217,238, 78,205, 46, 47, 42,
+ 165, 80, 41,133, 34,130, 25,197,236,182,217, 54,175,134,188,101,
+ 133,181,147, 46,200, 76, 99, 66,143,106,126,127,196,130,211, 52,
+ 63,160,172,185, 38,201, 75,138,255,206,177,198,190, 10, 3,167,
+ 223,180, 65, 23, 82,198, 41, 40, 78, 49, 86,154,198,156, 92,132,
+ 132,200, 44, 59, 59,219, 55,111,222,192, 56, 89,160,240,120,171,
+ 211,176,226,235, 64,203, 38, 94,248,210, 23,195, 78, 71,254,228,
+ 223,195,183,190,145, 95,251,145, 23,225, 19,159,196, 86,187,250,
+ 123, 62,253,183,228, 91,223,128, 63,249,247, 0, 0,175,252, 4,
+ 94,249,137, 92,120, 25,255,206,151,222,255,165, 47, 62, 60,126,
+ 77, 82, 45, 78, 48,161,207,230,189,198,167,126,237, 87,231,207,
+ 156,122,109,243,202, 63,253,198,255, 12, 0, 6, 94,151,255,234,
+ 123,223,254,237,223, 45, 68,155, 63,250,242, 87,158,248,248, 71,
+ 95, 58,246, 30, 0,216, 94, 93,253,235, 47,255,209, 67,123,164,
+ 109, 33, 5, 53, 8, 78,180,186, 63,185,244, 86,179,219, 86, 74,
+ 53, 72, 17, 41, 17, 3, 47, 76, 55,225,192, 42, 37,102,201,229,
+ 131, 44,203,244, 37, 95,239, 7, 82,202,192,138,179, 66,226,132,
+ 254, 56, 65,212,170,250, 76, 10,251,114,139,247,207,252, 49, 37,
+ 100, 21,139, 36,118, 73,235,211, 77,210, 73, 64,250,253,222,141,
+ 235,215,123, 59, 59, 51,130,139,141,102,139,148, 21, 95,116,160,
+ 101, 19, 71,206,159,147, 27,215, 60,120, 1,224,167,255, 86,220,
+ 239,191,254,213,255,112,229, 59, 63,112, 95, 98, 87,206,159,155,
+ 63,115,242,217, 79,127,170,251,145, 23,229,194, 79,224,205,139,
+ 233, 23, 94,249,137,124,255, 59,225,243,239, 95, 57,127,238,214,
+ 36,187,200, 90,127,229, 47, 81,255,232, 87, 50,120,237,196,131,
+ 95, 57,247, 89, 3,175,175,255,235,127, 83,121,251, 63,255, 87,
+ 255,230,220,167, 63,117,231,173,203, 23,191,254,205,135, 63,113,
+ 67, 8, 1,224, 74,163,181,157,196,215, 95,191,120,252,252, 57,
+ 0,108, 54,155,164, 8, 82, 9,102, 82, 48, 11, 50,191,222, 73,
+ 160, 2,100,222,123, 91,215, 89,216,105, 18,242, 46, 12, 21,128,
+ 144, 73,129,152,236,173,197, 28,102,101,253,209, 10,236, 2,172,
+ 238,225, 85,240,140,174,248, 34, 66, 17, 24,244,251, 55,174, 95,
+ 91, 93, 93,155, 22, 92, 12,155,105,242,133, 70,124, 29,252, 95,
+ 111, 12,163, 63,214, 47, 93,254,238,239,253, 65,225,202, 91, 47,
+ 95,184,245,242,133, 70,167,243,238,207,127,174,248, 13, 27, 27,
+ 143,107,124,127, 8,249,181,114,254,220,217,143,127,236,122,127,
+ 205,192, 11, 0,222, 49,123, 2, 0,174,126,247, 7,227,190,229,
+ 206,165,203,223,250,173,223,121, 91,238, 45,218,112, 38, 64, 58,
+ 219,153, 26,238,108,220,190,120,105,233,137,211, 68,212, 82, 77,
+ 36,229,194,203, 94,150,170, 50,125, 17,175, 38,170, 40, 70,188,
+ 168, 8, 74, 36,155,148,188,226, 30,189,100, 58,119, 74,128, 64,
+ 99,203,234, 11,105,215, 94,202, 11, 0,134,195,193,141, 27, 55,
+ 174, 95,191,222, 17, 88, 80,225,169,118, 55, 19, 95,198, 57,214,
+ 53, 95, 19,238, 33,233,208, 5,119,231, 62,253, 73, 0,248,151,
+ 223,251, 63,179,146,136,127,247,198,127, 4,128,119,125,254, 23,
+ 38,243,161,206,202,241, 3,164,103,187,115,221,222, 96,237,242,
+ 213,225,112, 24,199, 49, 0, 40, 69,170,106, 16, 41,162,236,139,
+ 68,138,136,148, 34, 51,148,249, 52,125,239, 12, 69,206, 53,120,
+ 104,207, 65, 76, 83, 45,239,239, 82,222, 5, 42,254,217,233, 1,
+ 82,148, 30, 58,242, 15,166,243,137, 82, 74, 33, 97, 20,141,110,
+ 221,186,121,245,242,149, 22,195,146, 10, 79,183,167, 90, 68, 13,
+ 82,117,193,253,253,159,245, 15,141, 7,193,189,210,245,109,123,
+ 233, 94,121,231,185,235,253,181,239,175,190,150, 93,243,253,213,
+ 215,254,248,173,111,127,246,244,135,223,253,249,207,253,232,203,
+ 95,153,204,199,218,184, 72, 33,122,166, 51,251,202,230,198,198,
+ 205,155,178,178,220,237, 66,171,213, 34, 82,146, 55,104, 69, 17,
+ 177, 90,172, 32,192,178,182, 11,142, 16, 43,196, 67,126,114, 84,
+ 245,113, 2,149, 23,238,126,169, 98, 55,185, 49,166,209, 79,235,
+ 177, 58,179, 71, 4,144,225, 96,120,227,250,141, 75,111,190, 25,
+ 48, 47,169,240, 84,171,219, 34,213,204, 99,251,135,245,151, 63,
+ 113, 22,254,251,223,184,235,239,250,251,255,176,134,231,131,241,
+ 143, 15,255, 60,136,250,253,169,217,206, 84,216,118, 75, 82,127,
+ 231,194, 31,255,204,177,119, 63,243,153, 79, 77, 38,191,114, 23,
+ 9,208, 84,116,178,213,189,124,115,117, 93,235,100,121, 25, 68,
+ 218,157,142, 82,100,139, 38, 80, 68,144, 42,124,100, 69, 13,148,
+ 255,222,179,142,224,150, 86, 29,198,134, 9, 89,147,212, 2,197,
+ 42,182, 53,113,186, 63,151, 99, 47, 42,173,112,148, 94,175,127,
+ 237,234,213, 75,111,190, 25,138,172, 80,176,220,104,117, 84,208,
+ 82,222,156,227, 67, 32,216,183,126,235,119,158,124,233,163,229,
+ 235,127,244,229, 63, 26,247, 45,111,124,253, 47, 42, 75,243,239,
+ 92,186,252,182,135,247,111,139,165, 12, 14, 21,187, 0, 0,174,
+ 254,213,247,159,253,204,207,125,225,236,207,102, 37,169, 71, 59,
+ 11,255,248,185,207, 79,135,157, 81, 60,185,139, 42, 28,132,209,
+ 98,216, 20,128, 43,171,119,214,163, 72,152, 89,164, 59,213, 13,
+ 84, 0, 0, 41,191, 76,187, 29,174,230, 87,198,176, 42, 9,230,
+ 130,172,234, 49,154,100,148, 97,197,231,101,241, 85,170,243, 42,
+ 240,171,162,196,222,100, 94,128,200,204, 59, 59,219,151,223,186,
+ 124,245,202,149,166,200, 18, 5,203,141,246, 66,216,104,146,202,
+ 170,237, 31,154,229,126,227,207,254,226,110,167,194,123,183,215,
+ 190,246, 47,126,243,145,176,152,147,161,191, 30,254,248,241, 31,
+ 254,209,147, 31,255,216, 63,120,246,179, 95,189,252,237,157,120,
+ 240,133,179, 63,251, 15,158,253, 44, 0,108,175,174,126,251,127,
+ 253,221, 9, 79,117,204,194, 60, 32, 90, 12,155, 45,162, 55,182,
+ 118, 86,227,183,244,137, 19, 73,146,204,204, 76, 55, 26, 77, 36,
+ 5, 25,187,200,214,231,131,219,132, 97, 44,191,252,202,207,125,
+ 185, 70,153, 28, 88,221, 27,191, 42,244, 87,101,177, 42, 34, 64,
+ 156, 36, 27,119, 54,222,186,244,230,237, 91,183, 91, 44, 75, 42,
+ 60,222,234, 76,169,176, 69,212, 32, 10,168,142,189,238, 67,114,
+ 21,186,161, 76,146,254,146,251,190,193, 3,245,143,189,254,143,
+ 191,252,149,247,127,233,239,252,250,135,254,203,163,157,133,233,
+ 176, 51,234,247,127,252,229,175, 92,248,234,215, 14,129, 41, 50,
+ 8, 3, 0,162, 41, 8,207,117,103, 95,237,109,174, 94,124,115,
+ 116,236,104, 20,141,230,231,231,219,237, 14,145, 2,112,186, 29,
+ 82,169,160, 2,202, 65,216, 56,253, 5, 19, 61, 3,137,123,127,
+ 205,181,145, 88,236, 68,232,237,217,232,252, 47,218, 71, 16, 25,
+ 12,134,183,111,223,186,244,230,155,189,237,157, 14,203, 98, 26,
+ 216,171, 38,169,166,129, 87,189,189,246,225,179,143,135,179,254,
+ 235,194, 87,191,246,196,199, 63,246,244,233, 83, 70,132,127,231,
+ 247,255, 32, 62, 84,203,241,201,244,101, 39, 2,128,115, 83,179,
+ 175,247,182,174,191,249, 86,124,100, 57,142,226,185,249,249,169,
+ 233,169, 70, 24, 34, 81, 65,115, 21, 83, 48,247, 2,184, 77,103,
+ 202, 8, 59, 92, 17, 24, 86,102, 96, 99, 54, 13, 42, 34,172, 64,
+ 48, 0,208, 73,178,189,189,125,245,234,213,183, 46, 93, 34,150,
+ 46,203, 82,208, 56,213,234, 54,149, 74,109,163,129, 87,205,174,
+ 67, 56,130,201,124, 97,222,115,252,233,191,248,205,249,211,167,
+ 122,171,171,189,219,107,135,235,136, 99,134, 48, 0, 36, 66,129,
+ 167,187, 51,221,209,224,250,237,181,213,193, 96, 48,232,207,204,
+ 204,206, 47, 44,116,187, 29,149, 38, 98, 57,196,242,126, 88,246,
+ 114, 97, 73, 13,120,123,110, 23, 58,210, 28,166, 99, 84,104,117,
+ 61,110,199,179, 18,194, 60, 33,198,204,131,193,224,246,237, 91,
+ 151,223,186,188,185,185,209,100,153, 5,181,216,108,174, 52, 90,
+ 70,118,133,182,212,171, 86, 94,135, 50,253, 58,188,235, 31,227,
+ 94,255, 80,175,150, 48, 70,210, 20,101, 34,225,137, 86,103, 46,
+ 104,188,217,223, 89,235, 95,237,207,110,247,251,189,249,133,133,
+ 217,217,217, 86,171, 77, 68,214, 28,238, 14,175, 92,133,237, 41,
+ 190,100,242,142,198,216,235,156,222,253,229,142,208, 30,194,156,
+ 6, 95,194, 50, 26,141, 54, 54,238, 92,189,114,245,218,181,171,
+ 129, 64,151,101, 65,133,199, 90,157,174, 10,154,164, 26, 68, 33,
+ 146,217, 24,173,174, 83,125,176,196,122,152,207,174, 96, 47,114,
+ 202, 94, 87,214,227,126, 78, 90, 84,102, 67, 14, 32, 10,194,103,
+ 187,179,215, 71,253, 27,235,155,235,189,254,206,246,206,157,153,
+ 233,133,133,133,153,153,217, 86,187,165, 72, 33,161,167,194,188,
+ 10,124,103, 73,115,177,145,233, 97, 61, 58, 94,183,236,194,230,
+ 103, 99,151,107, 3,179,140,134,195,205,205,205, 27,215,111, 92,
+ 187,118, 53,137,147, 54,203, 52,170,197,102,218, 85,162,129,166,
+ 194, 30, 21, 98, 93,100,255,200,250,199, 9,209,135,143, 3,194,
+ 40, 61, 3,133, 16, 78,180,186, 43,205,214, 27,253,157, 27, 55,
+ 110, 14, 55, 55, 55,239,108, 76,207,204,204,205,207,205,206,206,
+ 118, 58,157, 48,108, 16,102,114,204,239,242,231,144,171,132, 45,
+ 57, 44, 15, 23,238,170,191,220,173,152, 10,123, 9,129, 72,156,
+ 36,131,254, 96, 99, 99,227,246,173, 91, 55,110, 92,215,113, 18,
+ 178, 76,177, 44,134,141, 19,173,110,131,168, 73, 20,162, 10, 9,
+ 157,253,132,106,120, 61, 32,213,133,135,145, 95,245,120, 64, 8,
+ 51,109, 8, 17, 8, 73,148,224,211,221,153, 19,186,115,101,216,
+ 187,121,123,117,117,107,107,237,246,237,238,244,244,236,220,236,
+ 236,236,220,212, 84,183,213,110,135, 65,136, 10, 1,160,106, 17,
+ 164,159,122,201, 33, 63, 52, 30,200,138,213,247, 34,146, 36,201,
+ 112, 56,236,237,236,172,223, 89,191,125,235,214,250,250, 58, 9,
+ 4, 44, 45,150,197,176,177,210,105,119, 72,153,126, 56,153, 97,
+ 36,179,250,177,134,215,161,140,188,238,155, 95,181,234, 58, 16,
+ 21,102,119,253, 32, 20, 18, 84,136, 79,119,102, 78,104,125,109,
+ 212, 95,219,218,217,233,245,183, 86, 87,175,181, 91,221,110,119,
+ 118,110,110,122,122,166,211,105, 55,155,173, 70,163, 17, 4, 1,
+ 169,180,197,113,105,237,208,161,218,133, 24,171,240,229,171, 48,
+ 179,163,109,146, 36,113, 28,141, 70,163,126,127,176,185,177,177,
+ 182,182,182,190,190,198,204, 1, 75, 91,164, 37, 56, 27, 54,150,
+ 27,173,142,197, 86, 96,155, 17,214,178,235,225,162,236,192,159,
+ 112, 65,141,173, 73, 19, 98,102,239, 15, 5,164, 20, 6, 72, 29,
+ 53,125, 70,166, 86,163,225,237,104,184, 57,220,220,218,218,185,
+ 115,243, 54, 52,194,102,179,217,237,118,167,166,166, 58,221, 78,
+ 179,217, 10,195, 48, 8, 2, 21, 40,183, 14,224,145,200,191,192,
+ 52,147,213, 90, 39, 73, 18,199,241,112, 56,232,247,122,219,219,
+ 59,219,219, 91,189, 94, 15, 0, 2,150,134, 64,192, 50,165,130,
+ 249, 70, 99,193,238,123, 22, 34, 6, 72,138, 48, 0, 36,187,244,
+ 177,150, 93, 15, 95,143, 29,220,115,176,246,143,147,103,152, 0,
+ 76, 34, 70, 32,154, 36, 0, 12, 68,142,183, 58, 43,141,214,136,
+ 121, 53, 30,110,196,209,230, 78, 47,233, 15,214, 55, 54,110, 3,
+ 50, 2, 40, 10,131,176,209,108,132, 97,104,230, 43, 31,177,193,
+ 204, 81, 20,141,134,163, 56,137, 1,128, 4, 72,128, 64,218, 44,
+ 74,100, 90,133, 51, 97, 56, 23, 54,155, 68, 1, 82,128,104,138,
+ 233,205,214, 65, 42,171,167,168,201,245,246, 57,202, 3, 42,226,
+ 169,249, 53,177, 66, 44,111,168,170, 0, 24, 69, 35, 53, 72, 58,
+ 74,157,104,118, 18,145,141, 36,218, 74,162,190,214, 67, 78,162,
+ 36,214, 81,146,244, 7, 35,194, 71,248,176, 4, 44, 1,128, 18,
+ 9,145, 90, 74,181, 72, 77, 55,194,153, 48, 84,144,210, 74, 33,
+ 170, 44,228,202, 39, 70,108,234, 95, 63,183, 38, 0,100, 19,197,
+ 175,218, 83, 30,104, 16,148, 26, 30, 66, 96, 65,133,194, 34, 12,
+ 200, 2, 90,164, 69,106,185,209, 98, 49, 87,202,102, 18,139,200,
+ 182,142, 69, 30,205, 7, 6, 1,166,154, 1, 2, 78, 7, 33, 1,
+ 80, 74, 40, 36, 68, 83, 61,175, 16, 41, 13, 16, 17, 33,219,244,
+ 172, 38,215,193,160, 8, 39,130, 14,181,254, 58, 4, 20, 3, 0,
+ 101, 86, 28,153, 0, 27,129, 69, 24, 64, 68, 24,132, 5, 4,164,
+ 69,129,128,172, 64, 91,108, 5,190, 60,114,135, 34, 93,162,109,
+ 55, 70, 49,239, 9,210,110,170,100,191, 84, 11,174, 73,101,222,
+ 131,127, 74, 22,249, 37, 50,182,114,187,126, 54, 76,134, 28, 67,
+ 1, 81,136,166, 21,190, 0,176,221, 14,209, 33,151, 60,162,199,
+ 1,125,138,121,204, 2, 39,244,175,159,171,147,233, 29, 31,248,
+ 51, 51, 40,192,107, 63, 17,103,253,228,120, 91, 41,102, 66,177,
+ 244,129, 18, 0,195, 50,128, 20,103,143,170,177,119,254,124,183,
+ 138,181, 54,137, 19, 77, 44,187, 73,231, 65, 61, 33, 3, 31, 94,
+ 102,171, 64,244,183, 63, 78,191, 92, 63, 36,147,168,200,204,131,
+ 147,203,142, 67, 92, 50,113, 87,134,186, 6,214,225, 1,153, 28,
+ 92, 21, 69,224, 3,211,228,114,226,236, 73, 47,187,194, 11,235,
+ 8,127,162,180, 73,173, 68,234, 49, 9,186,171,156,192,102, 42,
+ 232,193,242, 34,112, 49,201,108,186,229,121, 78,181, 62, 25,234,
+ 81,143,122,220,181,115,180, 32,203,152,117, 16, 22, 46,175,117,
+ 20,246,154, 20,131,179,119,106, 22, 59, 32,212, 76,171, 71, 61,
+ 234,177, 47,136, 9,216,153, 37,176, 93, 56, 15,206, 63, 10, 51,
+ 3, 8,160, 32,152, 85,102,192, 89,111, 22,169,246, 44,133,253,
+ 234,235, 81,143,122,212,220, 74, 53, 87,222,174,206, 82,236, 32,
+ 231, 31,153, 89, 16,205,123, 1,180,173,138, 57,235,204,143,158,
+ 244, 50,248,170, 83,253,122,212,163, 30, 46,188, 50,255,230,188,
+ 25,156,129,136, 45,121, 57, 16,126, 49,128,144, 48, 18, 1, 10,
+ 164,149, 69, 34,130,144,206, 75,154,173, 16,176, 54,144,245,168,
+ 71, 61, 60, 47,230,233, 47,112,153,101,183,157, 49, 31,130,217,
+ 233, 7, 24, 68, 57,252,210, 90,139,104, 1, 66, 96, 83, 98,196,
+ 146,237,204,181, 11,179,208, 78, 89,214,163, 30,245,120, 60,217,
+ 133, 89, 57, 34,128, 0, 48, 56,204, 2, 96, 1, 6, 97, 16, 1,
+ 8,130, 7,185,230, 39,255, 89, 90,107,101, 82, 47, 20, 54,101,
+ 205, 44, 34, 12,204,238,125, 69,216, 27,157, 53,203,234, 81,143,
+ 71, 87, 99,237,246, 37,199, 48,166,204, 50,235,115,249, 0,138,
+ 39,114,126, 5, 65,192, 73,162, 17, 53, 49, 41, 69, 72, 8, 72,
+ 34,162, 89, 68,128, 5,236,186, 13,211,172, 55, 11,239,235, 2,
+ 176,122,212,227,113, 24,222,146,109,244,187, 75,230,251,214, 74,
+ 182, 73, 60,219,205,151, 83,132,137, 48,136,136,184,253,157,112,
+ 95,120,220, 7,191,186,221,238,109, 69, 20, 37, 9, 9,177,144,
+ 217, 71, 93, 0,152,133,217, 20,120, 91,120,165,157,123,177,230,
+ 86, 61,234,241, 56, 43, 50, 44, 80, 71, 0,128,157,169, 70, 6,
+ 48,189, 82, 44,194,128, 27, 97, 24,132, 15, 80,251,165,252,154,
+ 158,158,214, 0, 73, 18, 19, 42,173, 56,221, 74, 29, 32,181,177,
+ 105, 33, 5, 80,186, 83,149,160,160, 93,181, 98, 35,253, 26,103,
+ 245,168,199, 99, 9, 49,244,205, 99, 70, 43, 45,162, 93,241, 5,
+ 2, 68,141, 70,227,222,221,105,233, 75, 41,191,230,102,231,226,
+ 70,160, 54, 98, 34, 77, 28, 16,165, 18, 12, 69,140,254, 2, 16,
+ 115, 79,209,218, 70,187,134,214,172,155,172, 35,252,122,212,227,
+ 241, 32,214, 24,164, 8,100,211,141,194, 14,185,180,136,150,212,
+ 78, 74, 24, 84,240,171, 84, 80,129, 99, 63,197,106,253, 53, 53,
+ 61,165, 91,205, 36,142, 21, 41, 98, 33, 98, 84, 10,140, 6,147,
+ 180,144, 21,237,102,121,229, 55, 41,253,190,154,101,245,168,199,
+ 35,134,173, 2,114,202, 32, 51,158, 81, 11, 24,120,105,145, 68,
+ 88,131, 65, 24, 8, 0, 4, 65, 24,134,251,150, 89,123,135, 98,
+ 105,150,214, 8, 27,225,194, 92, 18,199,113, 20,197, 81,148,196,
+ 145,142, 99,157, 36, 58,209,172, 89,132, 17, 4,115,132,165, 73,
+ 24,250,197,172,117, 81, 88, 61,234,241,184, 81, 45,143,238,197,
+ 153,109, 76,201,197,218,234, 47,227,207,168,219, 81, 74,193,190,
+ 227,122,172,248, 77, 37,126, 33, 0, 18,174, 60,117, 54, 22,142,
+ 227, 40,137,226, 56,138,147, 40,214,113,194, 58,225, 36, 17,205,
+ 194,105, 9, 24, 98,190, 77,123,250,134, 21,248,170, 89, 86,143,
+ 122, 60,210,204,242, 58,157,100,105, 61, 67,238, 25, 19, 54, 18,
+ 44,173,252, 2,162,246,252, 44,238,183,254,126,215, 30,186,152,
+ 241,203, 94, 58,117,250,180,158,234, 70,163, 40,138, 70,142, 10,
+ 75, 88,107, 97, 78, 75, 40,208,238,137,144,153, 71,116,100,100,
+ 45,193,234, 81,143, 71,218, 60, 98, 94,176, 90, 60,221,179,228,
+ 62, 17, 78,172,121, 76,132,181,112,154,139, 53, 27,211, 83,211,
+ 123,253,112,191, 52,191, 80,161, 81,226, 75, 94,191,186,178,178,
+ 194,179,211,124,245, 58,105, 69,138, 73, 49,114, 0,138, 21,145,
+ 217,232, 24, 68, 80,196, 52, 29,103, 49, 93,198, 37,205,242,209,
+ 244, 0,245, 86,115,215, 41, 88, 61,234,241, 72,210, 12, 29,220,
+ 152, 79, 24,192, 77,235, 13,185, 18, 35,190,196, 54,162,104, 53,
+ 58,157,182,255, 51, 92, 58,225,238,198,173,242, 43,121, 45, 89,
+ 171,213,234,156, 61, 99,126,101,172,117,156, 36,113, 20, 37, 81,
+ 164,227,152,181,137,225,172,133,180,155,187,228, 22,178,150, 96,
+ 245,168,199, 99, 32,190,188, 62, 14,102,201,144,164,123, 47,112,
+ 78, 46, 73, 68, 98, 54, 8,227,172,255, 4,205, 76, 43, 21,148,
+ 225,229,168, 47,251,179, 17, 11,147, 3,227,150,253, 80, 14, 62,
+ 196,167,223,251, 30,152,158, 74,216,220, 3, 78, 68, 18,102,157,
+ 104, 29, 39,156,104, 96, 6,145,172,120,130,192,108,250,146, 89,
+ 72,196,146,103,173, 89, 86,143,122, 60,122, 44, 67,159, 47, 38,
+ 185,215, 32,134, 92,137,112,194, 28,139,196,146, 47,219,134, 70,
+ 56,187,184, 88, 1,174,114,241, 4, 66,105, 94, 16,171,191,238,
+ 234, 47, 4,124,234,169,167,240,137,147, 73, 46,255,216, 58, 88,
+ 97, 97,102, 6,177,155,190,228,209,125,118, 49, 79,196,246, 84,
+ 125,245,168, 71, 61, 14,159,248,242,120,147,159,217,102, 19,172,
+ 204, 54,198,204,177,112, 34,204, 22, 95, 12,160,167,186,115,179,
+ 179,222, 26, 36,180, 90, 7, 51, 27,234,125, 25,178,127,232,252,
+ 106,244,238, 26,185,182,175,213,108, 45,189,235,188, 14, 40, 17,
+ 142,141, 2,100, 73, 68,180, 48,103,205, 19, 17, 16,128, 82,253,
+ 229, 75, 48,103, 23, 43,172, 17, 86,143,122, 60, 98, 44,195,138,
+ 24,157,157, 82,175,132, 83,120,197,204, 49,179,105, 4,198, 0,
+ 64,212, 88,152, 83,165,206, 19, 25,194, 48,199,147,155,170,185,
+ 248,116,172,157,131,177,192,197, 12, 34,190,247,131, 31,184,241,
+ 31,191, 17, 95,189, 73,192, 68, 64,166,153, 33, 16, 0,187,141,
+ 199,156,153, 71, 68, 1, 2,144, 52,228, 79,247,189, 23,216,101,
+ 77, 81, 29,235,215,163, 30,147, 47,185, 42,196,151,167,155,108,
+ 147,249,212, 57, 26,114, 9, 71,204,177,176,216, 80, 95, 68,184,
+ 211, 58,178,178,226, 57,208,202, 95,107, 9,134, 69, 90, 90,187,
+ 138,197,219,146,239,107, 97,121,105,169,243,238,243,137,152,187,
+ 34, 6,165,214, 66, 10, 11,128,157,112,204, 37, 24, 98,254,169,
+ 239, 34,235, 32,172, 30,245, 56,108,163,122,227, 30,183, 82, 42,
+ 133,151, 0,167,240, 28,110,250, 69, 0, 0, 32, 0, 73, 68, 65,
+ 84,226, 68, 56, 18,142, 56,133,151,206,186, 80,152, 31,183, 48,
+ 215,110,183,209,227, 31,230, 18, 12,243,192, 62,219,143, 56,155,
+ 221,116,234,228,157,249,131,188,254,171,144,135, 17,125,240,227,
+ 47,209,241, 35,153, 8,244, 16,102,155,144,101, 8, 36, 4, 50,
+ 63, 5, 60, 23,233,108,137, 92, 35,172, 30,245, 56,220,122, 12,
+ 243,170, 79,187,229,104, 90,179,154,214,169, 26, 86, 24,132, 37,
+ 204, 98, 59,127,137, 8,119,219, 43,199,143,123, 85,171, 41,193,
+ 208,243,143, 22, 84, 46,187,114,114,184,113, 24,228,121, 24,101,
+ 19, 9,104,239,228,177, 99,199,186,239,121,103,194, 98,212, 96,
+ 108,167, 18, 44,194, 50,251,151,146,147,208,190,153,203, 37,132,
+ 65,149, 10,173, 71, 61,234, 49,177,254, 17,199,157,179,232,194,
+ 11, 76,181,106,156,139, 47, 29,177,182,133,248,144, 54, 62, 93,
+ 152,235,118,187, 0,133, 94, 21,224, 83, 36,157, 14,116, 6,128,
+ 183,218,199,185, 91,206,207, 32, 71,197,217,108,158,232, 99,159,
+ 252, 27,116,246, 84, 33,141, 51, 8, 99,225,116, 59, 34,204,193,
+ 156, 27,201,244, 55,102,156, 70,172,206,242,107,132,213,163, 30,
+ 147, 30,128, 97,201, 57,230, 38, 83,192,100,246, 49,167,228, 26,
+ 177,142,152, 51, 93,102, 42,194,146,153,169, 99,167, 78,186, 66,
+ 38,229,131,131, 41,207,174,121,235, 18, 29,118,229, 30, 19,115,
+ 177,229,215, 79,228, 42,110, 97,113,241,232, 7, 95,208,173,134,
+ 129, 87, 36,218, 32,204,148,134,153, 44,204,248,200,108, 45,183,
+ 73,190, 8,211,169, 73,196, 61, 17, 86,143,122,212, 99,226,216,
+ 133, 21,159,123,147,129,105,181, 4,136,182,202, 38, 98, 61, 98,
+ 142,152,117,218,121,213, 68, 99, 2,129,106,172, 44,181,154, 45,
+ 112,122,213, 20,126,137,195,168,140,104, 14,220,208, 7,104,138,
+ 149,252,115,207,237,101,132, 35,196, 15,191,248, 98,112,238,169,
+ 76,127,165, 8, 75,203,106,197, 24,201, 84,194, 25,102,229, 22,
+ 50,189, 6,205,123, 79,222,185, 8,171, 57, 86,143,122, 76, 46,
+ 188,156,249, 64,171,185,108,157, 61, 91,120, 69,194, 35,214,230,
+ 45,157,115,148, 84,127, 49, 64, 50, 55,115,244,248,113,116, 3,
+ 123, 39,167, 47,193,202, 14, 42, 94,145,219,200, 66,253,127,154,
+ 127,185,211,133,246,150,173, 86,235,249,159,251, 36, 44, 45, 68,
+ 204,145, 69, 88,196, 58,118,139, 90,157,169,138,180, 40,204,153,
+ 136,204, 16, 70, 99,227,252, 26, 97,245,168,199,196,217, 70, 24,
+ 51,237, 38, 86,124,153,229, 65,145,240,136,205, 91,234, 28,221,
+ 110,247,210,110, 46,158, 62, 25, 40, 5,158,214, 2,112,121,180,
+ 207,145,137, 46,155,226,103,171,199,201,129,153,123, 35, 68,196,
+ 39,159,124,114,233, 99, 31,212,205, 70, 54,179, 16,231,197,181,
+ 162,109, 81, 69,150,134,165,130,203,254,202, 12, 97, 8, 99,103,
+ 36,235,229,146,245,168,199,100,192,171, 88,246, 85,168,118, 55,
+ 193,150, 89,158,157,195, 75,235, 33,235,145,137,189,236,182, 29,
+ 90, 68, 2, 69,199,142,204,206,206,129, 95, 30, 1, 78, 56,239,
+ 165, 96,169,240,162, 42,249,149,171, 47,116,219, 94, 32, 64, 90,
+ 63,225,174, 4,114,176, 72,164, 94,252,196, 39,154,239,125,103,
+ 134,173,136,109,137,135,173,242,208,226, 86, 84, 24,132,129,231,
+ 37,193, 79,225,176, 76,250, 26, 97,245,168,199,164,195,203,246,
+ 150, 72, 69,204,136,181,133,151, 22,200,154, 23,166,251,119, 36,
+ 203, 11, 39, 78,157,242, 23,126, 99,217, 60,186,236, 34, 7, 95,
+ 84, 69, 49, 23, 34,217, 79,162,188, 2,195, 73,253,179, 31, 25,
+ 134,225,139,127,243,231,233,201,211, 57,188,204, 5,209,134, 98,
+ 153,145, 20, 71, 82, 17, 88, 33,102, 17,230, 23, 85, 96, 21,194,
+ 106,138,213,163, 30,147, 3,175,140, 92,249, 6, 28, 90, 36, 22,
+ 137, 82,120,113, 21,188,132, 69,146,185,233, 19, 79, 60,161,136,
+ 60,217, 85, 40, 85,117,194, 46,151, 88, 68, 6,101,132, 68,213,
+ 34,204, 89, 12,105,212,146, 87,129,225, 40, 48, 66, 68, 34,154,
+ 155,159,127,238,111,126, 74,150, 23,173,139,212, 17,167,240,138,
+ 36,243,146, 98,215,106,218,138, 10, 27,234, 99,246,222, 44,252,
+ 118,155,184,214, 94,178, 30,245,152, 48,120,185,121,151, 41,162,
+ 79,201,197, 98,167, 26,245,144, 51,229, 37, 34,121,231, 85, 45,
+ 194,157,246,194,147, 79, 52, 91, 45,112, 48,227, 34,204, 82, 10,
+ 115, 66, 17, 17,146, 25,233,101,123, 53,209,152, 48,223, 82,140,
+ 48,239,101,239,231,255,206, 15,127,242,201,179, 39, 62,241, 34,
+ 119, 90,110,149,173, 41,250,200,234, 42,180,216,245,154,146,247,
+ 8, 35, 64,133,102, 70,210, 80, 12, 76,129, 43,213, 94,178, 30,
+ 245,152, 84,120,217,166, 55, 32, 0,102,247, 13, 83,164, 58, 98,
+ 30, 90,120, 13, 89, 51,164,116,203, 98,123, 9,131,214,153,147,
+ 115,115,115,249, 58, 33, 39,246, 2,207,219, 17,165,174,145,178,
+ 208, 43, 3, 24,122,228, 34,215, 76,102,245,247,230, 7, 6,224,
+ 236, 37, 82, 18,117,118, 40,122,239,123,222,187,125,103, 99,253,
+ 27,223,150,193,144, 25, 4,133, 73,152, 73, 16,152, 64, 0, 25,
+ 72, 1, 40,244,148, 20, 34,128, 0,129, 89,219,141,128, 32, 2,
+ 156,173,158,242,247, 93,203, 66, 52,169, 23,120,215,163, 30, 15,
+ 11, 94, 99, 55, 67,179,150, 80,219,181,217,182, 78,149, 71,162,
+ 83,204, 57,182,145,195,128, 78, 29, 63,122,228,136, 83, 40, 95,
+ 168, 85, 45, 70, 94,228, 48,134, 28, 5,150,125, 76,111, 84, 57,
+ 27, 9,128, 0,193,152, 64,141, 28,145, 71, 68, 20, 4,234,195,
+ 31,251,232, 55,146,120,227, 91,223,145,225, 72, 0,153, 65, 16,
+ 152,132, 89, 4, 41, 32, 16, 64, 17,195, 62,191, 72, 67,132, 0,
+ 25,133, 4, 5, 5, 4, 5, 68, 16, 57,157,185, 68, 0,179,137,
+ 36, 56, 29,122,160,166, 88, 61,234,113, 48,228,130, 93,226,102,
+ 177, 93, 37,108, 51,123,187, 66,136,217, 36, 95,177,176, 57, 57,
+ 61,120, 41, 5, 39,142,158, 60,125, 58, 83, 93,110, 97,189, 23,
+ 120, 89,174,144, 21, 92, 62,195,148,197, 87,102, 49,115,129,230,
+ 152, 71, 39,191,183, 68,243, 44,164, 5, 33,102, 63, 63, 8,195,
+ 15,126,244,163,205,103,223,145, 32,102,117,183,246,175, 74, 47,
+ 251,113, 88,102,129, 49,171, 14,203,214, 75, 90, 47,233, 76, 41,
+ 64, 33, 17,195,218, 76,214,163, 30, 7, 32,187, 42,108, 99,190,
+ 117,118,222,207, 75, 76, 82, 52, 98, 30,106, 61,212,122,200, 58,
+ 102,150, 18,188,132,144, 87, 22, 79,157, 57, 67, 78,145,106,121,
+ 97, 99,166,166,200, 85, 94, 42, 3,151,242, 62,181, 34, 44,151,
+ 82,133, 90, 10, 4, 68,171,191, 42,204, 35,250,226, 78, 41, 69,
+ 212, 8,195,143,124,234,147,223, 84, 52,248,241, 43, 60,140, 24,
+ 144, 25, 24,133, 81, 24,136, 81, 24, 41, 64, 96, 68,149,229, 92,
+ 89,120,103,182, 80, 50, 91,122, 3, 18,130, 8, 8,138, 0,178,
+ 8,154, 13,190,125, 33,102, 13,104, 45,196,234, 81,143, 7, 28,
+ 120,129,179, 30,200,216, 29,179, 71,163,215,143, 80, 36, 74,157,
+ 163, 54,203,131,202,183,228, 48,224,229,133,211, 79, 61, 69, 68,
+ 246,148,205, 49, 89,172,145,168, 48,140,164,204, 40, 73, 48, 7,
+ 96, 78, 2,150,247,168, 71, 0, 8,198,205,105, 82, 46,193,188,
+ 95,212,106,182, 62,242,137, 79,252,101,163,177,253,157, 31,202,
+ 112,100,152,101, 92, 36, 35,105, 4, 38, 9,128, 24, 80, 1, 42,
+ 48,202, 43,131, 81,106, 24, 9, 68, 4, 5,205,174,146, 66,102,
+ 247, 34,144,130,119,172,237,100, 61,234,113, 64,240,114,201, 5,
+ 217,186, 31,103, 3, 33,179, 88, 48, 22, 30, 25,217,149,222, 94,
+ 76, 45, 88, 90,109, 31, 6,120,242,216,153,211,167,137,168,184,
+ 180,198,197,138, 21, 80,101,116, 21, 57, 70,202,151, 96, 89, 97,
+ 24, 21,166, 31,141, 46, 10, 10, 75,145, 8,137,137,125,237,229,
+ 252, 92,165,148,162, 70, 24,190,255, 67, 31,250, 43,129,237,239,
+ 254,128,135, 35, 1, 96, 70, 70,208, 86,136,105,148, 0, 41, 64,
+ 100, 68, 5,233,190,221, 8,130,222,159, 39,104, 18,125,200,133,
+ 152,164, 91, 45,213, 20,171, 71, 61, 14, 60,240, 42,144,139, 1,
+ 116,186,123, 16,199,156,246, 46, 53, 75, 6,115,143,153, 46,111,
+ 4,177,129,253,201,211,167, 41,239,137,143,110,145,189, 27,164,
+ 23,243,121,165, 12,188, 84, 62,204,149,164,200,190,243, 44,100,
+ 54, 13,153,215,175, 34, 66, 96,141, 93,177,144, 63,207,213, 20,
+ 145, 38, 82,100,127,133, 82, 74, 5, 65,248,190, 15,188,255, 39,
+ 157,246,173,191,250, 30,223,217, 10, 16, 83, 33,134,162, 33,189,
+ 192, 72, 10, 49, 64, 82, 89,143, 67,244,118,142, 19, 4, 18, 17,
+ 192, 28, 94,233, 5, 91,134, 81, 53, 59, 89, 83,172, 30,245,184,
+ 31,217,229,122, 64,119,146,209,172, 8,204, 91,254,177,142,132,
+ 217, 58, 35,200,225, 37, 44,160, 59,173,246,153, 83, 71,143, 28,
+ 193, 50,188,192, 53,143, 69,207,168,236,123,229,193, 43, 35,152,
+ 50, 20, 51,183, 67,155,192,251,141,193,242,245,224,129, 69,151,
+ 228,232,226, 84,130, 57,248, 74, 37,152,202, 62, 6, 42,228,240,
+ 217,103,159,237,116, 58,111,124,251, 47,229,198,109, 6,100,128,
+ 44, 17,211, 72, 26, 37, 32, 98, 16, 5,100,188,164,161,152,223,
+ 65,209, 4, 92,230, 14,165,118, 50,149,134,134, 98,104, 55,153,
+ 171, 41, 86,143,122,220,151,236, 18, 7, 67,185,230,242,247,109,
+ 116, 90,254, 9,139,243,157, 22,121,194, 0,201,236,244,194,217,
+ 39,230,230,102,157,173,206, 16, 43,245, 87, 94,199,224,103,233,
+ 46,181,220, 79, 45,189, 84,209, 64,146,151,129, 89, 33,100,242,
+ 123,241,188, 37, 33,113,209,165,234, 76,130, 25,253,165, 20, 43,
+ 21, 4,193,201,147, 39, 59,157,206,143,191,245,109,190,116,149,
+ 153, 25, 81, 91,120,105, 36, 13,162,145, 2,148, 0,145,145,200,
+ 82, 12, 11,221,250, 77, 89, 5, 32,185, 46,178, 76, 49, 7, 89,
+ 146,191,176, 72,141,177,122,212,163, 10, 94,233, 43,126, 25, 67,
+ 46,185, 50,207,152,216,192, 43,102,214,246,155,140,252,202, 58,
+ 79, 48, 97,178, 52,127,252,236, 89,211,207,222,135,151, 95,170,
+ 154,151,111,149, 51, 46, 85, 64,152,131, 47,195,153, 98, 77, 24,
+ 146, 87, 31,145,201,152,192, 82,194,199,166, 65, 88,174,192,216,
+ 252,116,118,224,149,129,108,110,110,238,133,151,126,230, 7,237,
+ 239,196, 63,189,200, 81,204,146,122, 73,141,162,193,224, 12, 53,
+ 146,114, 40, 70, 32,100, 52,159, 13,197, 76,221,106, 58,225, 56,
+ 142, 98,102, 26,211,206, 81,218, 7,198, 87,104,245,168, 71, 61,
+ 252, 61,190, 36,205,145,109,110,229,147,203,120, 70, 55,243,114,
+ 103,253, 51,217, 37, 0, 58, 12,224,232,242, 19, 79, 60,161,130,
+ 192,219,168, 49,195, 73,161,133,151,165,151,202,216,229, 36, 94,
+ 129,115, 33, 40,249,200,220, 64, 22,234,239,243, 89,205,188,126,
+ 85, 10, 11,136, 8,133, 51, 13,166, 72, 49, 49, 27,126, 25,118,
+ 217,183,128,153, 57, 96,110,181,219,239,251,208, 7, 95, 95, 90,
+ 184,253,227,151,131,181, 13, 6, 52,182,145, 57,151, 99, 10, 73,
+ 35, 42, 20,133,168, 16,149,100,229, 96,198, 59,166, 47, 26,146,
+ 115,220,163, 24,218, 87, 15,176, 20,115,181,152,179,230,180, 6,
+ 89, 61,234,145, 75,175, 98,185,131,237,129,227,206, 51,218, 29,
+ 179,153,197,227, 29, 88,217, 37, 0,201,116,183,123,250,196,202,
+ 242, 10, 22,186, 65,103, 20, 43,212,214,151, 4,151, 59, 2,165,
+ 84, 16,168, 32,112, 8,230,114, 44, 47,162, 64,127,254,177,176,
+ 29, 81,144, 22, 83, 72,158,130, 17,161, 8,146,144, 16, 19, 41,
+ 69,204, 86,130,113,192, 14,187, 20,155,207,130, 32, 96,150, 48,
+ 124,234,236, 83,243,115,243,175,126,239,251,250,202,117,197,172,
+ 80, 52, 98,144,122, 73, 84,233,123, 10, 12,191, 44,194, 8, 16,
+ 65, 40,165, 82, 30,240,167, 91, 73, 26,123, 41, 32, 32,230,243,
+ 244, 50,160, 85,110,149, 32,171, 41, 86,143,199, 28, 91, 0,142,
+ 224, 18, 17,237,151, 71,228,202, 43,237,168,204, 5,225,150,201,
+ 46,227, 25,143, 61,249,100,167,211,129,242, 14,218, 80,220,124,
+ 35,223,208,199, 15,188,200, 85, 91, 65,144, 94, 14,130, 2,190,
+ 40,207,191,148, 93,208,157, 21, 96,248, 27,172, 1, 6,238,214,
+ 106, 88,114,144, 68, 66,164,148, 98,102, 98, 86,204,172,148, 10,
+ 84,192, 86,121, 49,179,176,112,192,166,201,198,252,252,252,123,
+ 62,246,209, 87,254,250,175, 71,175, 95,226, 94,159, 17,217, 81,
+ 94,206,123, 84, 72, 25,194, 20, 34,129,160,141,198,156, 61,222,
+ 82, 24,101, 20,203,221,101,201, 84,186,138, 89,106, 57, 86,143,
+ 199,144, 92,146,151,104, 57,130, 11, 28,217,149, 98, 43, 77,235,
+ 57, 77,190,202, 4,204, 61, 99,171,169,142,173, 60,113,234,148,
+ 82,170, 2, 94,165,192, 62, 95,149,173,138,105,125,174,185, 2,
+ 243, 63,200, 63,122, 14, 50,173,172,200,218, 81, 84,245, 99, 77,
+ 239, 73,224,134,125,174,250, 19, 17, 50,255,172,246, 50, 35, 8,
+ 2,102,163,195, 2, 78, 57,198,129, 4,233,126, 35, 34,173,102,
+ 243, 93,239,126,247,141,229,229, 43, 47,191,162,111,220, 54, 66,
+ 204, 0,203, 85, 97,233,149,144,106, 49, 66,164, 92,142,229, 1,
+ 191,183, 97, 82, 26,122,165,246,220, 53,149, 70,142,165,182,189,
+ 6, 89, 61, 30, 75,181,149,113,135,157, 86,206,185, 91, 4,209,
+ 194, 9,123,179,141,229,200,204,228,245,169,236,154,159, 93, 60,
+ 125,106,110,118,214,219, 10, 49,171, 94, 24, 3,175, 66, 93,189,
+ 107, 24, 29,108,217,207,172, 18, 11,130,192,203,191, 92,255,232,
+ 172, 31,242,118, 2, 49,235,135,210,240, 9, 12, 18,220,121,207,
+ 148, 97,164,136, 36, 35, 88,134, 48, 97, 97, 49, 18,204,192, 43,
+ 72, 59, 95,139,200,209,163, 71,103,103,103, 95,187,112, 97,116,
+ 233, 74,176,211,211,130, 10,197, 72,173, 4, 41,200,225, 69, 42,
+ 179,147, 57,194,192,163, 88,161,211,142,185, 44,104,230,128, 83,
+ 147, 89,131,172, 30,143,153,212, 2,168,192,150,228,216,242,170,
+ 186,204,122, 70, 87,127, 73, 53, 10,211,159,166, 59, 45,117,100,
+ 249,137,147, 39, 85, 16, 20,100, 23,248,219,104, 87,194,203,173,
+ 21,117,224,165, 44,184,220,161, 84,250,193,175,160,200,151,113,
+ 123,240,202, 86, 62,154,187, 18,216,213,134, 89,138,238,210, 11,
+ 81,144,132, 20, 41, 33,118, 8,198, 65, 16, 8, 51, 75, 32, 22,
+ 95,146, 9, 48, 73,149,103,171,213, 62,255,174,119,173, 29, 61,
+ 250,214, 43, 23,240,214,154,138, 99, 37,152, 75, 48,112, 84, 88,
+ 198, 47,176, 90, 12,170, 65,150, 7,245, 70, 67, 10, 74, 26,150,
+ 217,116,204,250,202,253,128,172, 48, 77, 83,143,122, 76, 62,179,
+ 202,216,114,235, 33,210, 38,130,190,230, 42,240, 11,118, 37,151,
+ 40, 74, 22,231, 86, 78,159,158,158,154, 42,182,145,246,225,133,
+ 133,158,129,222, 82,233,188,210,189, 96, 24,131,208,251, 16,248,
+ 240,114,179,251,180,236,190, 80,187,234,136, 47, 0, 8,210,164,
+ 60,149, 96, 14,192,172,139, 20, 17, 81, 66,162, 72, 68,177,100,
+ 176, 98,230,192,124,200,201, 37, 89,105, 92,218, 0, 13,100,113,
+ 113,113,230, 67, 31,188,124,229,202,198,235, 23,245,157, 77,197,
+ 172,173, 97, 84,226,193, 75,153, 2,177,220, 78, 66, 14, 50, 1,
+ 52, 25, 25,102, 51,149,182,120, 76, 28, 81,107,126, 53, 26,105,
+ 182, 55,200, 32,223, 78,184, 6, 89, 61, 14,143,218,114, 23,241,
+ 56,125, 32,116,105,122, 49,213, 95,246, 74, 25,243,163, 83,114,
+ 33, 38, 51, 83,221,227, 71, 79,173,172,152,197,216, 21,158, 49,
+ 211, 92,174,246,202,219, 74, 80, 94, 35,145, 37,244, 70, 96,133,
+ 65, 16,132, 65, 24,250, 20,203,209,166,130, 64,169,128,108,210,
+ 159,215,126,149, 26,175,186,187,186, 5,206,159,226,192, 53,237,
+ 171, 35, 25,194, 20, 41, 33, 17, 37, 98, 61, 99, 16, 4, 30,184,
+ 36, 39,152,109, 37,157, 99,251,204,233,211, 43,203,203,151, 46,
+ 94, 28, 92,187, 17,108,237,104,102, 66, 84, 8, 36,168,144, 40,
+ 229,151,184,113,152,178,157,118,148, 32, 33,160,177,150,198,226,
+ 102, 91, 90,138,215,134, 45,175,189, 40,130,172,194, 90,186, 93,
+ 46,100, 76,189, 95, 61,234, 49, 25,130,107, 55,108,217,221,100,
+ 11,178, 43,189, 38,177,107,128,170,101,151, 33, 23,161,238,118,
+ 194,229,197,211,199,143,135, 97,232,166,205, 99, 60,163,173,245,
+ 42,244,195,113,224,101,125,161, 51, 50,201, 21, 26,140,133,110,
+ 118, 31, 84,184, 71,242, 26,226, 64,161,195,150,229, 23,162, 73,
+ 190,220,134, 93, 64,132, 0, 36, 2, 41,193,148, 40, 33, 17, 35,
+ 194,198, 13,200, 62,184, 7,200,252,241,157, 78,231,233,115,231,
+ 122, 39, 79, 94,122,253,245,232,198,109,181,211,215,166,175,180,
+ 72, 6,172, 28, 94,246,211, 92,130, 33, 42,163,194, 28,156, 33,
+ 0, 66, 74, 52, 41,246,195, 77, 11, 67,140, 57,206, 50, 50,176,
+ 235,195, 51,227,233,227,170,102, 89, 61, 38, 72,112,185,229,163,
+ 92,165,182, 50,102,185,202,203, 37, 26,148,150,110,139,127, 65,
+ 119, 90,184, 56,127,226,228,201,102,179, 9,165,189,117,220, 10,
+ 175,138,181, 65, 88,174,174,183,153, 87,102, 25,195, 48,116, 25,
+ 150,193,203,185,214, 22,130,145, 87,249,133,101, 5,230, 78, 28,
+ 128, 89, 63, 4, 5, 9,230, 6, 97,150, 98, 6, 97, 74, 21,146,
+ 174, 10,205, 85, 65, 46,119, 76, 77, 77, 61,251,220,115,155,167,
+ 54,175, 94,186, 20,221, 90, 85, 59,125, 66,212, 54,182,119,225,
+ 69,227, 66, 49,107, 45,209,128, 12, 28, 81,230, 77, 89,122,123,
+ 169,184, 25, 25,166, 12,243,220, 37,212, 44,171,199,164, 96,171,
+ 156,109, 85,152,196,242,101,183,194,171, 18, 88, 80, 34, 23, 44,
+ 204,173, 28, 63,222,237,116,188,170,208,113,178,203,201,188,104,
+ 156,109,116,224,149,139,172, 48, 27,198, 71,250,240, 82,121, 0,
+ 150, 59,199,194,172, 99,149,248, 2,183,254,190, 32,193, 32, 95,
+ 62, 46, 78, 16,230, 32, 12,202,242, 11,100,252, 73,238,238,165,
+ 52, 55, 55, 55, 61, 61,189,181,181,117,237,210, 91,209,234,186,
+ 234,245,137,153, 16, 82,144, 57,252, 34, 79,136, 65, 33,221, 71,
+ 123,125,198, 50, 91,220,230,177, 12,220,248,223,110,146, 4, 54,
+ 58,203, 86,120,213, 44,171,199, 65, 15,172,164,137,236,109, 18,
+ 199,161,138,237,101, 22,209,105, 10, 63,158,143,230, 61,161,238,
+ 180,113,126,118,229,216,177, 49,228,242,211,174, 66,230,149,245,
+ 115, 46,182, 55, 37,107, 28, 85,230, 19, 51,118, 5,238, 91,224,
+ 41,175,140, 94, 94,236, 85,220,202,182, 66,124,249,249,151,157,
+ 136,116,251, 97, 16,129,233, 25,145, 39,243, 74, 84,154,206,167,
+ 4, 43, 62, 32, 82,129,174,108,227, 54, 68,208, 90,167, 20,155,
+ 157,157,126,238, 93,189, 94,239,218,149, 43,163,155,183,105,167,
+ 79, 90, 27,123,104,202,193, 84,129,101,217,110, 70,185, 16,203,
+ 182,200,205, 68, 89,186,245,145,207, 50,243,203,165,114, 87,116,
+ 183,238,127, 23,150,185,121, 89,197,236, 77,125,106,214,163,138,
+ 86, 48,238,228, 16, 40,119, 4, 76, 75,183, 82, 30,121,241,214,
+ 56,132,177,128,185,176,159, 95, 42,138,116,167, 29, 44, 45, 28,
+ 63,122,180,101,221, 98,217, 48,150,101, 87,117,157, 68, 33,243,
+ 202,164,151, 27,121, 25,120,101,232,242,117,152,101, 87,154,220,
+ 231,225,151,227, 28,193,111,155, 83,248,243,178,250, 85,201, 38,
+ 34, 69,160, 92,225, 65, 68,230, 60, 86,160,188,249,197,172,165,
+ 108,182,227,146, 20,101, 87,174,252,156,163,160,181, 70, 68,208,
+ 122,106,106,234, 29,207, 60, 51, 58,115,230,198,205, 27, 59, 87,
+ 111,192,206,142, 26, 70, 70,100, 37,136,132,144, 7,249, 14,200,
+ 82,198,101,101, 22,246,178,105,171,143,150,101,148,109, 59, 46,
+ 128,254,110,154,224,239, 62, 57,142,101, 96,203,255, 37,127,241,
+ 220, 27,103, 53,209, 30,123, 90,217, 72,214,127, 62,236, 71,106,
+ 165,151, 93, 90,101, 32,203,175, 44, 98,107, 23,253, 0, 0,186,
+ 25,114,167,211, 57,178,188,180,180, 20, 6,193,158,228, 2,187,
+ 78, 58, 87, 94, 68,165,201,198,162,109,244, 74, 84,173,248,114,
+ 254, 59,174, 49,180,177, 87,154,223,147, 82, 94,205,106,185,216,
+ 222,157,118,204,238,120, 80,117,204,109,163,231,244,219,210,198,
+ 214, 41,182, 76,150, 15, 42,223, 37,174,178, 36, 52,207,159,208,
+ 149, 96,238, 65,201,132, 24, 34,182, 90,173,211,167, 78, 39,199,
+ 142,175,175,175,175, 93,187,158,220,217,164,193,144, 88, 19, 98,
+ 82,150, 93, 96,251,235, 23,138,197,108, 58,134, 62,203,208,122,
+ 76,203, 50, 65,191,203,218, 56,150,185,182, 81,242, 70,110,123,
+ 227, 76,188,103, 70, 77,180, 71,155, 86,187,236,229, 35,149,204,
+ 202, 42,182,178,114, 83,183, 98, 62,223, 11,214, 65, 88,134, 45,
+ 115, 97,191,129, 26,162,110, 55, 97,118,122,110,101,101,110,118,
+ 150,148,170,190,211,238, 41, 80, 50,140,224,247,147, 40, 7,246,
+ 148,205, 30,250,202,171,196,175, 84,129, 57,213, 19, 42, 40, 57,
+ 199, 76,219,121, 11,182,177,186,137,108,224,162, 43, 91, 53, 45,
+ 158,139,204,162,176, 84,131,121, 15, 78,126,102,138,247,128,250,
+ 252, 42, 21,113,160,246,133, 88, 54, 86, 86, 86, 22, 23, 23,123,
+ 189,222,173,155, 55,135,171,107,180,181, 67,113,162, 33,163, 82,
+ 78, 49, 85, 84, 97,222,167, 70,130,185, 44, 67,251, 41, 34,144,
+ 100, 96,207,113, 6, 14,206,178, 99,229,224,204,101, 25, 56,171,
+ 196,115,156, 85,153,205,154,104,143,158,176,218, 51,130,207,236,
+ 97,133,206,178, 43, 19,129,211,205,171,203, 83,138, 69,231,152,
+ 239,244, 83, 84, 90, 99,239, 12,135,129,158,234, 52,230,231,150,
+ 151,151,219,237,118,113,253,207,238,228,170, 90,146, 93,222,125,
+ 99, 23,120, 21,249, 21,230, 73, 88, 81,124,121,173,191,138,229,
+ 170, 57, 69,161, 66,124,149,244,151, 83, 75, 33,146,183,225, 7,
+ 48, 26,140,211, 44,204, 60, 56,169,143,180,150, 81,198, 88,232,
+ 221,118,176, 76, 7, 51,103, 20, 99,102, 68,156,158,158,158,154,
+ 154,138, 79,159,222,216,216, 88,191,117, 43, 89,223,160,193,144,
+ 18,109,154, 85,160, 64,133,236, 74,185, 6, 25,206,208, 94, 46,
+ 216,201, 20, 94, 98, 5,154, 43,205, 0, 48, 93, 88,153,215,249,
+ 150, 15, 91,182,172,220,193, 89,246,188,245,112,230, 18, 13,198,
+ 90,206, 7, 10, 53,169, 73,115, 32,156, 66, 40, 60,172, 69,102,
+ 185,203,167,211, 60,203,210,170,176,154, 90,198,184,197, 92,136,
+ 57,159,234,187, 89,240, 38,138,116,187,133,115, 51,179,139,139,
+ 179,179, 51, 74, 41,128,187, 35, 23,140,221,106, 22,203,105,253,
+ 184,216, 43,197,151,143, 45, 91, 71, 17,102,101,171,233,226, 34,
+ 82,222,198,143, 78,175, 9,215, 32, 85,110,167, 24, 84,204,141,
+ 160,123,106,162, 83,214,154, 27, 73,115, 90, 42, 80,165, 71,220,
+ 57, 14, 80,220,215,168,140,243, 84,130, 49,187, 20, 19,251,105,
+ 163,209, 88, 94, 94, 94, 92, 92, 28, 13,135,171,107,107, 59, 55,
+ 111, 37,189,190, 26, 12,137,133, 77,229,151, 83, 17, 86, 86, 97,
+ 104,233,230,238, 53,153,251,202,140,101,230, 30, 10,148,112,102,
+ 136, 38,224,108, 70, 89, 38,154, 20,158, 9,197,236, 44,111,151,
+ 237,105, 52,128,253, 65,173,144,249,222,223, 57, 44, 53,164,202,
+ 223,141,119,245,179,197,153,177, 25, 23,102,153,141, 20,157, 5,
+ 137, 41,158,138, 61, 33,138, 87,122,202, 75,246,245,136,217,215,
+ 60, 36,221,110, 74,167,221, 93, 94, 90,152,159,111, 52, 26, 48,
+ 78,112,237, 77, 46,175, 54, 53, 43, 79,117,235, 36,188, 22,208,
+ 222,140, 99,161, 64, 53, 12,131, 48, 47,249,114,107,190,108,197,
+ 170,221,174, 67,149,108, 99,190,207, 99,121,114,116,156,254,202,
+ 93,100,222,153,198,126, 15, 17, 48,151,109,100,193, 53, 66,190,
+ 67, 27, 22, 68,104,105, 10,195,182,218, 64,173,217, 26, 73,179,
+ 190, 18,153, 13,200, 88, 4, 17,219,237,246,201, 19, 39,244,177,
+ 99,253,126,127,253,206,122,255,214, 42,244, 7, 6,100, 8,192,
+ 6,100, 86,112,161,151,232, 67,214, 37,145,192,185, 96,111,105,
+ 54,214,205,246, 36,183, 56, 75,213, 89,122, 4,197,217, 70,216,
+ 30,162, 2,209, 92,117,235, 9, 80,231, 53,218,211,104, 0,224,
+ 30, 92, 7,122,165, 87,248,187, 0,146, 60,168, 51, 95, 14, 25,
+ 149,118,253, 49,120, 63,191, 74, 74, 10,203,166, 90,134, 83, 46,
+ 176,210,166,242,165,120,203,107, 54,239,139,175,236,154,244,242,
+ 190, 31, 4,113,177,213, 94, 92, 88,158,155,107,183, 90, 72,180,
+ 43,155,139, 9,125, 41,223, 1,111,175,198,170,253, 26,221,126,
+ 132, 65, 5,191, 50, 88,165,162, 43,229,150,191, 96,200,237,151,
+ 227,146,171, 80,173, 10,232, 85,113, 86,214,127, 85, 61,224,198,
+ 69,250, 65, 24, 0, 24, 23,201,224, 31,164, 49, 7,203, 69,121,
+ 118, 76,204,125, 77,136, 48, 73, 50,138,145,137,195,136, 88,107,
+ 205,140,214, 75, 26, 35,203,204, 98, 12, 45,226,244,212,212, 84,
+ 183,171,143,159, 24,244,251,235,119,238,244,111,167, 32, 67, 22,
+ 11, 26, 73,213,147,128, 59, 35, 73,182,168, 34, 47, 28, 75,223,
+ 251, 42,204,197,153, 11, 50, 68, 18,103, 58,213, 33,154, 57, 90,
+ 89,209,172,255,106, 81,140, 17, 11, 7,202,217,219, 37,219,182,
+ 36,127,226, 98, 33,105,188, 59,180,237,113, 22,200, 67,161,201,
+ 193,195, 13,239,246,190,163, 39,132,171, 15,203, 46,185,123,145,
+ 86, 78,149,105,118, 61, 59, 20,147, 42,241,229,198, 94, 50,166,
+ 100, 75,118,137,216,144,116,187,181, 95,108, 85, 10, 46, 39,161,
+ 135, 42,114, 21,100,151,103, 26,169, 74,121, 41,127, 69,118, 9,
+ 91,110,181,106, 9, 94, 10, 75, 21,171, 94,236, 53,254, 17, 13,
+ 198, 60,190, 94, 16,230, 43, 11, 34, 98, 0,103, 95,218,194, 97,
+ 171, 84, 91,136,229,100,142,144,144,146,188, 79, 99, 38,192,172,
+ 10,203,133,152, 67, 49, 17, 65,162,169,233,233,238,212, 20, 31,
+ 63,222, 31, 12,238, 24,144, 13,134, 52, 24,145,214, 8, 98, 56,
+ 194,144,110, 49,105,147,175,146,157,116,244, 90, 94, 53,230, 70,
+ 99, 2,142,187, 68, 74,165,169,103, 57,115,105,102, 55, 17,207,
+ 178,198,130,247,244,184,230,100,139,222,151,164, 98, 62, 68,156,
+ 202, 23, 41, 61, 65,221,109, 50,177,226, 4,192, 93, 78,227,201,
+ 144, 97,248, 64, 88,122,247,170,170,172,173,138,151,197, 22, 62,
+ 102,192,170,242,137,238,123,225,116,107,159, 92,115, 73,149, 22,
+ 219,253,224, 86,126,137, 21,113,187, 37,173,230, 56,108, 85, 38,
+ 92, 37,209,181, 71,212, 85, 53,205,152,243, 75,149,150, 8, 21,
+ 27,226,132, 89,127,137,226, 10,161,172,237,106, 65,121,217,212,
+ 190, 4,175, 98,236,133,251,225, 87, 33, 8,179, 89,190,157, 79,
+ 36, 2,102, 27,132,249,235, 13,253,250,216, 10,138, 21,142, 74,
+ 66, 9, 38, 72, 68,148, 36,121,205,154,214,154,136,181,102,127,
+ 152,251, 33,110,183, 30, 17, 68,156, 74, 21,217,241,209,104,184,
+ 185,185,181,189,182,198,189, 62, 13, 70,106, 20,165, 0, 23, 64,
+ 0,134,180,127, 43, 58,243,152,232,106, 49,119,154, 18, 60,195,
+ 152, 87,195,186,251, 7, 72, 73,163,217,202, 19,175,103,153,228,
+ 152,242,184,102, 27, 96,227,152,249,120,116,152,133,206, 51, 90,
+ 74, 79,111, 41,213,245, 73,213,163, 93,104,179, 13,187, 87, 87,
+ 190,125, 50, 12,239,255, 70,197, 63, 52,191,162, 16, 90,249,168,
+ 2, 17,143, 89, 25,173,220, 60,158, 11,215, 88, 96,121, 20,203,
+ 57,149,111,176, 40,251,240,134, 99, 75,183, 90, 45,234,182,187,
+ 243,243, 51, 51, 51,205, 70, 99, 47,108,249,217, 5, 86, 87,210,
+ 195,248, 84,218,221,107, 86,249,240,242, 58,169, 58,174, 81, 21,
+ 123,226,184, 5,170,249, 59,149,214,122,145,242, 11, 38,208,209,
+ 94,224,192, 11,112,143,135, 60,216, 69,101,103,255, 49,109,224,
+ 128, 37,132, 49,216, 8, 63, 37, 92,161,232, 13,252,109,120,137,
+ 144, 40,241,187, 99, 39, 73, 98, 62, 32,145, 46, 33, 44,181,147,
+ 68,100, 26, 37,162,213, 96, 14,200,140, 80, 84,157,110,187,221,
+ 57,114,228, 72, 28,199, 59, 59, 59,155,119,238, 68, 91,219, 48,
+ 24,170, 76,148,229,189,119,128,197, 54, 15,131,220,102, 22,112,
+ 150,170,179, 28, 91, 46,200, 42, 84, 88, 6, 71, 23,106,144,221,
+ 88, 50, 87,157,114, 13,138,117, 45,153,247,148, 92,161,137,191,
+ 84,160,218,235,151, 31,188,202,178,198,113, 25,194,216,197,170,
+ 15, 96, 50,225,190,106, 17, 96,247,186,170, 49,156,146,114,165,
+ 104, 73, 94,101,107,221, 28, 84,185,215,123,179,135,187,130, 44,
+ 5,150, 87, 27,225,210,109,159,144,146,170,105, 68,105, 53,195,
+ 153,169,249,217,185,169,110, 55,112,138, 78,247,233, 19, 97, 92,
+ 25,125, 85,235, 46, 55,237,170, 10,235,199,194,203, 47,250, 42,
+ 119, 38,204,192,149,175, 18,202,160,152,109, 80,155,195, 43, 63,
+ 41,156,109, 98,199, 63, 79,130,221,131, 2,183, 48,223,236, 91,
+ 102,142,161,131, 48,193,146, 88,200,238, 5, 22, 85, 97,134, 46,
+ 52, 9,152,135, 48,173,117,146, 20, 16, 70,204,154,136, 53, 51,
+ 49, 89, 71, 41, 34,156,129,172, 52,154,141, 70, 99, 97, 97,126,
+ 126,158,153, 71,163,209,214,246,214,206,157, 13,189,211,195,225,
+ 136, 70,113,198, 50, 43,148, 32,157,202,132,220, 27, 86, 9, 49,
+ 231,122,135,104,249, 52,101, 9, 94,224, 41,181,156, 86,249,151,
+ 32, 45, 42,203, 35, 51,119, 97,128,100, 83,159,158,118,243, 30,
+ 79,172,148,111, 99,108,253,125, 72, 30,169,186,237,253,104, 51,
+ 217,189,126, 74,170,111, 44,254,109,220, 13,190,192,223,169, 16,
+ 28, 54,249,151,253, 48,171, 82,115,249, 85,166,174, 16,203,108,
+ 99, 81,118,229,215, 20,235,192,246,143, 45, 81,164,155, 13,105,
+ 54,212, 84,183, 59, 59, 59, 61, 61, 93, 41,181,238, 17, 91,176,
+ 91, 21,147,107, 24, 83,162,100, 2,169,104, 27,109,187,155,192,
+ 237, 0,237, 55,179,175,144, 93,206,182,143,182, 57,180, 19,176,
+ 21,218,171,162,255,220,222,237,137, 22,236,231, 5, 51, 91,222,
+ 13,144,199, 97, 22, 97, 44, 64,174,101,202,151, 90, 22,242, 47,
+ 180,201,125,102, 21, 41,195,149, 97, 87, 74,177,236,141,137, 52,
+ 51,105,157,162,203, 25, 70,144, 73,149, 22,203,158, 97,132,168,
+ 58,157,118,187,125,100,121, 69,107, 61, 28, 13,183,119,118,122,
+ 27,155, 62,203,114,143,153, 97, 69, 91,156,129, 31,231,147,135,
+ 173,146, 16, 3, 40, 66,205, 89,244,144,177, 12,160,160,215, 28,
+ 33, 38,121,255, 50,112,103,114,115,199,151,191, 40, 33, 56,171,
+ 1, 60,223,224, 61,240,184,235, 60, 28, 30,140, 67,148, 10,155,
+ 91,165, 50,220,169,180,162,203,205,247,239,130,106, 60,229,242,
+ 198,153, 19, 44,244, 38, 5, 40,114, 10, 96, 12,170, 74,162,204,
+ 208,170, 58,182,207,110, 80, 42,100,216, 27, 91,227,153, 53,211,
+ 237, 78,181,154, 77, 34,218,135,212, 42,154,196,202,140,107, 79,
+ 205, 53, 54,237,170,174,242,242, 82,123, 85, 6, 88, 1, 91,165,
+ 180, 43, 23, 95,233,174,142,227,224,133,251,124, 94, 6,251,152,
+ 171,129,172,162,162,140, 48, 17, 98, 16,242,154, 21,102, 39,121,
+ 33,193, 79,239, 43, 89,144, 17, 17, 37, 58, 73, 63,106,143, 98,
+ 68,202,216, 73,102, 67,177,114, 34,150, 35,108,140, 22,179, 75,
+ 204, 17, 68,144,168, 27, 4,221, 78, 87, 86,142,104,173,135,195,
+ 225,206,206, 78,111,115, 83,239,244, 32,138,213, 40,162, 56, 49,
+ 249,184, 43,205,210,214,135,153, 35,147, 10,108,145,215,161,191,
+ 240, 85, 39, 26,203, 29,118,222, 57, 54,163, 21,166,175, 18, 78,
+ 243, 31,219, 90,214,179,150, 37,198, 57, 2, 13, 43, 83,252, 76,
+ 26, 99,249,249, 47, 37,154, 61, 24,120,237,102, 51,165,240,191,
+ 202, 0, 58,218,170, 60, 27,232, 56, 68,103, 81,151,107, 12,221,
+ 73,195,242, 4, 98,149,127,172, 6, 25, 87,125,117, 76, 33,131,
+ 236,143,212, 0, 0, 28, 6,220,108, 72, 24,170,169,206,238,204,
+ 26, 39,181,118, 81, 91, 62,182,160, 80, 0, 80, 25,117,141,139,
+ 234,171, 23, 55,170, 34,187,242, 13,132, 2, 15, 93,206, 94,142,
+ 123, 4, 94, 69,120,249,149, 72,247,195,175,226,116,100,142, 48,
+ 231,119, 56, 94, 18,179,141,217,192, 93, 34,100, 9,102,143, 85,
+ 26,219,155,220,139, 52,105,107, 24, 51,138,153,145,169, 48, 67,
+ 49, 19,135,101, 35,219, 58,132,153,169,152,236,143, 5,153, 0,
+ 16, 98, 48, 53, 53,213,237,202,202,138,102,142,162,104, 48,232,
+ 247,122,253,225,198, 38, 12, 6, 24, 37, 20, 39, 70,154,185, 56,
+ 131,172,248, 43,133,136, 91,211,144, 71, 99, 96,101, 26, 20, 68,
+ 153,175,197,192, 93,214,158,151, 98, 56, 97,191, 56, 55,206,226,
+ 87,241,204, 96, 70, 45,148,210,228,102,225, 9, 47,176,159, 56,
+ 180,170,148, 19,171,214,169,148, 42, 16,100,207,243,214, 59,197,
+ 165, 52, 35, 33,254,151,188, 50,209,236, 39, 72,113,222,176, 50,
+ 228, 2,135, 77, 80,149,115,193,190,253,227, 94,101,163,178, 31,
+ 102,137, 34, 14, 67, 14, 3,108,183,154,115,179,211,157, 78,187,
+ 221,110,132,225,190,153, 85,144, 90, 80,209,220, 6,138,205, 81,
+ 247,227, 22,211,247, 46,184,118, 85, 94,121,148, 21,120,197, 19,
+ 170,224, 21, 11,171,130, 20, 17,209,252,252,194, 65, 40,253, 96,
+ 31,183,113, 16, 6,214, 72,250, 79,105, 35,196,192, 32,206, 81,
+ 95,160,243, 3,105,145,159, 30, 49,163,179, 18, 75, 46,247,189,
+ 46, 13,165,181, 86,202,196, 97, 69, 33, 38, 66,101, 71,105,125,
+ 101,230, 37, 29,144,129,136,160, 85,109, 72, 20, 40,213,110,183,
+ 23,230, 23,228,196,137, 56, 73,134,195, 97,191,223,239,111,109,
+ 233,254, 0,162,136,140, 52, 99,169,194, 89,246,108, 18,118,202,
+ 83,193,115,133, 78, 51,178, 60,249, 66,175,204,194, 41,203, 0,
+ 159,110,224, 86,252,123, 24,205,251,100, 87, 71, 99,251,155, 1,
+ 192, 93,242,116,217,175, 30,147, 10, 67, 56,246,196,118, 97, 52,
+ 54,125,175,116,145,110,237,104, 81,109,185,193,150,231, 25,193,
+ 223,205,112,156,127,220,207,164, 68, 73, 53,142, 7, 22, 34, 55,
+ 2,110, 52,160,217, 80,237,118,103,102,186,211,105, 55,155,173,
+ 32, 8,198, 25, 35, 28, 63, 49, 83,237, 16,199, 4,243, 80,170,
+ 65, 40,212, 45,121,216, 42, 40, 47,139,173, 74,118, 21,172,163,
+ 242, 46, 6,110, 52, 86, 41,187, 14,104,182, 58,216,223,205, 28,
+ 35,153,182,152,113,235,194,204, 87,217, 82,204,129, 63,160, 70,
+ 141,140,136,230, 93, 22,222,231,177,189, 54, 22, 50,231,151,210,
+ 58, 41, 35,140,180,102,165,204,251,178,151, 76,101,152,253,152,
+ 226,202,180, 93, 76, 41,230,117, 92,180, 79,109,139, 51,251,190,
+ 73,212,104, 52,102,166,167,229,200, 17, 97,142,227,120, 48, 28,
+ 14,134,131, 81,127, 16,245,122, 48, 24, 98,148,144,214, 20, 39,
+ 110, 74, 85,144, 69, 94,123, 68, 17, 44, 86, 45,160,183, 74,161,
+ 112,217,121,121, 69, 55,219,170,138,240,177,212, 5, 5, 75,175,
+ 215, 56,158, 86, 21, 98, 76, 42,151,215,200,158,181, 22, 50,206,
+ 61,150,112, 38, 69, 61, 38,126, 53, 86,110, 32,139, 22,210,111,
+ 152, 5,165,110,165,224, 1, 75, 74, 45,152, 1,224,238, 42, 69,
+ 203, 34,107, 28,176, 56, 12, 68, 41, 14, 3,104,183,194,110,167,
+ 213,105,183, 91,173, 86,171, 29, 26, 96,221, 63,179, 74, 14,209,
+ 243,137,197,108,190,184, 0,104,111,114, 57,216, 26, 11, 47,101,
+ 203,230, 51,127, 24,184,166,210,219,126, 54,133, 23,229,187,104,
+ 191,189,252, 42, 32, 44,175, 11,195,172,183, 2, 18,176, 0, 8,
+ 17, 8, 10,176, 19, 17, 99,198, 47, 55,188,207, 2,252,132, 52,
+ 233,140, 95, 74,235,164, 66,130,105,173, 89,107,173,148, 30,135,
+ 48,159, 98, 57,200,178,230,177,213,190,210,129,152,248, 21,187,
+ 136,164, 84,179,217,156,155,157, 21, 0, 97,142,147, 36, 26,141,
+ 70, 81,212, 31,244,163,141, 45,142, 99,140, 19,138, 34, 76,152,
+ 76, 47, 32,223,178, 21,160,102,143, 94,102, 60,203, 5, 89, 88,
+ 76,238, 43,167, 38, 43, 2,178,146, 4,195,170,116,191, 26, 94,
+ 78, 75,218,251,159, 82,172, 58,219,165,138,101, 34,197,200,172,
+ 100, 33,139,104,115, 90, 24,185, 78,208,201,245,247,242,125,123,
+ 3, 75,246, 84,142, 32,138, 56, 80,220,104, 64,160,176,209,104,
+ 206,206, 76,181,219,141, 70,163,217,108,238,162,176, 96,236, 90,
+ 129,253, 49,171, 50,150,135, 61,123, 35,228, 57,211, 88,114,237,
+ 11, 94,185, 43,116, 86,255,228, 23,201, 65,151,211, 12, 71,101,
+ 167,251,219,206,175,221, 17, 6, 8, 32,100, 26,130, 17,179, 80,
+ 186,188,144,253, 37,144,140,108, 86, 11,229, 32,211,218, 82, 44,
+ 139,190,198, 72, 48,173,181, 98,214, 90,179,102,173, 52, 87,133,
+ 250,149, 66,108,175,104, 44,155,180, 4, 79,154,217,191, 15,204,
+ 86,108, 74, 53, 21, 53, 27,141, 41,128, 69, 88,148, 19,194,172,
+ 147, 56, 25,142, 70, 81, 52, 26, 14, 71,209,214, 22, 39, 9,142,
+ 98,140, 19, 20, 86,163,216, 43, 95,200, 48, 83, 44, 31,205,159,
+ 175,130,174, 3,173, 40, 34, 64,255,249,238, 87,141,129, 23,143,
+ 8,140, 41,142,245, 85, 88,190, 1,221, 61, 87,137, 86, 82,108,
+ 183, 32,223, 45, 50, 40, 92, 41, 62, 70,164,202, 66, 2,236,127,
+ 145,224, 93,208,106,172,182,106,134,130,196, 97, 96,104,213,152,
+ 153,110,181, 90,141, 70,163,213,108,170, 32, 48,116,184,187, 74,
+ 219,221, 58,205,131,219,167,175,210, 36,230,200,218, 71, 73,196,
+ 126,101,151,227,245,118, 17, 95, 99, 63,117, 42,196,168,208,200,
+ 203,206, 51, 78, 2,191, 60,132, 65,182,192,200,188,130, 59,203,
+ 140,213,100, 61, 27, 0, 0, 17, 42, 73, 68, 65, 84,140,145, 76,
+ 27,185, 22,123,229, 32, 35, 34, 49,105, 36,180, 5,171,105,213,
+ 132, 19,119, 37, 74,107,237, 83,140, 53,107,118, 46,229, 20,243,
+ 64,150,239, 10,206,214, 60,122, 91,236,150, 88,230, 33, 44, 83,
+ 100,142,193,204, 89,150,170, 30, 35, 87,144, 16, 3, 21, 52, 91,
+ 173, 44, 84, 97, 22,157, 36, 81, 28, 69, 81, 60, 28, 14, 71,189,
+ 158, 30,142, 32,138, 68, 51,197, 9, 10,211, 40,198,138,148,170,
+ 136,182, 2,221,192,109, 92,129, 21,168,192, 93, 79,217,177,177,
+ 125, 53,188, 16,238,105,133,115,169,136,107, 87,241, 53,222,108,
+ 142, 99,206, 1,169,170,106, 84, 17, 65,179,161,154,205,102,183,
+ 99,104, 21,134,161, 57,189,239,154, 86,187, 3,107, 63,193, 86,
+ 101,188, 85, 5, 47,119, 74,207, 78,246, 59,145,179, 27,214,103,
+ 213, 93,238, 63, 7, 68,187,194,203,243,137,150, 92, 84,213,131,
+ 208,105,134, 51, 25,252, 2,119,226, 41, 91,230, 93,152,242,202,
+ 50, 83, 34,176, 39,123,169,227,151,193,151, 70,237,191, 28, 16,
+ 105,149,209,140, 85,209, 63,154, 11, 70,133,217,247,198, 87,114,
+ 105,106, 50, 19, 99, 25,182, 76,216, 47,187,142, 2,194, 10,239,
+ 114, 80,167,210, 76,108,133, 5,162, 8, 41, 80, 74, 53,154,205,
+ 124, 91, 80, 17,214, 58,209, 58,137, 99,195,181, 40,138,226,237,
+ 109,102,198,225, 72, 4, 84, 20, 1,128,153, 34, 40, 63,203, 93,
+ 21,134,227,107, 73,101,215, 22, 11,178, 71,167,235,187, 5,197,
+ 62, 26, 35,220,211,247, 11,220,251,111,222,127, 17,131, 16, 74,
+ 24, 8, 0, 55, 26, 8, 32,173, 38, 41, 10,166,167, 26,141, 70,
+ 35,108, 52, 26,141, 48, 72,251, 25, 23,155,138,220,179, 37, 28,
+ 11,172,241,106,171, 44,183,246, 97, 21, 51, 90, 56,236, 40,112,
+ 203,153,103,244, 61,163,219,143,208, 71, 84,225,162,231, 20,199,
+ 147, 43,215,127,147,198,175,202, 73, 73, 47,209, 55,137,138,241,
+ 146,217,169,239,250,200,180,225, 4, 35,103,201,125, 58,255,145,
+ 86, 77, 80, 26,116,149,224,101,104,229, 92, 74,241,149,161, 75,
+ 103, 85, 22,169, 12,147,130,169,204, 18,253, 42, 57, 6, 99,230,
+ 43, 11,121, 63,120,210, 12, 16,196,238,206, 38,229,122, 19, 34,
+ 10,194, 0,154, 77, 55, 36, 98, 17,102,157, 36, 58,142,227, 56,
+ 142,147, 36,137,227, 56, 30, 12,244,104, 36,137,198, 40, 22, 3,
+ 53, 97, 96,177,181,105,149, 26, 10,177,116,170,226, 94,132, 56,
+ 232,101,141,242,160,111,191, 31, 60, 21, 2,117, 32, 52, 98, 10,
+ 1,164, 17, 98,160,168,209,108,116,218, 78, 43,189, 48, 8, 2,
+ 115,182,237, 39,253, 27, 31,194, 99, 69,205, 73,101,113, 41,184,
+ 221,202,113,108,221,214,248,249, 68, 24, 47,184, 60,120,149, 10,
+ 234, 51,177, 53,166,157,132,175,165, 84,197, 52,162,173, 65,173,
+ 16, 92,202,229, 99,169, 48,117, 50,249, 53, 38, 14,203,218, 79,
+ 59,183, 33, 18, 17, 19,234,163,109,140, 67, 72, 22, 55,166,111,
+ 142, 49,145,236,112, 76,147,210, 74,171,162,123,100,135, 98, 69,
+ 33,102,249,165,115, 9, 54,206, 81, 90,148,249, 56,219,167,175,
+ 172,164, 25,218,171, 28,117,150,154,205,212,170, 73, 78,125, 5,
+ 162,136,194, 32,108,183, 90,133, 60, 72,152, 53,179, 41,229,205,
+ 135, 78,146,193, 80,143, 34, 17,129, 56,198, 68, 11, 0,106,109,
+ 230, 13, 0, 32,115,166,251,203,176, 14,172,244,254, 46, 51,254,
+ 253,131,204,117,121,233, 5,165, 68, 41, 4,144, 64, 65, 24, 32,
+ 18, 53, 26, 97,187, 85,108,216, 66, 68, 74, 33,226,126,244,212,
+ 30,124,175,108,134, 80, 85,159, 85,182,132,123, 82,107,255, 62,
+ 177, 68, 47, 79,119,149,221,162, 93,134,157,243,171, 32,187, 10,
+ 2,140, 28,177,229,250, 74,175,192,194,153, 91, 76,169, 85, 37,
+ 187,252, 38,132,147,197,175,170, 56, 44,109,160,239,204,147, 57,
+ 66, 12, 81,152, 1, 17, 25, 77,151, 46, 27,241,155,142, 57,100,
+ 150, 11,165,213,170,100, 10,190,116, 10,179, 20, 82, 90,235, 44,
+ 194,231,156,101, 5,132,105,167,208, 85,118,161, 88,233,194,158,
+ 32, 43,196,252,197,212, 63, 95,210, 82, 52,155,105,127, 29,143,
+ 104, 21,103, 50, 2,128, 82, 74, 41,177,219,184,187, 22, 80,108,
+ 204,102,254,160, 36,209, 90, 39,204,194,172,163, 56,102,205, 34,
+ 146, 68,145,238,255,255,237,157,235,118, 27, 57, 14,132, 1,182,
+ 146,153,221,247,127,215, 61, 51,137,200,253,209, 55, 92, 10, 0,
+ 91,182, 99,249, 34, 29,123,168, 30,197,246, 81,172, 47,133, 98,
+ 1,252,223,249,253,255,249, 71,126,147,246,239,191,230, 87,169,
+ 253,250, 77,190,116,125,107, 69,214,184,255,184,153, 39,244,159,
+ 63,213,166,232, 95,127, 29,239,223,229,191,255,185,253,252,201,
+ 204,109,105, 63,110, 63,150,101, 97,230, 53, 58,121, 28,181, 69,
+ 87, 8, 85,113,138,242,177,203, 70, 91, 89, 72, 81,148,140,151,
+ 212, 74,247, 18,243,106,209,152,243, 1,185,116, 48,213,194, 75,
+ 210,107, 3,214,142, 48,169,203, 20,185,188, 61,175,125, 46, 48,
+ 192,139,101,150,241,233,248,229,236,176,163,150,180,191, 71,188,
+ 59, 98, 60, 70,223,103, 68,111,145,138,179,189,241,104, 23,218,
+ 40,182,194,107, 89,150,131, 95,242,174, 4,152,208, 94, 93, 94,
+ 16, 20,115, 21,165,248,124, 30, 43,158,128, 44, 46, 45,141,221,
+ 79,190,204, 20,186,108, 39, 26, 29, 26,237,124, 5,161, 60, 25,
+ 71,152,139, 7, 19,181,182, 14,253,216, 74,210, 1, 74,173, 67,
+ 233,172, 82,116, 19, 44,189,255,250,253,235,126, 63,251,246,122,
+ 239,191,127,255,186,223,187,159,148, 96, 80,120,249,215, 66, 64,
+ 7,252,175,165,221,110, 63,228,182,186,185,114,188, 49,200, 15,
+ 183,189,254,219, 57, 3,169,136, 83, 24, 85,211, 30,124,104,199,
+ 7, 69, 98, 6, 46,239,207, 55,215, 4, 20,198, 82,245,210, 9,
+ 48,229,226,139,103,156, 66, 11,109, 44, 6,154,235,196, 22,243,
+ 133,102,198,119,225,215,140, 16,219,118,239,134,213, 98,107, 45,
+ 185,105,177, 19,100, 39,197, 86,134,245, 53, 56,177, 44,203,253,
+ 222,151,142,252,251, 29, 90,119,101,129, 73, 83,204,148,148,189,
+ 175,236,218,239,178,176,220, 64,134, 88, 38, 17,150, 81, 44,228,
+ 89,184,128, 80, 19, 92, 27,226,112, 2,169,203, 88, 29, 11,174,
+ 195, 98, 68,212,150, 38,255,192,223,244,247,181,194,237, 49,122,
+ 189, 12, 58, 47,162, 82,181,143,202,181,215,238, 5, 88,129,170,
+ 201, 13,196,156, 92, 24, 94,102,178,223,217, 67,204, 7, 65,108,
+ 7, 35,203, 86, 32,167,192, 54, 44, 1,255,222,225,173, 53,117,
+ 178,134,194, 86,228,115, 5,211, 7,249,201,249,149, 11,177, 67,
+ 142,169, 78,107,230, 49, 58,119,238, 60,152,185,141,182,166,195,
+ 36,197,118,152, 45,189,111, 8,235,189, 47,247,123, 95,182,252,
+ 215, 94, 42,138,133,208, 96, 14,100,128, 95, 39,200,156, 55, 86,
+ 236, 84,122,168, 17,138,146, 69,114,140,236, 85,146,173,203,199,
+ 53, 83,126, 42,189,118,152, 88, 99, 4,182,189, 2, 92,130, 42,
+ 118,123,149,122,127,224, 57,110, 92,213,124,243, 10,107, 78, 94,
+ 57, 48,249, 93,195, 76,112, 37,187,136, 51,219,137, 65,181,232,
+ 176,133,199, 71, 52,233,217, 47,106,109, 23, 74,163, 5, 69,162,
+ 23, 92, 59,194, 28,182, 20,187,222,214,105,189,189,193,175, 88,
+ 234,136,137,232, 17,143, 49,120,112,231, 62, 6,175,159,152, 71,
+ 27,146, 98,167,123,213, 78,164,173, 20, 91, 65,181,116,100,123,
+ 9,114,221,141, 10,219,120,101, 19,175,160,168,148, 44, 11,228,
+ 152,151,100,228, 45,255, 74,145, 57,136,129,133, 50,191,197, 73,
+ 148, 82,178, 9,216,145, 5,156, 11, 81,132, 27,148,252,154, 27,
+ 139,175, 47,172,174, 52, 60, 63,198,172, 89,157,117, 85,109,249,
+ 131, 80, 33,194, 76, 49, 38, 39, 11,234, 82,209,170, 46, 54, 77,
+ 216,106,179, 81, 92,148,120, 90,150, 5, 33, 79, 24,255,154, 92,
+ 98,167, 96,255, 17, 15, 32, 67,217,245,214,255,250,221,222,236,
+ 151,208, 10, 49,115, 20,236, 56,182,227,218,104, 99,109,169,238,
+ 123,226,189,141,214,219, 62,177,176,157,198,123,211,228, 57, 65,
+ 6,157,123,141,173,172,223, 72,218,251, 39,190,124,224, 66,211,
+ 236, 2,203,140, 46, 43,253,178,124, 33,101, 26,153,254,227,177,
+ 143,122, 85,128,147,242, 77,138, 56, 11, 38, 14,135, 78, 95, 8,
+ 144,189, 34,176,102,106, 64,247, 99,207, 2, 43,252,152,220, 61,
+ 156,138,154, 78, 49, 75,159, 9,113,140,107, 57, 74, 52, 5,174,
+ 67,127, 37,253, 64,190,238, 3,240,130, 26,107,166, 78,180, 62,
+ 23, 46, 24,153,248,202, 63, 76,207,195, 47, 36,196,116, 57, 41,
+ 236,232,213, 17, 91,171,202,253,120, 14,238, 99,108,190,216,230,
+ 227,247,214,155,243,224,205, 6, 99,239,125, 57, 96,134,203, 70,
+ 253,108, 68,177, 49,122, 71, 20, 83,139,138, 98,175, 10,178,144,
+ 107, 33,209,156,105, 5,103,154,234,190,114,198,204, 98, 60,139,
+ 186,172, 58, 95, 86, 9,206,168, 42,232, 88, 65, 84, 25, 51, 14,
+ 210,170, 84, 88,111,140, 45, 77, 46,161,185,172, 59,207, 25,185,
+ 56, 67,211,146,240,202,126, 81, 41,184,206, 34,209, 24, 93,100,
+ 68, 87, 92, 48,242,199,210, 95, 72,136,157,229, 36, 29,199, 83,
+ 31, 97, 40,222,167,216,239, 51, 34,184,143,157, 96, 99,172,181,
+ 100, 27,237,208, 98, 67, 81,204, 19,109, 21,101,227,188, 56, 74,
+ 150,137,116,133, 79,237, 43,156,217,252,107, 78, 49, 61,245,194,
+ 98,108, 6,103, 22,100, 88,144,129, 21, 4,153,223,101,196, 50,
+ 106, 76,207,185, 31,227,241,209,135,243,189, 56,209, 60, 82,175,
+ 188, 2,108, 17,202,189,195, 82,103, 30, 91,114,224, 48,235,133,
+ 81, 38,137,183, 37,231,227,113, 11,183, 22,163,116, 4,167, 82,
+ 138, 17,217, 0, 2,245,134,128,199, 86, 83,135,185,198,228,138,
+ 165,240, 71,228, 23, 40, 39,137, 78, 83, 44,162, 24,211,174,196,
+ 6,143, 49,250, 1,178, 85,139,141,118, 18, 76,237, 33,122, 18,
+ 105,113,229,130, 20,138, 98, 67,242, 78, 55,129,203,187,140,236,
+ 251, 94, 74, 37,205,232, 64, 23,225, 8,198, 5,138,205,179, 12,
+ 235,179,151,176,204,122,106,127,196,255, 74,124,174,107,204, 2,
+ 235,151, 48, 43, 34, 23,134,151,120,179, 75,145,197,201, 28,103,
+ 143, 18, 37,140, 68,123,142,101,146,213, 99,108, 48,167, 63,212,
+ 38,128, 70,167,207,246, 43, 62, 3,114,121,171,235, 15,237,250,
+ 220,232, 15,221,144, 41,230, 40,182,111, 79,186,109,202, 29,104,
+ 141, 91, 31,125, 28,254,152,215, 72,214,200, 50, 8, 83, 56,139,
+ 117,156,253, 34, 88,139, 25,130,117, 80, 88,210, 69, 69,118,158,
+ 236, 76,149, 46,139,161,166,230, 58, 76,226, 44,138, 74, 84, 39,
+ 21,226,192,218,107,137, 47, 40,187,114,126, 65, 96, 57,193,101,
+ 80, 85, 49, 75,127,154, 83, 91, 51, 7,161,130, 41, 17, 78,115,
+ 177,211, 74, 86, 55, 65, 96,105,238,153, 71,199,103, 41,181,252,
+ 126, 34,156,239,236,201,245,103,172,174,247,229,151,162,152, 50,
+ 197,172,189,191,185,251, 58,108, 65,135, 32, 91,181,216,104, 99,
+ 19, 98, 27,197,128, 72, 58, 52, 26,196,153,128,151, 95,184,103,
+ 129, 78,240, 97,146,252,197,164,158, 1,180,152, 57,112,132, 0,
+ 193,106, 81,118,244, 6, 62, 34,202, 60,181, 2,138,213,136,154,
+ 167,216, 76, 83,244, 12,185,226,135,165,212, 18,179,214, 43,193,
+ 101,220,105,127, 28,134,215, 92,161,197, 37,225, 37, 39, 68, 0,
+ 106, 1,226, 56, 91,221,199, 26, 52,176, 84, 51,164,185, 35, 96,
+ 133,198,188,202,161, 62, 7,185,222,133, 95,128, 98,251,193,178,
+ 167, 47, 38, 40,118, 32, 76,190,215,133, 54,107, 99,195, 87,219,
+ 234,202,131, 39, 43,198, 70,164,157,188,182, 50,251,143, 49,185,
+ 108,108,223,231,197,142,239, 62, 5,178,173,204,164, 25,171,127,
+ 14, 97,136,104, 50,128,241, 50,150, 77, 3,237,138, 20,227, 73,
+ 144,205, 48, 11, 84, 53,230,173,151,195,203,232, 46,184,144,181,
+ 212, 76,132, 75,146,194,229,185, 18,237,197, 46,190,224,210, 12,
+ 64, 85, 65,133,165, 44, 54,177,205,233,180, 22, 19,206, 67,176,
+ 60, 39,241, 93,170,197, 39,225, 87,224,139,109, 50,108,168,225,
+ 87,103, 85,185, 78, 25,211, 39,114,172, 97,254,181,160, 28, 99,
+ 180,190,141, 91, 85,161, 7,211,235,232,244,147,188, 26,222,193,
+ 179, 20,191, 92, 63,101, 92, 83,134, 8,219,175,208,121, 33,160,
+ 152,199, 88,205, 50,105, 99,169,225,205, 49,206, 2, 85,245,186,
+ 240,202, 16,230,174,170, 11, 25,177, 10,102,225, 18, 49, 35,151,
+ 47, 14, 47,204, 62,197, 93,139, 62, 76,207, 14, 91, 64, 55, 1,
+ 74,233,144,131, 14, 94, 88,223, 77, 7,204, 72,185,242, 81, 6,
+ 53, 72, 69,188, 39,185,222,157, 95,193, 30,165, 43, 40,247,243,
+ 115,181, 28,147,198, 18,239, 71,114,172, 73,178,209, 71, 19,115,
+ 163, 97,127, 35, 88, 36,132, 83,208, 82, 20, 3,124, 4, 31, 3,
+ 216,252,208, 30,155,152,123, 1, 53,152,133,150,188,160, 63, 41,
+ 138,145, 56,149, 98, 68,216,242,231, 86,228,215,175,253,237,227,
+ 173, 75,119, 61,212, 93,136, 97,165,202, 2,218,162, 12, 65, 4,
+ 180, 34, 84,123, 97,225,229,234, 54, 35,142, 32,138,124,117,233,
+ 57, 5,228, 21,216, 43,128, 1,136,160, 72, 44, 75,197,247, 39,
+ 215,147,240, 43,165, 24,185,243, 87,135,247,248,201,181, 36,182,
+ 131, 12,221,176, 44,200,163,186,105, 58,129,164, 58,153, 5, 22,
+ 82,241,193, 14,202, 50, 62, 38,116, 87,156,230,143, 71,146,129,
+ 22,165, 97,201, 21, 38,251, 35, 69, 70,193,240,210,241,200, 12,
+ 194,124, 46, 13,231,226, 43,240,183, 8,246, 30, 6,197, 33, 37,
+ 135, 95, 32,108, 17, 56, 25,131, 38,203, 68,219,189,232,212, 80,
+ 139, 23,225,136, 9,196,196, 24, 88,219, 37,154, 96,150, 73, 66,
+ 168,198,132,167, 36,215, 83,241,203,188, 46,135, 53,230,229,152,
+ 44, 41, 15,167, 31,131,140, 86,151,159, 52, 63, 26, 10,110, 25,
+ 177, 20,104,168, 30,172,149,225,213, 61,180, 76, 73,105, 52, 88,
+ 21,126,213, 92, 19, 68,219,141,179,253, 68,176, 65, 80,157,157,
+ 103, 92, 20, 8,203,214,122, 25, 32,108, 92,249, 59,246,118,190,
+ 30,203,111,119, 33, 47, 79,125, 56, 36,131,243,183,228, 89,241,
+ 18, 73, 39,173, 28,167,168,112,186,148,157,212, 92, 90,162,217,
+ 135,141, 91, 54,246, 57,229,148, 69,149,181,178,212,232, 45,241,
+ 41,147, 90,198,225,122, 94,193,245,204,252, 10,229,152,240,248,
+ 135,252,237, 21,231, 5, 69, 32, 19,198,191, 58,135, 40, 56,149,
+ 168, 7,140,193,125,144, 50, 60,225, 60,251,158, 38, 92, 67,138,
+ 145,254,148, 38,199, 52,188, 30,138,245,203, 78,164, 17,145,107,
+ 148, 89,176,107,133,100,176,107,101,219,125, 2,138, 57, 51,230,
+ 114,122,203, 32, 12,108, 39,186, 24, 4, 21,161, 8,164,125, 0,
+ 91,162, 93, 63,115,212, 25,250,170,177,227,206,133, 13, 95, 97,
+ 43,138,154, 60, 53,185,158,153, 95, 86,142, 73,143,159,252,104,
+ 177, 26,100, 64,154, 69,246, 83,102, 87,141, 62,137,187,137, 47,
+ 149,103, 43,204, 35, 83, 89,198, 6, 63,196,214,113, 22,153, 2,
+ 153,214,101,132,167, 96,212,245,100,164,206, 10,241, 5,255,113,
+ 103,125,108, 9, 16, 3,168, 45, 81, 83, 76,138,175, 60, 15,225,
+ 236,121,184,175, 72,145,225, 21,235,176,153, 28, 69,140,163,118,
+ 229, 75, 77,137,172, 73,108,125, 8,193,245,129,248,149,200,177,
+ 75, 32, 3, 20, 3, 60,168,112, 54,201,186, 7,110,161,226,194,
+ 63,157,170, 38, 61,200, 8, 4, 96, 47, 25, 98,117,204,194,116,
+ 91,214, 27,150,241, 91, 36,172, 85, 46,133,185,210, 77, 69, 16,
+ 224,114,216,170, 49, 6,115, 81,111,115,163, 41, 96, 17,116,229,
+ 242,242,112, 14, 91, 31,131, 92, 31,136, 95, 72,142, 77,130,108,
+ 237, 25, 39,142,219,117,108, 40,158, 48, 74, 40,194, 24,165,185,
+ 136, 20,124, 38,140, 95,106, 45,109,222,203,159,212, 56,250,208,
+ 11,195, 27,147, 38,114, 97, 19, 23,117, 53, 73,143,231,239, 83,
+ 195, 62, 37, 24,206, 70, 88,112,133, 33, 84,181,144, 9, 84,149,
+ 144,136, 24, 17,213,104,136,114, 25,151,226, 63,230,190, 23,217,
+ 168,131,137,104,165, 17,249, 79,136,173,143,200,175, 7, 64,118,
+ 28,240, 38, 96,134,222,211,129, 52,203,184,230, 69, 19, 21,138,
+ 138, 52, 8,131,194, 54, 36, 23,153,108, 24,218,145,212,216, 58,
+ 46, 88,150,229,177, 49,151,172,176,187,147,100, 79,165,125, 36,
+ 69,129,236, 97, 38,148, 70, 21,181,163, 89,104,108, 57,183, 94,
+ 20,145,206,188,135, 32, 35,182,142,190,193,150,181,198, 40,234,
+ 116, 12,255, 67,185,148,139, 57, 21,136,172,184, 54, 4, 61,213,
+ 159, 7, 91, 31,154, 95,240,117, 31,114, 95,106,159,247,170,118,
+ 45, 19, 81,166, 93,240,204, 62, 11,138, 55, 39,136,230,235,190,
+ 202,155,199,237,145,104,243,209,237, 69, 6,119,155,180,192,228,
+ 42,118, 36, 35,116,129, 7, 28, 24, 96,214, 8, 75,119, 27, 51,
+ 138, 89,219, 43,186, 71,254,189,230,156,179,243, 51,143, 31, 20,
+ 155,232,127,133,193,215,128,149,161, 83, 23,248,122,105,208,244,
+ 131, 89,242, 95,135, 95,133,217,191,237, 86, 14, 63,138,229, 28,
+ 129,113,204,251,195,177,208, 64,166,121, 53, 20, 74, 36,183,206,
+ 47, 82, 49,105, 39,115,185, 10,120, 61,232,223,151, 97,176, 23,
+ 12,200, 7, 27,145,248,109,247,160,127, 31, 35, 44, 48,200,180,
+ 174,201,131,248,112,244, 68, 60,143,130, 98, 25,133, 0,138, 75,
+ 66, 36,177, 96, 91,207, 39,148, 90,159,155, 95, 69,117, 41, 56,
+ 54,246,243, 48,118,152,145,103, 89, 8,180, 68,239,224, 5, 10,
+ 157, 22,166, 21, 46, 3,211,198,238,172, 45, 50,182,237,135, 56,
+ 151,141, 46, 12,121,173, 44,252, 57,197, 60, 87, 73,170, 53,192,
+ 153,130, 23, 52,242,243,161, 18, 19, 62,127,186,155,151, 44, 60,
+ 179,220, 2,234,193, 9,235, 29,190, 42,148,245, 51,124,210,219,
+ 141, 62,237,141,205,187,234,140,146,173,110,153,110,178, 36,127,
+ 236,200, 86, 99, 38, 56,192,133, 39,190,168,188, 40,163,141, 2,
+ 175, 42, 52,176,242,125,197, 25,143, 62,238,136, 76,234, 69, 56,
+ 198,181,134, 86,108,224,211, 99,161,251,164,219, 17,166,239, 97,
+ 173, 85,226, 34,182,207, 92, 61,167,168, 4,159, 97, 36, 85, 18,
+ 239,160,216,201,138,152,245, 53,164,214, 87,227,215,156, 83,134,
+ 89,198, 18, 99,242,196,159, 41,156,165,152, 35, 71,165,217, 2,
+ 48, 42, 10, 19,213, 85,128,235,138,217,229,227,247, 52,153,250,
+ 154,175, 32,169, 26, 57,113,173, 99,219,230, 91,125, 28,191,114,
+ 204,242,242,211, 64,141, 42, 48,205, 2,171,142,149,126,105,102,
+ 125, 65,126, 77,177,140, 8, 28,147, 68, 99,247,254, 69, 39, 83,
+ 133,179,163,190,138, 88, 70,186,187,231,130,215, 30,195,203,244,
+ 9, 5,252, 10,125,250,224, 3,130, 42,113,237,231,234, 71, 70,
+ 69, 36, 37, 45, 68,174,166,140,125,125,192, 47,229,244,187,237,
+ 75,119,191,176, 39, 80, 73, 59,188, 87,154, 5,178,130,210, 57,
+ 0,214, 87,100,214, 23,231,215, 76,141, 9,188,255, 3,101, 37,
+ 206, 16,194,242,135,225, 69,131,171, 8, 85,214,198, 74,189,249,
+ 2, 94, 51,252, 74, 46, 92,124,209,201, 82, 42,227, 87,240, 80,
+ 113,170,240,248,245, 2, 66,205, 48, 43, 39, 17,100, 97,244,240,
+ 10,176,190,153,245,205,175,199, 89, 22, 72,179, 24,103,123,104,
+ 99,156,224,203,130, 9, 97,141,231,205,245,218,116,159, 89, 80,
+ 48,244,235,129,209, 57,145, 6, 43, 73,198,149, 32,171,211, 21,
+ 248, 33,132, 23,101,153,139,116,145, 86,161,213,152,158,178,250,
+ 75,236,246,111, 96,125,243,235,157,112, 38,144, 6, 38, 99,231,
+ 68,171, 48,231,158, 95,112, 42,189, 72,190,189,209, 62,156, 13,
+ 73,140, 64,137, 93,120,101, 57, 40, 38, 9, 71, 43,114, 61,150,
+ 174,243,139,190,248,156, 91,212,180, 74,107,192,111, 96,125,243,
+ 235,121,112,230,254,192,224,108,214,127, 57,183,166, 30,108,163,
+ 114, 15, 84, 78,193,177,161, 7,247,144, 8,228, 36, 8,158,239,
+ 104,190,204, 35, 47,104, 54, 57,157, 17,218,176, 73, 22, 62,228,
+ 234, 88, 15,136,173, 18, 79,217,122,134, 86,133, 18,253,190, 93,
+ 185,253, 31,230,204,154,229,115, 62,144, 15, 0, 0, 0, 0, 73,
+ 69, 78, 68,174, 66, 96,130
+};
+
+static const unsigned char _data_keyboard_png[11032] = {
+ 137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82,
+ 0, 0, 1,112, 0, 0, 0,178, 8, 2, 0, 0, 0,212, 44, 3,
+ 99, 0, 0, 0, 9,112, 72, 89,115, 0, 0, 11, 19, 0, 0, 11,
+ 19, 1, 0,154,156, 24, 0, 0, 0, 7,116, 73, 77, 69, 7,216,
+ 1, 30, 13, 6, 32,218,243, 41,227, 0, 0, 32, 0, 73, 68, 65,
+ 84,120,218,237,125,207,111, 35,199,181,110,217, 20,203,160, 89,
+ 6,221,101,112,186, 7, 84, 51,144,154,198,168, 21,152,116, 48,
+ 212, 98, 56,139,153, 0, 17, 3,220,120, 17,103,241,222, 91, 36,
+ 249,227,238,189,139, 36, 11,123, 51, 94,152, 50,144, 81,128,105,
+ 45,166, 7, 30,210,184, 67, 14,204,166, 16,182,136,116, 13,145,
+ 238, 33, 82, 52,145,226, 37,240, 22, 53,106,211, 36,245,139,234,
+ 106, 73,156,250,160,133,212, 18,120, 84,213,117,190,250,206,169,
+ 211,125,222,217,223,255, 27,136, 5,185,117, 29, 0,208, 59,114,
+ 165, 57,105, 78,154, 91, 85,115,239, 2, 9, 9, 9, 9, 73, 40,
+ 18, 18, 18,146, 80, 36, 36, 36, 36,161, 72,196,136, 68, 34,145,
+ 74,165,228, 60,220, 68, 32,132, 52, 77,147,132,114, 89,164, 82,
+ 169, 66,161, 16,155, 27,108,108,108, 64, 8, 33,132, 27, 27, 27,
+ 49,152,203,231,243,124,104, 24,227, 24,150, 75, 42,149,202,229,
+ 114, 66, 77, 96,140, 63, 41,126,242,233, 47, 62,205,102,179,225,
+ 69, 8, 97,161, 80, 72, 36, 18,162,233,178, 80, 40, 64, 8, 69,
+ 79, 99, 38,147,217,222,222,254,244, 23,159,110,111,111, 99,140,
+ 227, 89,153,169, 84, 42,123, 43, 27,167, 15,167, 82,169,141,141,
+ 13,209,119,141,223,184,141,141,141,211,125,252,221, 8,141,161,
+ 15, 80, 12,163,226,206,144, 74,165, 24, 99,154,166, 77, 38,147,
+ 56, 44,126,132,185, 33,132,144,232,123,150,207,231, 55, 54, 55,
+ 208, 7,232,211, 95,124, 90, 40, 20, 4, 89,204,173,231, 14, 59,
+ 135, 47,254,231,133,118, 91, 11,151,136,166,105,140, 49,209, 83,
+ 154,205,102, 83,239,167, 68,243, 50,132,112, 99,115,131, 82,218,
+ 254,190, 77, 41,205,255, 44, 47,148,194, 66, 81, 57, 26,141, 70,
+ 63,140,226,148,153, 27, 27, 27,163,209, 40, 6, 71,152, 76, 38,
+ 163,209,232,244, 45,252, 70,134, 60,217,108,150, 82,154, 72, 36,
+ 240, 71,152, 82, 26,131,136,157, 76, 38,140, 49,190, 27, 8,181,
+ 200,119,128,254,171,254,232,135, 81,251,251,246,104, 52,226,118,
+ 35, 31, 81, 34,145,160,148, 50,198, 70, 63,140, 56,103, 33,132,
+ 50, 31,102,122,189,158,104,198,204,222,202,182,191,111,227,143,
+ 176, 80, 15,231, 31,238,251, 62,165,212,247,253,240,138, 56,153,
+ 112,103,235,206,246,246,182,166,105, 92,232,125, 82,252, 36,159,
+ 207,199,176,185,194,247, 96,191,223,143,199,245,250,253, 62,124,
+ 15,158, 34,247,214,162,178, 20,131, 99,135, 11, 37,245,126,170,
+ 223,239,103, 50, 25,209,118,249, 46,154, 74,165, 38,255, 59,121,
+ 243,253,251,169, 76, 38,131, 16,242, 60, 79, 8,121,125,128,186,
+ 127,239, 50,198, 16, 66,148,210,120,102,149,235, 74, 77,211,250,
+ 175,250, 49,200,147,193,235,193,104, 52,242,255,233,107,154,214,
+ 237,118, 5, 25, 26,141, 70,225, 6,192,183, 4,126, 69, 16,184,
+ 20, 2, 0,228,114, 57,238,225,158,231,137,216, 12,230,195,186,
+ 193,235, 65, 60, 58,157,139,148,193,235, 65, 38,147,225, 28,189,
+ 10, 10,133, 49,246,252,219,231,190,239,251,190,255,252,219,231,
+ 49,220, 51, 30, 94,113, 46, 99,255, 22, 27, 17,208,127,209,108,
+ 54, 43, 58,191, 48, 63,132, 76, 38, 3, 33,244, 60, 15, 33, 36,
+ 78,168, 67, 8,179,183,178,156,139, 61,207, 19, 42, 82, 38,147,
+ 73,255, 85, 95,187,173,109,108,108,100,111,101,187,127,239,138,
+ 246, 58, 74,105, 42,149, 74, 36, 18,189,163, 94, 54,155, 21,164,
+ 46,103,111,220,135, 25,161, 68,185,144,169, 51, 31,102, 98, 10,
+ 121, 98,211, 41,241,192,243, 60,207,243, 38,147, 9,223,112, 70,
+ 163,209,104, 52,226, 23, 5, 89,236,245,122,147,201,132, 7,252,
+ 24, 99, 65, 57, 41, 30,114, 35,132,184,220, 27, 12, 6,185, 92,
+ 174,215,235,221,185,115, 39,151,203, 21, 62, 46, 76,103,106,163,
+ 85,124,131,215, 3,238,102,140, 49, 46, 82,132,238, 61,137, 68,
+ 34,243, 97,166,251,247,238, 96, 48,136, 65, 59,231,214,115,124,
+ 171, 75,172, 37, 68,167,213,249, 86, 23,191,211,113,115, 39,237,
+ 58,242,216,248, 28,183,237,253, 84,168,159, 69,239, 6,163,209,
+ 168,221,110,119,255,222, 77,172, 37, 52, 77,187,115,231,142, 32,
+ 189,112,216, 57,220,216,220,216,254,249,182,255, 79, 63,147,201,
+ 112, 39, 79, 36, 18, 47, 95,190,124,217,122,153, 91,207,137,240,
+ 55,252, 17,158,230, 98,161, 34, 37,151,203,105,183,181,222, 81,
+ 111,244,195, 40,255,179, 55,135,116,252, 44, 82,144, 69,198, 88,
+ 251,251,118,191,223,159, 76, 38,135,157, 67,209,217,168, 48, 86,
+ 189, 18,156,100,122, 77,242,197, 73,192, 24,135, 26,129,103,215,
+ 82,239,167, 38,255, 59, 65, 8,241, 93, 72,232,214, 58,250, 97,
+ 116,120,120, 88, 40, 20, 52, 77, 59, 60, 60, 20,177,207,124,215,
+ 248,142,175,140,237,159,111, 31,118, 14, 17, 66,161,118, 0, 0,
+ 240, 36, 78,180, 70, 95,182, 94, 78, 71, 1,140,177,151,173,151,
+ 226, 98,171,222, 81,175,223,239,251,190, 95, 40, 20,242,249,124,
+ 187,221,230,225,164,184, 72, 36,156,177, 21,147,234,231, 71,148,
+ 132,194,147, 82, 43, 3,126, 8,194, 19,218,124, 95, 45,124, 92,
+ 224,161,120, 12,177, 49,207, 2,112,209, 46,212, 74, 46,151, 27,
+ 188, 30,240,204,165, 80, 67, 11, 39, 77,144,226,227, 26,132,127,
+ 248,100, 50,105,183,219,133, 66,225,206,157, 59,240, 61,184, 98,
+ 171,244,186, 33,210, 58, 20,132,174, 80,131,137,112, 0,190,207,
+ 12, 6, 3,254,205,100, 50,225,223,139, 35,148,237,237,237,124,
+ 62,143, 49,230, 71,143,153, 15, 51, 66, 79, 4, 83,169, 84,230,
+ 195, 12,167,203,153, 65,197,118,112, 32,142,188,194,104,113, 50,
+ 153,248,190, 15,223,131,236,223, 44,230, 20,230, 21,166, 51,174,
+ 36,113,179,118,190,219, 51,110, 54,155,105,132, 10,198,230, 73,
+ 127,147,205,102,181,219, 90,184,153, 47, 59, 65,195,102,171,229,
+ 251, 1, 0, 0, 99,197,220,218, 66, 40, 45,108,205,141,187,174,
+ 75, 8,161,116, 8, 0,208,212, 91,134, 97,204,155, 75,165, 82,
+ 60,159,151, 74,165,120,193, 82, 52,106,206,233, 12, 41,157,183,
+ 216,239,247,121,174, 52,177,150, 24, 13, 70,221,110,119, 57,242,
+ 162,116,232, 56,206,204,197,249, 59,152,203,229,250,175,250,220,
+ 4,165, 52,183,158,227,135,226, 75, 59, 94,219,233, 76, 79,105,
+ 169, 84,140,252,198,121,132, 16,143, 44,252, 85, 56, 64,198,216,
+ 224,245, 32,183,158,131, 16,242,244, 51,250, 0,245,142,122, 24,
+ 227, 66,161,208,110,183, 47, 74,151,140,141,219,142,227,186, 71,
+ 0, 0,132,210,134,177,169,169,170, 72, 66,252,209,220,233,142,
+ 48,250, 97, 20, 9,161,180,157,142,227,116,206,227,119,167, 59,
+ 194,217,132,226, 7,193,227,199,251,148, 82, 85,213, 78, 33,148,
+ 193, 96,128, 16,186, 76, 46,189, 94,111,212, 27, 13, 0,128,170,
+ 106,227, 49,107, 54,155,142,227, 84,171,187, 88, 81, 34,191, 97,
+ 126, 16,212,106,123,188,220, 35,157, 70,227, 49,171, 55, 26,205,
+ 86,107,222,220, 96, 48,224,174,197,143,120, 34,177,222,117, 93,
+ 203,178, 0, 0,170,166,206, 19, 10,231, 20, 77,211, 46,147,213,
+ 163, 67,202, 39,115, 26, 51,119,144,215,182,133, 10,136, 49,214,
+ 253,123, 55,155,205, 78, 38,147, 37,178, 54,140,141,107,123,123,
+ 190,239, 67, 8, 21, 5,243, 73, 22,225,108,196, 35,243, 67,155,
+ 31,224,225,225, 97, 54,155,229,197, 74,163,209, 27,106,246,125,
+ 63,155,205, 94,116,161, 50, 54,126,244,213, 87,148, 82,140,113,
+ 50, 9, 93,215,117, 28,167, 92, 46,111,155, 91, 98,116,199,240,
+ 209, 87, 95,241,112, 59,153,132,167, 59,130,239,251,218,109, 13,
+ 92,174,154,231,235,218, 55,132,120,220, 23,206,244,187,204,135,
+ 25,239, 31,222,146,132,242,162,217,178,109,251, 60,207, 65,240,
+ 227,137, 75, 78,165,174,235,247, 43, 21, 8,147,156, 50, 45,203,
+ 170,215, 27,191,124,248, 32,242,123,134,210, 72,215,245,233,125,
+ 134,155,123,250,244,217,175,171,191,250,201,126,120, 44,184,162,
+ 74,179, 49, 54,182,172,131,211, 83,131,124,233, 95,114, 81, 2,
+ 0,170,213,221, 83, 54,210,201,100, 50, 35, 39, 7,131,193,210,
+ 91, 2,103, 19,113,110, 22,162, 84, 42,206, 11, 31,143,144, 90,
+ 109, 79, 83,111,205,179,243,233, 67, 62, 15,158,218, 54,165,180,
+ 82,169, 28,203,159,113,109,111,207,182,237,188,174,139, 80,208,
+ 79,172, 3,198, 88,120,239,248,230,247,248,241,254,239, 62,255,
+ 237, 73,132,130, 49, 94,122,193,180,157, 14, 33,158, 97, 24,247,
+ 43,247, 66,115,150,117,240,217,111,254, 99,254,143, 57, 21,156,
+ 98,235,221,211,181,165,109,219,134, 97, 84,119,119, 99,136,205,
+ 74,165,226, 47, 31, 62,224,108, 2, 0, 40, 24,155, 24, 99,215,
+ 21,242,166, 41, 8,147,247, 43,247,166,157,141,155, 35,196, 19,
+ 61,204, 39,150, 5, 0, 48, 12,227,244, 20,192, 37, 9,101, 24,
+ 239, 41, 67,219,233,248,190, 95, 42, 22, 69,179,201, 73,224,114,
+ 221, 52, 77, 65,146,129,175,144,112,241,232,235,235, 92, 6,138,
+ 8,118,184,123,135,139, 19, 43, 74,185, 92,166,148,182,157,206,
+ 194, 93,161,119,212,211, 52,109,233,244,101,171,213, 2, 0,236,
+ 148,203,161, 57,195, 48,124,223,159, 23,152,137, 68, 66,211,180,
+ 222, 81,239,148,128,241, 52, 66,209, 84,181, 90,221,189, 95,185,
+ 23, 58,121,204, 72, 38, 97,156,230, 24, 99,162, 75, 84,219, 78,
+ 199,117,221, 74,229, 30, 76,198, 49,165, 66,227,252,216,252,249,
+ 156, 9, 35,195, 48, 4, 45, 84, 46, 67, 56,173, 28, 71,148, 67,
+ 174,115, 5, 4,227, 62, 0, 0,165,127, 34,124,242,186, 14, 0,
+ 8, 78, 8, 33,125,223,127,241,226,197,210, 73,116,223,247, 85,
+ 85,155,158, 58, 93, 95, 7, 0,184, 93,119,158,188, 94,188,120,
+ 113,250, 86,247,238, 53, 89,145, 39, 81,181,170,198,244,106,137,
+ 182,211,161,148,154, 91, 91, 66,215, 61, 87,124,124,125,136,245,
+ 177,225, 48,206,155,197,239, 20,132, 73,198,198, 30, 33,130,178,
+ 39, 39,161,217,106, 1, 0, 76, 97,226,136,127,242,227,253,125,
+ 206, 41, 47,154, 45,199,113, 76,211, 20,119, 98, 48, 47,168, 1,
+ 0,252,176, 34,106,254, 10, 66,198,156, 78, 8, 44,157, 2,187,
+ 190,133,109,205,102, 19, 0, 96,156,156, 6,142,106,103, 3, 0,
+ 120,228, 85, 16,248,165, 98, 81,196,169,196,116,108, 12, 33, 12,
+ 181,165,232, 77, 27, 0,240,167, 63,255,133,103,106, 48,198,250,
+ 250,186,105,154, 34,246,240,112, 81, 62,181,159,241,187, 6, 0,
+ 64, 8,149,203,119, 99,160, 78,198,198,142,227,168,170, 38, 34,
+ 121, 31, 70, 1, 15, 31, 62,176,172,131, 47,190,252,146,151,255,
+ 137, 91, 42, 88,193,124, 65,150,126,186,219,137, 83,229,243,130,
+ 136,243, 11, 99,227,213, 33, 20,143,144,122,163,113,250,185, 82,
+ 20,219,248,143, 71, 33,170,170, 37, 69,198, 59,245,122,131, 16,
+ 175, 90,221,141, 39,126, 52,205, 59, 0, 0,158,164,100,227,177,
+ 235,186,245, 70,195, 61, 58,170,238, 70,255, 15,240, 69, 73, 8,
+ 129, 16, 62,124,248,128,231,155,109,251,153,101, 29,224,223, 96,
+ 209,219,120,219,113, 24, 99, 66, 55,158, 99,153, 0,249, 96, 25,
+ 99,108, 60,102,108, 44,226, 86, 66,152, 52, 77,179,217,108, 62,
+ 177, 14,248,160,136, 71,220,163, 35,112, 67,112, 29, 9,133, 31,
+ 84, 99,140, 69,156,239,204, 4,116,127,252,195,239, 67,169, 98,
+ 219,118,167,211, 89,152,220,190,252,136,234,141, 70,169, 88,140,
+ 45,132,204,235,250,180, 58,216, 41,223,125, 98, 29, 56,142,211,
+ 118, 28,113,121,211,105,182,130, 16,214,106,123,205, 86,107,167,
+ 124, 87,232, 72, 91,173, 22, 58,181, 66, 42,146,112,216,178, 44,
+ 195, 48,184,186,108, 54,155,245, 70,131, 16, 34, 98,169, 0, 0,
+ 74,197, 34, 99,204,113, 28, 46,159, 17, 66,149,202,189, 90,109,
+ 47,182, 8,107,165, 8,133,210, 97,173,182, 7, 0,120,248,224,
+ 65,108,201, 96,132,210, 92,193,214, 27,141,182,211,137,124,117,
+ 242,115, 98, 85, 83, 61, 66,166,115, 28,111, 74,248, 20, 28,195,
+ 72, 75,197,162,227, 56,174,123, 36,136, 80,140,205,205,233, 81,
+ 188, 57,242,244,197, 38, 83,120,230,171, 84, 44, 10,181, 98,219,
+ 182,170,106,252, 84, 21, 0, 80, 42, 21,147, 16,218,182,253,162,
+ 217, 18, 49,153,252, 8,114,167, 92,246, 3, 31, 66,136, 21,133,
+ 47,155,153,192, 36,154,149,159, 70, 96, 46,227,198,227,229,229,
+ 214,228,245, 34, 20,198,198,143,247,247, 1, 0,213,234,110,252,
+ 124,172,106, 42,104, 8, 57,112,229,137,113, 78,148, 51, 43, 21,
+ 156, 85, 45, 18, 33,105, 10, 75, 49, 96, 16,123, 26,152,195,113,
+ 58, 16, 66,161,167, 75, 30, 33,140,177,153, 10,151,109,115,203,
+ 182,109,113,236,204,253, 57, 92, 21,188,100, 86,207,235,130, 86,
+ 197,244, 1, 22, 56, 62, 14, 95, 46, 39,181,118,173,216,164,182,
+ 183, 71, 41, 21, 84, 29,123, 14,183, 15, 0, 0, 34, 50, 41,213,
+ 234,238,188, 39,240,106, 75,140, 21,238,144, 49,164,165, 0, 0,
+ 24, 43, 34,150, 62,198,152, 16, 50,191,203,137, 48, 55, 61, 34,
+ 94,178, 17,127, 89, 3, 79, 88,198, 99, 87,116,214, 89,215,117,
+ 215,117,167, 83, 66,156,191,148,165,238,221,187,215,138, 77,120,
+ 129, 96, 12,108, 50,127,180,233, 17,210,104, 52, 32,132,133, 83,
+ 75,206,150, 78,214,204,124,113,249,138,177,162,169,170,136,117,
+ 217,118, 58,211, 89,122, 74,135,182,253, 12, 28,151, 24, 68,142,
+ 173,173, 45, 74,233, 19,235, 32,188,155, 79,109, 91,156,185,144,
+ 148,121, 40, 39,116,169,104,170, 10, 33,108,182, 90,211, 11,230,
+ 120,116,122, 12, 11,181,182,183, 7, 0,216,217, 17,149,138,226,
+ 169, 95, 62, 34, 0,128, 31, 4,142,227, 32,132,150, 59,161,187,
+ 46, 10,197, 15,222,188, 97,228,209,163,175,230,131,255,200,143,
+ 232,248,243, 32,225, 83, 39,195, 33,165,148, 66, 8,203,229,242,
+ 85, 85,241, 69,157,181,177, 44, 0,248,195, 32,227,241,155,186,
+ 219, 74,165, 34, 40,182, 42, 24,155,132, 16,199,113, 8, 33,233,
+ 52, 10, 2,159, 49,102,154,166,184, 80,142,231,209, 85, 85,139,
+ 33, 52,174, 84,238, 61,126,188,255,232,209, 87,188, 42,138,143,
+ 206, 48, 12, 65,153, 96,254, 24,193, 84, 84,130,132,238,178,121,
+ 93, 55, 12, 35,188,119,132,120,252,180,110,185, 79, 59, 47,161,
+ 148,138,197,180,200,247,101,160, 52, 58,105,171, 81,181,232, 23,
+ 165,105,154,105,132,194,231, 98, 21, 69,217,218,218, 18,244,104,
+ 198, 73,131, 42,129,162,136, 82, 75,142,207, 62,251,141,219,117,
+ 61,242, 10, 0,144, 76,194, 82,177,184,240, 89,234, 8,113,191,
+ 114, 79, 85, 85, 46,158,103,158,147, 18, 66, 40, 67, 90, 42, 22,
+ 69,164, 21, 22,186,220,239, 62,255,220,113, 28, 62,159,162, 71,
+ 135, 21, 28,250,130,170,169, 49,228,215,166,239,157,105,154,151,
+ 121,202,255,157,253,253,191,197,227, 66,178,199,189, 52, 39,205,
+ 173,188, 57,249, 78, 89, 9, 9, 9, 73, 40, 18, 18, 18,146, 80,
+ 36, 36, 36, 86, 24,239,180,157, 67, 57, 11, 18, 18, 18, 82,161,
+ 72, 72, 72, 92, 47,172,201,228,182, 52, 39,205, 73,115, 82,161,
+ 72, 72, 72,200,144, 71, 66, 66, 66, 18,138,132,132,132, 68,124,
+ 132, 2, 33,212, 52, 77, 78,232,229,193,223, 45, 46,186, 49,168,
+ 132,196,181, 39,148,219, 43, 75, 40, 27, 27, 27, 16, 66, 8,225,
+ 198,198,134,104, 91,147,201, 4, 66,152,207,231, 99,238,235,154,
+ 205,102, 11,133,130,104, 43,185, 92, 46,151,203,173, 82,203, 90,
+ 9, 25,242, 92, 12, 24,227, 84, 42,197, 24,211, 52, 45,158,142,
+ 191,221,110,151, 82, 26,167,226,211, 52, 77,187,173, 81,241,221,
+ 124, 70,163, 17, 66, 40, 6, 94,150,144,132,114, 77,145,205,102,
+ 41,165,137, 68, 2,127,132,105, 92, 13,180,186,221,238,101, 90,
+ 145, 94, 20, 8,161,209, 15,163,203,244,165, 62, 39,124,223, 31,
+ 12, 6,232, 3, 25,208, 69,131, 84, 42, 21,131,174, 60, 63,214,
+ 228, 45, 57, 51,148, 75,189,159,234,247,251,188, 75, 46,141,183,
+ 35,159,132,196,233, 72, 36, 18, 49,176,115, 34,145, 88,216,146,
+ 125,222, 29, 36,161,156, 1,198,216,243,111,159,135,187,171,156,
+ 16,137,183, 84, 7,125,188, 64, 7,133,174,113, 83, 9, 37,145,
+ 72,108,108,108,160, 15,208,100, 50, 25,188, 30,112, 15,207,102,
+ 179,135,135,242,137,164,203, 78,236,104, 52,138,141,163,185,197,
+ 120, 18, 82,171,234,225,185, 92,142, 79, 35, 0, 32,140,122,218,
+ 237,182, 8,115,148,210,121,238, 88,133,144, 39,149, 74, 81, 74,
+ 61,207, 75, 36, 18, 24, 99,206,154,253, 87,125,185,194,150, 6,
+ 198, 24, 99,156, 72, 36,250,253,152,166,113, 48, 24,208,127,209,
+ 59,119,238,248,190, 31, 67,214, 38,102, 94, 14, 67, 3,222, 17,
+ 76,144,161,201,100,194,195, 13, 30,146, 95,159, 72,252,134, 17,
+ 10,165, 52,156,187,193, 96, 32,233, 32, 18,142,230,242, 68,220,
+ 234,159,119,134,209,104,148, 72, 36, 86,175,214,102, 58, 52,240,
+ 254,225,137,163, 75,198, 24,255,112,132, 16,254, 8,139,230,101,
+ 132,208,106,134, 60, 18,145,131,159, 37,109,111,111,107,154, 22,
+ 207,185, 82, 38,147,201,222,202,190,248,159, 23,177, 81, 88,156,
+ 27,222, 57, 67,131,155,133,209,104,212,254,254, 92,193,148, 36,
+ 20,137, 55, 59,222,194, 52,190,160,109, 28, 28,103, 82, 36, 98,
+ 115,245, 72, 34,172,203, 18,138, 71,136,235, 30,241, 14, 88, 8,
+ 165, 85, 85,141,176,117, 0,239,132,160, 96,101,166, 3, 72,219,
+ 233, 12, 41,157,121, 75, 59,255,227,116,164, 93,108,235,245,198,
+ 252, 69, 65,111,135,231,131, 10,127, 84,176,162,169,154,160,150,
+ 29, 51,182,102, 16,121, 79, 18, 62,141,243, 31,187,240, 62, 70,
+ 53,186,147,204, 69, 62,186,208, 17,136,247, 99, 39,179,180,224,
+ 110,202,231,247,187,243,187,250,249,135,166,169,234,210,183,108,
+ 237,228, 45,107,252,196,178, 92,215,229, 17, 20,132,208,113, 60,
+ 199,113, 90,173,214,195, 7, 15, 34, 89, 34, 16,194,122,163,129,
+ 49,158, 33, 20,219,182,249,246, 53,189, 56,252,192,175, 55, 26,
+ 209, 54,157,172, 55, 22, 16,138,170,169, 34, 8,197,113, 58,132,
+ 204, 6,186, 34, 90, 14,157,100, 75, 28,161,208,225, 2,174,167,
+ 116,104, 89, 22, 66, 40,114,115,124,116,243, 31,123,210,245,168,
+ 224, 7, 1, 33,132, 49,166,170,154, 33, 44,251, 19,131,223,205,
+ 128,247,168,138,106,101,158, 72, 40,124, 84,186,174,239,148,203,
+ 124, 24,140,141,121,223,249,199,251,251,213,221,221,203,239,174,
+ 188,133,165,239,251,211,109, 16,121, 43, 89, 0,128, 71, 94,149,
+ 166,135, 77, 94, 1, 0,212,159,182,152,189, 60, 84, 85,251,117,
+ 245, 87,177, 9,212, 63,254,225,247,124, 38, 61,226, 89,214, 65,
+ 189,209,152, 23,104,151,199,244,136,190,174,125, 67,136,199,237,
+ 158, 30,242, 32,132, 16, 66, 75,108,119,188, 13,123,171,213,154,
+ 38, 20,199,113, 0, 0,197,185, 94, 75,169, 84, 42,149, 74,177,
+ 127,223,176,120,135,247,123,228,147, 41,116,193,196,224,119, 11,
+ 193, 27,108, 95,126,101,190,123,178,226,114, 49,198,191,124,248,
+ 35, 41, 66,152, 44,149,138,165, 98,209,247,253,102,179, 25,201,
+ 48,244,245,117, 0,128, 55,181,157,114,245, 85, 42, 22, 9,241,
+ 166,155,105,114,249,167,169,171,240,252, 33,132,201,188,174, 87,
+ 42,247,192,113, 63,205, 43, 71,175,215, 27,141, 70, 11, 51,249,
+ 103, 2,161,180, 97, 24,190,239,123,199,237,141, 25, 27, 55, 91,
+ 45,180, 40, 46,200,229,114, 16,194,120,234,134, 10,133,194,167,
+ 191,248,116,250,235, 90, 85,169, 95,161,223,157,190, 50,203,229,
+ 242,210, 43,115,237, 36, 85, 9, 0,216,218, 90,208, 89,222, 52,
+ 205,122,163,225,116, 58,145,104, 75, 85, 83, 65, 3, 16,242, 42,
+ 228, 66,143,188,194, 24,243, 70,205, 30,241,194,235,132,120, 24,
+ 227,213,232, 19, 26, 70,124,224,184,237,246,149, 99, 50,153, 92,
+ 198,201,185, 72,169,215,191,211,170, 42, 0,160,237, 56,140, 49,
+ 190, 46,103, 51, 29,237,118,108,131,138,211, 86, 84,209, 92, 60,
+ 126,119,230, 14,177,244,202, 92,172, 80,130, 32, 0, 0, 44, 20,
+ 60, 60, 78,161,148,206,216, 91, 46,219,204,219, 44,242,136,145,
+ 143,129, 16, 79, 85, 85,174, 68,120,152,195,153, 27, 0,160,138,
+ 239,201, 24, 39,120,100, 23, 91,243, 83,209, 75,208, 48, 12, 66,
+ 60,222, 81,188,117,130, 60,145, 56, 29, 75,248,157, 80,181, 18,
+ 25,161,240,146,246,147, 62, 49,153,132, 0, 0, 63,240,103,182,
+ 184,229,178,205,170,170, 81, 74,121,143, 97, 30,251,168,234, 45,
+ 8,147,170,170,133, 68,195,227,160,200, 19, 40, 0,128,225,144,
+ 214,235,141,233,175,120,238, 22,165,195, 70,227, 59, 0,128,177,
+ 42, 94,199,219,241, 54,155,173,182,211,161,148, 22,139, 69, 73,
+ 16, 23,197, 18,126, 39, 2,205,102, 11, 0,160, 47,149,218,187,
+ 250, 58, 20, 93, 95, 39,196,243, 8, 41,160, 77, 46, 73,184, 60,
+ 209,245,117,219,182, 41, 29, 34,148,230,251,158,136, 4, 10,165,
+ 116, 38,197, 45, 84, 82,126, 93,251, 6, 0, 48, 30, 51,223,247,
+ 33,132,149, 74, 69, 91, 21,217,197, 69,138,227, 56,132, 16, 41,
+ 79,110, 28, 28,167, 67, 60,194,198, 99,215,117, 41,165, 24,227,
+ 229,238,224,213, 19,138,166,169, 0, 0, 66, 72,193,216, 36,132,
+ 132,137, 18,126,253,152,104,136,160, 4, 74,204,167, 60, 33,139,
+ 1, 0,170,213, 93,172, 40,171,180, 40,121, 38,133, 82, 90,169,
+ 84,164,139,222, 52, 66,113,248, 55, 24,227,114,185,188,109,110,
+ 45,247, 57,139, 9,101,254, 52,119, 26,227, 49, 3, 0, 96, 5,
+ 71, 50, 18,172, 40, 16,194, 32, 8, 24, 27,251,190, 95, 58,150,
+ 202,252,186,235,186,154,170, 50,198, 86, 35,129,194,201,203, 35,
+ 164, 86,219,123,250,244, 89,252, 92, 38, 90,164,168,170, 70,136,
+ 39,229,201,146,190, 16,163,223,205,128, 31, 27, 95,254,115, 22,
+ 231, 80, 20, 69, 1, 0,116,221, 5,205,129,184,219, 35,132, 34,
+ 212, 11,170,170,250,190,207,131, 67, 85, 83,167,162, 33,157, 16,
+ 242,230,186,128, 4,202,149,137, 50, 85,213,117,157, 16,111,225,
+ 12, 75,156, 7,243,185,201,225,240,198,191,251, 42,102,191, 19,
+ 129,197,132,194, 51,133,173, 86,107,254, 87, 60,227, 96,108, 70,
+ 185, 5,241,244, 79,189,254, 29, 56, 62,247, 9,137,134, 49,198,
+ 207,210, 86,163, 2, 37,196, 78,185, 12, 33,180,237,103,215,228,
+ 216,248, 6, 65,215,215,231,189,142,210, 33,165, 84,143,186, 68,
+ 48,102,196,236,119,241, 17, 10,223, 66,125,223,255,235,227,125,
+ 126,254,194, 57,178, 94,111, 52,155, 77,140,113,180, 37,240,156,
+ 68,134, 67,170,254,148, 53,248,249, 89, 16, 4, 43, 86,129,194,
+ 163, 3,115,107,107, 62, 37, 44,113, 38,242,186, 14, 33,180,109,
+ 59,172,163,163,116,248,120,127, 31,220,252, 35,179,152,253, 78,
+ 4, 78, 76,202,222,175, 84,120, 21,176,235,186,252,153, 2,126,
+ 166,133, 49,142,188,254, 23,161, 52, 47,250,158, 41,233, 9,107,
+ 243,197,205, 35, 33,222,127,254,215,127,139, 8, 38,207, 68,169,
+ 84,116, 58,157,102,179,105, 24,155, 43,150,157, 21,205,197,229,
+ 114,217,178,172, 90,109,111,122,101,154,166,153, 23,166, 80, 60,
+ 66,154,205, 86, 16,248, 0,128,175,107,223, 24,198,166,160, 60,
+ 81,156,126, 23, 43,161, 64,152,252,229,195, 7,211, 79, 61,242,
+ 81,125,246,155,255, 16,241,127, 20,139,197, 33,165,243, 11,162,
+ 88,252, 36,240, 3, 61, 47,100,161,148, 22,213, 74,160,180,144,
+ 231,190, 12, 99, 83,155, 75, 3, 85, 42,247,136, 71, 40,165,226,
+ 8,101,161, 93,161,162, 61, 6,115, 5, 99, 83, 83,213,102,171,
+ 197, 87,166, 97, 24,134,177, 41,122, 27,192,138, 18, 3,239,207,
+ 251,157, 97, 24,209, 62,229, 63, 3, 85, 83, 75,160, 24,213,178,
+ 95, 59, 83,131,133,247,137, 63, 25,213,118, 58, 34,198,118,210,
+ 103,230,117, 93,220,182, 19, 67, 21,243,233, 3,156,158,222, 56,
+ 237,174,128, 57,132,210, 59,229,187,113, 6, 35,113, 86, 12,197,
+ 105, 46, 90, 91, 23,232,203,179,179,115, 23, 66,104, 89, 86,251,
+ 122, 60,207, 38, 33, 33,113,221,112, 1, 66,193,138, 82,173,238,
+ 66, 8, 91,173,150, 60,155,144,144,144,184,112,200,179,152, 83,
+ 146,112,197,206, 92, 36, 36, 36, 34,193, 59,109, 71,118,180,145,
+ 144,144,136, 61,228,145,144,144,144, 56, 35,228,233, 29,197, 84,
+ 253,157, 91,215, 1, 0,210,156, 52, 39,205,173,176, 57,169, 80,
+ 36, 36, 36, 36,161, 72, 72, 72, 72, 66,145,144,144,144,132, 34,
+ 33, 33, 33,113, 54,110, 94, 43, 82, 8, 97, 62,159,239,118,187,
+ 49,247,178,212, 52,109, 52, 26,197,211,161, 61,151,203,241,126,
+ 157,188,187,133, 80, 91, 24, 99,140, 49, 0,192,247,125,254, 28,
+ 154,132,196, 91,164, 80, 24, 99, 16,194,108, 54, 27,167,209, 68,
+ 34,161,221,214, 38,147, 73, 60,230, 82,169, 20,132,144, 82, 26,
+ 131, 69,198, 24,165, 20,125,128,120, 91, 15, 9,137,183, 75,161,
+ 0, 0,250,253,190,118, 91,235,245,122,177, 89,204,100, 50,224,
+ 248, 93,176,177,241,166,231,121, 49, 24,162,148, 82, 74,181,219,
+ 87,240,254, 42,132,144,166,105,130,186,231, 32,132, 48,198,158,
+ 231,197,223,149,125,185, 6,140, 87,104, 46,108,134, 61,221, 45,
+ 112,186, 67,118,169, 84,228,111,159, 57,243, 49,194, 27,153, 67,
+ 241,125, 63,145, 72,112, 39,143,141, 80, 70, 63,140,128, 68,116,
+ 62, 80, 40, 20, 54, 54, 55,196, 57, 30, 15, 21,183,127,190,157,
+ 207,231,227, 20, 95,217,108,182,240,113, 33, 54, 5, 29,137, 57,
+ 199,233, 36, 33, 84,176,226, 56,157, 39,214,193,244, 69, 85, 83,
+ 249, 91, 89,137,247,147,158,234, 43,165, 80, 38,147,137,255, 79,
+ 31, 99, 28, 79, 70, 3, 0, 16, 79,235,204,183,132, 74, 52, 77,
+ 131, 16,122,158, 55, 56, 28,136,139,233, 38,147, 73,183,219,245,
+ 60, 15, 99,124,103,235,206,224,245, 32, 30,181,194, 77,196, 38,
+ 139,162, 50,135,177,162,169,106, 94,215,191,174,125,227, 7, 1,
+ 127,243, 11,191,184,250, 33, 15, 0, 96, 48, 24,108,108,110, 64,
+ 8,227, 23,180, 18,203,129,103,211, 57,149,196,150,253,229,145,
+ 99,191,223,207,102,179,156, 86,186,221,174,232,149,249,252,219,
+ 231,113, 58, 66,180,230, 52,245,150,219,117, 57,161,240,102, 61,
+ 233,139,116, 89,122,247,230, 18, 10,251, 55,227,199, 19, 18, 55,
+ 11,137, 68, 34,145, 72,172,182,197,213,128,162, 40,170,166, 98,
+ 124,129,247,212,173,221,220,209,250,190,207,179,110,242,198,223,
+ 8, 48,198,218,237, 54, 66, 40,155,205,106,183,181,120, 98, 16,
+ 110, 14,125,128, 6,175, 7, 47, 91, 47,165,158, 61,219,173,130,
+ 32,124,215,247, 91, 20,242,112, 66,209,110,107, 49,103,212, 37,
+ 46, 9,126,168, 4, 33,212, 52,109,251,231,219,131,215, 3, 65,
+ 249, 41, 8,225,198,198, 6,124, 15,246, 95,245,187,221,110,108,
+ 71,254, 55,153,241,199,109,199, 25, 14,135,151,121,233,234,218,
+ 77, 30, 63, 27,188, 30,240,150,244,114, 53,220,184,123,215,237,
+ 118,123,189,158,184,211,144, 68, 34,209,239,247,227, 47,213,131,
+ 16, 66, 8, 71,163, 81, 60, 20,150, 72, 36,178,217,108,191,223,
+ 191,140, 57,140,149,227,174, 88,183,170,187,187,211, 23,235,224,
+ 59, 0,192,175,171,191, 74, 35,228, 56, 29,175,246, 13, 0, 96,
+ 103,231,238, 73,239,235, 62, 23,161,116, 93, 55,240, 3,211, 52,
+ 69,191,168,141,115,164,235, 30, 1, 0, 32, 76,170,170,154,215,
+ 117,132,210,167,100, 82,242, 63,203,247,122,189,139,206,166, 71,
+ 126,114, 6,150,132, 80,211, 84,209,239, 52,159, 62,216, 15,161,
+ 106, 2, 95, 71,236, 7,129,219,117, 61,242, 42, 92, 34,170,122,
+ 43,242,151,126,243,113,205,191,241,251,164,235, 33, 38,147,201,
+ 37, 35,214, 83, 76,140, 70,163,168,138,140,249,106, 49, 12, 99,
+ 122, 41, 50, 54,110, 54,155, 73, 8,103,218, 0, 99,140,181,219,
+ 218,119,141,239, 4,141,107, 6, 60,126, 4, 0, 92,102, 38, 23,
+ 190,238,123,230, 98,225,124,157, 67,206, 69, 40,150,117,192, 24,
+ 155,159,187,200,217,164,182,183,231,251, 62,132, 80, 81, 48,111,
+ 77, 50, 28, 14, 79,121,185, 57,255,227, 68, 34,113, 81, 66, 33,
+ 30,153,239,176,133, 16,122,248,240,129, 56, 90,113,156, 14, 33,
+ 179,119,189, 4,138, 34, 8,133,177,241, 95, 31,239,115,115, 8,
+ 161,116, 26, 17,226, 17,226, 53,155,205, 74,165, 18,237,187,233,
+ 249,184,230, 87,255, 73,215, 99, 48, 29, 45,248,106, 81, 53,117,
+ 154, 80,248, 90,253,236,179,223,204,175,162,193,235,203, 30,135,
+ 159,127, 92,131,193, 0, 33, 20, 73,253, 4, 99, 99,222,246,247,
+ 108, 69,163,156,216,120,239,108, 66,233,186, 46, 99, 12, 33,212,
+ 233,116,132, 18, 74,179,217,244,125,223, 48,140,251,149,123,225,
+ 206,112,102,187,144,203, 16,115,216,211,139,239,228,205, 86,235,
+ 209,163,175, 68, 55,250,250,227, 31,126,127, 78, 41,139, 16, 90,
+ 78, 57,135,212,172,235,250, 78,185, 28,186, 1,165,195,174,235,
+ 206,176, 9,151,232, 50, 10,187, 16,158, 88, 7,190,239, 87, 42,
+ 149,249,237, 7,125,128,218,223,183, 99,251, 79, 70,163, 81, 36,
+ 165,198,225,154,185,144,227, 44, 67, 40,142,211,129, 16,110,109,
+ 109,217,182, 29, 86,188,136, 0, 87,230, 59,229,114,120, 37,182,
+ 214, 36,188,135,147,170,169,181,218,158,101, 29,252,238,243,223,
+ 94,249,146, 77,189,159, 42,124, 92,104,127,223, 94, 34, 67,244,
+ 212,182,103,168,249,120,243, 76,207,111, 9, 92,162, 75,142, 56,
+ 63, 94, 52, 91,142,227,148,138,197,121,161, 7, 33,236, 29,245,
+ 110, 92, 82,143,179, 9,165,244,179,207,126, 19, 58, 56,165, 67,
+ 190, 21,133,223,240, 61,190, 86,219, 59,229,163,222, 61,211,146,
+ 235,186,250,113,183, 45, 71,124, 71,158, 43, 60,216,211, 84,213,
+ 48, 12, 74,233,149, 55, 30,106,183,219,207,191,125,254,252,219,
+ 231, 75, 44, 77,198,198,142,227, 64, 8,167,169,249,116,137,199,
+ 109,201, 3,248,115,102, 55,108,219, 54, 12, 99, 97, 60,194, 24,
+ 235,247,251, 55,148, 77,170,213,221,144, 77,234,245,198,163,175,
+ 190,242,131,160,237,116,190,248,242,203,176,141,244,153,120,247,
+ 172,233,115, 0, 0,134,177,137, 80, 90,215,117,199,113,196, 13,
+ 76,215,215,193,113,151,249,171, 2,255, 31,130, 32,184,185, 43,
+ 222, 35, 30, 0, 64,215,117,217,234, 36,114,248, 65, 96,219, 54,
+ 198,120, 70,250,221, 92, 44,100, 19, 0,128,105,154, 8,161, 90,
+ 109,207,178, 44,195, 48,206, 31, 43,156, 17,242,116, 58, 29,132,
+ 16,255, 56, 93,215, 93,215,237,186,174,160,222,160, 5,195,232,
+ 116, 58,142,227, 16, 66,138,139,244,100, 12,224,217,132,176,151,
+ 243, 77, 68,224, 7, 0, 0,148, 78,199,108,183, 94,159,221, 9,
+ 134,195,149, 58,206,103,140, 89,214, 1, 0, 32, 60, 88, 93, 1,
+ 120,196,227,185,182,153, 84, 6,132,201,205,205, 77,219,182, 1,
+ 0,230, 69, 50,167,107,167,243,177,239,251,166,105,242, 31,243,
+ 186,110, 1,224, 56, 29, 65,132, 2, 97,178,186,187,251,212,182,
+ 29,199,177, 44,171,209,104,148,203,119,197, 53, 54,190, 42,252,
+ 231,127,253,247,244,143,162,115,192,243, 70, 85, 85,251,117,245,
+ 87,209, 19,202,149, 74,203, 24, 96,219,207, 24, 99,140,177,182,
+ 227, 8, 61,157,136, 19,121, 93,175, 84, 42,150,101, 61,177, 14,
+ 166,101, 87, 24,217, 5, 65, 80,171,237,205,232,151, 37, 9,133,
+ 103, 76, 24, 99,225,230,131, 16,114, 93,151,177,177, 32, 57, 13,
+ 97,242,126,229, 94,169, 88,172, 55, 26,142,227, 60,126,188,255,
+ 240,225,131, 21,227,148, 82,241, 39,177,119, 84, 93,239,207,105,
+ 84,156,219,207,159, 94,125, 93,251,102,254,152,252,230, 34,157,
+ 70,213,221,123,181,189,189, 70,163,113,122,121,212,205, 2, 15,
+ 5, 44,203, 2, 0,132,156,130,177, 98,154,230, 78,249, 46, 99,
+ 227, 39,150, 21,141, 66,225, 25,147,249,188,137,104,134, 70, 40,
+ 125,191,114, 79,215,215, 31, 63,222,111, 52,190,139,147, 80, 40,
+ 29, 2, 0, 52,245,150, 64,223, 22, 92, 52,161, 96, 5, 0, 64,
+ 135,195,133, 70, 87, 94, 71,136,188,113,159, 32,148,174, 84,238,
+ 213,106,123, 79,172, 3, 17, 42,239,202, 57,133, 49, 22, 42, 17,
+ 152, 76,114, 37,129, 21,197,237,186,110,215,157, 95, 87, 23, 32,
+ 20, 94,126, 82, 46,151,103,184,227, 79,127,254,139,232,130,148,
+ 80,140, 97,140, 99, 46,157,230,162, 76,193,202,205, 93, 28,154,
+ 170, 1, 0,200,185,211,242, 18, 23,156, 94,213, 52,205,102,179,
+ 249,162,217, 90,153,192, 39,228, 20,199,233,132,117,213, 39, 65,
+ 85,181, 83, 10,151,214, 78,119,173,130, 97,204, 92, 55, 12,163,
+ 217,108, 10, 45, 72,185, 42,180,157, 14, 33, 30, 66,232, 70, 7,
+ 89, 16, 38, 13,195,112, 28,167, 94,111,136, 86, 67,111,169, 84,
+ 41, 22, 93,215, 93,177,192, 7,156,187,184,254,116, 44, 62, 54,
+ 14,203, 79,230,115, 37,198, 49,147, 69, 62,158, 23,205, 22, 99,
+ 227,105,247,230,213, 89, 49, 76,165, 71,200, 19,235,192,178, 44,
+ 8,225,195,135, 15, 86, 96,197, 67, 8,235,141,198, 83,251, 25,
+ 15,226, 36,162,165,236, 74,229, 30, 99, 44,124, 91,162,196, 25,
+ 10,133,151,159,232,139, 54,106,172, 40, 8, 33,199,113, 78,121,
+ 196,102, 57,216,182,109,219, 54,127,240,100, 56,164,148, 82,140,
+ 241, 57,171,179,150,195, 76,205,159,170,106,167, 60, 70,121,131,
+ 128, 80,186, 90,221,125,252,120,191,217,108, 54,155,205,233, 41,
+ 149, 43, 62,170,192,135,203, 64,161,129,207,204,129, 96,169, 88,
+ 188,254,146,115,237, 4, 14,134,165, 98,241, 36,229, 95, 46,223,
+ 13,252, 96,186, 32, 55, 18, 84,171,187,174,123,196,107, 64, 20,
+ 69,217,218,218, 42, 24,134,160,227, 36, 85, 83, 75,224,199,123,
+ 147, 70, 72, 83, 85,209,242,213, 48, 54,133,166,123,103,120,255,
+ 119,159,255,182,237,116, 8, 33, 92,164,164,211,200,216,220, 76,
+ 31, 87, 21,197, 48,174, 56,199, 43, 20,124,181,204,156,199,237,
+ 148,203,226,138,125, 22, 78, 29,127, 89,244,141, 36,148,211, 67,
+ 169,252,113, 37,126,228,172, 31,219,195, 59,113,218, 58,231,172,
+ 94,219,168,120,233,113,197, 96,122, 56,164, 49, 60,217,184,112,
+ 181, 64,152, 20,167, 23,174,164,170, 83, 32,161, 72, 72, 92, 91,
+ 80, 58,244, 8,129, 48,233, 56, 29, 74,105, 88,120, 41, 33, 9,
+ 69, 66,226,226,132, 50,164,214,113,169,149,174,235, 51,133,130,
+ 18,146, 80, 36, 36, 46, 22,128, 84,171,187, 0, 0,148, 70,171,
+ 116,106,187, 26,120,167,237,200, 22, 86, 18, 18, 18,209,224, 93,
+ 57, 5, 18, 18, 18,145,133, 60,189, 35, 55, 30, 75,185,117, 29,
+ 0, 32,205, 73,115,210,220, 10,155,147, 10, 69, 66, 66, 66, 18,
+ 138,132,132,132, 36, 20, 9, 9, 9, 73, 40, 18, 18, 18, 18,146,
+ 80, 36, 36, 36, 36,161, 72, 72, 72, 72, 66,145,144,144,144,132,
+ 34, 33, 33, 33,113, 37,132,194,216,120,190, 3,139,132,132,132,
+ 4,184,232,195,129, 97, 71,101, 58, 28,174, 76,243, 52, 9, 9,
+ 137, 43, 80, 40, 97,215,194, 82,177,232, 56,142,124,161,166,132,
+ 132,196,146, 10,101,166, 7,106, 26,161,153,206, 64, 18, 18, 18,
+ 18,231, 34,148,249,142,202, 11,187,141, 73, 72, 72, 72, 66,185,
+ 48,155,112, 72, 78,145,144,120,171,208,118, 58,173, 86, 43,157,
+ 78,223,175, 84, 78,122,123,252,218,114,108, 18, 57,167, 80, 58,
+ 156,239,121,202, 97, 24, 70,228, 47,230,122,209,108,141, 25,155,
+ 127,201,112,215,117, 3, 63, 48, 77, 83,208,219,246,193,155,118,
+ 98,111,222, 68,143, 80, 90, 81,148,104, 95,238,239, 17, 66, 60,
+ 162,106, 11,222,171,204, 39, 57,141, 80,228,239, 64,158, 57,248,
+ 19,218, 69,128,219,210,243,250,204,130,228,163, 91, 56,240,203,
+ 204,228, 66, 91,211,255,137,136,249,188,158,112,156,142,239,251,
+ 190,239,159,210,140,248, 12, 66,225,103, 58, 8,161,167, 79,159,
+ 241, 43,188,115,141, 31, 4,225, 21, 8,161,227, 56, 16,194,203,
+ 116,234,161, 67,122, 82,219, 93, 85, 19,178, 52,185,185,105, 78,
+ 161,116,248,248,241,254,194,246,102,145,192, 15, 2,203, 58,224,
+ 205, 85, 49,198, 0, 0,199,241, 0, 0, 11,169,109,105,240, 22,
+ 95,198,208,152,247,171,174,235,214, 27,141,178,128, 86, 71, 11,
+ 239, 29,239,182, 45,200,150, 71, 94,205,116, 23,230, 75,168, 4,
+ 138, 81, 17, 10,241, 8,183,181,240, 76,147, 79, 38, 0, 64, 85,
+ 181,149, 33,148,115,118, 4, 29, 51,182,100,200,163, 40, 74, 50,
+ 249,166, 77,193,120,204,124,223,103,140, 1, 0, 24, 99,132,120,
+ 170,170, 1, 0, 20, 5, 3, 0, 96,242, 82, 78,168,169,234, 31,
+ 255,240,251, 25,113,244,197,151, 95, 66, 8, 69,244,187,216, 54,
+ 183, 58,157, 78,179,213,154,150, 63, 79,172, 3, 8,161,160,214,
+ 98,140,141,107,181, 61,198,152,105,154,165, 98, 49,228,172,182,
+ 211,137,182, 39, 9,239,196,230,186, 46, 0,179, 62,224,186, 71,
+ 0, 0, 65,141, 86, 85, 85, 11, 61,188,235,186,150,117,208,108,
+ 54, 13, 99, 83, 80,227, 52, 66,188,174,235,198,208, 52,246,148,
+ 201,132, 16,178,147, 93,235, 38,178, 73,173,182,247,255,254,239,
+ 255, 17,152, 67,153, 38,102,143,144, 90,109,207,113, 58,196, 35,
+ 188, 9,187,208, 6,244, 79,109,155, 49, 38,174, 49,104,165,114,
+ 239,209,163,175,158, 88, 7,124, 20,188,177,113,185, 92, 22, 36,
+ 212,249,112,230, 55,109, 17,155,155,174,235,205,102,115,198,223,
+ 24, 27, 19,226, 97,140, 99,120,177,115, 94,215, 89,121,108, 89,
+ 150,219,117, 69, 16,138,170,106, 65,224,219,246,179, 24, 8, 69,
+ 85, 87,231,206,243, 0, 0, 10,171, 73, 68, 65, 84, 85,199,113,
+ 230,201,139,247,234, 61, 41, 78,191,161,108,114,121,126,188,112,
+ 165,172,227, 56,245, 70, 67,244, 60,122,132, 56,142,163,235,186,
+ 184,118, 92, 88, 81, 76,211,228, 27, 29, 99, 99,219,182, 49,198,
+ 130,218, 74, 50, 54,230, 81, 97, 60, 61, 31,120,255,105,174, 71,
+ 166, 37, 58, 0, 96,115, 51, 38,113, 46,154,182,138,197, 34,165,
+ 52,134,162,109, 93, 95, 95, 56,153,140, 49, 83, 88, 19,210, 27,
+ 202, 38,224, 66,149,178, 40,141, 98,235,129, 98,219,207, 32,132,
+ 247, 43, 21,161, 86, 74,197,162,235,186,150,117,160,235, 58, 99,
+ 172, 34,236,172,202, 35, 30, 23, 14,226,114,189,103, 70, 61,174,
+ 235,138,139,119, 22,109, 60, 29, 0,128,158, 23,101,110,219,220,
+ 106,181, 90,205, 86, 75,104, 6,157,231,164,116, 93,159,155,204,
+ 35,132,208, 10,180,193, 62, 63,155,248, 65, 64,136, 23, 37,161,
+ 204,231, 77, 5,181, 98,172,215, 27,190,239,151,203,101,209,238,
+ 7, 97,178, 82,185, 87,171,237, 57,142, 99,154,166,184,245, 17,
+ 248, 1, 0, 64, 92, 43,220, 51,163, 30,198,198,174,235, 10,141,
+ 119,134,195, 31,245,130, 71, 94, 5,129, 95,169, 84,132,186, 28,
+ 191,119, 79,109, 91,116,213, 2, 39,148,233,168,199,117, 93,195,
+ 48, 86,146, 77,102, 58,180, 47,158,144,147,247,137, 11, 55,250,
+ 170, 86,119, 53, 85,229,249, 20, 17, 35,164,116,216,108,181,196,
+ 69, 31,243,178,139,127,163,172,196,110, 51, 29,245, 52,155, 77,
+ 215, 61,226, 62, 16, 67,188, 67,233, 79,246, 27,211, 52, 69, 71,
+ 61,154,170,170,170,230, 56,142, 97,108, 10,237, 84,157,215,117,
+ 11,128,112, 50,219, 78,135, 49,102,220,252,147, 29, 74,135, 75,
+ 68, 58,170,170,157,178, 79, 92,152, 80,108,251, 89, 50, 9,199,
+ 99, 81,201,109,158,188, 44, 11, 56,110, 60,201, 28,132, 16, 33,
+ 100,219,118, 62,174,144, 36,158,168, 7, 99, 28, 10,117, 30,239,
+ 20, 68,110,170,211,167, 60,126, 16,212,235,141, 90,109,175, 82,
+ 169, 8, 61, 82,189, 95,185,247,197,151, 95,214,235,223,105, 85,
+ 129,132, 2, 97,114, 58,234,113, 93,119, 53,226, 29,132,210, 23,
+ 205, 43,235,186,126,122, 34, 98,237, 34,107, 20, 79,231, 80, 68,
+ 108,119, 30, 33,174,235,154,166, 41,116,195,153, 49, 87, 42, 22,
+ 85, 77,173,213,246,234,141,198,142, 24, 34, 83,176, 2, 0, 96,
+ 227,113,156,203,101,115,115,211,182,237,174,235,106,170,198,143,
+ 36, 98,163, 75,172, 40,247, 43,149, 63,253,249,207,141, 70, 67,
+ 40,161, 32,148, 46, 21,139,245, 70,163,237,116,132, 10,162, 48,
+ 234,225,147, 89, 22, 83, 91, 16, 63,120,180, 56,205, 41,188,205,
+ 235, 73,114,254,204, 73,190, 0,161, 64,152, 20,148, 52,225, 96,
+ 108,108, 89, 7,177, 29,133, 0, 0, 44,235, 0, 33,196, 7,165,
+ 170,154,184,186, 9,172, 96,190,179,237,196,165,188,184, 80,183,
+ 109,219,117,143, 24, 27,115,151,136,115,165,114,242,162,148,138,
+ 54,100,154,102,179,213,106, 52, 26, 66, 85,109, 24,245,240,201,
+ 204,199, 59,153,113,114,202, 37,247,242,107,244,198,182,102,179,
+ 73, 41,141, 33, 23,203, 81,175, 55, 40,165,225,201, 14,159,214,
+ 176,252, 55,242,141, 84, 85, 53, 74,233,139,102, 43, 78, 65,139,
+ 49, 38,132, 16, 66,226,247, 1,238,120, 8,161, 24,152,171, 92,
+ 46, 83, 74,155,205,151, 49, 68, 61,162,115,219, 87,197, 41, 81,
+ 229,152,175, 11,161, 80, 58,172, 55, 26,177, 85, 49,243,212,239,
+ 116,157, 11, 66,105,195, 48, 8,241,218, 78, 71,132,197,157,157,
+ 187, 0, 0,219,182,235,245, 6,119,182, 48,221, 48,253, 99,228,
+ 81, 15,165,148, 16,162,199,155, 30,242,131,160,182,183, 7, 0,
+ 48, 98, 41,123, 41, 24,155, 24,227,243, 28,106, 94, 50,234, 97,
+ 140,185,174, 27, 91, 45,207, 95, 31,239,255,233,207,127,241, 8,
+ 185, 65,156,178,118, 77, 8,133, 43, 46, 66,188,249, 83,171, 82,
+ 177, 24,121,168,197,223, 14, 53, 83,101,191, 83, 46,187,174, 43,
+ 40, 59,139, 21,229,225,195, 7,150,117, 80,111, 52,234,141, 6,
+ 198, 56,153,132,220, 7,248,193,153,184,168,135, 82, 90, 20, 31,
+ 69,206,223, 59, 93,215,133,198,200,211, 40,151,239, 10, 58,118,
+ 156,137,122,226,212,122, 60,149, 78, 60, 18, 79, 74,241,126,229,
+ 30,132,112, 69, 8, 69,213,212, 18, 40,158,244,171,200,213,184,
+ 166,222, 50,205, 59, 51,194,149,151,165, 4,126, 64,135, 20, 67,
+ 69,196,138,212, 62,215,218,142, 67, 8,225,170,196, 48, 12, 69,
+ 81,120,134, 69, 80,212, 83, 46,151,199,140,137,246,129,153,180,
+ 87, 18, 66, 77, 83, 5,157,131,148,138,197,244, 92, 36,165,169,
+ 42, 31,105,132,171,133,175,201,176,176, 0,194,100,165, 82, 97,
+ 140, 77, 47,155,133,255, 76,116, 44, 89, 38,132,196, 89,240,114,
+ 249, 28,223, 59,251,251,127,139,231,127,149, 61,238,165, 57,105,
+ 110,229,205,201, 54, 26, 18, 18, 18,146, 80, 36, 36, 36, 36,161,
+ 72, 72, 72,172, 48,222,105, 59,135,114, 22, 36, 36, 36,164, 66,
+ 145,144,144,184, 94, 88,147,201,237,155,104, 78, 66, 46,149,235,
+ 105, 78, 42, 20, 9, 9, 9, 73, 40, 18, 18, 18,146, 80, 36, 36,
+ 36, 36,161, 72, 72, 72, 72,156,141, 53, 57, 5, 18, 18,145, 32,
+ 147,201, 96,140, 51, 31,102, 0, 0,244, 95,180,215,235,141, 70,
+ 35,169, 80, 36, 36, 36,150, 4, 99,172,253,125,187,253,125,123,
+ 50,153, 20, 62, 46,200,144, 71, 66, 98, 53,161,105, 90,161, 32,
+ 214,195, 7,131, 65,175,215,163,148, 82, 74,123,189, 94, 34,145,
+ 136,225,253, 82,146, 80, 36, 36, 36, 36,161, 72, 72,220, 64,228,
+ 114,185,171, 18, 68,236,223, 44,134, 87,234, 74, 66,145,144,136,
+ 15,217, 91,217,124, 62, 31,179,209,124, 62,159,249, 48,115,120,
+ 248, 54, 62, 37, 39, 79,121, 36,110, 62,107,100,179,137, 68,226,
+ 164,223,226,143, 48, 0, 32,146,198,189,231,212, 38,248, 35,252,
+ 178,245,242, 45, 60,226,145,132, 34,177, 18,113,205,250, 25,113,
+ 77,230,195,204,224,245, 32,158,127, 6, 33,228,255,211,127, 59,
+ 217, 68, 18,138,196, 42,224,101,235,229, 73, 10,165,240,113, 97,
+ 50,153,180,191,111,103, 50,153,203,191,129,249, 60,232,245,122,
+ 147,201,228,173,189, 23,146, 80, 36,110, 60, 78,145, 3,156, 77,
+ 70,163, 81, 38,147,137,231,159,225,180, 21, 91,132, 37, 9,229,
+ 122,193, 15, 2,207, 35, 99,198, 0, 0, 10, 86, 52, 85, 91,153,
+ 246,198, 18, 0, 0,206, 38,209,126, 38,165, 67,199,113, 84, 77,
+ 93,216,221, 98, 99,115, 3, 0,240,252,219,231,146, 80,222, 46,
+ 116, 93,215,182,159, 81, 74, 33,132,138,130,199, 99, 86,111, 52,
+ 0, 0,166,105,150,138, 69, 73, 43, 43, 47, 94, 46,179,114,234,
+ 141, 70, 85, 91,220, 3,184,255,170,255, 54, 79,248, 91, 74, 40,
+ 79,172, 3,199,113, 12,195,168,238,238, 78,183, 89,105, 59, 29,
+ 219,182, 9, 33,213,221, 93,201, 41,171, 4,198, 88, 84,228,210,
+ 106,181, 16, 66, 39, 53,223,234,245,122,111,243, 60,191,141,117,
+ 40,245,122,195,117,221,106,117,247,126,229,222, 76,175,175,130,
+ 177, 89,173,238, 82, 74,159, 88,150,116,194,149,138,109,125, 63,
+ 18, 87,247,131,128, 82,106,196,213,141,116, 5, 21, 10,132, 16,
+ 99, 12, 0,240,188, 55,189, 99, 49,198, 16, 66,254, 99,248,219,
+ 169, 8,147, 46, 81, 32,232, 17, 66, 60,146,132,176, 96, 24,116,
+ 72,221,174,171,231,117,222,122,142, 55, 24,223, 54,183,234,245,
+ 6, 0,192, 48, 12,206, 2,126, 16,184, 93, 23, 0,112,161,126,
+ 151,188,137,114,185, 92,230, 59,140, 31, 4,205,102,139,210, 33,
+ 0, 0, 99, 69, 85,111,229,117,189, 92, 46, 91,150,229, 7,129,
+ 160,222,119, 18, 55, 23,205,102,139, 47,194, 21, 27, 87, 84,110,
+ 126, 54,161,100, 50,153,236,173,108, 34,145, 24, 12, 6, 92, 52,
+ 98,140,209, 7, 40,180,164,221,214,126, 66, 13,255,240, 46, 74,
+ 40, 30, 33, 97, 99,218,225,112, 88, 42, 22,155,173,150, 71, 94,
+ 253,186,250, 43, 63, 8,108,219,230,157, 46,121,142,131,141,199,
+ 188, 97,162,227,116,154,205,230, 69, 9,165,222,104, 32,132,182,
+ 205, 45, 30,224, 88,150,165,170,154,166,222, 2, 0, 52, 91, 45,
+ 223, 15,242,186, 94, 48, 54,109,219,118,187,174, 36, 20,137, 25,
+ 184,174,171,170,218,140,176, 93, 1, 68,229,230,103, 19, 74, 54,
+ 155, 29,188, 30, 32,132, 48,198,243,162,145, 82,250,252,219,231,
+ 8,161,194,199, 5,239, 31, 94, 72,111, 23, 2,241, 8, 0,160,
+ 90,221,229, 93,126, 33, 76,154, 91, 91,245, 70,195, 35,196,113,
+ 58, 16, 66,211, 52,127,252,227,227,102,244,174,235, 34,132, 46,
+ 74, 94,174,235,154, 91, 91, 0, 0,198,198,182,109,235,186,254,
+ 203,135, 15,222,252,234,232, 40,204,155, 40, 10,246,200,171,146,
+ 116, 32,137, 41,180,157, 14, 99,204, 48, 86, 48,222,137,202,205,
+ 207,200,161,164, 82, 41,248, 30,164,148, 14, 6, 3, 94,194, 44,
+ 2,188,221, 52, 23,147,220,165, 77,211,132, 16,218,246, 51,199,
+ 113,204,173,173,208,207,117, 93,247,125,159,210, 33, 15,101,213,
+ 11,118,165,247,131,128, 29,247,211,238,186, 46, 99,108, 90,221,
+ 248,190, 47, 78,146, 60,181,159,125, 93,251,230,204, 63,251,186,
+ 246,205,121,254, 76,226,170,228, 9,132, 80,116,231,249,248, 17,
+ 161,155,159, 65, 40, 60,112, 26, 12, 6,148,210, 68, 34, 33,168,
+ 58,168, 96,108,154,166,233,186,238, 23, 95,126,233, 7, 1,167,
+ 149,114,185,236,251,254,140, 60,193,138, 2, 33,244, 8,241, 60,
+ 130, 49, 70,233,139, 41,207,233,114,163, 33,165,252, 3,227,185,
+ 103,190, 31, 16,114,182,124, 35,196, 59,207,159, 73,196, 15, 74,
+ 135,174,235,234,186,190,122,199,127, 17,186,249,218,153,145, 21,
+ 0,224,147,226, 39,225,143,131,129,144,103, 34,118,202,119, 13,
+ 99,243,209,163,175,234,245, 6,143, 65, 10,198,166,101, 89,138,
+ 130,103,238,159,174,235,174,235, 14,135, 67,125,125,253,242,118,
+ 25, 27,243,207,231,121,217, 31,233,102, 40, 36,147, 47,213,199,
+ 205, 69,215,117, 1, 0,186,190,190,122, 67,139,208,205,215,206,
+ 20, 66,254, 63,125,190,177, 35,132, 50, 31,102, 64,247,205,111,
+ 249,219,168, 38,147,201,229,143,247,249,173, 58,231,163, 22,170,
+ 170,218,182,205, 24,171, 84,238,241, 83,158,243, 99,186, 44, 90,
+ 207,235,245, 70,163,237, 56, 60, 65, 91,111, 52, 32,132,116, 56,
+ 4, 0,120,132, 80, 74, 69,100,242,165,250,184,185,232,116, 58,
+ 8,161, 85,141,119,162,114,243,181, 51,133,144,231,121,220, 18,
+ 198, 56,255, 65, 62,148, 67,252,149,153,244, 95,180,221,110, 95,
+ 114, 72,129, 31,240, 19, 28, 8,161,105,110,157,254,199,121, 93,
+ 183, 44, 11, 33,132, 21,229,162,132,194, 35, 38, 66, 94,229,117,
+ 29, 43,138, 97, 24,182,109,119, 58, 29,254, 91,126, 90, 76,233,
+ 48, 8,124,211, 52,163,205,228,239,236,220,125,107,159,239, 88,
+ 1,248, 65,224,251,254,116,244,189, 98,241, 78, 84,110,190,118,
+ 106,216,239, 15, 6,131,208, 13, 6,131, 65,251,251, 54, 99,140,
+ 191, 47,147, 95,228, 15, 86,142, 70, 35,254,171,229,134, 84, 42,
+ 21,245,188,206, 24,195, 63, 13,112,170,213,221,105,217, 82,173,
+ 238,162, 52,130, 48, 25, 94, 55, 12,131,103, 88,207, 15, 93,215,
+ 29,199,225,197,245,247, 43,247,116,125, 61,240,131, 52, 66, 5,
+ 99, 19, 0,128, 80,154,120,164, 84,250, 68,187, 96,186,247, 60,
+ 92, 38,221,242,230,194,113, 58, 0, 0,126, 62, 24, 27,158, 88,
+ 7,148, 14,119,118,238, 10, 93, 60,209,186,249,105,132, 50, 35,
+ 114, 38,147,201, 73,103,180,167,252,234, 50,254, 54,227,213,225,
+ 143,225, 55, 8,165, 47,170, 35,118,202,101,215,117,107,123,123,
+ 188,184, 62,175,235,211, 34, 86, 83,213,200,169, 68, 98, 37, 8,
+ 197,193, 24,199, 92,126,226, 56, 14,132, 80,244, 86, 20,173,155,
+ 191,117,165,247, 92,224, 80, 74,191,248,242,203,122,189,225, 29,
+ 87,181,120,132,180,157,206, 19,235,128, 31, 51, 73, 72,132,160,
+ 116,104,110,109,149,203,119,227, 52,202, 87,166,126,211, 82, 54,
+ 111,227,195,129, 88, 81,126,247,249,231,245, 70,163,217,106,241,
+ 220,205,116, 64, 4,147, 80,186,144,196, 52, 16, 74, 95,168, 26,
+ 59,162, 72, 36, 0, 0,156,153, 82,148,132,114, 93,116,202, 78,
+ 249,238, 78,249, 46,165, 67, 58,164,128, 63,173, 32,211, 28, 18,
+ 215, 6, 65, 16, 96,140,111,220,154,124,219, 95,176,180, 68, 22,
+ 70, 66, 34, 6,220,175,220,187,137,255,182,108,163, 33, 33, 33,
+ 17, 25,254, 63,181, 34,148,206,219,178, 22,153, 0, 0, 0, 0,
+ 73, 69, 78, 68,174, 66, 96,130
+};
+
+
+static const FileEntry _file_entries[] =
+{
+
+ { "arrow_down.png", _data_arrow_down_png, 3438 },
+ { "arrow_left.png", _data_arrow_left_png, 4122 },
+ { "arrow_right.png", _data_arrow_right_png, 4147 },
+ { "arrow_up.png", _data_arrow_up_png, 3493 },
+ { "back.png", _data_back_png, 3564 },
+ { "end.png", _data_end_png, 3562 },
+ { "home.png", _data_home_png, 3578 },
+ { "key.png", _data_key_png, 2857 },
+ { "layout", _data_layout, 7714 },
+ { "menu.png", _data_menu_png, 3079 },
+ { "power.png", _data_power_png, 3782 },
+ { "select.png", _data_select_png, 3374 },
+ { "send.png", _data_send_png, 3561 },
+ { "spacebar.png", _data_spacebar_png, 2916 },
+ { "volume_down.png", _data_volume_down_png, 3586 },
+ { "volume_up.png", _data_volume_up_png, 3856 },
+ { "device.png", _data_device_png, 45511 },
+ { "keyboard.png", _data_keyboard_png, 11032 },
+ { NULL, NULL, 0 }
+};
+
diff --git a/skins/skin_file.c b/skins/skin_file.c
new file mode 100644
index 0000000..4856b76
--- /dev/null
+++ b/skins/skin_file.c
@@ -0,0 +1,699 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skin_file.h"
+#include "android_utils.h"
+#include "android_charmap.h"
+#include "osdep.h"
+
+/** UTILITY ROUTINES
+ **/
+static SkinImage*
+skin_image_find_in( const char* dirname, const char* filename )
+{
+ char buffer[1024];
+ char* p = buffer;
+ char* end = p + sizeof(buffer);
+
+ p = bufprint( p, end, "%s" PATH_SEP "%s", dirname, filename );
+ if (p >= end)
+ return SKIN_IMAGE_NONE;
+
+ return skin_image_find_simple(buffer);
+}
+
+/** SKIN BACKGROUND
+ **/
+
+static void
+skin_background_done( SkinBackground* background )
+{
+ if (background->image)
+ skin_image_unref(&background->image);
+}
+
+static int
+skin_background_init_from( SkinBackground* background,
+ AConfig* node,
+ const char* basepath )
+{
+ const char* img = aconfig_str(node, "image", NULL);
+ int x = aconfig_int(node, "x", 0);
+ int y = aconfig_int(node, "y", 0);
+
+ background->valid = 0;
+
+ if (img == NULL) /* no background */
+ return -1;
+
+ background->image = skin_image_find_in( basepath, img );
+ if (background->image == SKIN_IMAGE_NONE) {
+ background->image = NULL;
+ return -1;
+ }
+
+ background->rect.pos.x = x;
+ background->rect.pos.y = y;
+ background->rect.size.w = skin_image_w( background->image );
+ background->rect.size.h = skin_image_h( background->image );
+
+ background->valid = 1;
+
+ return 0;
+}
+
+/** SKIN DISPLAY
+ **/
+
+static void
+skin_display_done( SkinDisplay* display )
+{
+ qframebuffer_done( display->qfbuff );
+}
+
+static int
+skin_display_init_from( SkinDisplay* display, AConfig* node )
+{
+ display->rect.pos.x = aconfig_int(node, "x", 0);
+ display->rect.pos.y = aconfig_int(node, "y", 0);
+ display->rect.size.w = aconfig_int(node, "width", 0);
+ display->rect.size.h = aconfig_int(node, "height", 0);
+ display->rotation = aconfig_unsigned(node, "rotation", SKIN_ROTATION_0);
+
+ display->valid = ( display->rect.size.w > 0 && display->rect.size.h > 0 );
+
+ if (display->valid) {
+ SkinRect r;
+ skin_rect_rotate( &r, &display->rect, -display->rotation );
+ qframebuffer_init( display->qfbuff,
+ r.size.w,
+ r.size.h,
+ 0,
+ QFRAME_BUFFER_RGB565 );
+
+ qframebuffer_fifo_add( display->qfbuff );
+ }
+ return display->valid ? 0 : -1;
+}
+
+/** SKIN BUTTON
+ **/
+
+typedef struct
+{
+ const char* name;
+ AndroidKeyCode code;
+} KeyInfo;
+
+static KeyInfo _keyinfo_table[] = {
+ { "dpad-up", kKeyCodeDpadUp },
+ { "dpad-down", kKeyCodeDpadDown },
+ { "dpad-left", kKeyCodeDpadLeft },
+ { "dpad-right", kKeyCodeDpadRight },
+ { "dpad-center", kKeyCodeDpadCenter },
+ { "soft-left", kKeyCodeSoftLeft },
+ { "soft-right", kKeyCodeSoftRight },
+ { "volume-up", kKeyCodeVolumeUp },
+ { "volume-down", kKeyCodeVolumeDown },
+ { "power", kKeyCodePower },
+ { "home", kKeyCodeHome },
+ { "back", kKeyCodeBack },
+ { "del", kKeyCodeDel },
+ { "0", kKeyCode0 },
+ { "1", kKeyCode1 },
+ { "2", kKeyCode2 },
+ { "3", kKeyCode3 },
+ { "4", kKeyCode4 },
+ { "5", kKeyCode5 },
+ { "6", kKeyCode6 },
+ { "7", kKeyCode7 },
+ { "8", kKeyCode8 },
+ { "9", kKeyCode9 },
+ { "star", kKeyCodeStar },
+ { "pound", kKeyCodePound },
+ { "phone-dial", kKeyCodeCall },
+ { "phone-hangup", kKeyCodeEndCall },
+ { "q", kKeyCodeQ },
+ { "w", kKeyCodeW },
+ { "e", kKeyCodeE },
+ { "r", kKeyCodeR },
+ { "t", kKeyCodeT },
+ { "y", kKeyCodeY },
+ { "u", kKeyCodeU },
+ { "i", kKeyCodeI },
+ { "o", kKeyCodeO },
+ { "p", kKeyCodeP },
+ { "a", kKeyCodeA },
+ { "s", kKeyCodeS },
+ { "d", kKeyCodeD },
+ { "f", kKeyCodeF },
+ { "g", kKeyCodeG },
+ { "h", kKeyCodeH },
+ { "j", kKeyCodeJ },
+ { "k", kKeyCodeK },
+ { "l", kKeyCodeL },
+ { "DEL", kKeyCodeDel },
+ { "z", kKeyCodeZ },
+ { "x", kKeyCodeX },
+ { "c", kKeyCodeC },
+ { "v", kKeyCodeV },
+ { "b", kKeyCodeB },
+ { "n", kKeyCodeN },
+ { "m", kKeyCodeM },
+ { "COMMA", kKeyCodeComma },
+ { "PERIOD", kKeyCodePeriod },
+ { "ENTER", kKeyCodeNewline },
+ { "AT", kKeyCodeAt },
+ { "SPACE", kKeyCodeSpace },
+ { "SLASH", kKeyCodeSlash },
+ { "CAP", kKeyCodeCapLeft },
+ { "SYM", kKeyCodeSym },
+ { "ALT", kKeyCodeAltLeft },
+ { "ALT2", kKeyCodeAltRight },
+ { "CAP2", kKeyCodeCapRight },
+ { 0, 0 },
+};
+
+static unsigned
+keyinfo_lookup_code(const char *name)
+{
+ KeyInfo *ki = _keyinfo_table;
+ while(ki->name) {
+ if(!strcmp(name, ki->name))
+ return ki->code;
+ ki++;
+ }
+ return 0;
+}
+
+
+static void
+skin_button_free( SkinButton* button )
+{
+ if (button) {
+ skin_image_unref( &button->image );
+ qemu_free(button);
+ }
+}
+
+static SkinButton*
+skin_button_create_from( AConfig* node, const char* basepath )
+{
+ SkinButton* button = qemu_mallocz(sizeof(*button));
+ if (button) {
+ const char* img = aconfig_str(node, "image", NULL);
+ int x = aconfig_int(node, "x", 0);
+ int y = aconfig_int(node, "y", 0);
+
+ button->name = node->name;
+ button->rect.pos.x = x;
+ button->rect.pos.y = y;
+
+ if (img != NULL)
+ button->image = skin_image_find_in( basepath, img );
+
+ if (button->image == SKIN_IMAGE_NONE) {
+ skin_button_free(button);
+ return NULL;
+ }
+
+ button->rect.size.w = skin_image_w( button->image );
+ button->rect.size.h = skin_image_h( button->image );
+
+ button->keycode = keyinfo_lookup_code( button->name );
+ if (button->keycode == 0) {
+ dprint( "Warning: skin file button uses unknown key name '%s'", button->name );
+ }
+ }
+ return button;
+}
+
+/** SKIN PART
+ **/
+
+static void
+skin_part_free( SkinPart* part )
+{
+ if (part) {
+ skin_background_done( part->background );
+ skin_display_done( part->display );
+
+ SKIN_PART_LOOP_BUTTONS(part,button)
+ skin_button_free(button);
+ SKIN_PART_LOOP_END
+ part->buttons = NULL;
+ qemu_free(part);
+ }
+}
+
+static SkinLocation*
+skin_location_create_from_v2( AConfig* node, SkinPart* parts )
+{
+ const char* partname = aconfig_str(node, "name", NULL);
+ int x = aconfig_int(node, "x", 0);
+ int y = aconfig_int(node, "y", 0);
+ SkinRotation rot = aconfig_int(node, "rotation", SKIN_ROTATION_0);
+ SkinPart* part;
+ SkinLocation* location;
+
+ if (partname == NULL) {
+ dprint( "### WARNING: ignoring part location without 'name' element" );
+ return NULL;
+ }
+
+ for (part = parts; part; part = part->next)
+ if (!strcmp(part->name, partname))
+ break;
+
+ if (part == NULL) {
+ dprint( "### WARNING: ignoring part location with unknown name '%s'", partname );
+ return NULL;
+ }
+
+ location = qemu_mallocz(sizeof(*location));
+ if (location != NULL) {
+ location->part = part;
+ location->anchor.x = x;
+ location->anchor.y = y;
+ location->rotation = rot;
+ }
+ return location;
+}
+
+static SkinPart*
+skin_part_create_from_v1( AConfig* root, const char* basepath )
+{
+ SkinPart* part = qemu_mallocz(sizeof(*part));
+
+ if (part != NULL) {
+ AConfig* node;
+ SkinBox box;
+
+ part->name = root->name;
+
+ node = aconfig_find(root, "background");
+ if (node)
+ skin_background_init_from(part->background, node, basepath);
+
+ node = aconfig_find(root, "display");
+ if (node)
+ skin_display_init_from(part->display, node);
+
+ node = aconfig_find(root, "button");
+ if (node) {
+ for (node = node->first_child; node != NULL; node = node->next)
+ {
+ SkinButton* button = skin_button_create_from(node, basepath);
+
+ if (button != NULL) {
+ button->next = part->buttons;
+ part->buttons = button;
+ }
+ }
+ }
+
+ skin_box_minmax_init( &box );
+
+ if (part->background->valid)
+ skin_box_minmax_update( &box, &part->background->rect );
+
+ if (part->display->valid)
+ skin_box_minmax_update( &box, &part->display->rect );
+
+ SKIN_PART_LOOP_BUTTONS(part, button)
+ skin_box_minmax_update( &box, &button->rect );
+ SKIN_PART_LOOP_END
+
+ if ( !skin_box_minmax_to_rect( &box, &part->rect ) ) {
+ skin_part_free(part);
+ part = NULL;
+ }
+ }
+ return part;
+}
+
+static SkinPart*
+skin_part_create_from_v2( AConfig* root, const char* basepath )
+{
+ SkinPart* part = qemu_mallocz(sizeof(*part));
+
+ if (part != NULL) {
+ AConfig* node;
+ SkinBox box;
+
+ part->name = root->name;
+
+ node = aconfig_find(root, "background");
+ if (node)
+ skin_background_init_from(part->background, node, basepath);
+
+ node = aconfig_find(root, "display");
+ if (node)
+ skin_display_init_from(part->display, node);
+
+ node = aconfig_find(root, "buttons");
+ if (node) {
+ for (node = node->first_child; node != NULL; node = node->next)
+ {
+ SkinButton* button = skin_button_create_from(node, basepath);
+
+ if (button != NULL) {
+ button->next = part->buttons;
+ part->buttons = button;
+ }
+ }
+ }
+
+ skin_box_minmax_init( &box );
+
+ if (part->background->valid)
+ skin_box_minmax_update( &box, &part->background->rect );
+
+ if (part->display->valid)
+ skin_box_minmax_update( &box, &part->display->rect );
+
+ SKIN_PART_LOOP_BUTTONS(part, button)
+ skin_box_minmax_update( &box, &button->rect );
+ SKIN_PART_LOOP_END
+
+ if ( !skin_box_minmax_to_rect( &box, &part->rect ) ) {
+ skin_part_free(part);
+ part = NULL;
+ }
+ }
+ return part;
+}
+
+/** SKIN LAYOUT
+ **/
+
+static void
+skin_layout_free( SkinLayout* layout )
+{
+ if (layout) {
+ SKIN_LAYOUT_LOOP_LOCS(layout,loc)
+ qemu_free(loc);
+ SKIN_LAYOUT_LOOP_END
+ layout->locations = NULL;
+ qemu_free(layout);
+ }
+}
+
+SkinDisplay*
+skin_layout_get_display( SkinLayout* layout )
+{
+ SKIN_LAYOUT_LOOP_LOCS(layout,loc)
+ SkinPart* part = loc->part;
+ if (part->display->valid) {
+ return part->display;
+ }
+ SKIN_LAYOUT_LOOP_END
+ return NULL;
+}
+
+SkinRotation
+skin_layout_get_dpad_rotation( SkinLayout* layout )
+{
+ SKIN_LAYOUT_LOOP_LOCS(layout, loc)
+ SkinPart* part = loc->part;
+ SKIN_PART_LOOP_BUTTONS(part,button)
+ if (button->keycode == kKeyCodeDpadUp)
+ return loc->rotation;
+ SKIN_PART_LOOP_END
+ SKIN_LAYOUT_LOOP_END
+
+ return SKIN_ROTATION_0;
+}
+
+
+static int
+skin_layout_event_decode( const char* event, int *ptype, int *pcode, int *pvalue )
+{
+ typedef struct {
+ const char* name;
+ int value;
+ } EventName;
+
+ static const EventName _event_names[] = {
+ { "EV_SW", 0x05 },
+ { NULL, 0 },
+ };
+
+ const char* x = strchr(event, ':');
+ const char* y = NULL;
+ const EventName* ev = _event_names;
+
+ if (x != NULL)
+ y = strchr(x+1, ':');
+
+ if (x == NULL || y == NULL) {
+ dprint( "### WARNING: invalid skin layout event format: '%s', should be '<TYPE>:<CODE>:<VALUE>'", event );
+ return -1;
+ }
+
+ for ( ; ev->name != NULL; ev++ )
+ if (!memcmp( event, ev->name, x - event ) && ev->name[x-event] == 0)
+ break;
+
+ if (!ev->name) {
+ dprint( "### WARNING: unrecognized skin layout event name: %.*s", x-event, event );
+ return -1;
+ }
+
+ *ptype = ev->value;
+ *pcode = strtol(x+1, NULL, 0);
+ *pvalue = strtol(y+1, NULL, 0);
+ return 0;
+}
+
+static SkinLayout*
+skin_layout_create_from_v2( AConfig* root, SkinPart* parts )
+{
+ SkinLayout* layout = qemu_mallocz(sizeof(*layout));
+ int width, height;
+ SkinLocation** ptail;
+ AConfig* node;
+
+ if (layout == NULL)
+ return NULL;
+
+ width = aconfig_int( root, "width", 400 );
+ height = aconfig_int( root, "height", 400 );
+
+ node = aconfig_find( root, "event" );
+ if (node != NULL) {
+ skin_layout_event_decode( node->value,
+ &layout->event_type,
+ &layout->event_code,
+ &layout->event_value );
+ } else {
+ layout->event_type = 0x05; /* close keyboard by default */
+ layout->event_code = 0;
+ layout->event_value = 1;
+ }
+
+ layout->name = root->name;
+ layout->color = aconfig_unsigned( root, "color", 0x808080 ) | 0xff000000;
+ ptail = &layout->locations;
+
+ for (node = root->first_child; node; node = node->next)
+ {
+ if (!memcmp(node->name, "part", 4)) {
+ SkinLocation* location = skin_location_create_from_v2( node, parts );
+ if (location == NULL) {
+ continue;
+ }
+ *ptail = location;
+ ptail = &location->next;
+ }
+ }
+
+ if (layout->locations == NULL)
+ goto Fail;
+
+ layout->size.w = width;
+ layout->size.h = height;
+
+ return layout;
+
+Fail:
+ skin_layout_free(layout);
+ return NULL;
+}
+
+/** SKIN FILE
+ **/
+
+static int
+skin_file_load_from_v1( SkinFile* file, AConfig* aconfig, const char* basepath )
+{
+ SkinPart* part;
+ SkinLayout* layout;
+ SkinLayout** ptail = &file->layouts;
+ SkinLocation* location;
+ int nn;
+
+ file->parts = part = skin_part_create_from_v1( aconfig, basepath );
+ if (part == NULL)
+ return -1;
+
+ for (nn = 0; nn < 2; nn++)
+ {
+ layout = qemu_mallocz(sizeof(*layout));
+ if (layout == NULL) return -1;
+
+ layout->color = 0xff808080;
+
+ location = qemu_mallocz(sizeof(*location));
+ if (location == NULL) {
+ qemu_free(layout);
+ return -1;
+ }
+
+ layout->event_type = 0x05; /* close keyboard by default */
+ layout->event_code = 0;
+ layout->event_value = 1;
+
+ location->part = part;
+ switch (nn) {
+ case 0:
+ location->anchor.x = 0;
+ location->anchor.y = 0;
+ location->rotation = SKIN_ROTATION_0;
+ layout->size = part->rect.size;
+ break;
+
+#if 0
+ case 1:
+ location->anchor.x = part->rect.size.h;
+ location->anchor.y = 0;
+ location->rotation = SKIN_ROTATION_90;
+ layout->size.w = part->rect.size.h;
+ layout->size.h = part->rect.size.w;
+ layout->event_value = 0;
+ break;
+
+ case 2:
+ location->anchor.x = part->rect.size.w;
+ location->anchor.y = part->rect.size.h;
+ location->rotation = SKIN_ROTATION_180;
+ layout->size = part->rect.size;
+ break;
+#endif
+ default:
+ location->anchor.x = 0;
+ location->anchor.y = part->rect.size.w;
+ location->rotation = SKIN_ROTATION_270;
+ layout->size.w = part->rect.size.h;
+ layout->size.h = part->rect.size.w;
+ layout->event_value = 0;
+ break;
+ }
+ layout->locations = location;
+
+ *ptail = layout;
+ ptail = &layout->next;
+ }
+ return 0;
+}
+
+static int
+skin_file_load_from_v2( SkinFile* file, AConfig* aconfig, const char* basepath )
+{
+ AConfig* node;
+
+ /* first, load all parts */
+ node = aconfig_find(aconfig, "parts");
+ if (node == NULL)
+ return -1;
+ else
+ {
+ SkinPart** ptail = &file->parts;
+ for (node = node->first_child; node != NULL; node = node->next)
+ {
+ SkinPart* part = skin_part_create_from_v2( node, basepath );
+ if (part == NULL) {
+ dprint( "## WARNING: can't load part '%s' from skin\n", node->name ? "<NULL>" : node->name );
+ continue;
+ }
+ part->next = NULL;
+ *ptail = part;
+ ptail = &part->next;
+ }
+ }
+
+ if (file->parts == NULL)
+ return -1;
+
+ /* then load all layouts */
+ node = aconfig_find(aconfig, "layouts");
+ if (node == NULL)
+ return -1;
+ else
+ {
+ SkinLayout** ptail = &file->layouts;
+ for (node = node->first_child; node != NULL; node = node->next)
+ {
+ SkinLayout* layout = skin_layout_create_from_v2( node, file->parts );
+ if (layout == NULL) {
+ dprint( "## WARNING: ignoring layout in skin file" );
+ continue;
+ }
+ *ptail = layout;
+ layout->next = NULL;
+ ptail = &layout->next;
+ }
+ }
+ if (file->layouts == NULL)
+ return -1;
+
+ return 0;
+}
+
+SkinFile*
+skin_file_create_from_aconfig( AConfig* aconfig, const char* basepath )
+{
+ SkinFile* file = qemu_mallocz(sizeof(*file));
+
+ if (file != NULL) {
+ if ( aconfig_find(aconfig, "parts") != NULL) {
+ if (skin_file_load_from_v2( file, aconfig, basepath ) < 0) {
+ skin_file_free( file );
+ file = NULL;
+ }
+ }
+ else {
+ if (skin_file_load_from_v1( file, aconfig, basepath ) < 0) {
+ skin_file_free( file );
+ file = NULL;
+ }
+ }
+ }
+ return file;
+}
+
+void
+skin_file_free( SkinFile* file )
+{
+ if (file) {
+ SKIN_FILE_LOOP_LAYOUTS(file,layout)
+ skin_layout_free(layout);
+ SKIN_FILE_LOOP_END_LAYOUTS
+ file->layouts = NULL;
+
+ SKIN_FILE_LOOP_PARTS(file,part)
+ skin_part_free(part);
+ SKIN_FILE_LOOP_END_PARTS
+ file->parts = NULL;
+
+ qemu_free(file);
+ }
+}
diff --git a/skins/skin_file.h b/skins/skin_file.h
new file mode 100644
index 0000000..1670889
--- /dev/null
+++ b/skins/skin_file.h
@@ -0,0 +1,132 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_SKIN_FILE_H
+#define _ANDROID_SKIN_FILE_H
+
+#include "skin_image.h"
+#include "android_config.h"
+#include "framebuffer.h"
+
+/** Layout
+ **/
+
+typedef struct SkinBackground {
+ SkinImage* image;
+ SkinRect rect;
+ char valid;
+} SkinBackground;
+
+typedef struct SkinDisplay {
+ SkinRect rect; /* display rectangle */
+ SkinRotation rotation; /* framebuffer rotation */
+ char valid;
+ QFrameBuffer qfbuff[1];
+} SkinDisplay;
+
+typedef struct SkinButton {
+ struct SkinButton* next;
+ const char* name;
+ SkinImage* image;
+ SkinRect rect;
+ unsigned keycode;
+} SkinButton;
+
+typedef struct SkinPart {
+ struct SkinPart* next;
+ const char* name;
+ SkinBackground background[1];
+ SkinDisplay display[1];
+ SkinButton* buttons;
+ SkinRect rect; /* bounding box of all parts */
+} SkinPart;
+
+#define SKIN_PART_LOOP_BUTTONS(part,button) \
+ do { \
+ SkinButton* __button = (part)->buttons; \
+ while (__button != NULL) { \
+ SkinButton* __button_next = __button->next; \
+ SkinButton* button = __button;
+
+#define SKIN_PART_LOOP_END \
+ __button = __button_next; \
+ } \
+ } while (0);
+
+typedef struct SkinLocation {
+ SkinPart* part;
+ SkinPos anchor;
+ SkinRotation rotation;
+ struct SkinLocation* next;
+} SkinLocation;
+
+typedef struct SkinLayout {
+ struct SkinLayout* next;
+ const char* name;
+ unsigned color;
+ int event_type;
+ int event_code;
+ int event_value;
+ SkinSize size;
+ SkinLocation* locations;
+} SkinLayout;
+
+#define SKIN_LAYOUT_LOOP_LOCS(layout,loc) \
+ do { \
+ SkinLocation* __loc = (layout)->locations; \
+ while (__loc != NULL) { \
+ SkinLocation* __loc_next = (__loc)->next; \
+ SkinLocation* loc = __loc;
+
+#define SKIN_LAYOUT_LOOP_END \
+ __loc = __loc_next; \
+ } \
+ } while (0);
+
+extern SkinDisplay* skin_layout_get_display( SkinLayout* layout );
+
+extern SkinRotation skin_layout_get_dpad_rotation( SkinLayout* layout );
+
+typedef struct SkinFile {
+ SkinPart* parts;
+ SkinLayout* layouts;
+ int num_parts;
+ int num_layouts;
+} SkinFile;
+
+#define SKIN_FILE_LOOP_LAYOUTS(file,layout) \
+ do { \
+ SkinLayout* __layout = (file)->layouts; \
+ while (__layout != NULL) { \
+ SkinLayout* __layout_next = __layout->next; \
+ SkinLayout* layout = __layout;
+
+#define SKIN_FILE_LOOP_END_LAYOUTS \
+ __layout = __layout_next; \
+ } \
+ } while (0);
+
+#define SKIN_FILE_LOOP_PARTS(file,part) \
+ do { \
+ SkinPart* __part = (file)->parts; \
+ while (__part != NULL) { \
+ SkinPart* __part_next = __part->next; \
+ SkinPart* part = __part;
+
+#define SKIN_FILE_LOOP_END_PARTS \
+ __part = __part_next; \
+ } \
+ } while (0);
+
+extern SkinFile* skin_file_create_from_aconfig( AConfig* aconfig, const char* basepath );
+extern void skin_file_free( SkinFile* file );
+
+#endif /* _ANDROID_SKIN_FILE_H */
diff --git a/skins/skin_image.c b/skins/skin_image.c
new file mode 100644
index 0000000..6ae4462
--- /dev/null
+++ b/skins/skin_image.c
@@ -0,0 +1,742 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skin_image.h"
+#include "android_resource.h"
+#include <assert.h>
+#include <limits.h>
+
+#define DEBUG 0
+
+#if DEBUG
+static void D(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+#else
+#define D(...) do{}while(0)
+#endif
+
+/********************************************************************************/
+/********************************************************************************/
+/***** *****/
+/***** U T I L I T Y F U N C T I O N S *****/
+/***** *****/
+/********************************************************************************/
+/********************************************************************************/
+
+SDL_Surface*
+sdl_surface_from_argb32( void* base, int w, int h )
+{
+ return SDL_CreateRGBSurfaceFrom(
+ base, w, h, 32, w*4,
+#if WORDS_BIGENDIAN
+ 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000
+#else
+ 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000
+#endif
+ );
+}
+
+static void*
+rotate_image( void* data, unsigned width, unsigned height, SkinRotation rotation )
+{
+ void* result;
+
+ result = malloc( width*height*4 );
+ if (result == NULL)
+ return NULL;
+
+ switch (rotation & 3)
+ {
+ case SKIN_ROTATION_0:
+ memcpy( (char*)result, (const char*)data, width*height*4 );
+ break;
+
+ case SKIN_ROTATION_270:
+ {
+ unsigned* start = (unsigned*)data;
+ unsigned* src_line = start + (width-1);
+ unsigned* dst_line = (unsigned*)result;
+ unsigned hh;
+
+ for (hh = width; hh > 0; hh--)
+ {
+ unsigned* src = src_line;
+ unsigned* dst = dst_line;
+ unsigned count = height;
+
+ for ( ; count > 0; count-- ) {
+ dst[0] = src[0];
+ dst += 1;
+ src += width;
+ }
+
+ src_line -= 1;
+ dst_line += height;
+ }
+ }
+ break;
+
+ case SKIN_ROTATION_180:
+ {
+ unsigned* start = (unsigned*)data;
+ unsigned* src_line = start + width*(height-1);
+ unsigned* dst_line = (unsigned*)result;
+ unsigned hh;
+
+ for (hh = height; hh > 0; hh--)
+ {
+ unsigned* src = src_line + (width-1);
+ unsigned* dst = dst_line;
+
+ while (src >= src_line)
+ *dst++ = *src--;
+
+ dst_line += width;
+ src_line -= width;
+ }
+ }
+ break;
+
+ case SKIN_ROTATION_90:
+ {
+ unsigned* start = (unsigned*)data;
+ unsigned* src_line = start + width*(height-1);
+ unsigned* dst_line = (unsigned*)result ;
+ unsigned hh;
+
+ for (hh = width; hh > 0; hh--)
+ {
+ unsigned* src = src_line;
+ unsigned* dst = dst_line;
+ unsigned count;
+
+ for (count = height; count > 0; count--) {
+ dst[0] = src[0];
+ dst += 1;
+ src -= width;
+ }
+
+ dst_line += height;
+ src_line += 1;
+ }
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ return result;
+}
+
+
+static void
+blend_image( unsigned* dst_pixels,
+ unsigned* src_pixels,
+ unsigned w,
+ unsigned h,
+ int alpha )
+{
+ unsigned* dst = dst_pixels;
+ unsigned* dst_end = dst + w*h;
+ unsigned* src = src_pixels;
+
+ for ( ; dst < dst_end; dst++, src++ )
+ {
+ {
+ unsigned ag = (src[0] >> 8) & 0xff00ff;
+ unsigned rb = src[0] & 0xff00ff;
+
+ ag = (ag*alpha) & 0xff00ff00;
+ rb = ((rb*alpha) >> 8) & 0x00ff00ff;
+
+ dst[0] = ag | rb;
+ }
+ }
+}
+
+
+static unsigned
+skin_image_desc_hash( SkinImageDesc* desc )
+{
+ unsigned h = 0;
+ int n;
+
+ for (n = 0; desc->path[n] != 0; n++) {
+ int c = desc->path[n];
+ h = h*33 + c;
+ }
+ h += desc->rotation*1573;
+ h += desc->blend * 7;
+
+ return h;
+}
+
+
+static int
+skin_image_desc_equal( SkinImageDesc* a,
+ SkinImageDesc* b )
+{
+ return (a->rotation == b->rotation &&
+ a->blend == b->blend &&
+ !strcmp(a->path, b->path));
+}
+
+/********************************************************************************/
+/********************************************************************************/
+/***** *****/
+/***** S K I N I M A G E S *****/
+/***** *****/
+/********************************************************************************/
+/********************************************************************************/
+
+enum {
+ SKIN_IMAGE_CLONE = (1 << 0) /* this image is a clone */
+};
+
+struct SkinImage {
+ unsigned hash;
+ SkinImage* link;
+ int ref_count;
+ SkinImage* next;
+ SkinImage* prev;
+ SDL_Surface* surface;
+ unsigned flags;
+ unsigned w, h;
+ void* pixels; /* 32-bit ARGB */
+ SkinImageDesc desc;
+};
+
+
+
+
+static const SkinImage _no_image[1] = {
+ { 0, NULL, 0, NULL, NULL, NULL, 0, 0, 0, NULL, { "<none>", SKIN_ROTATION_0, 0 } }
+};
+
+SkinImage* SKIN_IMAGE_NONE = (SkinImage*)&_no_image;
+
+static void
+skin_image_free( SkinImage* image )
+{
+ if (image && image != _no_image)
+ {
+ if (image->surface) {
+ SDL_FreeSurface(image->surface);
+ image->surface = NULL;
+ }
+
+ if (image->pixels) {
+ free( image->pixels );
+ image->pixels = NULL;
+ }
+
+ free(image);
+ }
+}
+
+
+static SkinImage*
+skin_image_alloc( SkinImageDesc* desc, unsigned hash )
+{
+ int len = strlen(desc->path);
+ SkinImage* image = calloc(1, sizeof(*image) + len + 1);
+
+ if (image) {
+ image->desc = desc[0];
+ image->desc.path = (const char*)(image + 1);
+ memcpy( (char*)image->desc.path, desc->path, len );
+ ((char*)image->desc.path)[len] = 0;
+
+ image->hash = hash;
+ image->next = image->prev = image;
+ image->ref_count = 1;
+ }
+ return image;
+}
+
+
+extern void *loadpng(const char *fn, unsigned *_width, unsigned *_height);
+extern void *readpng(const unsigned char* base, size_t size, unsigned *_width, unsigned *_height);
+
+static int
+skin_image_load( SkinImage* image )
+{
+ void* data;
+ unsigned w, h;
+ const char* path = image->desc.path;
+
+ if (path[0] == ':') {
+ size_t size;
+ const unsigned char* base;
+
+ if (path[1] == '/' || path[1] == '\\')
+ path += 1;
+
+ base = android_resource_find( path+1, &size );
+ if (base == NULL) {
+ fprintf(stderr, "failed to locate built-in image file '%s'\n", path );
+ return -1;
+ }
+
+ data = readpng(base, size, &w, &h);
+ if (data == NULL) {
+ fprintf(stderr, "failed to load built-in image file '%s'\n", path );
+ return -1;
+ }
+ } else {
+ data = loadpng(path, &w, &h);
+ if (data == NULL) {
+ fprintf(stderr, "failed to load image file '%s'\n", path );
+ return -1;
+ }
+ }
+
+ /* the data is loaded into memory as RGBA bytes by libpng. we want to manage
+ * the values as 32-bit ARGB pixels, so swap the bytes accordingly depending
+ * on our CPU endianess
+ */
+ {
+ unsigned* d = data;
+ unsigned* d_end = d + w*h;
+
+ for ( ; d < d_end; d++ ) {
+ unsigned pix = d[0];
+#if WORDS_BIGENDIAN
+ /* R,G,B,A read as RGBA => ARGB */
+ pix = ((pix >> 8) & 0xffffff) | (pix << 24);
+#else
+ /* R,G,B,A read as ABGR => ARGB */
+ pix = (pix & 0xff00ff00) | ((pix >> 16) & 0xff) | ((pix & 0xff) << 16);
+#endif
+ d[0] = pix;
+ }
+ }
+
+ image->pixels = data;
+ image->w = w;
+ image->h = h;
+
+ image->surface = sdl_surface_from_argb32( image->pixels, w, h );
+ if (image->surface == NULL) {
+ fprintf(stderr, "failed to create SDL surface for '%s' image\n", path);
+ return -1;
+ }
+ return 0;
+}
+
+
+/* simple hash table for images */
+
+#define NUM_BUCKETS 64
+
+typedef struct {
+ SkinImage* buckets[ NUM_BUCKETS ];
+ SkinImage mru_head;
+ int num_images;
+ unsigned long total_pixels;
+ unsigned long max_pixels;
+ unsigned long total_images;
+} SkinImageCache;
+
+
+static void
+skin_image_cache_init( SkinImageCache* cache )
+{
+ memset(cache, 0, sizeof(*cache));
+#if DEBUG
+ cache->max_pixels = 1;
+#else
+ cache->max_pixels = 4*1024*1024; /* limit image cache to 4 MB */
+#endif
+ cache->mru_head.next = cache->mru_head.prev = &cache->mru_head;
+}
+
+
+static void
+skin_image_cache_remove( SkinImageCache* cache,
+ SkinImage* image )
+{
+ /* remove from hash table */
+ SkinImage** pnode = cache->buckets + (image->hash & (NUM_BUCKETS-1));
+ SkinImage* node;
+
+ for (;;) {
+ node = *pnode;
+ assert(node != NULL);
+ if (node == NULL) /* should not happen */
+ break;
+ if (node == image) {
+ *pnode = node->link;
+ break;
+ }
+ pnode = &node->link;
+ }
+
+ D( "skin_image_cache: remove '%s' (rot=%d), %d pixels\n",
+ node->desc.path, node->desc.rotation, node->w*node->h );
+
+ /* remove from mru list */
+ image->prev->next = image->next;
+ image->next->prev = image->prev;
+
+ cache->total_pixels -= image->w*image->h;
+ cache->total_images -= 1;
+}
+
+
+static SkinImage*
+skin_image_cache_raise( SkinImageCache* cache,
+ SkinImage* image )
+{
+ if (image != cache->mru_head.next) {
+ SkinImage* prev = image->prev;
+ SkinImage* next = image->next;
+
+ /* remove from mru list */
+ prev->next = next;
+ next->prev = prev;
+
+ /* add to top */
+ image->prev = &cache->mru_head;
+ image->next = image->prev->next;
+ image->prev->next = image;
+ image->next->prev = image;
+ }
+ return image;
+}
+
+
+static void
+skin_image_cache_flush( SkinImageCache* cache )
+{
+ SkinImage* image = cache->mru_head.prev;
+ int count = 0;
+
+ D("skin_image_cache_flush: starting\n");
+ while (cache->total_pixels > cache->max_pixels &&
+ image != &cache->mru_head)
+ {
+ SkinImage* prev = image->prev;
+
+ if (image->ref_count == 0) {
+ skin_image_cache_remove(cache, image);
+ count += 1;
+ }
+ image = prev;
+ }
+ D("skin_image_cache_flush: finished, %d images flushed\n", count);
+}
+
+
+static SkinImage**
+skin_image_lookup_p( SkinImageCache* cache,
+ SkinImageDesc* desc,
+ unsigned *phash )
+{
+ unsigned h = skin_image_desc_hash(desc);
+ unsigned index = h & (NUM_BUCKETS-1);
+ SkinImage** pnode = &cache->buckets[index];
+ for (;;) {
+ SkinImage* node = *pnode;
+ if (node == NULL)
+ break;
+ if (node->hash == h && skin_image_desc_equal(desc, &node->desc))
+ break;
+ pnode = &node->link;
+ }
+ *phash = h;
+ return pnode;
+}
+
+
+static SkinImage*
+skin_image_create( SkinImageDesc* desc, unsigned hash )
+{
+ SkinImage* node;
+
+ node = skin_image_alloc( desc, hash );
+ if (node == NULL)
+ return SKIN_IMAGE_NONE;
+
+ if (desc->rotation == SKIN_ROTATION_0 &&
+ desc->blend == SKIN_BLEND_FULL)
+ {
+ if (skin_image_load(node) < 0) {
+ skin_image_free(node);
+ return SKIN_IMAGE_NONE;
+ }
+ }
+ else
+ {
+ SkinImageDesc desc0 = desc[0];
+ SkinImage* parent;
+
+ desc0.rotation = SKIN_ROTATION_0;
+ desc0.blend = SKIN_BLEND_FULL;
+
+ parent = skin_image_find( &desc0 );
+ if (parent == SKIN_IMAGE_NONE)
+ return SKIN_IMAGE_NONE;
+
+ SDL_LockSurface(parent->surface);
+
+ if (desc->rotation == SKIN_ROTATION_90 ||
+ desc->rotation == SKIN_ROTATION_270)
+ {
+ node->w = parent->h;
+ node->h = parent->w;
+ } else {
+ node->w = parent->w;
+ node->h = parent->h;
+ }
+
+ node->pixels = rotate_image( parent->pixels, parent->w, parent->h,
+ desc->rotation );
+
+ SDL_UnlockSurface(parent->surface);
+ skin_image_unref(&parent);
+
+ if (node->pixels == NULL) {
+ skin_image_free(node);
+ return SKIN_IMAGE_NONE;
+ }
+
+ if (desc->blend != SKIN_BLEND_FULL)
+ blend_image( node->pixels, node->pixels, node->w, node->h, desc->blend );
+
+ node->surface = sdl_surface_from_argb32( node->pixels, node->w, node->h );
+ if (node->surface == NULL) {
+ skin_image_free(node);
+ return SKIN_IMAGE_NONE;
+ }
+ }
+ return node;
+}
+
+
+static SkinImageCache _image_cache[1];
+static int _image_cache_init;
+
+SkinImage*
+skin_image_find( SkinImageDesc* desc )
+{
+ SkinImageCache* cache = _image_cache;
+ unsigned hash;
+ SkinImage** pnode = skin_image_lookup_p( cache, desc, &hash );
+ SkinImage* node = *pnode;
+
+ if (!_image_cache_init) {
+ _image_cache_init = 1;
+ skin_image_cache_init(cache);
+ }
+
+ if (node) {
+ node->ref_count += 1;
+ return skin_image_cache_raise( cache, node );
+ }
+ node = skin_image_create( desc, hash );
+ if (node == SKIN_IMAGE_NONE)
+ return node;
+
+ /* add to hash table */
+ node->link = *pnode;
+ *pnode = node;
+
+ /* add to mru list */
+ skin_image_cache_raise( cache, node );
+
+ D( "skin_image_cache: add '%s' (rot=%d), %d pixels\n",
+ node->desc.path, node->desc.rotation, node->w*node->h );
+
+ cache->total_pixels += node->w*node->h;
+ if (cache->total_pixels > cache->max_pixels)
+ skin_image_cache_flush( cache );
+
+ return node;
+}
+
+
+SkinImage*
+skin_image_find_simple( const char* path )
+{
+ SkinImageDesc desc;
+
+ desc.path = path;
+ desc.rotation = SKIN_ROTATION_0;
+ desc.blend = SKIN_BLEND_FULL;
+
+ return skin_image_find( &desc );
+}
+
+
+SkinImage*
+skin_image_ref( SkinImage* image )
+{
+ if (image && image != _no_image)
+ image->ref_count += 1;
+
+ return image;
+}
+
+
+void
+skin_image_unref( SkinImage** pimage )
+{
+ SkinImage* image = *pimage;
+
+ if (image) {
+ if (image != _no_image && --image->ref_count == 0) {
+ if ((image->flags & SKIN_IMAGE_CLONE) != 0) {
+ skin_image_free(image);
+ }
+ }
+ *pimage = NULL;
+ }
+}
+
+
+SkinImage*
+skin_image_rotate( SkinImage* source, SkinRotation rotation )
+{
+ SkinImageDesc desc;
+ SkinImage* image;
+
+ if (source == _no_image || source->desc.rotation == rotation)
+ return source;
+
+ desc = source->desc;
+ desc.rotation = rotation;
+ image = skin_image_find( &desc );
+ skin_image_unref( &source );
+ return image;
+}
+
+
+SkinImage*
+skin_image_clone( SkinImage* source )
+{
+ SkinImage* image;
+
+ if (source == NULL || source == _no_image)
+ return SKIN_IMAGE_NONE;
+
+ image = calloc(1,sizeof(*image));
+ if (image == NULL)
+ goto Fail;
+
+ image->desc = source->desc;
+ image->hash = source->hash;
+ image->flags = SKIN_IMAGE_CLONE;
+ image->w = source->w;
+ image->h = source->h;
+ image->pixels = rotate_image( source->pixels, source->w, source->h,
+ SKIN_ROTATION_0 );
+ if (image->pixels == NULL)
+ goto Fail;
+
+ image->surface = sdl_surface_from_argb32( image->pixels, image->w, image->h );
+ if (image->surface == NULL)
+ goto Fail;
+
+ return image;
+Fail:
+ if (image != NULL)
+ skin_image_free(image);
+ return SKIN_IMAGE_NONE;
+}
+
+SkinImage*
+skin_image_clone_full( SkinImage* source,
+ SkinRotation rotation,
+ int blend )
+{
+ SkinImageDesc desc;
+ SkinImage* clone;
+
+ if (source == NULL || source == SKIN_IMAGE_NONE)
+ return SKIN_IMAGE_NONE;
+
+ if (rotation == SKIN_ROTATION_0 &&
+ blend == SKIN_BLEND_FULL)
+ {
+ return skin_image_clone(source);
+ }
+
+ desc.path = source->desc.path;
+ desc.rotation = rotation;
+ desc.blend = blend;
+
+ clone = skin_image_create( &desc, 0 );
+ if (clone != SKIN_IMAGE_NONE)
+ clone->flags |= SKIN_IMAGE_CLONE;
+
+ return clone;
+}
+
+/* apply blending to a source skin image and copy the result to a target clone image */
+extern void
+skin_image_blend_clone( SkinImage* clone, SkinImage* source, int blend )
+{
+ SDL_LockSurface( clone->surface );
+ blend_image( clone->pixels, source->pixels, source->w, source->h, blend );
+ SDL_UnlockSurface( clone->surface );
+ SDL_SetAlpha( clone->surface, SDL_SRCALPHA, 255 );
+}
+
+int
+skin_image_w( SkinImage* image )
+{
+ return image ? image->w : 0;
+}
+
+int
+skin_image_h( SkinImage* image )
+{
+ return image ? image->h : 0;
+}
+
+int
+skin_image_org_w( SkinImage* image )
+{
+ if (image) {
+ if (image->desc.rotation == SKIN_ROTATION_90 ||
+ image->desc.rotation == SKIN_ROTATION_270)
+ return image->h;
+ else
+ return image->w;
+ }
+ return 0;
+}
+
+int
+skin_image_org_h( SkinImage* image )
+{
+ if (image) {
+ if (image->desc.rotation == SKIN_ROTATION_90 ||
+ image->desc.rotation == SKIN_ROTATION_270)
+ return image->w;
+ else
+ return image->h;
+ }
+ return 0;
+}
+
+SDL_Surface*
+skin_image_surface( SkinImage* image )
+{
+ return image ? image->surface : NULL;
+}
diff --git a/skins/skin_image.h b/skins/skin_image.h
new file mode 100644
index 0000000..ad069b2
--- /dev/null
+++ b/skins/skin_image.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_SKIN_IMAGE_H
+#define _ANDROID_SKIN_IMAGE_H
+
+#include "android.h"
+#include <SDL.h>
+#include "skin_rect.h"
+
+/* helper functions */
+
+extern SDL_Surface* sdl_surface_from_argb32( void* base, int w, int h );
+
+/* skin image file objects */
+
+/* opaque skin image type. all skin images are placed in a simple MRU cache
+ * to limit the emulator's memory usage, with the exception of 'clones' created
+ * with skin_image_clone() or skin_image_clone_blend()
+ */
+typedef struct SkinImage SkinImage;
+
+/* a descriptor for a given skin image */
+typedef struct SkinImageDesc {
+ const char* path; /* image file path (must be .png) */
+ AndroidRotation rotation; /* rotation */
+ int blend; /* blending, 0..256 value */
+} SkinImageDesc;
+
+#define SKIN_BLEND_NONE 0
+#define SKIN_BLEND_HALF 128
+#define SKIN_BLEND_FULL 256
+
+/* a special value returned when an image cannot be properly loaded */
+extern SkinImage* SKIN_IMAGE_NONE;
+
+/* return the SDL_Surface* pointer of a given skin image */
+extern SDL_Surface* skin_image_surface( SkinImage* image );
+extern int skin_image_w ( SkinImage* image );
+extern int skin_image_h ( SkinImage* image );
+extern int skin_image_org_w ( SkinImage* image );
+extern int skin_image_org_h ( SkinImage* image );
+
+/* get an image from the cache (load it from the file if necessary).
+ * returns SKIN_IMAGE_NONE in case of error. cannot return NULL
+ * this function also increments the reference count of the skin image,
+ * use "skin_image_unref()" when you don't need it anymore
+ */
+extern SkinImage* skin_image_find( SkinImageDesc* desc );
+
+extern SkinImage* skin_image_find_simple( const char* path );
+
+/* increment the reference count of a given skin image,
+ * don't do anything if 'image' is NULL */
+extern SkinImage* skin_image_ref( SkinImage* image );
+
+/* decrement the reference count of a given skin image. if
+ * the count reaches 0, the image becomes eligible for cache flushing.
+ * unless it was created through a skin_image_clone... function, where
+ * it is immediately discarded...
+ */
+extern void skin_image_unref( SkinImage** pimage );
+
+/* get the rotation of a given image. this decrements the reference count
+ * of the source after returning the target, whose reference count is incremented
+ */
+extern SkinImage* skin_image_rotate( SkinImage* source, SkinRotation rotation );
+
+/* create a skin image clone. the clone is not part of the cache and will
+ * be destroyed immediately when its reference count reaches 0. this is useful
+ * if you need to modify the content of the clone (e.g. blending)
+ */
+extern SkinImage* skin_image_clone( SkinImage* source );
+
+/* create a skin image clone, the clone is a rotated version of a source image
+ */
+extern SkinImage* skin_image_clone_full( SkinImage* source,
+ SkinRotation rotation,
+ int blend );
+
+/* apply blending to a source skin image and copy the result to a target clone image */
+extern void skin_image_blend_clone( SkinImage* clone, SkinImage* source, int blend );
+
+#endif /* _ANDROID_SKIN_IMAGE_H */
diff --git a/skins/skin_keyboard.c b/skins/skin_keyboard.c
new file mode 100644
index 0000000..829b279
--- /dev/null
+++ b/skins/skin_keyboard.c
@@ -0,0 +1,783 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skin_keyboard.h"
+#include "android_utils.h"
+#include "android.h"
+#include "vl.h"
+
+#define DEBUG 1
+
+#if DEBUG
+# define D(...) VERBOSE_PRINT(keys,__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
+
+#define USE_KEYSET 1
+
+/** LAST PRESSED KEYS
+ ** a small buffer of last pressed keys, this is used to properly
+ ** implement the Unicode keyboard mode (SDL key up event always have
+ ** their .unicode field set to 0
+ **/
+typedef struct {
+ int unicode; /* Unicode of last pressed key */
+ int sym; /* SDL key symbol value (e.g. SDLK_a) */
+ int mod; /* SDL key modifier value */
+} LastKey;
+
+#define MAX_LAST_KEYS 16
+#define MAX_KEYCODES 256*2
+
+struct SkinKeyboard {
+ const AKeyCharmap* charmap;
+ SkinKeyset* kset;
+ char enabled;
+ char raw_keys;
+ char last_count;
+ int keycode_count;
+
+ SkinRotation rotation;
+
+ SkinKeyCommandFunc command_func;
+ void* command_opaque;
+ SkinKeyEventFunc press_func;
+ void* press_opaque;
+
+ LastKey last_keys[ MAX_LAST_KEYS ];
+ int keycodes[ MAX_KEYCODES ];
+};
+
+
+void
+skin_keyboard_set_keyset( SkinKeyboard* keyboard, SkinKeyset* kset )
+{
+ if (kset == NULL)
+ return;
+ if (keyboard->kset && keyboard->kset != android_keyset) {
+ skin_keyset_free(keyboard->kset);
+ }
+ keyboard->kset = kset;
+}
+
+
+const char*
+skin_keyboard_charmap_name( SkinKeyboard* keyboard )
+{
+ if (keyboard && keyboard->charmap)
+ return keyboard->charmap->name;
+
+ return "qwerty";
+}
+
+void
+skin_keyboard_set_rotation( SkinKeyboard* keyboard,
+ SkinRotation rotation )
+{
+ keyboard->rotation = (rotation & 3);
+}
+
+void
+skin_keyboard_on_command( SkinKeyboard* keyboard, SkinKeyCommandFunc cmd_func, void* cmd_opaque )
+{
+ keyboard->command_func = cmd_func;
+ keyboard->command_opaque = cmd_opaque;
+}
+
+void
+skin_keyboard_on_key_press( SkinKeyboard* keyboard, SkinKeyEventFunc press_func, void* press_opaque )
+{
+ keyboard->press_func = press_func;
+ keyboard->press_opaque = press_opaque;
+}
+
+void
+skin_keyboard_add_key_event( SkinKeyboard* kb,
+ unsigned code,
+ unsigned down )
+{
+ if (code != 0 && kb->keycode_count < MAX_KEYCODES) {
+ //dprint("add keycode %d, down %d\n", code % 0x1ff, down );
+ kb->keycodes[(int)kb->keycode_count++] = ( (code & 0x1ff) | (down ? 0x200 : 0) );
+ }
+}
+
+
+void
+skin_keyboard_flush( SkinKeyboard* kb )
+{
+ if (kb->keycode_count > 0) {
+ if (VERBOSE_CHECK(keys)) {
+ int nn;
+ printf(">> KEY" );
+ for (nn = 0; nn < kb->keycode_count; nn++) {
+ int code = kb->keycodes[nn];
+ printf(" [0x%03x,%s]", (code & 0x1ff), (code & 0x200) ? "down" : " up " );
+ }
+ printf( "\n" );
+ }
+ kbd_put_keycodes(kb->keycodes, kb->keycode_count);
+ kb->keycode_count = 0;
+ }
+}
+
+
+static void
+skin_keyboard_cmd( SkinKeyboard* keyboard,
+ SkinKeyCommand command,
+ int param )
+{
+ if (keyboard->command_func) {
+ keyboard->command_func( keyboard->command_opaque, command, param );
+ }
+}
+
+
+static LastKey*
+skin_keyboard_find_last( SkinKeyboard* keyboard,
+ int sym )
+{
+ LastKey* k = keyboard->last_keys;
+ LastKey* end = k + keyboard->last_count;
+
+ for ( ; k < end; k++ ) {
+ if (k->sym == sym)
+ return k;
+ }
+ return NULL;
+}
+
+static void
+skin_keyboard_add_last( SkinKeyboard* keyboard,
+ int sym,
+ int mod,
+ int unicode )
+{
+ LastKey* k = keyboard->last_keys + keyboard->last_count;
+
+ if (keyboard->last_count < MAX_LAST_KEYS) {
+ k->sym = sym;
+ k->mod = mod;
+ k->unicode = unicode;
+
+ keyboard->last_count += 1;
+ }
+}
+
+static void
+skin_keyboard_remove_last( SkinKeyboard* keyboard,
+ int sym )
+{
+ LastKey* k = keyboard->last_keys;
+ LastKey* end = k + keyboard->last_count;
+
+ for ( ; k < end; k++ ) {
+ if (k->sym == sym) {
+ /* we don't need a sorted array, so place the last
+ * element in place at the position of the removed
+ * one... */
+ k[0] = end[-1];
+ keyboard->last_count -= 1;
+ break;
+ }
+ }
+}
+
+static void
+skin_keyboard_clear_last( SkinKeyboard* keyboard )
+{
+ keyboard->last_count = 0;
+}
+
+static int
+skin_keyboard_rotate_sym( SkinKeyboard* keyboard,
+ int sym )
+{
+ switch (keyboard->rotation) {
+ case SKIN_ROTATION_90:
+ switch (sym) {
+ case SDLK_LEFT: sym = SDLK_DOWN; break;
+ case SDLK_RIGHT: sym = SDLK_UP; break;
+ case SDLK_UP: sym = SDLK_LEFT; break;
+ case SDLK_DOWN: sym = SDLK_RIGHT; break;
+ }
+ break;
+
+ case SKIN_ROTATION_180:
+ switch (sym) {
+ case SDLK_LEFT: sym = SDLK_RIGHT; break;
+ case SDLK_RIGHT: sym = SDLK_LEFT; break;
+ case SDLK_UP: sym = SDLK_DOWN; break;
+ case SDLK_DOWN: sym = SDLK_UP; break;
+ }
+ break;
+
+ case SKIN_ROTATION_270:
+ switch (sym) {
+ case SDLK_LEFT: sym = SDLK_UP; break;
+ case SDLK_RIGHT: sym = SDLK_DOWN; break;
+ case SDLK_UP: sym = SDLK_RIGHT; break;
+ case SDLK_DOWN: sym = SDLK_LEFT; break;
+ }
+ break;
+
+ default: ;
+ }
+ return sym;
+}
+
+#if USE_KEYSET
+static AndroidKeyCode
+skin_keyboard_key_to_code( SkinKeyboard* keyboard,
+ unsigned sym,
+ int mod,
+ int down )
+{
+ AndroidKeyCode code = 0;
+ int mod0 = mod;
+ SkinKeyCommand command;
+
+ /* first, handle the arrow keys directly */
+ /* rotate them if necessary */
+ sym = skin_keyboard_rotate_sym(keyboard, sym);
+ mod &= (KMOD_CTRL | KMOD_ALT | KMOD_SHIFT);
+
+ switch (sym) {
+ case SDLK_LEFT: code = kKeyCodeDpadLeft; break;
+ case SDLK_RIGHT: code = kKeyCodeDpadRight; break;
+ case SDLK_UP: code = kKeyCodeDpadUp; break;
+ case SDLK_DOWN: code = kKeyCodeDpadDown; break;
+ default: ;
+ }
+
+ if (code != 0) {
+ D("handling arrow (sym=%d mod=%d)", sym, mod);
+ if (!keyboard->raw_keys) {
+ int doCapL, doCapR, doAltL, doAltR;
+
+ if (!down) {
+ LastKey* k = skin_keyboard_find_last(keyboard, sym);
+ if (k != NULL) {
+ mod = k->mod;
+ skin_keyboard_remove_last( keyboard, sym );
+ }
+ } else {
+ skin_keyboard_add_last( keyboard, sym, mod, 0);
+ }
+
+ doCapL = (mod & 0x7ff) & KMOD_LSHIFT;
+ doCapR = (mod & 0x7ff) & KMOD_RSHIFT;
+ doAltL = (mod & 0x7ff) & KMOD_LALT;
+ doAltR = (mod & 0x7ff) & KMOD_RALT;
+
+ if (down) {
+ if (doAltL) skin_keyboard_add_key_event( keyboard, kKeyCodeAltLeft, 1 );
+ if (doAltR) skin_keyboard_add_key_event( keyboard, kKeyCodeAltRight, 1 );
+ if (doCapL) skin_keyboard_add_key_event( keyboard, kKeyCodeCapLeft, 1 );
+ if (doCapR) skin_keyboard_add_key_event( keyboard, kKeyCodeCapRight, 1 );
+ }
+ skin_keyboard_add_key_event(keyboard, code, down);
+
+ if (!down) {
+ if (doCapR) skin_keyboard_add_key_event( keyboard, kKeyCodeCapRight, 0 );
+ if (doCapL) skin_keyboard_add_key_event( keyboard, kKeyCodeCapLeft, 0 );
+ if (doAltR) skin_keyboard_add_key_event( keyboard, kKeyCodeAltRight, 0 );
+ if (doAltL) skin_keyboard_add_key_event( keyboard, kKeyCodeAltLeft, 0 );
+ }
+ code = 0;
+ }
+ return code;
+ }
+
+ /* special case for keypad keys, ignore them here if numlock is on */
+ if ((mod0 & KMOD_NUM) != 0) {
+ switch (sym) {
+ case SDLK_KP0:
+ case SDLK_KP1:
+ case SDLK_KP2:
+ case SDLK_KP3:
+ case SDLK_KP4:
+ case SDLK_KP5:
+ case SDLK_KP6:
+ case SDLK_KP7:
+ case SDLK_KP8:
+ case SDLK_KP9:
+ case SDLK_KP_PLUS:
+ case SDLK_KP_MINUS:
+ case SDLK_KP_MULTIPLY:
+ case SDLK_KP_DIVIDE:
+ case SDLK_KP_EQUALS:
+ case SDLK_KP_PERIOD:
+ case SDLK_KP_ENTER:
+ return 0;
+ }
+ }
+
+ /* now try all keyset combos */
+ command = skin_keyset_get_command( keyboard->kset, sym, mod );
+ if (command != SKIN_KEY_COMMAND_NONE) {
+ D("handling command %s from (sym=%d, mod=%d, str=%s)",
+ skin_key_command_to_str(command), sym, mod, skin_key_symmod_to_str(sym,mod));
+ skin_keyboard_cmd( keyboard, command, down );
+ return 0;
+ }
+ D("could not handle (sym=%d, mod=%d, str=%s)", sym, mod,
+ skin_key_symmod_to_str(sym,mod));
+ return -1;
+}
+#else /* !USE_KEYSET */
+/* this will look for non-Unicode key strokes, e.g. arrows, F1, F2, etc...
+ * note that we have some special handling for shift-<arrow>, these will
+ * be emulated as two key strokes on the device
+ */
+static AndroidKeyCode
+skin_keyboard_key_to_code( SkinKeyboard* keyboard,
+ unsigned sym,
+ int mod,
+ int down )
+{
+ AndroidKeyCode code = 0;
+ int doAltShift = 0;
+
+ sym = skin_keyboard_rotate_sym(keyboard, sym);
+
+ switch (sym) {
+ case SDLK_LEFT: code = kKeyCodeDpadLeft; doAltShift = 1; break;
+ case SDLK_RIGHT: code = kKeyCodeDpadRight; doAltShift = 1; break;
+ case SDLK_UP: code = kKeyCodeDpadUp; doAltShift = 1; break;
+ case SDLK_DOWN: code = kKeyCodeDpadDown; doAltShift = 1; break;
+ case SDLK_HOME: code = kKeyCodeHome; break;
+ case SDLK_BACKSPACE: code = kKeyCodeDel; doAltShift = 1; break;
+ case SDLK_ESCAPE: code = kKeyCodeBack; break;
+ case SDLK_RETURN: code = kKeyCodeNewline; doAltShift = 1; break;
+ case SDLK_F1: code = kKeyCodeSoftLeft; break;
+ case SDLK_F2: code = kKeyCodeSoftRight; break;
+ case SDLK_F3: code = kKeyCodeCall; break;
+ case SDLK_F4: code = kKeyCodeEndCall; break;
+ case SDLK_F5: code = kKeyCodeSearch; break;
+ case SDLK_F7: code = kKeyCodePower; break;
+
+ case SDLK_F8: /* network connect/disconnect */
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_TOGGLE_NETWORK, 1 );
+ }
+ return 0;
+
+#ifdef CONFIG_TRACE
+ case SDLK_F9: /* start tracing */
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_TOGGLE_TRACING, 1 );
+ }
+ return 0;
+
+ case SDLK_F10: /* stop tracing */
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_TOGGLE_TRACING, 1 );
+ }
+ return 0;
+#endif
+
+ case SDLK_F12: /* change orientation */
+ if (down && (mod & (KMOD_LCTRL | KMOD_RCTRL)) != 0) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_CHANGE_LAYOUT, +1 );
+ }
+ return 0;
+
+ case SDLK_PAGEUP: return kKeyCodeSoftLeft;
+ case SDLK_PAGEDOWN: return kKeyCodeSoftRight;
+
+ case SDLK_t:
+ if (down && (mod & (KMOD_LCTRL| KMOD_RCTRL)) != 0) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_TOGGLE_TRACKBALL, 1 );
+ return 0;
+ }
+ break;
+
+ case SDLK_KP5:
+ if ((mod & (KMOD_LCTRL | KMOD_RCTRL)) != 0)
+ code = kKeyCodeCamera;
+ break;
+ }
+
+ if (code != 0) {
+ if (doAltShift && !keyboard->raw_keys) {
+ int doCapL, doCapR, doAltL, doAltR;
+
+ if (!down) {
+ LastKey* k = skin_keyboard_find_last(keyboard, sym);
+ if (k != NULL) {
+ mod = k->mod;
+ skin_keyboard_remove_last( keyboard, sym );
+ }
+ } else {
+ skin_keyboard_add_last( keyboard, sym, mod, 0);
+ }
+
+ doCapL = (mod & 0x7ff) & KMOD_LSHIFT;
+ doCapR = (mod & 0x7ff) & KMOD_RSHIFT;
+ doAltL = (mod & 0x7ff) & KMOD_LALT;
+ doAltR = (mod & 0x7ff) & KMOD_RALT;
+
+ if (down) {
+ if (doAltL) skin_keyboard_add_key_event( keyboard, kKeyCodeAltLeft, 1 );
+ if (doAltR) skin_keyboard_add_key_event( keyboard, kKeyCodeAltRight, 1 );
+ if (doCapL) skin_keyboard_add_key_event( keyboard, kKeyCodeCapLeft, 1 );
+ if (doCapR) skin_keyboard_add_key_event( keyboard, kKeyCodeCapRight, 1 );
+ }
+ skin_keyboard_add_key_event(keyboard, code, down);
+
+ if (!down) {
+ if (doCapR) skin_keyboard_add_key_event( keyboard, kKeyCodeCapRight, 0 );
+ if (doCapL) skin_keyboard_add_key_event( keyboard, kKeyCodeCapLeft, 0 );
+ if (doAltR) skin_keyboard_add_key_event( keyboard, kKeyCodeAltRight, 0 );
+ if (doAltL) skin_keyboard_add_key_event( keyboard, kKeyCodeAltLeft, 0 );
+ }
+ code = 0;
+ }
+ return code;
+ }
+
+ if ((mod & KMOD_NUM) == 0) {
+ switch (sym) {
+ case SDLK_KP8: return kKeyCodeDpadUp;
+ case SDLK_KP2: return kKeyCodeDpadDown;
+ case SDLK_KP4: return kKeyCodeDpadLeft;
+ case SDLK_KP6: return kKeyCodeDpadRight;
+ case SDLK_KP5: return kKeyCodeDpadCenter;
+
+ case SDLK_KP_PLUS: return kKeyCodeVolumeUp;
+ case SDLK_KP_MINUS: return kKeyCodeVolumeDown;
+
+ case SDLK_KP_MULTIPLY:
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_ONION_ALPHA_UP, 1 );
+ }
+ return 0;
+
+ case SDLK_KP_DIVIDE:
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_ONION_ALPHA_DOWN, 1 );
+ }
+ return 0;
+
+ case SDLK_KP7:
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_CHANGE_LAYOUT_PREV, 1 );
+ }
+ return 0;
+
+ case SDLK_KP9:
+ if (down) {
+ skin_keyboard_cmd( keyboard, SKIN_KEY_COMMAND_CHANGE_LAYOUT_NEXT, 1 );
+ }
+ return 0;
+ }
+ }
+ return -1;
+}
+#endif /* !USE_KEYSET */
+
+/* this gets called only if the reverse unicode mapping didn't work
+ * or wasn't used (when in raw keys mode)
+ */
+static AndroidKeyCode
+skin_keyboard_raw_key_to_code(SkinKeyboard* kb, unsigned sym, int down)
+{
+ switch(sym){
+ case SDLK_1: return kKeyCode1;
+ case SDLK_2: return kKeyCode2;
+ case SDLK_3: return kKeyCode3;
+ case SDLK_4: return kKeyCode4;
+ case SDLK_5: return kKeyCode5;
+ case SDLK_6: return kKeyCode6;
+ case SDLK_7: return kKeyCode7;
+ case SDLK_8: return kKeyCode8;
+ case SDLK_9: return kKeyCode9;
+ case SDLK_0: return kKeyCode0;
+
+ case SDLK_q: return kKeyCodeQ;
+ case SDLK_w: return kKeyCodeW;
+ case SDLK_e: return kKeyCodeE;
+ case SDLK_r: return kKeyCodeR;
+ case SDLK_t: return kKeyCodeT;
+ case SDLK_y: return kKeyCodeY;
+ case SDLK_u: return kKeyCodeU;
+ case SDLK_i: return kKeyCodeI;
+ case SDLK_o: return kKeyCodeO;
+ case SDLK_p: return kKeyCodeP;
+ case SDLK_a: return kKeyCodeA;
+ case SDLK_s: return kKeyCodeS;
+ case SDLK_d: return kKeyCodeD;
+ case SDLK_f: return kKeyCodeF;
+ case SDLK_g: return kKeyCodeG;
+ case SDLK_h: return kKeyCodeH;
+ case SDLK_j: return kKeyCodeJ;
+ case SDLK_k: return kKeyCodeK;
+ case SDLK_l: return kKeyCodeL;
+ case SDLK_z: return kKeyCodeZ;
+ case SDLK_x: return kKeyCodeX;
+ case SDLK_c: return kKeyCodeC;
+ case SDLK_v: return kKeyCodeV;
+ case SDLK_b: return kKeyCodeB;
+ case SDLK_n: return kKeyCodeN;
+ case SDLK_m: return kKeyCodeM;
+ case SDLK_COMMA: return kKeyCodeComma;
+ case SDLK_PERIOD: return kKeyCodePeriod;
+ case SDLK_SPACE: return kKeyCodeSpace;
+ case SDLK_SLASH: return kKeyCodeSlash;
+ case SDLK_RETURN: return kKeyCodeNewline;
+ case SDLK_BACKSPACE: return kKeyCodeDel;
+
+/* these are qwerty keys not on a device keyboard */
+ case SDLK_TAB: return kKeyCodeTab;
+ case SDLK_BACKQUOTE: return kKeyCodeGrave;
+ case SDLK_MINUS: return kKeyCodeMinus;
+ case SDLK_EQUALS: return kKeyCodeEquals;
+ case SDLK_LEFTBRACKET: return kKeyCodeLeftBracket;
+ case SDLK_RIGHTBRACKET: return kKeyCodeRightBracket;
+ case SDLK_BACKSLASH: return kKeyCodeBackslash;
+ case SDLK_SEMICOLON: return kKeyCodeSemicolon;
+ case SDLK_QUOTE: return kKeyCodeApostrophe;
+
+ case SDLK_RSHIFT: return kKeyCodeCapRight;
+ case SDLK_LSHIFT: return kKeyCodeCapLeft;
+ case SDLK_RMETA: return kKeyCodeSym;
+ case SDLK_LMETA: return kKeyCodeSym;
+ case SDLK_RALT: return kKeyCodeAltRight;
+ case SDLK_LALT: return kKeyCodeAltLeft;
+ case SDLK_RCTRL: return kKeyCodeSym;
+ case SDLK_LCTRL: return kKeyCodeSym;
+
+ default:
+ /* fprintf(stderr,"* unknown sdl keysym %d *\n", sym); */
+ return -1;
+ }
+}
+
+
+static void
+skin_keyboard_do_key_event( SkinKeyboard* kb,
+ AndroidKeyCode code,
+ int down )
+{
+ if (kb->press_func) {
+ kb->press_func( kb->press_opaque, code, down );
+ }
+ skin_keyboard_add_key_event(kb, code, down);
+}
+
+
+int
+skin_keyboard_process_unicode_event( SkinKeyboard* kb, unsigned int unicode, int down )
+{
+ const AKeyCharmap* cmap = kb->charmap;
+ int n;
+
+ if (unicode == 0)
+ return 0;
+
+ /* check base keys */
+ for (n = 0; n < cmap->num_entries; n++) {
+ if (cmap->entries[n].base == unicode) {
+ skin_keyboard_add_key_event(kb, cmap->entries[n].code, down);
+ return 1;
+ }
+ }
+
+ /* check caps + keys */
+ for (n = 0; n < cmap->num_entries; n++) {
+ if (cmap->entries[n].caps == unicode) {
+ if (down)
+ skin_keyboard_add_key_event(kb, kKeyCodeCapLeft, down);
+ skin_keyboard_add_key_event(kb, cmap->entries[n].code, down);
+ if (!down)
+ skin_keyboard_add_key_event(kb, kKeyCodeCapLeft, down);
+ return 2;
+ }
+ }
+
+ /* check fn + keys */
+ for (n = 0; n < cmap->num_entries; n++) {
+ if (cmap->entries[n].fn == unicode) {
+ if (down)
+ skin_keyboard_add_key_event(kb, kKeyCodeAltLeft, down);
+ skin_keyboard_add_key_event(kb, cmap->entries[n].code, down);
+ if (!down)
+ skin_keyboard_add_key_event(kb, kKeyCodeAltLeft, down);
+ return 2;
+ }
+ }
+
+ /* check caps + fn + keys */
+ for (n = 0; n < cmap->num_entries; n++) {
+ if (cmap->entries[n].caps_fn == unicode) {
+ if (down) {
+ skin_keyboard_add_key_event(kb, kKeyCodeAltLeft, down);
+ skin_keyboard_add_key_event(kb, kKeyCodeCapLeft, down);
+ }
+ skin_keyboard_add_key_event(kb, cmap->entries[n].code, down);
+ if (!down) {
+ skin_keyboard_add_key_event(kb, kKeyCodeCapLeft, down);
+ skin_keyboard_add_key_event(kb, kKeyCodeAltLeft, down);
+ }
+ return 3;
+ }
+ }
+
+ /* no match */
+ return 0;
+}
+
+
+void
+skin_keyboard_enable( SkinKeyboard* keyboard,
+ int enabled )
+{
+ keyboard->enabled = enabled;
+ if (enabled) {
+ SDL_EnableUNICODE(!keyboard->raw_keys);
+ SDL_EnableKeyRepeat(0,0);
+ }
+}
+
+void
+skin_keyboard_process_event( SkinKeyboard* kb, SDL_Event* ev, int down )
+{
+ unsigned code;
+ int unicode = ev->key.keysym.unicode;
+ int sym = ev->key.keysym.sym;
+ int mod = ev->key.keysym.mod;
+
+ /* ignore key events if we're not enabled */
+ if (!kb->enabled) {
+ printf( "ignoring key event sym=%d mod=0x%x unicode=%d\n",
+ sym, mod, unicode );
+ return;
+ }
+
+ /* first, try the keyboard-mode-independent keys */
+ code = skin_keyboard_key_to_code( kb, sym, mod, down );
+ if (code == 0)
+ return;
+
+ if ((int)code > 0) {
+ skin_keyboard_do_key_event(kb, code, down);
+ skin_keyboard_flush(kb);
+ return;
+ }
+
+ /* Ctrl-K is used to switch between 'unicode' and 'raw' modes */
+ if (sym == SDLK_k)
+ {
+ int mod2 = mod & 0x7ff;
+
+ if ( mod2 == KMOD_LCTRL || mod2 == KMOD_RCTRL ) {
+ if (down) {
+ skin_keyboard_clear_last(kb);
+ kb->raw_keys = !kb->raw_keys;
+ SDL_EnableUNICODE(!kb->raw_keys);
+ D( "switching keyboard to %s mode", kb->raw_keys ? "raw" : "unicode" );
+ }
+ return;
+ }
+ }
+
+ if (!kb->raw_keys) {
+ /* ev->key.keysym.unicode is only valid on keydown events, and will be 0
+ * on the corresponding keyup ones, so remember the set of last pressed key
+ * syms to "undo" the job
+ */
+ if ( !down && unicode == 0 ) {
+ LastKey* k = skin_keyboard_find_last(kb, sym);
+ if (k != NULL) {
+ unicode = k->unicode;
+ skin_keyboard_remove_last(kb, sym);
+ }
+ }
+ }
+ if (!kb->raw_keys &&
+ skin_keyboard_process_unicode_event( kb, unicode, down ) > 0)
+ {
+ if (down)
+ skin_keyboard_add_last( kb, sym, mod, unicode );
+
+ skin_keyboard_flush( kb );
+ return;
+ }
+
+ code = skin_keyboard_raw_key_to_code( kb, sym, down );
+
+ if ( !kb->raw_keys &&
+ (code == kKeyCodeAltLeft || code == kKeyCodeAltRight ||
+ code == kKeyCodeCapLeft || code == kKeyCodeCapRight ||
+ code == kKeyCodeSym) )
+ return;
+
+ if (code == -1) {
+ D("ignoring keysym %d", sym );
+ } else if (code > 0) {
+ skin_keyboard_do_key_event(kb, code, down);
+ skin_keyboard_flush(kb);
+ }
+}
+
+
+SkinKeyboard*
+skin_keyboard_create_from_aconfig( AConfig* aconfig, int use_raw_keys )
+{
+ SkinKeyboard* kb = qemu_mallocz(sizeof(*kb));
+ const char* charmap_name = "qwerty";
+ AConfig* node;
+
+ if (kb == NULL)
+ return kb;
+
+ node = aconfig_find( aconfig, "keyboard" );
+ if (node != NULL)
+ charmap_name = aconfig_str(node, "charmap", charmap_name);
+
+ {
+ int nn;
+
+ for (nn = 0; nn < android_charmap_count; nn++) {
+ if ( !strcmp(android_charmaps[nn]->name, charmap_name) ) {
+ kb->charmap = android_charmaps[nn];
+ break;
+ }
+ }
+
+ if (!kb->charmap) {
+ fprintf(stderr, "### warning, skin requires unknown '%s' charmap, reverting to '%s'\n",
+ charmap_name, android_charmaps[0]->name );
+ kb->charmap = android_charmaps[0];
+ }
+ }
+ kb->raw_keys = use_raw_keys;
+ kb->enabled = 0;
+
+ /* add default keyset */
+ if (android_keyset)
+ kb->kset = android_keyset;
+ else
+ kb->kset = skin_keyset_new_from_text( skin_keyset_get_default() );
+
+ return kb;
+}
+
+void
+skin_keyboard_free( SkinKeyboard* keyboard )
+{
+ if (keyboard) {
+ qemu_free(keyboard);
+ }
+}
diff --git a/skins/skin_keyboard.h b/skins/skin_keyboard.h
new file mode 100644
index 0000000..6be3643
--- /dev/null
+++ b/skins/skin_keyboard.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_SKIN_KEYBOARD_H
+#define _ANDROID_SKIN_KEYBOARD_H
+
+#include "android_charmap.h"
+#include "android_config.h"
+#include "skin_image.h" /* for SkinRotation */
+#include "skin_keyset.h"
+#include <SDL.h>
+
+typedef struct SkinKeyboard SkinKeyboard;
+
+typedef void (*SkinKeyCommandFunc)( void* opaque, SkinKeyCommand command, int param );
+
+typedef void (*SkinKeyEventFunc)( void* opaque, AndroidKeyCode code, int down );
+
+extern SkinKeyboard* skin_keyboard_create_from_aconfig( AConfig* aconfig, int use_raw_keys );
+
+extern void skin_keyboard_set_keyset( SkinKeyboard* keyboard, SkinKeyset* kset );
+
+extern const char* skin_keyboard_charmap_name( SkinKeyboard* keyboard );
+
+extern void skin_keyboard_free( SkinKeyboard* keyboard );
+
+extern void skin_keyboard_enable( SkinKeyboard* keyboard,
+ int enabled );
+
+extern void skin_keyboard_on_command( SkinKeyboard* keyboard,
+ SkinKeyCommandFunc cmd_func,
+ void* cmd_opaque );
+
+extern void skin_keyboard_set_rotation( SkinKeyboard* keyboard,
+ SkinRotation rotation );
+
+extern void skin_keyboard_on_key_press( SkinKeyboard* keyboard,
+ SkinKeyEventFunc press_func,
+ void* press_opaque );
+
+extern void skin_keyboard_process_event( SkinKeyboard* keyboard, SDL_Event* ev, int down );
+extern int skin_keyboard_process_unicode_event( SkinKeyboard* kb, unsigned int unicode, int down );
+
+extern void skin_keyboard_add_key_event( SkinKeyboard* k, unsigned code, unsigned down );
+extern void skin_keyboard_flush( SkinKeyboard* kb );
+
+/* defined in android_main.c */
+extern SkinKeyboard* android_emulator_get_keyboard( void );
+
+#endif /* _ANDROID_SKIN_KEYBOARD_H */
+
diff --git a/skins/skin_keyset.c b/skins/skin_keyset.c
new file mode 100644
index 0000000..ffde933
--- /dev/null
+++ b/skins/skin_keyset.c
@@ -0,0 +1,540 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skins/skin_keyset.h"
+#include "android_utils.h"
+#include "android.h"
+#include <SDL.h>
+
+#define DEBUG 1
+
+#if 1
+# define D_ACTIVE VERBOSE_CHECK(keys)
+#else
+# define D_ACTIVE DEBUG
+#endif
+
+#if DEBUG
+# define D(...) VERBOSE_PRINT(keys,__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
+#define _SKIN_KEY_COMMAND(x,y) #x ,
+static const char* const command_strings[ SKIN_KEY_COMMAND_MAX ] = {
+ SKIN_KEY_COMMAND_LIST
+};
+#undef _SKIN_KEY_COMMAND
+
+const char*
+skin_key_command_to_str( SkinKeyCommand cmd )
+{
+ if (cmd > SKIN_KEY_COMMAND_NONE && cmd < SKIN_KEY_COMMAND_MAX)
+ return command_strings[cmd];
+
+ return NULL;
+}
+
+SkinKeyCommand
+skin_key_command_from_str( const char* str, int len )
+{
+ int nn;
+ if (len < 0)
+ len = strlen(str);
+ for (nn = 0; nn < SKIN_KEY_COMMAND_MAX; nn++) {
+ const char* cmd = command_strings[nn];
+
+ if ( !memcmp( cmd, str, len ) && cmd[len] == 0 )
+ return (SkinKeyCommand) nn;
+ }
+ return SKIN_KEY_COMMAND_NONE;
+}
+
+
+#define _SKIN_KEY_COMMAND(x,y) y ,
+static const char* const command_descriptions[ SKIN_KEY_COMMAND_MAX ] = {
+ SKIN_KEY_COMMAND_LIST
+};
+#undef _SKIN_KEY_COMMAND
+
+const char*
+skin_key_command_description( SkinKeyCommand cmd )
+{
+ if (cmd > SKIN_KEY_COMMAND_NONE && cmd < SKIN_KEY_COMMAND_MAX)
+ return command_descriptions[cmd];
+
+ return NULL;
+}
+
+#define _KEYSYM1_(x) _KEYSYM_(x,x)
+
+#define _KEYSYM_LIST \
+ _KEYSYM1_(BACKSPACE) \
+ _KEYSYM1_(TAB) \
+ _KEYSYM1_(CLEAR) \
+ _KEYSYM_(RETURN,ENTER) \
+ _KEYSYM1_(PAUSE) \
+ _KEYSYM1_(ESCAPE) \
+ _KEYSYM1_(SPACE) \
+ _KEYSYM_(EXCLAIM,EXCLAM) \
+ _KEYSYM_(QUOTEDBL,DOUBLEQUOTE) \
+ _KEYSYM_(HASH,HASH) \
+ _KEYSYM1_(DOLLAR) \
+ _KEYSYM1_(AMPERSAND) \
+ _KEYSYM1_(QUOTE) \
+ _KEYSYM_(LEFTPAREN,LPAREN) \
+ _KEYSYM_(RIGHTPAREN,RPAREN) \
+ _KEYSYM1_(ASTERISK) \
+ _KEYSYM1_(PLUS) \
+ _KEYSYM1_(COMMA) \
+ _KEYSYM1_(MINUS) \
+ _KEYSYM1_(PERIOD) \
+ _KEYSYM1_(SLASH) \
+ _KEYSYM1_(0) \
+ _KEYSYM1_(1) \
+ _KEYSYM1_(2) \
+ _KEYSYM1_(3) \
+ _KEYSYM1_(4) \
+ _KEYSYM1_(5) \
+ _KEYSYM1_(6) \
+ _KEYSYM1_(7) \
+ _KEYSYM1_(8) \
+ _KEYSYM1_(9) \
+ _KEYSYM1_(COLON) \
+ _KEYSYM1_(SEMICOLON) \
+ _KEYSYM1_(LESS) \
+ _KEYSYM_(EQUALS,EQUAL) \
+ _KEYSYM1_(GREATER) \
+ _KEYSYM1_(QUESTION) \
+ _KEYSYM1_(AT) \
+ _KEYSYM1_(LEFTBRACKET) \
+ _KEYSYM1_(BACKSLASH) \
+ _KEYSYM1_(RIGHTBRACKET) \
+ _KEYSYM1_(CARET) \
+ _KEYSYM1_(UNDERSCORE) \
+ _KEYSYM1_(BACKQUOTE) \
+ _KEYSYM_(a,A) \
+ _KEYSYM_(b,B) \
+ _KEYSYM_(c,C) \
+ _KEYSYM_(d,D) \
+ _KEYSYM_(e,E) \
+ _KEYSYM_(f,F) \
+ _KEYSYM_(g,G) \
+ _KEYSYM_(h,H) \
+ _KEYSYM_(i,I) \
+ _KEYSYM_(j,J) \
+ _KEYSYM_(k,K) \
+ _KEYSYM_(l,L) \
+ _KEYSYM_(m,M) \
+ _KEYSYM_(n,N) \
+ _KEYSYM_(o,O) \
+ _KEYSYM_(p,P) \
+ _KEYSYM_(q,Q) \
+ _KEYSYM_(r,R) \
+ _KEYSYM_(s,S) \
+ _KEYSYM_(t,T) \
+ _KEYSYM_(u,U) \
+ _KEYSYM_(v,V) \
+ _KEYSYM_(w,W) \
+ _KEYSYM_(x,X) \
+ _KEYSYM_(y,Y) \
+ _KEYSYM_(z,Z) \
+ _KEYSYM1_(DELETE) \
+ _KEYSYM_(KP_PLUS,KEYPAD_PLUS) \
+ _KEYSYM_(KP_MINUS,KEYPAD_MINUS) \
+ _KEYSYM_(KP_MULTIPLY,KEYPAD_MULTIPLY) \
+ _KEYSYM_(KP_DIVIDE,KEYPAD_DIVIDE) \
+ _KEYSYM_(KP_ENTER,KEYPAD_ENTER) \
+ _KEYSYM_(KP_PERIOD,KEYPAD_PERIOD) \
+ _KEYSYM_(KP_EQUALS,KEYPAD_EQUALS) \
+ _KEYSYM_(KP1,KEYPAD_1) \
+ _KEYSYM_(KP2,KEYPAD_2) \
+ _KEYSYM_(KP3,KEYPAD_3) \
+ _KEYSYM_(KP4,KEYPAD_4) \
+ _KEYSYM_(KP5,KEYPAD_5) \
+ _KEYSYM_(KP6,KEYPAD_6) \
+ _KEYSYM_(KP7,KEYPAD_7) \
+ _KEYSYM_(KP8,KEYPAD_8) \
+ _KEYSYM_(KP9,KEYPAD_9) \
+ _KEYSYM_(KP0,KEYPAD_0) \
+ _KEYSYM1_(UP) \
+ _KEYSYM1_(DOWN) \
+ _KEYSYM1_(RIGHT) \
+ _KEYSYM1_(LEFT) \
+ _KEYSYM1_(INSERT) \
+ _KEYSYM1_(HOME) \
+ _KEYSYM1_(END) \
+ _KEYSYM1_(PAGEUP) \
+ _KEYSYM1_(PAGEDOWN) \
+ _KEYSYM1_(F1) \
+ _KEYSYM1_(F2) \
+ _KEYSYM1_(F3) \
+ _KEYSYM1_(F4) \
+ _KEYSYM1_(F5) \
+ _KEYSYM1_(F6) \
+ _KEYSYM1_(F7) \
+ _KEYSYM1_(F8) \
+ _KEYSYM1_(F9) \
+ _KEYSYM1_(F10) \
+ _KEYSYM1_(F11) \
+ _KEYSYM1_(F12) \
+ _KEYSYM1_(F13) \
+ _KEYSYM1_(F14) \
+ _KEYSYM1_(F15) \
+ _KEYSYM1_(SCROLLOCK) \
+ _KEYSYM1_(SYSREQ) \
+ _KEYSYM1_(PRINT) \
+ _KEYSYM1_(BREAK) \
+
+#define _KEYSYM_(x,y) { SDLK_##x, #y },
+static const struct { int _sym; const char* _str; } keysym_names[] =
+{
+ _KEYSYM_LIST
+ { 0, NULL }
+};
+#undef _KEYSYM_
+
+int
+skin_keysym_str_count( void )
+{
+ return sizeof(keysym_names)/sizeof(keysym_names[0])-1;
+}
+
+const char*
+skin_keysym_str( int index )
+{
+ if (index >= 0 && index < skin_keysym_str_count())
+ return keysym_names[index]._str;
+
+ return NULL;
+}
+
+const char*
+skin_key_symmod_to_str( int sym, int mod )
+{
+ static char temp[32];
+ char* p = temp;
+ char* end = p + sizeof(temp);
+ int nn;
+
+ if ((mod & KMOD_LCTRL) != 0) {
+ p = bufprint(p, end, "Ctrl-");
+ }
+ if ((mod & KMOD_RCTRL) != 0) {
+ p = bufprint(p, end, "RCtrl-");
+ }
+ if ((mod & KMOD_LSHIFT) != 0) {
+ p = bufprint(p, end, "Shift-");
+ }
+ if ((mod & KMOD_RSHIFT) != 0) {
+ p = bufprint(p, end, "RShift-");
+ }
+ if ((mod & KMOD_LALT) != 0) {
+ p = bufprint(p, end, "Alt-");
+ }
+ if ((mod & KMOD_RALT) != 0) {
+ p = bufprint(p, end, "RAlt-");
+ }
+ for (nn = 0; keysym_names[nn]._sym != 0; nn++) {
+ if (keysym_names[nn]._sym == sym) {
+ p = bufprint(p, end, "%s", keysym_names[nn]._str);
+ return temp;;
+ }
+ }
+
+ if (sym >= 32 && sym <= 127) {
+ p = bufprint(p, end, "%c", sym);
+ return temp;
+ }
+
+ return NULL;
+}
+
+
+int
+skin_key_symmod_from_str( const char* str, int *psym, int *pmod )
+{
+ int mod = 0;
+ int match = 1;
+ int nn;
+ const char* s0 = str;
+ static const struct { const char* prefix; int mod; } mods[] =
+ {
+ { "^", KMOD_LCTRL },
+ { "Ctrl", KMOD_LCTRL },
+ { "ctrl", KMOD_LCTRL },
+ { "RCtrl", KMOD_RCTRL },
+ { "rctrl", KMOD_RCTRL },
+ { "Alt", KMOD_LALT },
+ { "alt", KMOD_LALT },
+ { "RAlt", KMOD_RALT },
+ { "ralt", KMOD_RALT },
+ { "Shift", KMOD_LSHIFT },
+ { "shift", KMOD_LSHIFT },
+ { "RShift", KMOD_RSHIFT },
+ { "rshift", KMOD_RSHIFT },
+ { NULL, 0 }
+ };
+
+ while (match) {
+ match = 0;
+ for (nn = 0; mods[nn].prefix != NULL; nn++) {
+ const char* prefix = mods[nn].prefix;
+ int len = strlen(prefix);
+
+ if ( !memcmp(str, prefix, len) ) {
+ str += len;
+ match = 1;
+ mod |= mods[nn].mod;
+ if (str[0] == '-' && str[1] != 0)
+ str++;
+ break;
+ }
+ }
+ }
+
+ for (nn = 0; keysym_names[nn]._sym; nn++) {
+#ifdef _WIN32
+ if ( !stricmp(str, keysym_names[nn]._str) )
+#else
+ if ( !strcasecmp(str, keysym_names[nn]._str) )
+#endif
+ {
+ *psym = keysym_names[nn]._sym;
+ *pmod = mod;
+ return 0;
+ }
+ }
+
+ D("%s: can't find sym value for '%s' (mod=%d, str=%s)", __FUNCTION__, s0, mod, str);
+ return -1;
+}
+
+
+typedef struct {
+ int sym;
+ int mod;
+ SkinKeyCommand command;
+} SkinKeyItem;
+
+
+struct SkinKeyset {
+ int num_items;
+ int max_items;
+ SkinKeyItem* items;
+};
+
+
+static int
+skin_keyset_add( SkinKeyset* kset, int sym, int mod, SkinKeyCommand command )
+{
+ SkinKeyItem* item = kset->items;
+ SkinKeyItem* end = item + kset->num_items;
+ SkinKeyItem* first = NULL;
+ int count = 0;
+
+ D( "adding binding %s to %s", skin_key_command_to_str(command), skin_key_symmod_to_str(sym,mod));
+ for ( ; item < end; item++) {
+ if (item->command == command) {
+ if (!first)
+ first = item;
+ if (++count == SKIN_KEY_COMMAND_MAX_BINDINGS) {
+ /* replace the first (oldest) one in the list */
+ first->sym = sym;
+ first->mod = mod;
+ return 0;
+ }
+ continue;
+ }
+ if (item->sym == sym && item->mod == mod) {
+ /* replace a (sym,mod) binding */
+ item->command = command;
+ return 0;
+ }
+ }
+ if (kset->num_items >= kset->max_items) {
+ int old_size = kset->max_items;
+ int new_size = old_size + (old_size >> 1) + 4;
+ SkinKeyItem* new_items = realloc( kset->items, new_size*sizeof(SkinKeyItem) );
+ if (new_items == NULL) {
+ return -1;
+ }
+ kset->items = new_items;
+ kset->max_items = new_size;
+ }
+ item = kset->items + kset->num_items++;
+ item->command = command;
+ item->sym = sym;
+ item->mod = mod;
+ return 1;
+}
+
+
+SkinKeyset*
+skin_keyset_new ( AConfig* root )
+{
+ SkinKeyset* kset = calloc(1, sizeof(*kset));
+ AConfig* node = root->first_child;;
+
+ if (kset == NULL)
+ return NULL;
+
+ for ( ; node != NULL; node = node->next )
+ {
+ SkinKeyCommand command;
+ int sym, mod;
+ char* p;
+
+ command = skin_key_command_from_str( node->name, -1 );
+ if (command == SKIN_KEY_COMMAND_NONE) {
+ D( "ignoring unknown keyset command '%s'", node->name );
+ continue;
+ }
+ p = (char*)node->value;
+ while (*p) {
+ char* q = strpbrk( p, " \t,:" );
+ if (q == NULL)
+ q = p + strlen(p);
+
+ if (q > p) {
+ int len = q - p;
+ char keys[24];
+ if (len+1 >= (int)sizeof(keys)) {
+ D("key binding too long: '%s'", p);
+ }
+ else {
+ memcpy( keys, p, len );
+ keys[len] = 0;
+ if ( skin_key_symmod_from_str( keys, &sym, &mod ) < 0 ) {
+ D( "ignoring unknown keys '%s' for command '%s'",
+ keys, node->name );
+ } else {
+ skin_keyset_add( kset, sym, mod, command );
+ }
+ }
+ } else if (*q)
+ q += 1;
+
+ p = q;
+ }
+ }
+ return kset;
+}
+
+
+SkinKeyset*
+skin_keyset_new_from_text( const char* text )
+{
+ AConfig* root = aconfig_node("","");
+ char* str = strdup(text);
+ SkinKeyset* result;
+
+ D("kset new from:\n%s", text);
+ aconfig_load( root, str );
+ result = skin_keyset_new( root );
+ free(str);
+ D("kset done result=%p", result);
+ return result;
+}
+
+
+void
+skin_keyset_free( SkinKeyset* kset )
+{
+ if (kset) {
+ free(kset->items);
+ kset->items = NULL;
+ kset->num_items = 0;
+ kset->max_items = 0;
+ free(kset);
+ }
+}
+
+
+extern int
+skin_keyset_get_bindings( SkinKeyset* kset,
+ SkinKeyCommand command,
+ SkinKeyBinding* bindings )
+{
+ if (kset) {
+ int count = 0;
+ SkinKeyItem* item = kset->items;
+ SkinKeyItem* end = item + kset->num_items;
+
+ for ( ; item < end; item++ ) {
+ if (item->command == command) {
+ bindings->sym = item->sym;
+ bindings->mod = item->mod;
+ bindings ++;
+ if ( ++count >= SKIN_KEY_COMMAND_MAX_BINDINGS ) {
+ /* shouldn't happen, but be safe */
+ break;
+ }
+ }
+ }
+ return count;
+ }
+ return -1;
+}
+
+
+/* retrieve the command corresponding to a given (sym,mod) pair. returns SKIN_KEY_COMMAND_NONE if not found */
+SkinKeyCommand
+skin_keyset_get_command( SkinKeyset* kset, int sym, int mod )
+{
+ if (kset) {
+ SkinKeyItem* item = kset->items;
+ SkinKeyItem* end = item + kset->num_items;
+
+ for ( ; item < end; item++ ) {
+ if (item->sym == sym && item->mod == mod) {
+ return item->command;
+ }
+ }
+ }
+ return SKIN_KEY_COMMAND_NONE;
+}
+
+
+const char*
+skin_keyset_get_default( void )
+{
+ return
+ "BUTTON_CALL F3\n"
+ "BUTTON_HANGUP F4\n"
+ "BUTTON_HOME Home\n"
+ "BUTTON_BACK Escape\n"
+ "BUTTON_MENU F2, PageUp\n"
+ "BUTTON_STAR Shift-F2, PageDown\n"
+ "BUTTON_POWER F7\n"
+ "BUTTON_SEARCH F5\n"
+ "BUTTON_CAMERA Ctrl-Keypad_5, Ctrl-F3\n"
+ "BUTTON_VOLUME_UP Keypad_Plus, Ctrl-F5\n"
+ "BUTTON_VOLUME_DOWN Keypad_Minus, Ctrl-F6\n"
+
+ "TOGGLE_NETWORK F8\n"
+ "TOGGLE_TRACING F9\n"
+ "TOGGLE_FULLSCREEN Alt-Enter\n"
+
+ "BUTTON_DPAD_CENTER Keypad_5\n"
+ "BUTTON_DPAD_UP Keypad_8\n"
+ "BUTTON_DPAD_LEFT Keypad_4\n"
+ "BUTTON_DPAD_RIGHT Keypad_6\n"
+ "BUTTON_DPAD_DOWN Keypad_2\n"
+
+ "TOGGLE_TRACKBALL Ctrl-T\n"
+
+ "CHANGE_LAYOUT_PREV Keypad_7, Ctrl-F11\n"
+ "CHANGE_LAYOUT_NEXT Keypad_9, Ctrl-F12\n"
+ "ONION_ALPHA_UP Keypad_Multiply\n"
+ "ONION_ALPHA_DOWN Keypad_Divide\n"
+ ;
+}
diff --git a/skins/skin_keyset.h b/skins/skin_keyset.h
new file mode 100644
index 0000000..7b8831f
--- /dev/null
+++ b/skins/skin_keyset.h
@@ -0,0 +1,121 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_SKIN_KEYSET_H_
+#define _ANDROID_SKIN_KEYSET_H_
+
+#include "android_config.h"
+
+/* A SkinKeySet maps keystrokes to specific commands. we have a few hard-coded
+ * keysets in the emulator binary, and the user can define its own if he wants
+ * to...
+ */
+typedef struct SkinKeyset SkinKeyset;
+
+#define SKIN_KEY_COMMAND_LIST \
+ _SKIN_KEY_COMMAND(NONE,"no key") \
+ _SKIN_KEY_COMMAND(BUTTON_HOME,"Home button") \
+ _SKIN_KEY_COMMAND(BUTTON_MENU,"Menu (Soft-Left) button") \
+ _SKIN_KEY_COMMAND(BUTTON_STAR,"Star (Soft-Right) button") \
+ _SKIN_KEY_COMMAND(BUTTON_BACK,"Back button") \
+ _SKIN_KEY_COMMAND(BUTTON_CALL,"Call/Dial button") \
+ _SKIN_KEY_COMMAND(BUTTON_HANGUP,"Hangup/EndCall button") \
+ _SKIN_KEY_COMMAND(BUTTON_POWER,"Power button") \
+ _SKIN_KEY_COMMAND(BUTTON_SEARCH,"Search button") \
+ _SKIN_KEY_COMMAND(BUTTON_VOLUME_UP,"Volume up button") \
+ _SKIN_KEY_COMMAND(BUTTON_VOLUME_DOWN,"Volume down button") \
+ _SKIN_KEY_COMMAND(BUTTON_CAMERA,"Camera button") \
+ _SKIN_KEY_COMMAND(CHANGE_LAYOUT_PREV,"switch to previous layout") \
+ _SKIN_KEY_COMMAND(CHANGE_LAYOUT_NEXT,"switch to next layout") \
+ _SKIN_KEY_COMMAND(TOGGLE_NETWORK,"toggle cell network on/off") \
+ _SKIN_KEY_COMMAND(TOGGLE_TRACING,"toggle code profiling") \
+ _SKIN_KEY_COMMAND(TOGGLE_FULLSCREEN,"toggle fullscreen mode") \
+ _SKIN_KEY_COMMAND(TOGGLE_TRACKBALL,"toggle trackball mode") \
+ _SKIN_KEY_COMMAND(BUTTON_DPAD_CENTER,"DPad center") \
+ _SKIN_KEY_COMMAND(BUTTON_DPAD_LEFT,"DPad left") \
+ _SKIN_KEY_COMMAND(BUTTON_DPAD_RIGHT,"DPad right") \
+ _SKIN_KEY_COMMAND(BUTTON_DPAD_UP,"DPad up") \
+ _SKIN_KEY_COMMAND(BUTTON_DPAD_DOWN,"DPad down") \
+ _SKIN_KEY_COMMAND(ONION_ALPHA_UP,"increase onion alpha") \
+ _SKIN_KEY_COMMAND(ONION_ALPHA_DOWN,"decrease onion alpha") \
+
+
+/* the list of commands in the emulator */
+#define _SKIN_KEY_COMMAND(x,y) SKIN_KEY_COMMAND_##x,
+typedef enum {
+ SKIN_KEY_COMMAND_LIST
+ SKIN_KEY_COMMAND_MAX // do not remove
+} SkinKeyCommand;
+#undef _SKIN_KEY_COMMAND
+
+/* retrieve the textual name of a given command, this is the command name without
+ * the "SKIN_KEY_COMMAND_" prefix. returns NULL if command is NONE or invalid
+ * the result is a static constant string that must not be freed
+ */
+extern const char* skin_key_command_to_str ( SkinKeyCommand command );
+
+/* convert a string into a SkinKeyCommand. returns SKIN_COMMAND_NONE if the string
+ * is unknown
+ */
+extern SkinKeyCommand skin_key_command_from_str( const char* str, int len );
+
+/* returns a short human-friendly description of the command */
+extern const char* skin_key_command_description( SkinKeyCommand cmd );
+
+/* returns the number of keysym string descriptors */
+extern int skin_keysym_str_count( void );
+
+/* return the n-th keysym string descriptor */
+extern const char* skin_keysym_str( int index );
+
+/* convert a (sym,mod) pair into a descriptive string. e.g. "Ctrl-K" or "Alt-A", etc..
+ * result is a static string that is overwritten on each call
+ */
+extern const char* skin_key_symmod_to_str ( int sym, int mod );
+
+/* convert a key binding description into a (sym,mod) pair. returns 0 on success, -1
+ * if the string cannot be parsed.
+ */
+extern int skin_key_symmod_from_str ( const char* str, int *psym, int *pmod );
+
+/* create a new keyset from a configuration tree node */
+extern SkinKeyset* skin_keyset_new ( AConfig* root );
+extern SkinKeyset* skin_keyset_new_from_text( const char* text );
+
+/* destroy a given keyset */
+extern void skin_keyset_free( SkinKeyset* kset );
+
+/* maximum number of key bindings per command. one command can be bound to several
+ * key bindings for convenience
+ */
+#define SKIN_KEY_COMMAND_MAX_BINDINGS 3
+
+/* a structure that describe a key binding */
+typedef struct {
+ int sym; // really a SDL key symbol
+ int mod; // really a SDL key modifier
+} SkinKeyBinding;
+
+/* return the number of keyboard bindings for a given command. results are placed in the 'bindings' array
+ * which must have at least SKIN_KEY_MAX_BINDINGS items */
+extern int skin_keyset_get_bindings( SkinKeyset* kset,
+ SkinKeyCommand command,
+ SkinKeyBinding* bindings );
+
+/* return the command for a given keypress - SKIN_KEY_COMMAND_NONE is returned if unknown */
+extern SkinKeyCommand skin_keyset_get_command( SkinKeyset* kset, int sym, int mod );
+
+extern const char* skin_keyset_get_default( void );
+
+/* in android_main.c */
+extern SkinKeyset* android_keyset;
+
+#endif /* _ANDROID_SKIN_KEYSET_H_ */
diff --git a/skins/skin_rect.c b/skins/skin_rect.c
new file mode 100644
index 0000000..d60dbd2
--- /dev/null
+++ b/skins/skin_rect.c
@@ -0,0 +1,241 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skin_rect.h"
+#include <limits.h>
+
+#define SKIN_POS_INITIALIZER { 0, 0 }
+
+void
+skin_pos_rotate( SkinPos* dst, SkinPos* src, SkinRotation rotation )
+{
+ int x = src->x;
+ int y = src->y;
+
+ switch ( rotation & 3 ) {
+ case SKIN_ROTATION_0:
+ dst->x = x;
+ dst->y = y;
+ break;
+
+ case SKIN_ROTATION_90:
+ dst->x = -y;
+ dst->y = x;
+ break;
+
+ case SKIN_ROTATION_180:
+ dst->x = -x;
+ dst->y = -y;
+ break;
+
+ default:
+ dst->x = y;
+ dst->y = -x;
+ }
+}
+
+
+#define SKIN_SIZE_INITIALIZER { 0, 0 }
+
+int
+skin_size_contains( SkinSize* size, int x, int y )
+{
+ return ( (unsigned) x < (unsigned) size->w &&
+ (unsigned) y < (unsigned) size->h );
+}
+
+void
+skin_size_rotate( SkinSize* dst, SkinSize* src, SkinRotation rot )
+{
+ int w = src->w;
+ int h = src->h;
+
+ if ((rot & 1) != 0) {
+ dst->w = h;
+ dst->h = w;
+ } else {
+ dst->w = w;
+ dst->h = h;
+ }
+}
+
+/** SKIN RECTANGLES
+ **/
+#define SKIN_RECT_INITIALIZER { SKIN_POS_INITIALIZER, SKIN_SIZE_INITIALIZER }
+
+void
+skin_rect_init( SkinRect* r, int x, int y, int w, int h )
+{
+ if (w < 0 || h < 0)
+ x = y = w = h = 0;
+
+ r->pos.x = x;
+ r->pos.y = y;
+ r->size.w = w;
+ r->size.h = h;
+}
+
+
+void
+skin_rect_translate( SkinRect* r, int dx, int dy )
+{
+ r->pos.x += dx;
+ r->pos.y += dy;
+}
+
+
+void
+skin_rect_rotate( SkinRect* dst, SkinRect* src, SkinRotation rot )
+{
+ int x, y, w, h;
+
+ switch (rot & 3) {
+ case SKIN_ROTATION_90:
+ x = src->pos.x;
+ y = src->pos.y;
+ w = src->size.w;
+ h = src->size.h;
+ dst->pos.x = -(y + h);
+ dst->pos.y = x;
+ dst->size.w = h;
+ dst->size.h = w;
+ break;
+
+ case SKIN_ROTATION_180:
+ dst->pos.x = -(src->pos.x + src->size.w);
+ dst->pos.y = -(src->pos.y + src->size.h);
+ dst->size = src->size;
+ break;
+
+ case SKIN_ROTATION_270:
+ x = src->pos.x;
+ y = src->pos.y;
+ w = src->size.w;
+ h = src->size.h;
+ dst->pos.x = y;
+ dst->pos.y = -(x + w);
+ dst->size.w = h;
+ dst->size.h = w;
+ break;
+
+ default:
+ dst[0] = src[0];
+ }
+}
+
+
+int
+skin_rect_contains( SkinRect* r, int x, int y )
+{
+ return ( (unsigned)(x - r->pos.x) < (unsigned)r->size.w &&
+ (unsigned)(y - r->pos.y) < (unsigned)r->size.h );
+}
+
+SkinOverlap
+skin_rect_contains_rect( SkinRect *r1, SkinRect *r2 )
+{
+ SkinBox a, b;
+
+ skin_box_from_rect( &a, r1 );
+ skin_box_from_rect( &b, r2 );
+
+ if (a.x2 <= b.x1 || b.x2 <= a.x1 || a.y2 <= b.y1 || b.y2 <= a.y1) {
+ return SKIN_OUTSIDE;
+ }
+
+ if (b.x1 >= a.x1 && b.x2 <= a.x2 && b.y1 >= a.y1 && b.y2 <= a.y2) {
+ return SKIN_INSIDE;
+ }
+
+ return SKIN_OVERLAP;
+}
+
+
+int
+skin_rect_intersect( SkinRect* result, SkinRect* r1, SkinRect* r2 )
+{
+ SkinBox a, b, r;
+
+ skin_box_from_rect( &a, r1 );
+ skin_box_from_rect( &b, r2 );
+
+ if (a.x2 <= b.x1 || b.x2 <= a.x1 || a.y2 <= b.y1 || b.y2 <= a.y1) {
+ result->pos.x = result->pos.y = result->size.w = result->size.h = 0;
+ return 0;
+ }
+
+ r.x1 = (a.x1 > b.x1) ? a.x1 : b.x1;
+ r.x2 = (a.x2 < b.x2) ? a.x2 : b.x2;
+ r.y1 = (a.y1 > b.y1) ? a.y1 : b.y1;
+ r.y2 = (a.y2 < b.y2) ? a.y2 : b.y2;
+
+ skin_box_to_rect( &r, result );
+ return 1;
+}
+
+int
+skin_rect_equals( SkinRect* r1, SkinRect* r2 )
+{
+ return (r1->pos.x == r2->pos.x && r1->pos.y == r2->pos.y &&
+ r1->size.w == r2->size.w && r2->size.h == r2->size.h);
+}
+
+/** SKIN BOXES
+ **/
+void
+skin_box_minmax_init( SkinBox* box )
+{
+ box->x1 = box->y1 = INT_MAX;
+ box->x2 = box->y2 = INT_MIN;
+}
+
+void
+skin_box_minmax_update( SkinBox* a, SkinRect* r )
+{
+ SkinBox b[1];
+
+ skin_box_from_rect(b, r);
+
+ if (b->x1 < a->x1) a->x1 = b->x1;
+ if (b->y1 < a->y1) a->y1 = b->y1;
+ if (b->x2 > a->x2) a->x2 = b->x2;
+ if (b->y2 > a->y2) a->y2 = b->y2;
+}
+
+int
+skin_box_minmax_to_rect( SkinBox* box, SkinRect* r )
+{
+ if (box->x1 > box->x2) {
+ r->pos.x = r->pos.y = r->size.w = r->size.h = 0;
+ return 0;
+ }
+ skin_box_to_rect( box, r );
+ return 1;
+}
+
+void
+skin_box_from_rect( SkinBox* box, SkinRect* r )
+{
+ box->x1 = r->pos.x;
+ box->y1 = r->pos.y;
+ box->x2 = r->size.w + box->x1;
+ box->y2 = r->size.h + box->y1;
+}
+
+void
+skin_box_to_rect( SkinBox* box, SkinRect* r )
+{
+ r->pos.x = box->x1;
+ r->pos.y = box->y1;
+ r->size.w = box->x2 - box->x1;
+ r->size.h = box->y2 - box->y1;
+}
+
diff --git a/skins/skin_rect.h b/skins/skin_rect.h
new file mode 100644
index 0000000..757f888
--- /dev/null
+++ b/skins/skin_rect.h
@@ -0,0 +1,71 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_SKIN_RECT_H
+#define _ANDROID_SKIN_RECT_H
+
+/** Rectangles
+ **/
+
+typedef enum {
+ SKIN_ROTATION_0,
+ SKIN_ROTATION_90,
+ SKIN_ROTATION_180,
+ SKIN_ROTATION_270
+} SkinRotation;
+
+typedef struct {
+ int x, y;
+} SkinPos;
+
+extern void skin_pos_rotate( SkinPos* dst, SkinPos* src, SkinRotation rot );
+
+typedef struct {
+ int w, h;
+} SkinSize;
+
+extern void skin_size_rotate( SkinSize* dst, SkinSize* src, SkinRotation rot );
+extern int skin_size_contains( SkinSize* size, int x, int y );
+
+
+typedef struct {
+ SkinPos pos;
+ SkinSize size;
+} SkinRect;
+
+extern void skin_rect_init ( SkinRect* r, int x, int y, int w, int h );
+extern void skin_rect_translate( SkinRect* r, int dx, int dy );
+extern void skin_rect_rotate ( SkinRect* dst, SkinRect* src, SkinRotation rotation );
+extern int skin_rect_contains ( SkinRect* r, int x, int y );
+extern int skin_rect_intersect( SkinRect* result, SkinRect* r1, SkinRect* r2 );
+extern int skin_rect_equals ( SkinRect* r1, SkinRect* r2 );
+
+typedef enum {
+ SKIN_OUTSIDE = 0,
+ SKIN_INSIDE = 1,
+ SKIN_OVERLAP = 2
+} SkinOverlap;
+
+extern SkinOverlap skin_rect_contains_rect( SkinRect *r1, SkinRect *r2 );
+
+typedef struct {
+ int x1, y1;
+ int x2, y2;
+} SkinBox;
+
+extern void skin_box_init( SkinBox* box, int x1, int y1, int x2, int y2 );
+extern void skin_box_minmax_init( SkinBox* box );
+extern void skin_box_minmax_update( SkinBox* box, SkinRect* rect );
+extern int skin_box_minmax_to_rect( SkinBox* box, SkinRect* rect );
+extern void skin_box_from_rect( SkinBox* box, SkinRect* rect );
+extern void skin_box_to_rect( SkinBox* box, SkinRect* rect );
+
+#endif /* _ANDROID_SKIN_RECT_H */
diff --git a/skins/skin_region.c b/skins/skin_region.c
new file mode 100644
index 0000000..f15bf37
--- /dev/null
+++ b/skins/skin_region.c
@@ -0,0 +1,1448 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skin_region.h"
+#include <limits.h>
+#include <string.h>
+#include <stdlib.h> /* malloc/free */
+
+/*************************************************************************
+ *************************************************************************
+ ****
+ **** ASSERTION SUPPORT
+ ****
+ ****
+ ****/
+
+#ifdef UNIT_TEST
+#include <stdlib.h>
+#include <stdio.h>
+static void
+_rpanic(void)
+{
+ *((char*)(void*)0) = 1; /* should SEGFAULT */
+ /* put a breakpoint here */
+ exit(1);
+}
+
+#define RASSERT(cond) \
+ ({ if (!(cond)) { fprintf(stderr, "%s:%d:%s: assertion failed: %s", \
+ __FILE__, __LINE__, __FUNCTION__, #cond ); _rpanic(); } })
+
+#else
+#define RASSERT(cond) ((void)0)
+#endif
+
+
+/*************************************************************************
+ *************************************************************************
+ ****
+ **** IMPLEMENTATION DETAILS
+ ****
+ ****
+ ****/
+
+/* this implementation of regions encodes the the region's spans with the
+ following format:
+
+ region ::= yband+ YSENTINEL
+ yband ::= YTOP YBOTTOM scanline
+ scanline ::= span+ XSENTINEL
+ span ::= XLEFT XRIGHT
+
+ XSENTINEL ::= 0x7fff
+ YSENTINEL := 0x7fff
+
+ all values are sorted in increasing order, which means that:
+
+ - YTOP1 < YBOTTOM1 <= YTOP2 < YBOTTOM2 <= .... < YSENTINEL
+ - XLEFT1 < XRIGHT1 < XLEFT2 < XRIGHT2 < .... < XSENTINEL
+ (in a given scanline)
+*/
+
+/* convenience shortbuts */
+typedef SkinRegionRun Run;
+typedef SkinRegion Region;
+
+#define RUNS_RECT_COUNT 6 /* YTOP YBOT XLEFT XRIGHT XSENTINEL YSENTINEL */
+
+#define XSENTINEL SKIN_REGION_SENTINEL
+#define YSENTINEL SKIN_REGION_SENTINEL
+
+#define RUNS_EMPTY ((Run*)(void*)(-1))
+#define RUNS_RECT ((Run*)(void*)(0))
+
+static __inline__ int
+region_isEmpty( Region* r )
+{
+ return r->runs == RUNS_EMPTY;
+}
+
+static __inline__ int
+region_isRect( Region* r )
+{
+ return r->runs == RUNS_RECT;
+}
+
+static __inline__ int
+region_isComplex( Region* r )
+{
+ return r->runs != RUNS_EMPTY && r->runs != RUNS_RECT;
+}
+
+/** RunStore: ref-counted storage for runs
+ **/
+
+typedef struct {
+ int refcount;
+ int count;
+} RunStore;
+
+static void
+runstore_free( RunStore* s )
+{
+ free(s);
+}
+
+static RunStore*
+runstore_alloc( int count )
+{
+ RunStore* s = malloc( sizeof(*s) + sizeof(Run)*count );
+ RASSERT(s != NULL);
+ s->count = count;
+ s->refcount = 1;
+ return s;
+}
+
+static RunStore*
+runstore_edit( RunStore* s )
+{
+ RunStore* s2;
+
+ if (s->refcount == 1)
+ return s;
+
+ s2 = runstore_alloc( s->count );
+ if (s2) {
+ memcpy( s2, s, sizeof(*s) + s->count*sizeof(Run) );
+ s->refcount -= 1;
+ s2->refcount = 1;
+ }
+ return s2;
+}
+
+static void
+runstore_unrefp( RunStore* *ps )
+{
+ RunStore* s = *ps;
+ if (s != NULL) {
+ if (s->refcount <= 0)
+ runstore_free(s);
+ *ps = NULL;
+ }
+}
+
+static RunStore*
+runstore_ref( RunStore* s )
+{
+ if (s) s->refcount += 1;
+ return s;
+}
+
+static __inline__ RunStore*
+runstore_from_runs( Run* runs )
+{
+ RASSERT(runs != RUNS_EMPTY);
+ RASSERT(runs != RUNS_RECT);
+ return (RunStore*)runs - 1;
+}
+
+static __inline__ Run*
+runstore_to_runs( RunStore* s )
+{
+ RASSERT(s != NULL);
+ return (Run*)(s + 1);
+}
+
+static Run*
+region_edit( Region* r )
+{
+ RunStore* s;
+
+ RASSERT(region_isComplex(r));
+
+ s = runstore_from_runs(r->runs);
+ s = runstore_edit(s);
+ r->runs = runstore_to_runs(s);
+ return r->runs;
+}
+
+/** Run parsing
+ **/
+
+static Run*
+runs_next_scanline( Run* runs )
+{
+ RASSERT(runs[0] != YSENTINEL && runs[1] != YSENTINEL );
+ runs += 2;
+ do { runs += 1; } while (runs[-1] != XSENTINEL);
+ return runs;
+}
+
+static Run*
+runs_find_y( Run* runs, int y )
+{
+ do {
+ int ybot, ytop = runs[0];
+
+ if (y < ytop)
+ return NULL;
+
+ ybot = runs[1];
+ if (y < ybot)
+ return runs;
+
+ runs = runs_next_scanline( runs );
+ } while (runs[0] != YSENTINEL);
+
+ return NULL;
+}
+
+static void
+runs_set_rect( Run* runs, SkinRect* rect )
+{
+ runs[0] = rect->pos.y;
+ runs[1] = rect->pos.y + rect->size.h;
+ runs[2] = rect->pos.x;
+ runs[3] = rect->pos.x + rect->size.w;
+ runs[4] = XSENTINEL;
+ runs[5] = YSENTINEL;
+}
+
+static Run*
+runs_copy_scanline( Run* dst, Run* src )
+{
+ RASSERT(src[0] != YSENTINEL);
+ RASSERT(src[1] != YSENTINEL);
+ dst[0] = src[0];
+ dst[1] = src[1];
+ src += 2;
+ dst += 2;
+ do { *dst++ = *src++; } while (src[-1] != XSENTINEL);
+ return dst;
+}
+
+static Run*
+runs_copy_scanline_adj( Run* dst, Run* src, int ytop, int ybot )
+{
+ Run* runs2 = runs_copy_scanline( dst, src );
+ dst[0] = (Run) ytop;
+ dst[1] = (Run) ybot;
+ return runs2;
+}
+
+static __inline__ Run*
+runs_add_span( Run* dst, int left, int right )
+{
+ dst[0] = (Run) left;
+ dst[1] = (Run) right;
+ return dst + 2;
+}
+
+static __inline__ int
+runs_get_count( Run* runs )
+{
+ RunStore* s = runstore_from_runs(runs);
+ return s->count;
+}
+
+
+static void
+runs_coalesce_band( Run* *psrc_spans, Run* *pdst_spans, SkinBox* minmax )
+{
+ Run* sspan = *psrc_spans;
+ Run* dspan = *pdst_spans;
+ int pleft = sspan[0];
+ int pright = sspan[1];
+ int xleft, xright;
+
+ RASSERT(pleft != XSENTINEL);
+ RASSERT(pright != XSENTINEL);
+ RASSERT(pleft < pright);
+
+ if (pleft < minmax->x1) minmax->x1 = pleft;
+
+ sspan += 2;
+ xleft = sspan[0];
+
+ while (xleft != XSENTINEL)
+ {
+ xright = sspan[1];
+ RASSERT(xright != XSENTINEL);
+ RASSERT(xleft < xright);
+
+ if (xleft == pright) {
+ pright = xright;
+ } else {
+ dspan[0] = (Run) pleft;
+ dspan[1] = (Run) pright;
+ dspan += 2;
+ }
+ sspan += 2;
+ xleft = sspan[0];
+ }
+ dspan[0] = (Run) pleft;
+ dspan[1] = (Run) pright;
+ dspan[2] = XSENTINEL;
+ dspan += 3;
+ sspan += 1; /* skip XSENTINEL */
+
+ if (pright > minmax->x2) minmax->x2 = pright;
+
+ *psrc_spans = sspan;
+ *pdst_spans = dspan;
+}
+
+
+static int
+runs_coalesce( Run* dst, Run* src, SkinBox* minmax )
+{
+ Run* prev = NULL;
+ Run* dst0 = dst;
+ int ytop = src[0];
+ int ybot;
+
+ while (ytop != YSENTINEL)
+ {
+ Run* sspan = src + 2;
+ Run* dspan = dst + 2;
+
+ ybot = src[1];
+ RASSERT( ytop < ybot );
+ RASSERT( ybot != YSENTINEL );
+ RASSERT( src[2] != XSENTINEL );
+
+ if (ytop < minmax->y1) minmax->y1 = ytop;
+ if (ybot > minmax->y2) minmax->y2 = ybot;
+
+ dst[0] = (Run) ytop;
+ dst[1] = (Run) ybot;
+
+ runs_coalesce_band( &sspan, &dspan, minmax );
+
+ if (prev && prev[1] == dst[0] && (dst-prev) == (dspan-dst) &&
+ !memcmp(prev+2, dst+2, (dspan-dst-2)*sizeof(Run)))
+ {
+ /* coalesce two identical bands */
+ prev[1] = dst[1];
+ }
+ else
+ {
+ prev = dst;
+ dst = dspan;
+ }
+ src = sspan;
+ ytop = src[0];
+ }
+ dst[0] = YSENTINEL;
+ return (dst + 1 - dst0);
+}
+
+/*************************************************************************
+ *************************************************************************
+ ****
+ **** PUBLIC API
+ ****
+ ****/
+
+void
+skin_region_init_empty( SkinRegion* r )
+{
+ /* empty region */
+ r->bounds.pos.x = r->bounds.pos.y = 0;
+ r->bounds.size.w = r->bounds.size.h = 0;
+ r->runs = RUNS_EMPTY;
+}
+
+void
+skin_region_init( SkinRegion* r, int x1, int y1, int x2, int y2 )
+{
+ if (x1 >= x2 || y1 >= y2) {
+ skin_region_init_empty(r);
+ return;
+ }
+ r->bounds.pos.x = x1;
+ r->bounds.pos.y = y1;
+ r->bounds.size.w = x2 - x1;
+ r->bounds.size.h = y2 - y1;
+ r->runs = RUNS_RECT;
+}
+
+void
+skin_region_init_rect( SkinRegion* r, SkinRect* rect )
+{
+ if (rect == NULL || rect->size.w <= 0 || rect->size.h <= 0) {
+ skin_region_init_empty(r);
+ return;
+ }
+ r->bounds = rect[0];
+ r->runs = RUNS_RECT;
+}
+
+void
+skin_region_init_box( SkinRegion* r, SkinBox* box )
+{
+ if (box == NULL || box->x1 >= box->x2 || box->y1 >= box->y2) {
+ skin_region_init_empty(r);
+ return;
+ }
+ r->bounds.pos.x = box->x1;
+ r->bounds.pos.y = box->y1;
+ r->bounds.size.w = box->x2 - box->x1;
+ r->bounds.size.h = box->y2 - box->y1;
+ r->runs = RUNS_RECT;
+}
+
+void
+skin_region_init_copy( SkinRegion* r, SkinRegion* src )
+{
+ if (src == NULL || region_isEmpty(src))
+ skin_region_init_empty(r);
+ else {
+ r[0] = src[0];
+ if (region_isComplex(src)) {
+ RunStore* s = runstore_from_runs(r->runs);
+ runstore_ref(s);
+ }
+ }
+}
+
+
+void
+skin_region_reset( SkinRegion* r )
+{
+ if (r != NULL) {
+ if (region_isComplex(r)) {
+ RunStore* s = runstore_from_runs(r->runs);
+ runstore_unrefp( &s );
+ }
+ skin_region_init_empty(r);
+ }
+}
+
+
+
+void
+skin_region_copy( SkinRegion* r, SkinRegion* src )
+{
+ skin_region_reset(r);
+ skin_region_init_copy(r, src);
+}
+
+
+int
+skin_region_equals( SkinRegion* r1, SkinRegion* r2 )
+{
+ Run *runs1, *runs2;
+ RunStore *store1, *store2;
+
+ if (r1 == r2)
+ return 1;
+
+ if (!skin_rect_equals( &r1->bounds, &r2->bounds ))
+ return 0;
+
+ runs1 = r1->runs;
+ runs2 = r2->runs;
+
+ if (runs1 == runs2) /* empties and rects */
+ return 1;
+
+ if ( !region_isComplex(r1) || !region_isComplex(r2) )
+ return 0;
+
+ store1 = runstore_from_runs(runs1);
+ store2 = runstore_from_runs(runs2);
+
+ if (store1->count == store2->count &&
+ !memcmp( (char*)runs1, (char*)runs2, store1->count*sizeof(Run) ) )
+ return 1;
+
+ return 0;
+}
+
+void
+skin_region_translate( SkinRegion* r, int dx, int dy )
+{
+ Run* runs;
+
+ if (region_isEmpty(r))
+ return;
+
+ skin_rect_translate( &r->bounds, dx, dy );
+ if (region_isRect(r))
+ return;
+
+ runs = region_edit(r);
+ while (runs[0] != YSENTINEL) {
+ int ytop = runs[0];
+ int ybot = runs[1];
+
+ RASSERT(ybot != YSENTINEL);
+ runs[0] = (Run)(ytop + dy);
+ runs[1] = (Run)(ybot + dy);
+ runs += 2;
+ while (runs[0] != XSENTINEL) {
+ int xleft = runs[0];
+ int xright = runs[1];
+ RASSERT(xright != YSENTINEL);
+ runs[0] = (Run)(xleft + dx);
+ runs[1] = (Run)(xright + dx);
+ runs += 2;
+ }
+ runs += 1;
+ }
+}
+
+void
+skin_region_get_bounds( SkinRegion* r, SkinRect* bounds )
+{
+ if (r != NULL) {
+ bounds[0] = r->bounds;
+ } else {
+ bounds->pos.x = bounds->pos.y = 0;
+ bounds->size.w = bounds->size.h = 0;
+ }
+}
+
+int
+skin_region_is_empty( SkinRegion* r )
+{
+ return region_isEmpty(r);
+}
+
+int
+skin_region_is_rect( SkinRegion* r )
+{
+ return region_isRect(r);
+}
+
+int
+skin_region_is_complex( SkinRegion* r )
+{
+ return region_isComplex(r);
+}
+
+void
+skin_region_swap( SkinRegion* r, SkinRegion* r2 )
+{
+ SkinRegion tmp;
+ tmp = r[0];
+ r[0] = r2[0];
+ r2[0] = tmp;
+}
+
+
+SkinOverlap
+skin_region_contains( SkinRegion* r, int x, int y )
+{
+ if (region_isEmpty(r))
+ return SKIN_OUTSIDE;
+ if (region_isRect(r)) {
+ return skin_rect_contains(&r->bounds,x,y);
+ } else {
+ Run* runs = runs_find_y( r->runs, y );
+ if (runs != NULL) {
+ runs += 2;
+ do {
+ int xright, xleft = runs[0];
+
+ if (x < xleft) // also x < xleft == XSENTINEL
+ break;
+ xright = runs[1];
+ if (xright == XSENTINEL)
+ break;
+ if (x < xright)
+ return SKIN_INSIDE;
+ runs += 2;
+ } while (runs[0] != XSENTINEL);
+ }
+ return SKIN_OUTSIDE;
+ }
+}
+
+
+SkinOverlap
+skin_region_contains_rect( SkinRegion* r, SkinRect* rect )
+{
+ SkinRegion r2[1];
+ skin_region_init_rect( r2, rect );
+ return skin_region_test_intersect( r, r2 );
+}
+
+
+SkinOverlap
+skin_region_contains_box( SkinRegion* r, SkinBox* b )
+{
+ SkinRegion r2[1];
+
+ skin_region_init_box( r2, b );
+ return skin_region_test_intersect( r, r2 );
+}
+
+
+
+#define FLAG_REGION_1 (1 << 0)
+#define FLAG_REGION_2 (1 << 1)
+#define FLAG_REGION_BOTH (1 << 2)
+
+SkinOverlap
+skin_region_test_intersect( SkinRegion* r1,
+ SkinRegion* r2 )
+{
+ Run *runs1, *runs2;
+ Run run2_tmp[ RUNS_RECT_COUNT ];
+ SkinRect r;
+
+ if (region_isEmpty(r1) || region_isEmpty(r2))
+ return SKIN_OUTSIDE;
+
+ if ( !skin_rect_intersect( &r, &r1->bounds, &r2->bounds) )
+ return SKIN_OUTSIDE;
+
+ if (region_isRect(r1)) {
+ if (region_isRect(r2)) {
+ return skin_rect_contains_rect(&r1->bounds, &r2->bounds);
+ } else {
+ SkinRegion* tmp = r1;
+ r1 = r2;
+ r2 = tmp;
+ }
+ }
+ /* here r1 is guaranteed to be complex, r2 is either rect of complex */
+ runs1 = r1->runs;
+ if (region_isRect(r2)) {
+ runs2 = run2_tmp;
+ runs_set_rect(runs2, &r2->bounds);
+ }
+ else {
+ runs2 = r2->runs;
+ }
+
+ {
+ int flags = 0;
+
+ while (runs1[0] != YSENTINEL && runs2[0] != YSENTINEL)
+ {
+ int ytop1 = runs1[0];
+ int ybot1 = runs1[1];
+ int ytop2 = runs2[0];
+ int ybot2 = runs2[1];
+
+ if (ybot1 <= ytop2)
+ {
+ /* band1 over band2 */
+ flags |= FLAG_REGION_1;
+ runs1 = runs_next_scanline( runs1 );
+ }
+ else if (ybot2 <= ytop1)
+ {
+ /* band2 over band1 */
+ flags |= FLAG_REGION_2;
+ runs2 = runs_next_scanline( runs2 );
+ }
+ else /* band1 and band2 overlap */
+ {
+ Run* span1;
+ Run* span2;
+ int ybot;
+
+ if (ytop1 < ytop2) {
+ flags |= FLAG_REGION_1;
+ ytop1 = ytop2;
+ } else if (ytop2 < ytop1) {
+ flags |= FLAG_REGION_2;
+ ytop2 = ytop1;
+ }
+
+ ybot = (ybot1 < ybot2) ? ybot1 : ybot2;
+
+ span1 = runs1 + 2;
+ span2 = runs2 + 2;
+
+ while (span1[0] != XSENTINEL && span2[0] != XSENTINEL)
+ {
+ int xleft1 = span1[0];
+ int xright1 = span1[1];
+ int xleft2 = span2[0];
+ int xright2 = span2[1];
+
+ RASSERT(xright1 != XSENTINEL);
+ RASSERT(xright2 != XSENTINEL);
+
+ if (xright1 <= xleft2) {
+ flags |= FLAG_REGION_1;
+ span1 += 2;
+ }
+ else if (xright2 <= xleft1) {
+ flags |= FLAG_REGION_2;
+ span2 += 2;
+ }
+ else {
+ int xright;
+
+ if (xleft1 < xleft2) {
+ flags |= FLAG_REGION_1;
+ xleft1 = xleft2;
+ } else if (xleft2 < xleft1) {
+ flags |= FLAG_REGION_2;
+ xleft2 = xleft1;
+ }
+
+ xright = (xright1 < xright2) ? xright1 : xright2;
+
+ flags |= FLAG_REGION_BOTH;
+
+ if (xright == xright1)
+ span1 += 2;
+ if (xright == xright2)
+ span2 += 2;
+ }
+ }
+
+ if (span1[0] != XSENTINEL) {
+ flags |= FLAG_REGION_1;
+ }
+
+ if (span2[0] != XSENTINEL) {
+ flags |= FLAG_REGION_2;
+ }
+
+ if (ybot == ybot1)
+ runs1 = runs_next_scanline( runs1 );
+
+ if (ybot == ybot2)
+ runs2 = runs_next_scanline( runs2 );
+ }
+ }
+
+ if (runs1[0] != YSENTINEL) {
+ flags |= FLAG_REGION_1;
+ }
+
+ if (runs2[0] != YSENTINEL) {
+ flags |= FLAG_REGION_2;
+ }
+
+ if ( !(flags & FLAG_REGION_BOTH) ) {
+ /* no intersection at all */
+ return SKIN_OUTSIDE;
+ }
+
+ if ( (flags & FLAG_REGION_2) != 0 ) {
+ /* intersection + overlap */
+ return SKIN_OVERLAP;
+ }
+
+ return SKIN_INSIDE;
+ }
+}
+
+typedef struct {
+ Run* runs1;
+ Run* runs2;
+ Run* runs_base;
+ Run* runs;
+ RunStore* store;
+ Region result[1];
+ Run runs1_rect[ RUNS_RECT_COUNT ];
+ Run runs2_rect[ RUNS_RECT_COUNT ];
+} RegionOperator;
+
+
+static void
+region_operator_init( RegionOperator* o,
+ Region* r1,
+ Region* r2 )
+{
+ int run1_count, run2_count;
+ int maxruns;
+
+ RASSERT( !region_isEmpty(r1) );
+ RASSERT( !region_isEmpty(r2) );
+
+ if (region_isRect(r1)) {
+ run1_count = RUNS_RECT_COUNT;
+ o->runs1 = o->runs1_rect;
+ runs_set_rect( o->runs1, &r1->bounds );
+ } else {
+ o->runs1 = r1->runs;
+ run1_count = runs_get_count(r1->runs);
+ }
+
+ if (region_isRect(r2)) {
+ run2_count = RUNS_RECT_COUNT;
+ o->runs2 = o->runs2_rect;
+ runs_set_rect( o->runs2, &r2->bounds );
+ } else {
+ o->runs2 = r2->runs;
+ run2_count = runs_get_count(r2->runs);
+ }
+
+ maxruns = run1_count < run2_count ? run2_count : run1_count;
+ o->store = runstore_alloc( 3*maxruns );
+ o->runs_base = runstore_to_runs(o->store);
+}
+
+
+static void
+region_operator_do( RegionOperator* o, int wanted )
+{
+ Run* runs1 = o->runs1;
+ Run* runs2 = o->runs2;
+ Run* runs = o->runs_base;
+ int ytop1 = runs1[0];
+ int ytop2 = runs2[0];
+
+ if (ytop1 != YSENTINEL && ytop2 != YSENTINEL)
+ {
+ int ybot1, ybot2;
+
+ while (ytop1 != YSENTINEL && ytop2 != YSENTINEL)
+ {
+ int ybot;
+
+ ybot1 = runs1[1];
+ ybot2 = runs2[1];
+
+ RASSERT(ybot1 != YSENTINEL);
+ RASSERT(ybot2 != YSENTINEL);
+
+ if (ybot1 <= ytop2) {
+ if (wanted & FLAG_REGION_1)
+ runs = runs_copy_scanline_adj( runs, runs1, ytop1, ybot1 );
+ runs1 = runs_next_scanline( runs1 );
+ ytop1 = runs1[0];
+ continue;
+ }
+
+ if (ybot2 <= ytop1) {
+ if (wanted & FLAG_REGION_2)
+ runs = runs_copy_scanline_adj( runs, runs2, ytop2, ybot2 );
+ runs2 = runs_next_scanline(runs2);
+ ytop2 = runs2[0];
+ continue;
+ }
+
+ if (ytop1 < ytop2) {
+ if (wanted & FLAG_REGION_1)
+ runs = runs_copy_scanline_adj( runs, runs1, ytop1, ytop2 );
+ ytop1 = ytop2;
+ }
+ else if (ytop2 < ytop1) {
+ if (wanted & FLAG_REGION_2)
+ runs = runs_copy_scanline_adj( runs, runs2, ytop2, ytop1 );
+ ytop2 = ytop1;
+ }
+
+ ybot = (ybot1 <= ybot2) ? ybot1 : ybot2;
+
+ runs[0] = (Run) ytop1;
+ runs[1] = (Run) ybot;
+
+ /* do the common band */
+ {
+ Run* span1 = runs1 + 2;
+ Run* span2 = runs2 + 2;
+ Run* span = runs + 2;
+ int xleft1 = span1[0];
+ int xleft2 = span2[0];
+ int xright1, xright2;
+
+ while (xleft1 != XSENTINEL && xleft2 != XSENTINEL)
+ {
+ int xright;
+
+ xright1 = span1[1];
+ xright2 = span2[1];
+
+ RASSERT(xright1 != XSENTINEL);
+ RASSERT(xright2 != XSENTINEL);
+
+ if (xright1 <= xleft2) {
+ if (wanted & FLAG_REGION_1)
+ span = runs_add_span( span, xleft1, xright1 );
+ span1 += 2;
+ xleft1 = span1[0];
+ continue;
+ }
+
+ if (xright2 <= xleft1) {
+ if (wanted & FLAG_REGION_2)
+ span = runs_add_span( span, xleft2, xright2 );
+ span2 += 2;
+ xleft2 = span2[0];
+ continue;
+ }
+
+ if (xleft1 < xleft2) {
+ if (wanted & FLAG_REGION_1)
+ span = runs_add_span( span, xleft1, xleft2 );
+ xleft1 = xleft2;
+ }
+
+ else if (xleft2 < xleft1) {
+ if (wanted & FLAG_REGION_2)
+ span = runs_add_span( span, xleft2, xleft1 );
+ xleft2 = xleft1;
+ }
+
+ xright = (xright1 <= xright2) ? xright1 : xright2;
+
+ if (wanted & FLAG_REGION_BOTH)
+ span = runs_add_span( span, xleft1, xright );
+
+ xleft1 = xleft2 = xright;
+
+ if (xright == xright1) {
+ span1 += 2;
+ xleft1 = span1[0];
+ }
+ if (xright == xright2) {
+ span2 += 2;
+ xleft2 = span2[0];
+ }
+ }
+
+ if (wanted & FLAG_REGION_1) {
+ while (xleft1 != XSENTINEL) {
+ RASSERT(span1[1] != XSENTINEL);
+ span[0] = (Run) xleft1;
+ span[1] = span1[1];
+ span += 2;
+ span1 += 2;
+ xleft1 = span1[0];
+ }
+ }
+
+ if (wanted & FLAG_REGION_2) {
+ while (xleft2 != XSENTINEL) {
+ RASSERT(span2[1] != XSENTINEL);
+ span[0] = (Run) xleft2;
+ span[1] = span2[1];
+ span += 2;
+ span2 += 2;
+ xleft2 = span2[0];
+ }
+ }
+
+ if (span > runs + 2) {
+ span[0] = XSENTINEL;
+ runs = span + 1;
+ }
+ }
+
+ ytop1 = ytop2 = ybot;
+
+ if (ybot == ybot1) {
+ runs1 = runs_next_scanline( runs1 );
+ ytop1 = runs1[0];
+ }
+ if (ybot == ybot2) {
+ runs2 = runs_next_scanline( runs2 );
+ ytop2 = runs2[0];
+ }
+ }
+ }
+
+ if ((wanted & FLAG_REGION_1) != 0) {
+ while (ytop1 != YSENTINEL) {
+ runs = runs_copy_scanline_adj( runs, runs1, ytop1, runs1[1] );
+ runs1 = runs_next_scanline(runs1);
+ ytop1 = runs1[0];
+ }
+ }
+
+ if ((wanted & FLAG_REGION_2) != 0) {
+ while (ytop2 != YSENTINEL) {
+ runs = runs_copy_scanline_adj( runs, runs2, ytop2, runs2[1] );
+ runs2 = runs_next_scanline(runs2);
+ ytop2 = runs2[0];
+ }
+ }
+
+ runs[0] = YSENTINEL;
+ o->runs = runs + 1;
+}
+
+/* returns 1 if the result is not empty */
+static int
+region_operator_done( RegionOperator* o )
+{
+ Run* src = o->runs;
+ int count;
+ SkinBox minmax;
+ RunStore* store;
+
+ if (src <= o->runs_base + 1) {
+ /* result is empty */
+ skin_region_init_empty( o->result );
+ return 0;
+ }
+
+ /* coalesce the temp runs in-place and compute the corresponding bounds */
+ minmax.x1 = minmax.y1 = INT_MAX;
+ minmax.x2 = minmax.y2 = INT_MIN;
+
+ count = runs_coalesce( o->runs_base, o->runs_base, &minmax );
+ if (count == 1) {
+ /* result is empty */
+ skin_region_init_empty( o->result );
+ }
+ else
+ {
+ skin_box_to_rect( &minmax, &o->result->bounds );
+ if (count == RUNS_RECT_COUNT) {
+ o->result->runs = RUNS_RECT;
+ }
+ else
+ {
+ /* result is complex */
+ store = runstore_alloc( count );
+ o->result->runs = runstore_to_runs(store);
+ memcpy( o->result->runs, o->runs_base, count*sizeof(Run) );
+ }
+ }
+
+ /* release temporary runstore */
+ runstore_unrefp( &o->store );
+
+ return region_isEmpty(o->result);
+}
+
+
+
+int
+skin_region_intersect( SkinRegion* r, SkinRegion* r2 )
+{
+ RegionOperator oper[1];
+
+ if (region_isEmpty(r))
+ return 0;
+
+ if (region_isEmpty(r2))
+ return 1;
+
+ if ( skin_rect_contains_rect( &r->bounds, &r2->bounds ) == SKIN_OUTSIDE ) {
+ skin_region_init_empty(r);
+ return 0;
+ }
+
+ region_operator_init( oper, r, r2 );
+ region_operator_do( oper, FLAG_REGION_BOTH );
+ region_operator_done( oper );
+
+ skin_region_swap( r, oper->result );
+ skin_region_reset( oper->result );
+
+ return region_isEmpty( r );
+}
+
+
+/* performs r = (intersect r (region+_from_rect rect)), returns true iff
+ the resulting region is not empty */
+int
+skin_region_intersect_rect( SkinRegion* r, SkinRect* rect )
+{
+ Region r2[1];
+
+ skin_region_init_rect( r2, rect );
+ return skin_region_intersect( r, r2 );
+}
+
+/* performs r = (union r r2) */
+void
+skin_region_union( SkinRegion* r, SkinRegion* r2 )
+{
+ RegionOperator oper[1];
+
+ if (region_isEmpty(r)) {
+ skin_region_copy(r, r2);
+ return;
+ }
+
+ if (region_isEmpty(r2))
+ return;
+
+ region_operator_init( oper, r, r2 );
+ region_operator_do( oper, FLAG_REGION_1|FLAG_REGION_2|FLAG_REGION_BOTH );
+ region_operator_done( oper );
+
+ skin_region_swap( r, oper->result );
+ skin_region_reset( oper->result );
+}
+
+void
+skin_region_union_rect( SkinRegion* r, SkinRect* rect )
+{
+ Region r2[1];
+
+ skin_region_init_rect(r2, rect);
+ return skin_region_union( r, r2 );
+}
+
+/* performs r = (difference r r2) */
+void
+skin_region_substract( SkinRegion* r, SkinRegion* r2 )
+{
+ RegionOperator oper[1];
+
+ if (region_isEmpty(r) || region_isEmpty(r2))
+ return;
+
+ if ( skin_rect_contains_rect( &r->bounds, &r2->bounds ) == SKIN_OUTSIDE ) {
+ skin_region_init_empty(r);
+ return;
+ }
+
+ region_operator_init( oper, r, r2 );
+ region_operator_do( oper, FLAG_REGION_1 );
+ region_operator_done( oper );
+
+ skin_region_swap( r, oper->result );
+ skin_region_reset( oper->result );
+}
+
+void
+skin_region_substract_rect( SkinRegion* r, SkinRect* rect )
+{
+ Region r2[1];
+
+ skin_region_init_rect(r2, rect);
+ return skin_region_substract( r, r2 );
+}
+
+/* performs r = (xor r r2) */
+void
+skin_region_xor( SkinRegion* r, SkinRegion* r2 )
+{
+ RegionOperator oper[1];
+
+ if (region_isEmpty(r)) {
+ skin_region_copy(r, r2);
+ return;
+ }
+
+ if (region_isEmpty(r2))
+ return;
+
+ if ( skin_rect_contains_rect( &r->bounds, &r2->bounds ) == SKIN_OUTSIDE ) {
+ skin_region_init_empty(r);
+ return;
+ }
+
+ region_operator_init( oper, r, r2 );
+ region_operator_do( oper, FLAG_REGION_1 );
+ region_operator_done( oper );
+
+ skin_region_swap( r, oper->result );
+ skin_region_reset( oper->result );
+}
+
+
+void
+skin_region_iterator_init( SkinRegionIterator* iter,
+ SkinRegion* region )
+{
+ iter->region = region;
+ iter->band = NULL;
+ iter->span = NULL;
+}
+
+int
+skin_region_iterator_next( SkinRegionIterator* iter, SkinRect *rect )
+{
+ static const Run dummy[ 2 ] = { XSENTINEL, YSENTINEL };
+
+ Run* span = iter->span;
+ Run* band = iter->band;
+
+ if (span == NULL) {
+ Region* r = iter->region;
+ if (region_isEmpty(r))
+ return 0;
+ if (region_isRect(r)) {
+ rect[0] = r->bounds;
+ iter->span = (Run*) dummy;
+ return 1;
+ }
+ iter->band = band = r->runs;
+ iter->span = span = r->runs + 2;
+ }
+ else if (band == NULL)
+ return 0;
+
+ while (span[0] == XSENTINEL) {
+ band = span + 1;
+ if (band[0] == YSENTINEL || band[1] == YSENTINEL)
+ return 0;
+
+ iter->band = band;
+ iter->span = span = band + 2;
+ }
+
+ if (span[1] == XSENTINEL)
+ return 0;
+
+ rect->pos.y = band[0];
+ rect->pos.x = span[0];
+ rect->size.h = band[1] - band[0];
+ rect->size.w = span[1] - span[0];
+
+ iter->span = span + 2;
+ return 1;
+}
+
+int
+skin_region_iterator_next_box( SkinRegionIterator* iter, SkinBox *box )
+{
+ SkinRect rect;
+ int result = skin_region_iterator_next( iter, &rect );
+
+ if (result)
+ skin_box_from_rect( box, &rect );
+
+ return result;
+}
+
+#ifdef UNIT_TEST
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "skin_rect.c"
+
+static void
+panic(void)
+{
+ *((char*)0) = 1;
+ exit(0);
+}
+
+static void
+_expectCompare( Region* r, const SkinBox* boxes, int count )
+{
+ if (count == 0) {
+ if ( !skin_region_is_empty(r) ) {
+ printf( " result is not empty\n" );
+ panic();
+ }
+ }
+ else if (count == 1) {
+ SkinRect rect1, rect2;
+ if ( !skin_region_is_rect(r) ) {
+ printf( " result is not a rectangle\n" );
+ panic();
+ }
+ skin_region_get_bounds( r, &rect1 );
+ skin_box_to_rect( (SkinBox*)boxes, &rect2 );
+ if ( !skin_rect_equals( &rect1, &rect2 ) ) {
+ printf( " result is (%d,%d,%d,%d), expected (%d,%d,%d,%d)\n",
+ rect1.pos.x, rect1.pos.y,
+ rect1.pos.x + rect1.size.w, rect1.pos.y + rect1.size.h,
+ rect2.pos.x, rect2.pos.y,
+ rect2.pos.x + rect2.size.w, rect2.pos.y + rect2.size.h );
+ panic();
+ }
+ }
+ else {
+ SkinRegionIterator iter;
+ SkinBox b;
+ int n;
+
+ skin_region_iterator_init( &iter, r );
+ n = 0;
+ while (n < count) {
+ if ( !skin_region_iterator_next_box( &iter, &b ) ) {
+ printf( "missing region box (%d, %d, %d, %d)\n",
+ boxes->x1, boxes->y1, boxes->x2, boxes->y2 );
+ panic();
+ }
+
+ if (b.x1 != boxes->x1 || b.x2 != boxes->x2||
+ b.y1 != boxes->y1 || b.y2 != boxes->y2)
+ {
+ printf( "invalid region box (%d,%d,%d,%d) expecting (%d,%d,%d,%d)\n",
+ b.x1, b.y1, b.x2, b.y2,
+ boxes->x1, boxes->y1, boxes->x2, boxes->y2 );
+ panic();
+ }
+ boxes += 1;
+ n += 1;
+ }
+
+ if ( skin_region_iterator_next_box( &iter, &b ) ) {
+ printf( "excess region box (%d,%d,%d,%d)\n",
+ b.x1, b.y1, b.x2, b.y2 );
+ panic();
+ }
+ }
+}
+
+
+static void
+expectEmptyRegion( Region* r )
+{
+ printf( "expectEmptyRegion: " );
+ if (!skin_region_is_empty(r)) {
+ printf( "region not empty !!\n" );
+ panic();
+ }
+ printf( "ok\n" );
+}
+
+static void
+expectTestIntersect( Region* r1, Region* r2, SkinOverlap overlap )
+{
+ SkinOverlap result;
+ printf( "expectTestIntersect(%d): ", overlap );
+ result = skin_region_test_intersect(r1, r2);
+ if (result != overlap) {
+ printf( "bad result %d, expected %d\n", result, overlap );
+ panic();
+ }
+ printf( "ok\n" );
+}
+
+static void
+expectRectRegion( Region* r, int x1, int y1, int x2, int y2 )
+{
+ SkinRect rect;
+ SkinBox b;
+
+ printf( "expectRectRegion(%d,%d,%d,%d): ",x1,y1,x2,y2 );
+ if (!skin_region_is_rect(r)) {
+ printf( "region not rect !!\n" );
+ panic();
+ }
+
+ skin_region_get_bounds( r, &rect );
+ skin_box_from_rect( &b, &rect );
+
+ if (b.x1 != x1 || b.x2 != x2 || b.y1 != y1 || b.y2 != y2) {
+ printf( "rect region bounds are (%d,%d,%d,%d), expecting (%d,%d,%d,%d)\n",
+ b.x1, b.y1, b.x2, b.y2, x1, y1, x2, y2 );
+ panic();
+ }
+ printf( "ok\n" );
+}
+
+static void
+expectComplexRegion( Region* r, const SkinBox* boxes, int count )
+{
+ SkinRegionIterator iter;
+ SkinBox b;
+ int n;
+
+ printf( "expectComplexRegion(): " );
+ if (!skin_region_is_complex(r)) {
+ printf( "region is not complex !!\n" );
+ panic();
+ }
+ _expectCompare( r, boxes, count );
+ printf( "ok\n" );
+}
+
+static void
+expectIntersect( Region* r1, Region* r2, const SkinBox* boxes, int count )
+{
+ SkinRegion r[1];
+
+ printf( "expectIntersect(%d): ", count );
+ skin_region_init_copy( r, r1 );
+ skin_region_intersect( r, r2 );
+ _expectCompare( r, boxes, count );
+ printf( "ok\n" );
+}
+
+static void
+expectUnion( Region* r1, Region* r2, const SkinBox* boxes, int count )
+{
+ SkinRegion r[1];
+
+ printf( "expectUnion(%d): ", count );
+ skin_region_init_copy( r, r1 );
+ skin_region_union( r, r2 );
+ _expectCompare( r, boxes, count );
+ printf( "ok\n" );
+}
+
+
+static void
+expectSubstract( Region* r1, Region* r2, const SkinBox* boxes, int count )
+{
+ SkinRegion r[1];
+
+ printf( "expectSubstract(%d): ", count );
+ skin_region_init_copy( r, r1 );
+ skin_region_substract( r, r2 );
+ _expectCompare( r, boxes, count );
+ printf( "ok\n" );
+}
+
+
+int main( void )
+{
+ SkinRegion r[1], r2[1];
+
+ skin_region_init_empty( r );
+ expectEmptyRegion( r );
+
+ skin_region_init( r, 10, 20, 110, 120 );
+ expectRectRegion( r, 10, 20, 110, 120 );
+
+ skin_region_translate( r, 50, 80 );
+ expectRectRegion( r, 60, 100, 160, 200 );
+
+ skin_region_init( r, 10, 10, 40, 40 );
+ skin_region_init( r2, 20, 20, 50, 50 );
+ expectTestIntersect( r, r2, SKIN_OVERLAP );
+
+ skin_region_translate(r2, +20, + 20 );
+ expectTestIntersect( r, r2, SKIN_OUTSIDE );
+
+ skin_region_translate(r2, -30, -30 );
+ expectTestIntersect( r, r2, SKIN_INSIDE );
+
+ {
+ static const SkinBox result1[1] = {
+ { 20, 20, 40, 40 }
+ };
+ static const SkinBox result2[3] = {
+ { 10, 10, 40, 20 },
+ { 10, 20, 50, 40 },
+ { 20, 40, 50, 50 },
+ };
+ static const SkinBox result3[2] = {
+ { 10, 10, 40, 20 },
+ { 10, 20, 20, 40 },
+ };
+
+ skin_region_init( r, 10, 10, 40, 40 );
+ skin_region_init( r2, 20, 20, 50, 50 );
+ expectIntersect( r, r2, result1, 1 );
+ expectUnion( r, r2, result2, 3 );
+ expectSubstract( r, r2, result3, 2 );
+ }
+
+ return 0;
+}
+
+#endif /* UNIT_TEST */
diff --git a/skins/skin_region.h b/skins/skin_region.h
new file mode 100644
index 0000000..e7236e8
--- /dev/null
+++ b/skins/skin_region.h
@@ -0,0 +1,103 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_SKIN_REGION_H
+#define _ANDROID_SKIN_REGION_H
+
+#include "skin_rect.h"
+
+typedef struct SkinRegion SkinRegion;
+
+extern void skin_region_init_empty( SkinRegion* r );
+extern void skin_region_init( SkinRegion* r, int x1, int y1, int x2, int y2 );
+extern void skin_region_init_rect( SkinRegion* r, SkinRect* rect );
+extern void skin_region_init_box( SkinRegion* r, SkinBox* box );
+extern void skin_region_init_copy( SkinRegion* r, SkinRegion* r2 );
+extern void skin_region_reset( SkinRegion* r );
+
+/* finalize region, then copy src into it */
+extern void skin_region_copy( SkinRegion* r, SkinRegion* src );
+
+/* compare two regions for equality */
+extern int skin_region_equals( SkinRegion* r1, SkinRegion* r2 );
+
+/* swap two regions */
+extern void skin_region_swap( SkinRegion* r, SkinRegion* r2 );
+
+extern int skin_region_is_empty( SkinRegion* r );
+extern int skin_region_is_rect( SkinRegion* r );
+extern int skin_region_is_complex( SkinRegion* r );
+extern void skin_region_get_bounds( SkinRegion* r, SkinRect* bounds );
+
+extern void skin_region_translate( SkinRegion* r, int dx, int dy );
+
+extern SkinOverlap skin_region_contains( SkinRegion* r, int x, int y );
+
+extern SkinOverlap skin_region_contains_rect( SkinRegion* r,
+ SkinRect* rect );
+
+extern SkinOverlap skin_region_contains_box( SkinRegion* r, SkinBox* b );
+
+/* returns overlap mode for "is r2 inside r1" */
+extern SkinOverlap skin_region_test_intersect( SkinRegion* r1,
+ SkinRegion* r2 );
+
+/* performs r = (intersect r r2), returns true if the resulting region
+ is not empty */
+extern int skin_region_intersect ( SkinRegion* r, SkinRegion* r2 );
+extern int skin_region_intersect_rect( SkinRegion* r, SkinRect* rect );
+
+/* performs r = (intersect r (region+_from_rect rect)), returns true iff
+ the resulting region is not empty */
+
+/* performs r = (union r r2) */
+extern void skin_region_union ( SkinRegion* r, SkinRegion* r2 );
+extern void skin_region_union_rect( SkinRegion* r, SkinRect* rect );
+
+/* performs r = (difference r r2) */
+extern void skin_region_substract ( SkinRegion* r, SkinRegion* r2 );
+extern void skin_region_substract_rect( SkinRegion* r, SkinRect* rect );
+
+/* performs r = (xor r r2) */
+extern void skin_region_xor( SkinRegion* r, SkinRegion* r2 );
+
+typedef struct SkinRegionIterator SkinRegionIterator;
+
+/* iterator */
+extern void skin_region_iterator_init( SkinRegionIterator* iter,
+ SkinRegion* r );
+
+extern int skin_region_iterator_next( SkinRegionIterator* iter,
+ SkinRect *rect );
+
+extern int skin_rection_iterator_next_box( SkinRegionIterator* iter,
+ SkinBox *box );
+
+/* the following should be considered private definitions. they're only here
+ to allow clients to allocate SkinRegion objects themselves... */
+
+typedef signed short SkinRegionRun;
+#define SKIN_REGION_SENTINEL 0x7fff
+
+struct SkinRegion
+{
+ SkinRect bounds;
+ SkinRegionRun* runs;
+};
+
+struct SkinRegionIterator
+{
+ SkinRegion* region;
+ SkinRegionRun* band;
+ SkinRegionRun* span;
+};
+
+#endif /* _ANDROID_SKIN_REGION_H */
diff --git a/skins/skin_scaler.c b/skins/skin_scaler.c
new file mode 100644
index 0000000..60dcf8c
--- /dev/null
+++ b/skins/skin_scaler.c
@@ -0,0 +1,129 @@
+/* Copyright (C) 2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skin_scaler.h"
+#include <math.h>
+
+struct SkinScaler {
+ double scale;
+ double invscale;
+ int valid;
+};
+
+static SkinScaler _scaler0;
+
+SkinScaler*
+skin_scaler_create( void )
+{
+ _scaler0.scale = 1.0;
+ _scaler0.invscale = 1.0;
+ return &_scaler0;
+}
+
+/* change the scale of a given scaler. returns 0 on success, or -1 in case of
+ * problem (unsupported scale) */
+int
+skin_scaler_set( SkinScaler* scaler, double scale )
+{
+ /* right now, we only support scales in the 0.5 .. 1.0 range */
+ if (scale < 0.1)
+ scale = 0.1;
+ else if (scale > 3.0)
+ scale = 3.0;
+
+ scaler->scale = scale;
+ scaler->invscale = 1/scale;
+ scaler->valid = 1;
+
+ return 0;
+}
+
+void
+skin_scaler_free( SkinScaler* scaler )
+{
+ scaler=scaler;
+}
+
+typedef struct {
+ SDL_Rect rd; /* destination rectangle */
+ int sx, sy; /* source start position in 16.16 format */
+ int ix, iy; /* source increments in 16.16 format */
+ int src_pitch;
+ int src_w;
+ int src_h;
+ int dst_pitch;
+ uint8_t* dst_line;
+ uint8_t* src_line;
+ double scale;
+} ScaleOp;
+
+
+#define ARGB_SCALE_GENERIC scale_generic
+#define ARGB_SCALE_05_TO_10 scale_05_to_10
+#define ARGB_SCALE_UP_BILINEAR scale_up_bilinear
+#define ARGB_SCALE_UP_QUICK_4x4 scale_up_quick_4x4
+
+#include "skin_argb.h"
+
+
+void
+skin_scaler_scale( SkinScaler* scaler,
+ SDL_Surface* dst_surface,
+ SDL_Surface* src_surface,
+ int sx,
+ int sy,
+ int sw,
+ int sh )
+{
+ ScaleOp op;
+
+ if ( !scaler->valid )
+ return;
+
+ SDL_LockSurface( src_surface );
+ SDL_LockSurface( dst_surface );
+ {
+ op.scale = scaler->scale;
+ op.src_pitch = src_surface->pitch;
+ op.src_line = src_surface->pixels;
+ op.src_w = src_surface->w;
+ op.src_h = src_surface->h;
+ op.dst_pitch = dst_surface->pitch;
+ op.dst_line = dst_surface->pixels;
+
+ /* compute the destination rectangle */
+ op.rd.x = (int)(sx * scaler->scale);
+ op.rd.y = (int)(sy * scaler->scale);
+ op.rd.w = (int)(ceil((sx + sw) * scaler->scale)) - op.rd.x;
+ op.rd.h = (int)(ceil((sy + sh) * scaler->scale)) - op.rd.y;
+
+ /* compute the starting source position in 16.16 format
+ * and the corresponding increments */
+ op.sx = (int)(op.rd.x * scaler->invscale * 65536);
+ op.sy = (int)(op.rd.y * scaler->invscale * 65536);
+
+ op.ix = (int)( scaler->invscale * 65536 );
+ op.iy = op.ix;
+
+ op.dst_line += op.rd.x*4 + op.rd.y*op.dst_pitch;
+
+ if (op.scale >= 0.5 && op.scale <= 1.0)
+ scale_05_to_10( &op );
+ else if (op.scale > 1.0)
+ scale_up_quick_4x4( &op );
+ else
+ scale_generic( &op );
+ }
+ SDL_UnlockSurface( dst_surface );
+ SDL_UnlockSurface( src_surface );
+
+ SDL_UpdateRects( dst_surface, 1, &op.rd );
+}
diff --git a/skins/skin_scaler.h b/skins/skin_scaler.h
new file mode 100644
index 0000000..4f22c2b
--- /dev/null
+++ b/skins/skin_scaler.h
@@ -0,0 +1,36 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_SKIN_SCALER_H
+#define _ANDROID_SKIN_SCALER_H
+
+#include "skin_image.h"
+
+typedef struct SkinScaler SkinScaler;
+
+/* create a new image scaler. by default, it uses a scale of 1.0 */
+extern SkinScaler* skin_scaler_create( void );
+
+/* change the scale of a given scaler. returns 0 on success, or -1 in case of
+ * problem (unsupported scale) */
+extern int skin_scaler_set( SkinScaler* scaler, double scale );
+
+extern void skin_scaler_free( SkinScaler* scaler );
+
+extern void skin_scaler_scale( SkinScaler* scaler,
+ SDL_Surface* dst,
+ SDL_Surface* src,
+ int sx,
+ int sy,
+ int sw,
+ int sh );
+
+#endif /* _ANDROID_SKIN_SCALER_H */
diff --git a/skins/skin_surface.c b/skins/skin_surface.c
new file mode 100644
index 0000000..a148db9
--- /dev/null
+++ b/skins/skin_surface.c
@@ -0,0 +1,613 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skin_surface.h"
+#include "skin_argb.h"
+#include <SDL.h>
+
+#define DEBUG 1
+
+#if DEBUG
+#include "android_debug.h"
+#define D(...) VERBOSE_PRINT(surface,__VA_ARGS__)
+#else
+#define D(...) ((void)0)
+#endif
+
+struct SkinSurface {
+ int refcount;
+ uint32_t* pixels;
+ SDL_Surface* surface;
+ SkinSurfaceDoneFunc done_func;
+ void* done_user;
+};
+
+static void
+skin_surface_free( SkinSurface* s )
+{
+ if (s->done_func) {
+ s->done_func( s->done_user );
+ s->done_func = NULL;
+ }
+ if (s->surface) {
+ SDL_FreeSurface(s->surface);
+ s->surface = NULL;
+ }
+ free(s);
+}
+
+extern SkinSurface*
+skin_surface_ref( SkinSurface* surface )
+{
+ if (surface)
+ surface->refcount += 1;
+ return surface;
+}
+
+extern void
+skin_surface_unrefp( SkinSurface* *psurface )
+{
+ SkinSurface* surf = *psurface;
+ if (surf) {
+ if (--surf->refcount <= 0)
+ skin_surface_free(surf);
+ *psurface = NULL;
+ }
+}
+
+
+void
+skin_surface_set_done( SkinSurface* s, SkinSurfaceDoneFunc done_func, void* done_user )
+{
+ s->done_func = done_func;
+ s->done_user = done_user;
+}
+
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+# define ARGB32_R_MASK 0xff000000
+# define ARGB32_G_MASK 0x00ff0000
+# define ARGB32_B_MASK 0x0000ff00
+# define ARGB32_A_MASK 0x000000ff
+#else
+# define ARGB32_R_MASK 0x000000ff
+# define ARGB32_G_MASK 0x0000ff00
+# define ARGB32_B_MASK 0x00ff0000
+# define ARGB32_A_MASK 0xff000000
+#endif
+
+static SDL_Surface*
+_sdl_surface_create_rgb( int width,
+ int height,
+ int depth,
+ int flags )
+{
+ Uint32 rmask, gmask, bmask, amask;
+
+ if (depth == 8) {
+ rmask = gmask = bmask = 0;
+ amask = 0xff;
+ } else if (depth == 32) {
+ rmask = ARGB32_R_MASK;
+ gmask = ARGB32_G_MASK;
+ bmask = ARGB32_B_MASK;
+ amask = ARGB32_A_MASK;
+ } else
+ return NULL;
+
+ return SDL_CreateRGBSurface( flags, width, height, depth,
+ rmask, gmask, bmask, amask );
+}
+
+
+static SDL_Surface*
+_sdl_surface_create_rgb_from( int width,
+ int height,
+ int pitch,
+ void* pixels,
+ int depth )
+{
+ Uint32 rmask, gmask, bmask, amask;
+
+ if (depth == 8) {
+ rmask = gmask = bmask = 0;
+ amask = 0xff;
+ } else if (depth == 32) {
+ rmask = ARGB32_R_MASK;
+ gmask = ARGB32_G_MASK;
+ bmask = ARGB32_B_MASK;
+ amask = ARGB32_A_MASK;
+ } else
+ return NULL;
+
+ return SDL_CreateRGBSurfaceFrom( pixels, width, height, pitch, depth,
+ rmask, gmask, bmask, amask );
+}
+
+
+static SkinSurface*
+_skin_surface_create( SDL_Surface* surface,
+ void* pixels )
+{
+ SkinSurface* s = malloc(sizeof(*s));
+ if (s != NULL) {
+ s->refcount = 1;
+ s->pixels = pixels;
+ s->surface = surface;
+ s->done_func = NULL;
+ s->done_user = NULL;
+ }
+ else {
+ SDL_FreeSurface(surface);
+ free(pixels);
+ D( "not enough memory to allocate new skin surface !" );
+ }
+ return s;
+}
+
+
+SkinSurface*
+skin_surface_create_fast( int w, int h )
+{
+ SDL_Surface* surface;
+
+ surface = _sdl_surface_create_rgb( w, h, 32, SDL_HWSURFACE );
+ if (surface == NULL) {
+ surface = _sdl_surface_create_rgb( w, h, 32, SDL_SWSURFACE );
+ if (surface == NULL) {
+ D( "could not create fast %dx%d ARGB32 surface: %s",
+ w, h, SDL_GetError() );
+ return NULL;
+ }
+ }
+ return _skin_surface_create( surface, NULL );
+}
+
+
+SkinSurface*
+skin_surface_create_slow( int w, int h )
+{
+ SDL_Surface* surface;
+
+ surface = _sdl_surface_create_rgb( w, h, 32, SDL_SWSURFACE );
+ if (surface == NULL) {
+ D( "could not create slow %dx%d ARGB32 surface: %s",
+ w, h, SDL_GetError() );
+ return NULL;
+ }
+ return _skin_surface_create( surface, NULL );
+}
+
+
+SkinSurface*
+skin_surface_create_argb32_from(
+ int w,
+ int h,
+ int pitch,
+ uint32_t* pixels,
+ int do_copy )
+{
+ SDL_Surface* surface;
+ uint32_t* pixcopy = NULL;
+
+ if (do_copy) {
+ size_t size = h*pitch;
+ pixcopy = malloc( size );
+ if (pixcopy == NULL && size > 0) {
+ D( "not enough memory to create %dx%d ARGB32 surface",
+ w, h );
+ return NULL;
+ }
+ memcpy( pixcopy, pixels, size );
+ }
+
+ surface = _sdl_surface_create_rgb_from( w, h, pitch,
+ pixcopy ? pixcopy : pixels,
+ 32 );
+ if (surface == NULL) {
+ D( "could not create %dx%d slow ARGB32 surface: %s",
+ w, h, SDL_GetError() );
+ return NULL;
+ }
+ return _skin_surface_create( surface, pixcopy );
+}
+
+
+
+
+extern int
+skin_surface_lock( SkinSurface* s, SkinSurfacePixels *pix )
+{
+ if (!s || !s->surface) {
+ D( "error: trying to lock stale surface %p", s );
+ return -1;
+ }
+ if ( SDL_LockSurface( s->surface ) != 0 ) {
+ D( "could not lock surface %p: %s", s, SDL_GetError() );
+ return -1;
+ }
+ pix->w = s->surface->w;
+ pix->h = s->surface->h;
+ pix->pitch = s->surface->pitch;
+ pix->pixels = s->surface->pixels;
+ return 0;
+}
+
+/* unlock a slow surface that was previously locked */
+extern void
+skin_surface_unlock( SkinSurface* s )
+{
+ if (s && s->surface)
+ SDL_UnlockSurface( s->surface );
+}
+
+
+#if 0
+static uint32_t
+skin_surface_map_argb( SkinSurface* s, uint32_t c )
+{
+ if (s && s->surface) {
+ return SDL_MapRGBA( s->surface->format,
+ ((c) >> 16) & 255,
+ ((c) >> 8) & 255,
+ ((c) & 255),
+ ((c) >> 24) & 255 );
+ }
+ return 0x00000000;
+}
+#endif
+
+typedef struct {
+ int x;
+ int y;
+ int w;
+ int h;
+ int sx;
+ int sy;
+
+ uint8_t* dst_line;
+ int dst_pitch;
+ SDL_Surface* dst_lock;
+
+ uint8_t* src_line;
+ int src_pitch;
+ SDL_Surface* src_lock;
+ uint32_t src_color;
+
+} SkinBlit;
+
+
+static int
+skin_blit_init_fill( SkinBlit* blit,
+ SkinSurface* dst,
+ SkinRect* dst_rect,
+ uint32_t color )
+{
+ int x = dst_rect->pos.x;
+ int y = dst_rect->pos.y;
+ int w = dst_rect->size.w;
+ int h = dst_rect->size.h;
+ int delta;
+
+ if (x < 0) {
+ w += x;
+ x = 0;
+ }
+ delta = (x + w) - dst->surface->w;
+ if (delta > 0)
+ w -= delta;
+
+ if (y < 0) {
+ h += y;
+ y = 0;
+ }
+ delta = (y + h) - dst->surface->h;
+ if (delta > 0)
+ h -= delta;
+
+ if (w <= 0 || h <= 0)
+ return 0;
+
+ blit->x = x;
+ blit->y = y;
+ blit->w = w;
+ blit->h = h;
+
+ if ( !SDL_LockSurface(dst->surface) )
+ return 0;
+
+ blit->dst_lock = dst->surface;
+ blit->dst_pitch = dst->surface->pitch;
+ blit->dst_line = dst->surface->pixels + y*blit->dst_pitch;
+
+ blit->src_lock = NULL;
+ blit->src_color = color;
+
+ return 1;
+}
+
+static int
+skin_blit_init_blit( SkinBlit* blit,
+ SkinSurface* dst,
+ SkinPos* dst_pos,
+ SkinSurface* src,
+ SkinRect* src_rect )
+{
+ int x = dst_pos->x;
+ int y = dst_pos->y;
+ int sx = src_rect->pos.x;
+ int sy = src_rect->pos.y;
+ int w = src_rect->size.w;
+ int h = src_rect->size.h;
+ int delta;
+
+ if (x < 0) {
+ w += x;
+ sx -= x;
+ x = 0;
+ }
+ if (sx < 0) {
+ w += sx;
+ x -= sx;
+ sx = 0;
+ }
+
+ delta = (x + w) - dst->surface->w;
+ if (delta > 0)
+ w -= delta;
+
+ delta = (sx + w) - src->surface->w;
+ if (delta > 0)
+ w -= delta;
+
+ if (y < 0) {
+ h += y;
+ sy += y;
+ y = 0;
+ }
+ if (sy < 0) {
+ h += sy;
+ y -= sy;
+ sy = 0;
+ }
+ delta = (y + h) - dst->surface->h;
+ if (delta > 0)
+ h -= delta;
+
+ delta = (sy + h) - src->surface->h;
+
+ if (w <= 0 || h <= 0)
+ return 0;
+
+ blit->x = x;
+ blit->y = y;
+ blit->w = w;
+ blit->h = h;
+
+ blit->sx = sx;
+ blit->sy = sy;
+
+ if ( !SDL_LockSurface(dst->surface) )
+ return 0;
+
+ blit->dst_lock = dst->surface;
+ blit->dst_pitch = dst->surface->pitch;
+ blit->dst_line = (uint8_t*) dst->surface->pixels + y*blit->dst_pitch;
+
+ if ( !SDL_LockSurface(src->surface) ) {
+ SDL_UnlockSurface(dst->surface);
+ return 0;
+ }
+
+ blit->src_lock = src->surface;
+ blit->src_pitch = src->surface->pitch;
+ blit->src_line = (uint8_t*) src->surface->pixels + sy*blit->src_pitch;
+
+ return 1;
+}
+
+static void
+skin_blit_done( SkinBlit* blit )
+{
+ if (blit->src_lock)
+ SDL_UnlockSurface( blit->src_lock );
+ if (blit->dst_lock)
+ SDL_UnlockSurface( blit->dst_lock );
+ ARGB_DONE;
+}
+
+typedef void (*SkinLineFillFunc)( uint32_t* dst, uint32_t color, int len );
+typedef void (*SkinLineBlitFunc)( uint32_t* dst, const uint32_t* src, int len );
+
+static void
+skin_line_fill_copy( uint32_t* dst, uint32_t color, int len )
+{
+ uint32_t* end = dst + len;
+
+ while (dst + 4 <= end) {
+ dst[0] = dst[1] = dst[2] = dst[3] = color;
+ dst += 4;
+ }
+ while (dst < end) {
+ dst[0] = color;
+ dst += 1;
+ }
+}
+
+static void
+skin_line_fill_srcover( uint32_t* dst, uint32_t color, int len )
+{
+ uint32_t* end = dst + len;
+ uint32_t alpha = (color >> 24);
+
+ if (alpha == 255)
+ {
+ skin_line_fill_copy(dst, color, len);
+ }
+ else
+ {
+ ARGB_DECL(src_c);
+ ARGB_DECL_ZERO();
+
+ alpha = 255 - alpha;
+ alpha += (alpha >> 7);
+
+ ARGB_UNPACK(src_c,color);
+
+ for ( ; dst < end; dst++ )
+ {
+ ARGB_DECL(dst_c);
+
+ ARGB_READ(dst_c,dst);
+ ARGB_MULSHIFT(dst_c,dst_c,alpha,8);
+ ARGB_ADD(dst_c,src_c);
+ ARGB_WRITE(dst_c,dst);
+ }
+ }
+}
+
+static void
+skin_line_fill_dstover( uint32_t* dst, uint32_t color, int len )
+{
+ uint32_t* end = dst + len;
+ ARGB_DECL(src_c);
+ ARGB_DECL_ZERO();
+
+ ARGB_UNPACK(src_c,color);
+
+ for ( ; dst < end; dst++ )
+ {
+ ARGB_DECL(dst_c);
+ ARGB_DECL(val);
+
+ uint32_t alpha;
+
+ ARGB_READ(dst_c,dst);
+ alpha = 256 - (dst[0] >> 24);
+ ARGB_MULSHIFT(val,src_c,alpha,8);
+ ARGB_ADD(val,dst_c);
+ ARGB_WRITE(val,dst);
+ }
+}
+
+extern void
+skin_surface_fill( SkinSurface* dst,
+ SkinRect* rect,
+ uint32_t argb_premul,
+ SkinBlitOp blitop )
+{
+ SkinLineFillFunc fill;
+ SkinBlit blit[1];
+
+ switch (blitop) {
+ case SKIN_BLIT_COPY: fill = skin_line_fill_copy; break;
+ case SKIN_BLIT_SRCOVER: fill = skin_line_fill_srcover; break;
+ case SKIN_BLIT_DSTOVER: fill = skin_line_fill_dstover; break;
+ default: return;
+ }
+
+ if ( skin_blit_init_fill( blit, dst, rect, argb_premul ) ) {
+ uint8_t* line = blit->dst_line;
+ int pitch = blit->dst_pitch;
+ uint8_t* end = line + pitch*blit->h;
+
+ for ( ; line != end; line += pitch )
+ fill( (uint32_t*)line + blit->x, argb_premul, blit->w );
+ }
+}
+
+
+static void
+skin_line_blit_copy( uint32_t* dst, const uint32_t* src, int len )
+{
+ memcpy( (char*)dst, (const char*)src, len*4 );
+}
+
+
+
+static void
+skin_line_blit_srcover( uint32_t* dst, const uint32_t* src, int len )
+{
+ uint32_t* end = dst + len;
+ ARGB_DECL_ZERO();
+
+ for ( ; dst < end; dst++ ) {
+ ARGB_DECL(s);
+ ARGB_DECL(d);
+ ARGB_DECL(v);
+ uint32_t alpha;
+
+ ARGB_READ(s,src);
+ alpha = (src[0] >> 24);
+ if (alpha > 0) {
+ ARGB_READ(d,dst);
+ alpha = 256 - alpha;
+ ARGB_MULSHIFT(v,d,alpha,8);
+ ARGB_ADD(v,d);
+ ARGB_WRITE(v,dst);
+ }
+ }
+}
+
+static void
+skin_line_blit_dstover( uint32_t* dst, const uint32_t* src, int len )
+{
+ uint32_t* end = dst + len;
+ ARGB_DECL_ZERO();
+
+ for ( ; dst < end; dst++ ) {
+ ARGB_DECL(s);
+ ARGB_DECL(d);
+ ARGB_DECL(v);
+ uint32_t alpha;
+
+ ARGB_READ(d,dst);
+ alpha = (dst[0] >> 24);
+ if (alpha < 255) {
+ ARGB_READ(s,src);
+ alpha = 256 - alpha;
+ ARGB_MULSHIFT(v,s,alpha,8);
+ ARGB_ADD(v,s);
+ ARGB_WRITE(v,dst);
+ }
+ }
+}
+
+
+extern void
+skin_surface_blit( SkinSurface* dst,
+ SkinPos* dst_pos,
+ SkinSurface* src,
+ SkinRect* src_rect,
+ SkinBlitOp blitop )
+{
+ SkinLineBlitFunc func;
+ SkinBlit blit[1];
+
+ switch (blitop) {
+ case SKIN_BLIT_COPY: func = skin_line_blit_copy; break;
+ case SKIN_BLIT_SRCOVER: func = skin_line_blit_srcover; break;
+ case SKIN_BLIT_DSTOVER: func = skin_line_blit_dstover; break;
+ default: return;
+ }
+
+ if ( skin_blit_init_blit( blit, dst, dst_pos, src, src_rect ) ) {
+ uint8_t* line = blit->dst_line;
+ uint8_t* sline = blit->src_line;
+ int pitch = blit->dst_pitch;
+ int spitch = blit->src_pitch;
+ uint8_t* end = line + pitch*blit->h;
+
+ for ( ; line != end; line += pitch, sline += spitch )
+ func( (uint32_t*)line + blit->x, (uint32_t*)sline + blit->sx, blit->w );
+
+ skin_blit_done(blit);
+ }
+}
diff --git a/skins/skin_surface.h b/skins/skin_surface.h
new file mode 100644
index 0000000..2603a8f
--- /dev/null
+++ b/skins/skin_surface.h
@@ -0,0 +1,101 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_SKIN_SURFACE_H
+#define _ANDROID_SKIN_SURFACE_H
+
+#include "skin_region.h"
+#include <stdint.h>
+
+/* a SkinSurface models a 32-bit ARGB pixel image that can be blitted to or from
+ */
+typedef struct SkinSurface SkinSurface;
+
+/* increment surface's reference count */
+extern SkinSurface* skin_surface_ref( SkinSurface* surface );
+
+/* decrement a surface's reference count. takes the surface's address as parameter.
+ it will be set to NULL on exit */
+extern void skin_surface_unrefp( SkinSurface* *psurface );
+
+/* sets a callback that will be called when the surface is destroyed.
+ * used NULL for done_func to disable it
+ */
+typedef void (*SkinSurfaceDoneFunc)( void* user );
+
+extern void skin_surface_set_done( SkinSurface* s, SkinSurfaceDoneFunc done_func, void* done_user );
+
+
+/* there are two kinds of surfaces:
+
+ - fast surfaces, whose content can be placed in video memory or
+ RLE-compressed for faster blitting and blending. the pixel format
+ used internally might be something very different from ARGB32.
+
+ - slow surfaces, whose content (pixel buffer) can be accessed and modified
+ with _lock()/_unlock() but may be blitted far slower since they reside in
+ system memory.
+*/
+
+/* create a 'fast' surface that contains a copy of an input ARGB32 pixmap */
+extern SkinSurface* skin_surface_create_fast( int w, int h );
+
+/* create an empty 'slow' surface containing an ARGB32 pixmap */
+extern SkinSurface* skin_surface_create_slow( int w, int h );
+
+/* create a 'slow' surface from a given pixel buffer. if 'do_copy' is TRUE, then
+ * the content of 'pixels' is copied into a heap-allocated buffer. otherwise
+ * the data will be used directly.
+ */
+extern SkinSurface* skin_surface_create_argb32_from(
+ int w,
+ int h,
+ int pitch,
+ uint32_t* pixels,
+ int do_copy );
+
+/* surface pixels information for slow surfaces */
+typedef struct {
+ int w;
+ int h;
+ int pitch;
+ uint32_t* pixels;
+} SkinSurfacePixels;
+
+/* lock a slow surface, and returns its pixel information.
+ returns 0 in case of success, -1 otherwise */
+extern int skin_surface_lock ( SkinSurface* s, SkinSurfacePixels *pix );
+
+/* unlock a slow surface that was previously locked */
+extern void skin_surface_unlock( SkinSurface* s );
+
+/* list of composition operators for the blit routine */
+typedef enum {
+ SKIN_BLIT_COPY = 0,
+ SKIN_BLIT_SRCOVER,
+ SKIN_BLIT_DSTOVER,
+} SkinBlitOp;
+
+
+/* blit a surface into another one */
+extern void skin_surface_blit( SkinSurface* dst,
+ SkinPos* dst_pos,
+ SkinSurface* src,
+ SkinRect* src_rect,
+ SkinBlitOp blitop );
+
+/* blit a colored rectangle into a destination surface */
+extern void skin_surface_fill( SkinSurface* dst,
+ SkinRect* rect,
+ uint32_t argb_premul,
+ SkinBlitOp blitop );
+
+#endif /* _ANDROID_SKIN_SURFACE_H */
diff --git a/skins/skin_trackball.c b/skins/skin_trackball.c
new file mode 100644
index 0000000..4db8c95
--- /dev/null
+++ b/skins/skin_trackball.c
@@ -0,0 +1,579 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skin_trackball.h"
+#include "skin_image.h"
+#include "osdep.h"
+#include "vl.h"
+#include <math.h>
+
+/***********************************************************************/
+/***********************************************************************/
+/***** *****/
+/***** T R A C K B A L L *****/
+/***** *****/
+/***********************************************************************/
+/***********************************************************************/
+
+// a 3-d vector
+typedef double VectorRec[3];
+typedef double* Vector;
+
+/* define FIX16_IS_FLOAT to use floats for computations */
+#define FIX16_IS_FLOAT
+
+#ifdef FIX16_IS_FLOAT
+typedef float Fix16;
+#define FIX16_ONE 1.0
+#define FIX16_FROM_FLOAT(x) (x)
+#define FIX16_TO_FLOAT(x) (x)
+
+#else
+typedef int Fix16;
+
+#define FIX16_SHIFT 16
+#define FIX16_ONE (1 << FIX16_SHIFT)
+#define FIX16_FROM_FLOAT(x) (Fix16)((x) * FIX16_ONE)
+#define FIX16_TO_FLOAT(x) ((x)/(1.0*FIX16_ONE))
+
+#endif
+
+typedef Fix16 Fix16VectorRec[3];
+typedef Fix16* Fix16Vector;
+
+static Fix16
+fixedvector_len( Fix16Vector v )
+{
+ double x = FIX16_TO_FLOAT(v[0]);
+ double y = FIX16_TO_FLOAT(v[1]);
+ double z = FIX16_TO_FLOAT(v[2]);
+ double len = sqrt( x*x + y*y + z*z );
+
+ return FIX16_FROM_FLOAT(len);
+}
+
+static void
+fixedvector_from_vector( Fix16Vector f, Vector v )
+{
+ f[0] = FIX16_FROM_FLOAT(v[0]);
+ f[1] = FIX16_FROM_FLOAT(v[1]);
+ f[2] = FIX16_FROM_FLOAT(v[2]);
+}
+
+
+#ifdef FIX16_IS_FLOAT
+static double
+fixedvector_dot( Fix16Vector u, Fix16Vector v )
+{
+ return u[0]*v[0] + u[1]*v[1] + u[2]*v[2];
+}
+#else
+static Fix16
+fixedvector_dot( Fix16Vector u, Fix16Vector v )
+{
+ long long t;
+
+ t = (long long)u[0] * v[0] + (long long)u[1] * v[1] + (long long)u[2] * v[2];
+ return (Fix16)(t >> FIX16_SHIFT);
+}
+#endif
+
+static int
+norm( int dx, int dy )
+{
+ return (int) sqrt( dx*1.0*dx + dy*1.0*dy );
+}
+
+/*** ROTATOR: used to rotate the reference axis when mouse motion happens
+ ***/
+
+typedef struct
+{
+ VectorRec d;
+ VectorRec n;
+ double angle;
+
+} RotatorRec, *Rotator;
+
+
+#define ANGLE_FACTOR (M_PI/200)
+
+static void
+rotator_reset( Rotator rot, int dx, int dy )
+{
+ double len = sqrt( dx*dx + dy*dy );
+ double zx, zy;
+
+ if (len < 1e-3 ) {
+ zx = 1.;
+ zy = 0;
+ } else {
+ zx = dx / len;
+ zy = dy / len;
+ }
+ rot->d[0] = zx;
+ rot->d[1] = zy;
+ rot->d[2] = 0.;
+
+ rot->n[0] = -rot->d[1];
+ rot->n[1] = rot->d[0];
+ rot->n[2] = 0;
+
+ rot->angle = len * ANGLE_FACTOR;
+}
+
+static void
+rotator_apply( Rotator rot, double* vec )
+{
+ double d, n, z, d2, z2, cs, sn;
+
+ /* project on D, N, Z */
+ d = vec[0]*rot->d[0] + vec[1]*rot->d[1];
+ n = vec[0]*rot->n[0] + vec[1]*rot->n[1];
+ z = vec[2];
+
+ /* rotate on D, Z */
+ cs = cos( rot->angle );
+ sn = sin( rot->angle );
+
+ d2 = cs*d + sn*z;
+ z2 = -sn*d + cs*z;
+
+ /* project on X, Y, Z */
+ vec[0] = d2*rot->d[0] + n*rot->n[0];
+ vec[1] = d2*rot->d[1] + n*rot->n[1];
+ vec[2] = z2;
+}
+
+/*** TRACKBALL OBJECT
+ ***/
+typedef struct { int x, y, offset, alpha; Fix16VectorRec f; } SphereCoordRec, *SphereCoord;
+
+typedef struct SkinTrackBall
+{
+ int diameter;
+ unsigned* pixels;
+ SDL_Surface* surface;
+ VectorRec axes[3]; /* current ball axes */
+
+#define DOT_GRID 3 /* number of horizontal and vertical cells per side grid */
+#define DOT_CELLS 2 /* number of random dots per cell */
+#define DOT_MAX (6*DOT_GRID*DOT_GRID*DOT_CELLS) /* total number of dots */
+#define DOT_RANDOM_X 1007 /* horizontal random range in each cell */
+#define DOT_RANDOM_Y 1007 /* vertical random range in each cell */
+
+#define DOT_THRESHOLD FIX16_FROM_FLOAT(0.17)
+
+ Fix16VectorRec dots[ DOT_MAX ];
+
+ SphereCoordRec* sphere_map;
+ int sphere_count;
+
+ unsigned ball_color;
+ unsigned dot_color;
+ unsigned ring_color;
+
+ Uint32 ticks_last; /* ticks since last move */
+ int acc_x;
+ int acc_y;
+ int acc_threshold;
+ double acc_scale;
+
+} TrackBallRec, *TrackBall;
+
+
+static void
+trackball_init( TrackBall ball, int diameter, int ring,
+ unsigned ball_color, unsigned dot_color,
+ unsigned ring_color )
+{
+ int diameter2 = diameter + ring*2;
+
+ memset( ball, 0, sizeof(*ball) );
+
+ /* XXX: hard-coded constants are evil */
+ ball->acc_threshold = 20;
+ ball->acc_scale = 0.2;
+
+ /* init SDL surface */
+ ball->diameter = diameter2;
+ ball->ball_color = ball_color;
+ ball->dot_color = dot_color;
+ ball->ring_color = ring_color;
+
+ ball->pixels = (unsigned*)calloc( diameter2*diameter2, sizeof(unsigned) );
+ ball->surface = sdl_surface_from_argb32( ball->pixels, diameter2, diameter2 );
+
+ /* init axes */
+ ball->axes[0][0] = 1.; ball->axes[0][1] = 0.; ball->axes[0][2] = 0.;
+ ball->axes[1][0] = 0.; ball->axes[1][1] = 1.; ball->axes[1][2] = 0.;
+ ball->axes[2][0] = 0.; ball->axes[2][1] = 0.; ball->axes[2][2] = 1.;
+
+ /* init dots */
+ {
+ int side, nn = 0;
+
+ for (side = 0; side < 6; side++) {
+ VectorRec origin, axis1, axis2;
+ int xx, yy;
+
+ switch (side) {
+ case 0:
+ origin[0] = -1; origin[1] = -1; origin[2] = +1;
+ axis1 [0] = 1; axis1 [1] = 0; axis1 [2] = 0;
+ axis2 [0] = 0; axis2 [1] = 1; axis2 [2] = 0;
+ break;
+ case 1:
+ origin[0] = -1; origin[1] = -1; origin[2] = -1;
+ axis1 [0] = 1; axis1 [1] = 0; axis1 [2] = 0;
+ axis2 [0] = 0; axis2 [1] = 1; axis2 [2] = 0;
+ break;
+ case 2:
+ origin[0] = +1; origin[1] = -1; origin[2] = -1;
+ axis1 [0] = 0; axis1 [1] = 0; axis1 [2] = 1;
+ axis2 [0] = 0; axis2 [1] = 1; axis2 [2] = 0;
+ break;
+ case 3:
+ origin[0] = -1; origin[1] = -1; origin[2] = -1;
+ axis1 [0] = 0; axis1 [1] = 0; axis1 [2] = 1;
+ axis2 [0] = 0; axis2 [1] = 1; axis2 [2] = 0;
+ break;
+ case 4:
+ origin[0] = -1; origin[1] = -1; origin[2] = -1;
+ axis1 [0] = 1; axis1 [1] = 0; axis1 [2] = 0;
+ axis2 [0] = 0; axis2 [1] = 0; axis2 [2] = 1;
+ break;
+ default:
+ origin[0] = -1; origin[1] = +1; origin[2] = -1;
+ axis1 [0] = 1; axis1 [1] = 0; axis1 [2] = 0;
+ axis2 [0] = 0; axis2 [1] = 0; axis2 [2] = 1;
+ }
+
+ for (xx = 0; xx < DOT_GRID; xx++) {
+ double tx = xx*(2./DOT_GRID);
+ for (yy = 0; yy < DOT_GRID; yy++) {
+ double ty = yy*(2./DOT_GRID);
+ double x0 = origin[0] + axis1[0]*tx + axis2[0]*ty;
+ double y0 = origin[1] + axis1[1]*tx + axis2[1]*ty;
+ double z0 = origin[2] + axis1[2]*tx + axis2[2]*ty;
+ int cc;
+ for (cc = 0; cc < DOT_CELLS; cc++) {
+ double h = (rand() % DOT_RANDOM_X)/((double)DOT_RANDOM_X*DOT_GRID/2);
+ double v = (rand() % DOT_RANDOM_Y)/((double)DOT_RANDOM_Y*DOT_GRID/2);
+ double x = x0 + axis1[0]*h + axis2[0]*v;
+ double y = y0 + axis1[1]*h + axis2[1]*v;
+ double z = z0 + axis1[2]*h + axis2[2]*v;
+ double invlen = 1/sqrt( x*x + y*y + z*z );
+
+ ball->dots[nn][0] = FIX16_FROM_FLOAT(x*invlen);
+ ball->dots[nn][1] = FIX16_FROM_FLOAT(y*invlen);
+ ball->dots[nn][2] = FIX16_FROM_FLOAT(z*invlen);
+ nn++;
+ }
+ }
+ }
+ }
+ }
+
+ /* init sphere */
+ {
+ int diameter2 = diameter + 2*ring;
+ double radius = diameter*0.5;
+ double radius2 = diameter2*0.5;
+ int xx, yy;
+ int empty = 0, total = 0;
+
+ ball->sphere_map = calloc( diameter2*diameter2, sizeof(SphereCoordRec) );
+
+ for (yy = 0; yy < diameter2; yy++) {
+ for (xx = 0; xx < diameter2; xx++) {
+ double x0 = xx - radius2;
+ double y0 = yy - radius2;
+ double r0 = sqrt( x0*x0 + y0*y0 );
+ SphereCoord coord = &ball->sphere_map[total];
+
+ if (r0 <= radius) { /* ball pixel */
+ double rx = x0/radius;
+ double ry = y0/radius;
+ double rz = sqrt( 1.0 - rx*rx - ry*ry );
+
+ coord->x = xx;
+ coord->y = yy;
+ coord->offset = xx + yy*diameter2;
+ coord->alpha = 256;
+ coord->f[0] = FIX16_FROM_FLOAT(rx);
+ coord->f[1] = FIX16_FROM_FLOAT(ry);
+ coord->f[2] = FIX16_FROM_FLOAT(rz);
+ if (r0 >= radius-1.) {
+ coord->alpha = 256*(radius - r0);
+ }
+ /* illumination model */
+ {
+#define LIGHT_X -2.0
+#define LIGHT_Y -2.5
+#define LIGHT_Z 5.0
+
+ double lx = LIGHT_X - rx;
+ double ly = LIGHT_Y - ry;
+ double lz = LIGHT_Z - rz;
+ double lir = 1/sqrt(lx*lx + ly*ly + lz*lz);
+ double cosphi = lir*(lx*rx + ly*ry + lz*rz);
+ double scale = 1.1*cosphi + 0.3;
+
+ if (scale < 0)
+ scale = 0;
+
+ coord->alpha = coord->alpha * scale;
+ }
+ total++;
+ } else if (r0 <= radius2) { /* ring pixel */
+ coord->x = xx;
+ coord->y = yy;
+ coord->offset = xx + yy*diameter2;
+ coord->alpha = 0;
+ if (r0 >= radius2-1.) {
+ coord->alpha = -256*(r0 - (radius2-1.));
+ }
+ total++;
+
+ } else /* outside pixel */
+ empty++;
+ }
+ }
+ ball->sphere_count = total;
+ }
+}
+
+static int
+trackball_contains( TrackBall ball, int x, int y )
+{
+ return ( (unsigned)(x) < (unsigned)ball->diameter &&
+ (unsigned)(y) < (unsigned)ball->diameter );
+}
+
+static void
+trackball_done( TrackBall ball )
+{
+ free( ball->sphere_map );
+ ball->sphere_map = NULL;
+ ball->sphere_count = 0;
+
+ if (ball->surface) {
+ SDL_FreeSurface( ball->surface );
+ ball->surface = NULL;
+ }
+
+ if (ball->pixels) {
+ free( ball->pixels );
+ ball->pixels = NULL;
+ }
+}
+
+/*** TRACKBALL SPHERE PIXELS
+ ***/
+static unsigned
+color_blend( unsigned from, unsigned to, int alpha )
+{
+ unsigned from_ag = (from >> 8) & 0x00ff00ff;
+ unsigned to_ag = (to >> 8) & 0x00ff00ff;
+ unsigned from_rb = from & 0x00ff00ff;
+ unsigned to_rb = to & 0x00ff00ff;
+ unsigned result_ag = (from_ag + (alpha*(to_ag - from_ag) >> 8)) & 0xff00ff;
+ unsigned result_rb = (from_rb + (alpha*(to_rb - from_rb) >> 8)) & 0xff00ff;
+
+ return (result_ag << 8) | result_rb;
+}
+
+static int
+trackball_move( TrackBall ball, int dx, int dy )
+{
+ RotatorRec rot[1];
+ Uint32 now = SDL_GetTicks();
+
+ ball->acc_x += dx;
+ ball->acc_y += dy;
+
+ if ( norm( ball->acc_x, ball->acc_y ) > ball->acc_threshold )
+ {
+ int ddx = ball->acc_x * ball->acc_scale;
+ int ddy = ball->acc_y * ball->acc_scale;
+
+ ball->acc_x = 0;
+ ball->acc_y = 0;
+
+ kbd_mouse_event(ddx, ddy, 1, 0);
+ }
+
+ rotator_reset( rot, dx, dy );
+ rotator_apply( rot, ball->axes[0] );
+ rotator_apply( rot, ball->axes[1] );
+ rotator_apply( rot, ball->axes[2] );
+
+ if ( ball->ticks_last == 0 )
+ ball->ticks_last = now;
+ else if ( now > ball->ticks_last + (1000/60) ) {
+ ball->ticks_last = now;
+ return 1;
+ }
+ return 0;
+}
+
+#define BACK_COLOR 0x00000000
+#define LIGHT_COLOR 0xffffffff
+
+static void
+trackball_refresh( TrackBall ball )
+{
+ int diameter = ball->diameter;
+ unsigned* pixels = ball->pixels;
+ Fix16VectorRec faxes[3];
+ Fix16 dot_threshold = DOT_THRESHOLD * diameter;
+ int nn;
+
+ SDL_LockSurface( ball->surface );
+
+ fixedvector_from_vector( (Fix16Vector)&faxes[0], (Vector)&ball->axes[0] );
+ fixedvector_from_vector( (Fix16Vector)&faxes[1], (Vector)&ball->axes[1] );
+ fixedvector_from_vector( (Fix16Vector)&faxes[2], (Vector)&ball->axes[2] );
+
+ for (nn = 0; nn < ball->sphere_count; nn++) {
+ SphereCoord coord = &ball->sphere_map[nn];
+ unsigned color = BACK_COLOR;
+
+ if (coord->alpha > 0) {
+ /* are we near one of the points ? */
+ Fix16 ax = fixedvector_dot( (Fix16Vector)&coord->f, (Fix16Vector)&faxes[0] );
+ Fix16 ay = fixedvector_dot( (Fix16Vector)&coord->f, (Fix16Vector)&faxes[1] );
+ Fix16 az = fixedvector_dot( (Fix16Vector)&coord->f, (Fix16Vector)&faxes[2] );
+
+ Fix16 best_dist = FIX16_ONE;
+ int pp;
+
+ color = ball->ball_color;
+
+ for (pp = 0; pp < DOT_MAX; pp++) {
+ Fix16VectorRec d;
+ Fix16 dist;
+
+ d[0] = ball->dots[pp][0] - ax;
+ d[1] = ball->dots[pp][1] - ay;
+ d[2] = ball->dots[pp][2] - az;
+
+ if (d[0] > dot_threshold || d[0] < -dot_threshold ||
+ d[1] > dot_threshold || d[1] < -dot_threshold ||
+ d[2] > dot_threshold || d[2] < -dot_threshold )
+ continue;
+
+ dist = fixedvector_len( (Fix16Vector)&d );
+
+ if (dist < best_dist)
+ best_dist = dist;
+ }
+ if (best_dist < DOT_THRESHOLD) {
+ int a = 256*(DOT_THRESHOLD - best_dist) / DOT_THRESHOLD;
+ color = color_blend( color, ball->dot_color, a );
+ }
+
+ if (coord->alpha < 256) {
+ int a = coord->alpha;
+ color = color_blend( ball->ring_color, color, a );
+ }
+ else if (coord->alpha > 256) {
+ int a = (coord->alpha - 256);
+ color = color_blend( color, LIGHT_COLOR, a );
+ }
+ }
+ else /* coord->alpha <= 0 */
+ {
+ color = ball->ring_color;
+
+ if (coord->alpha < 0) {
+ int a = -coord->alpha;
+ color = color_blend( color, BACK_COLOR, a );
+ }
+ }
+
+ pixels[coord->x + diameter*coord->y] = color;
+ }
+ SDL_UnlockSurface( ball->surface );
+}
+
+void
+trackball_draw( TrackBall ball, int x, int y, SDL_Surface* dst )
+{
+ SDL_Rect d;
+
+ d.x = x;
+ d.y = y;
+ d.w = ball->diameter;
+ d.h = ball->diameter;
+
+ SDL_BlitSurface( ball->surface, NULL, dst, &d );
+ SDL_UpdateRects( dst, 1, &d );
+}
+
+
+SkinTrackBall*
+skin_trackball_create ( SkinTrackBallParameters* params )
+{
+ TrackBall ball = (TrackBall) qemu_mallocz(sizeof(*ball));
+ if (ball != NULL) {
+ trackball_init( ball,
+ params->diameter,
+ params->ring,
+ params->ball_color,
+ params->dot_color,
+ params->ring_color );
+ }
+ return ball;
+}
+
+int
+skin_trackball_contains( SkinTrackBall* ball, int x, int y )
+{
+ return trackball_contains(ball, x, y);
+}
+
+int
+skin_trackball_move( SkinTrackBall* ball, int dx, int dy )
+{
+ return trackball_move(ball, dx, dy);
+}
+
+void
+skin_trackball_refresh ( SkinTrackBall* ball )
+{
+ trackball_refresh(ball);
+}
+
+void
+skin_trackball_draw( SkinTrackBall* ball, int x, int y, SDL_Surface* dst )
+{
+ trackball_draw(ball, x, y, dst);
+}
+
+void
+skin_trackball_destroy ( SkinTrackBall* ball )
+{
+ if (ball) {
+ trackball_done(ball);
+ qemu_free(ball);
+ }
+}
+
+void
+skin_trackball_rect( SkinTrackBall* ball, SDL_Rect* rect )
+{
+ rect->x = 0;
+ rect->y = 0;
+ rect->w = ball->diameter;
+ rect->h = ball->diameter;
+}
diff --git a/skins/skin_trackball.h b/skins/skin_trackball.h
new file mode 100644
index 0000000..3ea6d2d
--- /dev/null
+++ b/skins/skin_trackball.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _ANDROID_SKIN_TRACKBALL_H
+#define _ANDROID_SKIN_TRACKBALL_H
+
+#include <SDL.h>
+
+typedef struct SkinTrackBall SkinTrackBall;
+
+typedef struct SkinTrackBallParameters
+{
+ int diameter;
+ int ring;
+ unsigned ball_color;
+ unsigned dot_color;
+ unsigned ring_color;
+}
+SkinTrackBallParameters;
+
+
+extern SkinTrackBall* skin_trackball_create ( SkinTrackBallParameters* params );
+extern void skin_trackball_rect ( SkinTrackBall* ball, SDL_Rect* rect );
+extern int skin_trackball_contains( SkinTrackBall* ball, int x, int y );
+extern int skin_trackball_move ( SkinTrackBall* ball, int dx, int dy );
+extern void skin_trackball_refresh ( SkinTrackBall* ball );
+extern void skin_trackball_draw ( SkinTrackBall* ball, int x, int y, SDL_Surface* dst );
+extern void skin_trackball_destroy ( SkinTrackBall* ball );
+
+#endif /* END */
+
diff --git a/skins/skin_window.c b/skins/skin_window.c
new file mode 100644
index 0000000..f3f5a66
--- /dev/null
+++ b/skins/skin_window.c
@@ -0,0 +1,1233 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "skin_window.h"
+#include "skin_image.h"
+#include "skin_scaler.h"
+#include "android_charmap.h"
+#include <SDL_syswm.h>
+#include <math.h>
+
+#include "framebuffer.h"
+
+/* when shrinking, we reduce the pixel ratio by this fixed amount */
+#define SHRINK_SCALE 0.6
+
+typedef struct Background {
+ SkinImage* image;
+ SkinRect rect;
+ SkinPos origin;
+} Background;
+
+static void
+background_done( Background* back )
+{
+ skin_image_unref( &back->image );
+}
+
+static void
+background_init( Background* back, SkinBackground* sback, SkinLocation* loc, SkinRect* frame )
+{
+ SkinRect r;
+
+ back->image = skin_image_rotate( sback->image, loc->rotation );
+ skin_rect_rotate( &r, &sback->rect, loc->rotation );
+ r.pos.x += loc->anchor.x;
+ r.pos.y += loc->anchor.y;
+
+ back->origin = r.pos;
+ skin_rect_intersect( &back->rect, &r, frame );
+}
+
+static void
+background_redraw( Background* back, SkinRect* rect, SDL_Surface* surface )
+{
+ SkinRect r;
+
+ if (skin_rect_intersect( &r, rect, &back->rect ) )
+ {
+ SDL_Rect rd, rs;
+
+ rd.x = r.pos.x;
+ rd.y = r.pos.y;
+ rd.w = r.size.w;
+ rd.h = r.size.h;
+
+ rs.x = r.pos.x - back->origin.x;
+ rs.y = r.pos.y - back->origin.y;
+ rs.w = r.size.w;
+ rs.h = r.size.h;
+
+ SDL_BlitSurface( skin_image_surface(back->image), &rs, surface, &rd );
+ //SDL_UpdateRects( surface, 1, &rd );
+ }
+}
+
+
+typedef struct ADisplay {
+ SkinRect rect;
+ SkinPos origin;
+ SkinRotation rotation;
+ SkinSize datasize; /* framebuffer size */
+ void* data; /* framebuffer pixels */
+ QFrameBuffer* qfbuff;
+ SkinImage* onion; /* onion image */
+ SkinRect onion_rect; /* onion rect, if any */
+} ADisplay;
+
+static void
+display_done( ADisplay* disp )
+{
+ disp->data = NULL;
+ disp->qfbuff = NULL;
+ skin_image_unref( &disp->onion );
+}
+
+static int
+display_init( ADisplay* disp, SkinDisplay* sdisp, SkinLocation* loc, SkinRect* frame )
+{
+ skin_rect_rotate( &disp->rect, &sdisp->rect, loc->rotation );
+ disp->rect.pos.x += loc->anchor.x;
+ disp->rect.pos.y += loc->anchor.y;
+
+ disp->rotation = (loc->rotation + sdisp->rotation) & 3;
+ switch (disp->rotation) {
+ case SKIN_ROTATION_0:
+ disp->origin = disp->rect.pos;
+ break;
+
+ case SKIN_ROTATION_90:
+ disp->origin.x = disp->rect.pos.x + disp->rect.size.w;
+ disp->origin.y = disp->rect.pos.y;
+ break;
+
+ case SKIN_ROTATION_180:
+ disp->origin.x = disp->rect.pos.x + disp->rect.size.w;
+ disp->origin.y = disp->rect.pos.y + disp->rect.size.h;
+ break;
+
+ default:
+ disp->origin.x = disp->rect.pos.x;
+ disp->origin.y = disp->rect.pos.y + disp->rect.size.h;
+ break;
+ }
+ skin_size_rotate( &disp->datasize, &sdisp->rect.size, sdisp->rotation );
+ skin_rect_intersect( &disp->rect, &disp->rect, frame );
+#if 0
+ fprintf(stderr, "... display_init rect.pos(%d,%d) rect.size(%d,%d) datasize(%d,%d)\n",
+ disp->rect.pos.x, disp->rect.pos.y,
+ disp->rect.size.w, disp->rect.size.h,
+ disp->datasize.w, disp->datasize.h);
+#endif
+ disp->qfbuff = sdisp->qfbuff;
+ disp->data = sdisp->qfbuff->pixels;
+ disp->onion = NULL;
+ return (disp->data == NULL) ? -1 : 0;
+}
+
+static __inline__ uint32_t rgb565_to_argb32( uint32_t pix )
+{
+ uint32_t r = ((pix & 0xf800) << 8) | ((pix & 0xe000) << 3);
+ uint32_t g = ((pix & 0x07e0) << 5) | ((pix & 0x0600) >> 1);
+ uint32_t b = ((pix & 0x001f) << 3) | ((pix & 0x001c) >> 2);
+
+ return 0xff000000 | r | g | b;
+}
+
+
+static void
+display_set_onion( ADisplay* disp, SkinImage* onion, SkinRotation rotation, int blend )
+{
+ int onion_w, onion_h;
+ SkinRect* rect = &disp->rect;
+ SkinRect* orect = &disp->onion_rect;
+
+ rotation = (rotation + disp->rotation) & 3;
+
+ skin_image_unref( &disp->onion );
+ disp->onion = skin_image_clone_full( onion, rotation, blend );
+
+ onion_w = skin_image_w(disp->onion);
+ onion_h = skin_image_h(disp->onion);
+
+ switch (rotation) {
+ case SKIN_ROTATION_0:
+ orect->pos = rect->pos;
+ break;
+
+ case SKIN_ROTATION_90:
+ orect->pos.x = rect->pos.x + rect->size.w - onion_w;
+ orect->pos.y = rect->pos.y;
+ break;
+
+ case SKIN_ROTATION_180:
+ orect->pos.x = rect->pos.x + rect->size.w - onion_w;
+ orect->pos.y = rect->pos.y + rect->size.h - onion_h;
+ break;
+
+ default:
+ orect->pos.x = rect->pos.x;
+ orect->pos.y = rect->pos.y + rect->size.h - onion_h;
+ }
+ orect->size.w = onion_w;
+ orect->size.h = onion_h;
+}
+
+#define DOT_MATRIX 0
+
+#if DOT_MATRIX
+
+static void
+dotmatrix_dither_argb32( unsigned char* pixels, int x, int y, int w, int h, int pitch )
+{
+ static const unsigned dotmatrix_argb32[16] = {
+ 0x003f00, 0x00003f, 0x3f0000, 0x000000,
+ 0x3f3f3f, 0x000000, 0x3f3f3f, 0x000000,
+ 0x3f0000, 0x000000, 0x003f00, 0x00003f,
+ 0x3f3f3f, 0x000000, 0x3f3f3f, 0x000000
+ };
+
+ int yy = y & 3;
+
+ pixels += 4*x + y*pitch;
+
+ for ( ; h > 0; h-- ) {
+ unsigned* line = (unsigned*) pixels;
+ int nn, xx = x & 3;
+
+ for (nn = 0; nn < w; nn++) {
+ unsigned c = line[nn];
+
+ c = c - ((c >> 2) & dotmatrix_argb32[(yy << 2)|xx]);
+
+ xx = (xx + 1) & 3;
+ line[nn] = c;
+ }
+
+ yy = (yy + 1) & 3;
+ pixels += pitch;
+ }
+}
+
+#endif /* DOT_MATRIX */
+
+static void
+display_redraw( ADisplay* disp, SkinRect* rect, SDL_Surface* surface )
+{
+ SkinRect r;
+
+ if (skin_rect_intersect( &r, rect, &disp->rect ))
+ {
+ int x = r.pos.x - disp->rect.pos.x;
+ int y = r.pos.y - disp->rect.pos.y;
+ int w = r.size.w;
+ int h = r.size.h;
+ int disp_w = disp->rect.size.w;
+ int disp_h = disp->rect.size.h;
+ int dst_pitch = surface->pitch;
+ uint8_t* dst_line = (uint8_t*)surface->pixels + r.pos.x*4 + r.pos.y*dst_pitch;
+ int src_pitch = disp->datasize.w*2;
+ uint8_t* src_line = (uint8_t*)disp->data;
+ int yy, xx;
+#if 0
+ fprintf(stderr, "--- display redraw r.pos(%d,%d) r.size(%d,%d) "
+ "disp.pos(%d,%d) disp.size(%d,%d) datasize(%d,%d) rect.pos(%d,%d) rect.size(%d,%d)\n",
+ r.pos.x - disp->rect.pos.x, r.pos.y - disp->rect.pos.y, w, h, disp->rect.pos.x, disp->rect.pos.y,
+ disp->rect.size.w, disp->rect.size.h, disp->datasize.w, disp->datasize.h,
+ rect->pos.x, rect->pos.y, rect->size.w, rect->size.h );
+#endif
+ SDL_LockSurface( surface );
+ switch ( disp->rotation & 3 )
+ {
+ case ANDROID_ROTATION_0:
+ src_line += x*2 + y*src_pitch;
+
+ for (yy = h; yy > 0; yy--)
+ {
+ uint32_t* dst = (uint32_t*)dst_line;
+ uint16_t* src = (uint16_t*)src_line;
+
+ for (xx = 0; xx < w; xx++) {
+ dst[xx] = rgb565_to_argb32(src[xx]);
+ }
+ src_line += src_pitch;
+ dst_line += dst_pitch;
+ }
+ break;
+
+ case ANDROID_ROTATION_90:
+ src_line += y*2 + (disp_w - x - 1)*src_pitch;
+
+ for (yy = h; yy > 0; yy--)
+ {
+ uint32_t* dst = (uint32_t*)dst_line;
+ uint8_t* src = src_line;
+
+ for (xx = w; xx > 0; xx--)
+ {
+ dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
+ src -= src_pitch;
+ dst += 1;
+ }
+ src_line += 2;
+ dst_line += dst_pitch;
+ }
+ break;
+
+ case ANDROID_ROTATION_180:
+ src_line += (disp_w -1 - x)*2 + (disp_h-1-y)*src_pitch;
+
+ for (yy = h; yy > 0; yy--)
+ {
+ uint16_t* src = (uint16_t*)src_line;
+ uint32_t* dst = (uint32_t*)dst_line;
+
+ for (xx = w; xx > 0; xx--) {
+ dst[0] = rgb565_to_argb32(src[0]);
+ src -= 1;
+ dst += 1;
+ }
+
+ src_line -= src_pitch;
+ dst_line += dst_pitch;
+ }
+ break;
+
+ default: /* ANDROID_ROTATION_270 */
+ src_line += (disp_h-1-y)*2 + x*src_pitch;
+
+ for (yy = h; yy > 0; yy--)
+ {
+ uint32_t* dst = (uint32_t*)dst_line;
+ uint8_t* src = src_line;
+
+ for (xx = w; xx > 0; xx--) {
+ dst[0] = rgb565_to_argb32(((uint16_t*)src)[0]);
+ dst += 1;
+ src += src_pitch;
+ }
+ src_line -= 2;
+ dst_line += dst_pitch;
+ }
+ }
+#if DOT_MATRIX
+ dotmatrix_dither_argb32( surface->pixels, r.pos.x, r.pos.y, r.size.w, r.size.h, surface->pitch );
+#endif
+ SDL_UnlockSurface( surface );
+
+ if (disp->onion != NULL) {
+ SkinRect r2;
+
+ if ( skin_rect_intersect( &r2, &r, &disp->onion_rect ) ) {
+ SDL_Rect rs, rd;
+
+ rd.x = r2.pos.x;
+ rd.y = r2.pos.y;
+ rd.w = r2.size.w;
+ rd.h = r2.size.h;
+
+ rs.x = rd.x - disp->onion_rect.pos.x;
+ rs.y = rd.y - disp->onion_rect.pos.y;
+ rs.w = rd.w;
+ rs.h = rd.h;
+
+ SDL_BlitSurface( skin_image_surface(disp->onion), &rs, surface, &rd );
+ }
+ }
+
+ SDL_UpdateRect( surface, r.pos.x, r.pos.y, w, h );
+ }
+}
+
+
+typedef struct Button {
+ SkinImage* image;
+ SkinRect rect;
+ SkinPos origin;
+ Background* background;
+ unsigned keycode;
+ int down;
+} Button;
+
+static void
+button_done( Button* button )
+{
+ skin_image_unref( &button->image );
+ button->background = NULL;
+}
+
+static void
+button_init( Button* button, SkinButton* sbutton, SkinLocation* loc, Background* back, SkinRect* frame )
+{
+ SkinRect r;
+
+ button->image = skin_image_rotate( sbutton->image, loc->rotation );
+ button->background = back;
+ button->keycode = sbutton->keycode;
+ button->down = 0;
+
+ skin_rect_rotate( &r, &sbutton->rect, loc->rotation );
+ r.pos.x += loc->anchor.x;
+ r.pos.y += loc->anchor.y;
+ button->origin = r.pos;
+ skin_rect_intersect( &button->rect, &r, frame );
+}
+
+static void
+button_redraw( Button* button, SkinRect* rect, SDL_Surface* surface )
+{
+ SkinRect r;
+
+ if (skin_rect_intersect( &r, rect, &button->rect ))
+ {
+ if ( button->down && button->image != SKIN_IMAGE_NONE )
+ {
+ SDL_Rect rs, rd;
+
+ rs.x = r.pos.x - button->origin.x;
+ rs.y = r.pos.y - button->origin.y;
+ rs.w = r.size.w;
+ rs.h = r.size.h;
+
+ rd.x = r.pos.x;
+ rd.y = r.pos.y;
+ rd.w = r.size.w;
+ rd.h = r.size.h;
+
+ if (button->image != SKIN_IMAGE_NONE) {
+ SDL_BlitSurface( skin_image_surface(button->image), &rs, surface, &rd );
+ if (button->down > 1)
+ SDL_BlitSurface( skin_image_surface(button->image), &rs, surface, &rd );
+ }
+ }
+ }
+}
+
+
+typedef struct {
+ char tracking;
+ char inside;
+ SkinPos pos;
+ ADisplay* display;
+} FingerState;
+
+static void
+finger_state_reset( FingerState* finger )
+{
+ finger->tracking = 0;
+ finger->inside = 0;
+}
+
+typedef struct {
+ Button* pressed;
+ Button* hover;
+} ButtonState;
+
+static void
+button_state_reset( ButtonState* button )
+{
+ button->pressed = NULL;
+ button->hover = NULL;
+}
+
+typedef struct {
+ char tracking;
+ SkinTrackBall* ball;
+ SkinRect rect;
+ SkinWindow* window;
+} BallState;
+
+static void
+ball_state_reset( BallState* state, SkinWindow* window )
+{
+ state->tracking = 0;
+ state->ball = NULL;
+
+ state->rect.pos.x = 0;
+ state->rect.pos.y = 0;
+ state->rect.size.w = 0;
+ state->rect.size.h = 0;
+ state->window = window;
+}
+
+static void
+ball_state_redraw( BallState* state, SkinRect* rect, SDL_Surface* surface )
+{
+ SkinRect r;
+
+ if (skin_rect_intersect( &r, rect, &state->rect ))
+ skin_trackball_draw( state->ball, 0, 0, surface );
+}
+
+static void
+ball_state_show( BallState* state )
+{
+ if ( !state->tracking ) {
+ state->tracking = 1;
+ SDL_ShowCursor(0);
+ SDL_WM_GrabInput( SDL_GRAB_ON );
+ skin_trackball_refresh( state->ball );
+ skin_window_redraw( state->window, &state->rect );
+ }
+}
+
+static void
+ball_state_hide( BallState* state )
+{
+ if ( state->tracking ) {
+ state->tracking = 0;
+ SDL_WM_GrabInput( SDL_GRAB_OFF );
+ SDL_ShowCursor(1);
+
+ skin_window_redraw( state->window, &state->rect );
+ }
+}
+
+static void
+ball_state_set( BallState* state, SkinTrackBall* ball )
+{
+ if ( state->tracking )
+ ball_state_hide( state );
+
+ state->ball = ball;
+ if (ball != NULL) {
+ SDL_Rect sr;
+
+ skin_trackball_rect( ball, &sr );
+ state->rect.pos.x = sr.x;
+ state->rect.pos.y = sr.y;
+ state->rect.size.w = sr.w;
+ state->rect.size.h = sr.h;
+ }
+}
+
+static void
+ball_state_toggle( BallState* state )
+{
+ if (state->tracking)
+ ball_state_hide( state );
+ else
+ ball_state_show( state );
+}
+
+typedef struct Layout {
+ int num_buttons;
+ int num_backgrounds;
+ int num_displays;
+ unsigned color;
+ Button* buttons;
+ Background* backgrounds;
+ ADisplay* displays;
+ SkinRect rect;
+ SkinLayout* slayout;
+} Layout;
+
+#define LAYOUT_LOOP_BUTTONS(layout,button) \
+ do { \
+ Button* __button = (layout)->buttons; \
+ Button* __button_end = __button + (layout)->num_buttons; \
+ for ( ; __button < __button_end; __button ++ ) { \
+ Button* button = __button;
+
+#define LAYOUT_LOOP_END_BUTTONS \
+ } \
+ } while (0);
+
+#define LAYOUT_LOOP_DISPLAYS(layout,display) \
+ do { \
+ ADisplay* __display = (layout)->displays; \
+ ADisplay* __display_end = __display + (layout)->num_displays; \
+ for ( ; __display < __display_end; __display ++ ) { \
+ ADisplay* display = __display;
+
+#define LAYOUT_LOOP_END_DISPLAYS \
+ } \
+ } while (0);
+
+
+static void
+layout_done( Layout* layout )
+{
+ int nn;
+
+ for (nn = 0; nn < layout->num_buttons; nn++)
+ button_done( &layout->buttons[nn] );
+
+ for (nn = 0; nn < layout->num_backgrounds; nn++)
+ background_done( &layout->backgrounds[nn] );
+
+ for (nn = 0; nn < layout->num_displays; nn++)
+ display_done( &layout->displays[nn] );
+
+ qemu_free( layout->buttons );
+ layout->buttons = NULL;
+
+ qemu_free( layout->backgrounds );
+ layout->backgrounds = NULL;
+
+ qemu_free( layout->displays );
+ layout->displays = NULL;
+
+ layout->num_buttons = 0;
+ layout->num_backgrounds = 0;
+ layout->num_displays = 0;
+}
+
+static int
+layout_init( Layout* layout, SkinLayout* slayout )
+{
+ int n_buttons, n_backgrounds, n_displays;
+
+ /* first, count the number of elements of each kind */
+ n_buttons = 0;
+ n_backgrounds = 0;
+ n_displays = 0;
+
+ layout->color = slayout->color;
+ layout->slayout = slayout;
+
+ SKIN_LAYOUT_LOOP_LOCS(slayout,loc)
+ SkinPart* part = loc->part;
+
+ if ( part->background->valid )
+ n_backgrounds += 1;
+ if ( part->display->valid )
+ n_displays += 1;
+
+ SKIN_PART_LOOP_BUTTONS(part, sbutton)
+ n_buttons += 1;
+ sbutton=sbutton;
+ SKIN_PART_LOOP_END
+ SKIN_LAYOUT_LOOP_END
+
+ layout->num_buttons = n_buttons;
+ layout->num_backgrounds = n_backgrounds;
+ layout->num_displays = n_displays;
+
+ /* now allocate arrays, then populate them */
+ layout->buttons = qemu_mallocz( sizeof(Button) * n_buttons );
+ layout->backgrounds = qemu_mallocz( sizeof(Background) * n_backgrounds );
+ layout->displays = qemu_mallocz( sizeof(ADisplay) * n_displays );
+
+ if (layout->buttons == NULL && n_buttons > 0) goto Fail;
+ if (layout->backgrounds == NULL && n_backgrounds > 0) goto Fail;
+ if (layout->displays == NULL && n_displays > 0) goto Fail;
+
+ n_buttons = 0;
+ n_backgrounds = 0;
+ n_displays = 0;
+
+ layout->rect.pos.x = 0;
+ layout->rect.pos.y = 0;
+ layout->rect.size = slayout->size;
+
+ SKIN_LAYOUT_LOOP_LOCS(slayout,loc)
+ SkinPart* part = loc->part;
+ Background* back = NULL;
+
+ if ( part->background->valid ) {
+ back = layout->backgrounds + n_backgrounds;
+ background_init( back, part->background, loc, &layout->rect );
+ n_backgrounds += 1;
+ }
+ if ( part->display->valid ) {
+ ADisplay* disp = layout->displays + n_displays;
+ display_init( disp, part->display, loc, &layout->rect );
+ n_displays += 1;
+ }
+
+ SKIN_PART_LOOP_BUTTONS(part, sbutton)
+ Button* button = layout->buttons + n_buttons;
+ button_init( button, sbutton, loc, back, &layout->rect );
+ n_buttons += 1;
+ SKIN_PART_LOOP_END
+ SKIN_LAYOUT_LOOP_END
+
+ return 0;
+
+Fail:
+ layout_done(layout);
+ return -1;
+}
+
+struct SkinWindow {
+ SDL_Surface* surface;
+ Layout layout;
+ SkinPos pos;
+ FingerState finger;
+ ButtonState button;
+ BallState ball;
+ char enabled;
+ char fullscreen;
+ char no_display;
+
+ SkinImage* onion;
+ SkinRotation onion_rotation;
+ int onion_alpha;
+
+ SkinScaler* scaler;
+ int shrink;
+ double shrink_scale;
+ unsigned* shrink_pixels;
+ SDL_Surface* shrink_surface;
+};
+
+static void
+add_finger_event(unsigned x, unsigned y, unsigned state)
+{
+ //fprintf(stderr, "::: finger %d,%d %d\n", x, y, state);
+ kbd_mouse_event(x, y, 0, state);
+}
+
+static void
+skin_window_find_finger( SkinWindow* window,
+ int x,
+ int y )
+{
+ FingerState* finger = &window->finger;
+
+ /* find the display that contains this movement */
+ finger->display = NULL;
+ finger->inside = 0;
+
+ LAYOUT_LOOP_DISPLAYS(&window->layout,disp)
+ if ( skin_rect_contains( &disp->rect, x, y ) ) {
+ finger->inside = 1;
+ finger->display = disp;
+ finger->pos.x = x - disp->origin.x;
+ finger->pos.y = y - disp->origin.y;
+
+ skin_pos_rotate( &finger->pos, &finger->pos, -disp->rotation );
+ break;
+ }
+ LAYOUT_LOOP_END_DISPLAYS
+}
+
+static void
+skin_window_move_mouse( SkinWindow* window,
+ int x,
+ int y )
+{
+ FingerState* finger = &window->finger;
+ ButtonState* button = &window->button;
+
+ if (finger->tracking) {
+ ADisplay* disp = finger->display;
+ char inside = 1;
+ int dx = x - disp->rect.pos.x;
+ int dy = y - disp->rect.pos.y;
+
+ if (dx < 0) {
+ dx = 0;
+ inside = 0;
+ }
+ else if (dx >= disp->rect.size.w) {
+ dx = disp->rect.size.w - 1;
+ inside = 0;
+ }
+ if (dy < 0) {
+ dy = 0;
+ inside = 0;
+ } else if (dy >= disp->rect.size.h) {
+ dy = disp->rect.size.h-1;
+ inside = 0;
+ }
+ finger->inside = inside;
+ finger->pos.x = dx + (disp->rect.pos.x - disp->origin.x);
+ finger->pos.y = dy + (disp->rect.pos.y - disp->origin.y);
+
+ skin_pos_rotate( &finger->pos, &finger->pos, -disp->rotation );
+ }
+
+ {
+ Button* hover = button->hover;
+
+ if (hover) {
+ if ( skin_rect_contains( &hover->rect, x, y ) )
+ return;
+
+ hover->down = 0;
+ skin_window_redraw( window, &hover->rect );
+ button->hover = NULL;
+ }
+
+ hover = NULL;
+ LAYOUT_LOOP_BUTTONS( &window->layout, butt )
+ if ( skin_rect_contains( &butt->rect, x, y ) ) {
+ hover = butt;
+ break;
+ }
+ LAYOUT_LOOP_END_BUTTONS
+
+ if (hover != NULL) {
+ hover->down = 1;
+ skin_window_redraw( window, &hover->rect );
+ button->hover = hover;
+ }
+ }
+}
+
+static void
+skin_window_trackball_press( SkinWindow* window, int down )
+{
+ send_key_event( kKeyCodeBtnMouse, down );
+}
+
+static void
+skin_window_trackball_move( SkinWindow* window, int xrel, int yrel )
+{
+ BallState* state = &window->ball;
+
+ if ( skin_trackball_move( state->ball, xrel, yrel ) ) {
+ skin_trackball_refresh( state->ball );
+ skin_window_redraw( window, &state->rect );
+ }
+}
+
+void
+skin_window_set_trackball( SkinWindow* window, SkinTrackBall* ball )
+{
+ BallState* state = &window->ball;
+
+ ball_state_set( state, ball );
+}
+
+void
+skin_window_toggle_trackball( SkinWindow* window )
+{
+ BallState* state = &window->ball;
+
+ if (state->ball != NULL) {
+ ball_state_toggle(state);
+ }
+}
+
+
+SkinWindow*
+skin_window_create( SkinLayout* slayout, int x, int y, double scale, int no_display )
+{
+ SkinWindow* window = qemu_mallocz(sizeof(*window));
+
+ /* position emulator window to its last position */
+ {
+ char temp[32];
+ sprintf(temp,"SDL_VIDEO_WINDOW_POS=%d,%d",x,y);
+ putenv(temp);
+ putenv("SDL_VIDEO_WINDOW_FORCE_VISIBLE=1");
+ }
+
+ window->shrink_scale = scale;
+ window->shrink = (scale != 1.0);
+ window->scaler = skin_scaler_create();
+ window->no_display = no_display;
+
+ if (skin_window_reset(window, slayout) < 0) {
+ skin_window_free( window );
+ return NULL;
+ }
+ //SDL_WM_SetCaption( "Android Emulator", "Android Emulator" );
+
+ SDL_WM_SetPos( x, y );
+ if ( !SDL_WM_IsFullyVisible( 1 ) ) {
+ dprint( "emulator window was out of view and was recentred\n" );
+ }
+
+ return window;
+}
+
+void
+skin_window_set_title( SkinWindow* window, const char* title )
+{
+ if (window && title)
+ SDL_WM_SetCaption( title, title );
+}
+
+int
+skin_window_reset ( SkinWindow* window, SkinLayout* slayout )
+{
+ Layout layout;
+ int flags;
+ ADisplay* disp;
+
+ if ( layout_init( &layout, slayout ) < 0 )
+ return -1;
+
+ disp = window->layout.displays;
+
+ layout_done( &window->layout );
+ window->layout = layout;
+
+ disp = window->layout.displays;
+ if (disp != NULL && window->onion)
+ display_set_onion( disp,
+ window->onion,
+ window->onion_rotation,
+ window->onion_alpha );
+
+
+ /* now resize window */
+ if (window->surface) {
+ SDL_FreeSurface(window->surface);
+ window->surface = NULL;
+ }
+
+ if (window->shrink_surface) {
+ SDL_FreeSurface(window->shrink_surface);
+ window->shrink_surface = NULL;
+ }
+
+ if (window->shrink_pixels) {
+ qemu_free(window->shrink_pixels);
+ window->shrink_pixels = NULL;
+ }
+
+ if ( !window->no_display ) {
+ int window_w = layout.rect.size.w;
+ int window_h = layout.rect.size.h;
+ SDL_Surface* surface;
+
+ if (window->shrink) {
+ window_w = (int) ceil(window_w*window->shrink_scale);
+ window_h = (int) ceil(window_h*window->shrink_scale);
+ }
+
+ flags = SDL_SWSURFACE;
+ if (window->fullscreen)
+ flags |= SDL_FULLSCREEN;
+
+ surface = SDL_SetVideoMode( window_w, window_h, 32, flags );
+ if (surface == NULL) {
+ fprintf(stderr, "### Error: could not create or resize SDL window: %s\n", SDL_GetError() );
+ exit(1);
+ }
+
+ if (!window->shrink)
+ window->surface = surface;
+ else
+ {
+ window_w = (int) ceil(window_w / window->shrink_scale);
+ window_h = (int) ceil(window_h / window->shrink_scale);
+
+ window->shrink_surface = surface;
+ window->shrink_pixels = qemu_mallocz( window_w * window_h * 4 );
+ if (window->shrink_pixels == NULL) {
+ fprintf(stderr, "### Error: could not allocate memory for rescaling surface\n");
+ exit(1);
+ }
+ window->surface = sdl_surface_from_argb32( window->shrink_pixels, window_w, window_h );
+ if (window->surface == NULL) {
+ fprintf(stderr, "### Error: could not create or resize SDL window: %s\n", SDL_GetError() );
+ exit(1);
+ }
+ skin_scaler_set( window->scaler, window->shrink_scale );
+ }
+ }
+
+ finger_state_reset( &window->finger );
+ button_state_reset( &window->button );
+ ball_state_reset( &window->ball, window );
+
+ skin_window_redraw( window, NULL );
+
+ if (slayout->event_type != 0) {
+ kbd_generic_event( slayout->event_type, slayout->event_code, slayout->event_value );
+ }
+
+ return 0;
+}
+
+void
+skin_window_free ( SkinWindow* window )
+{
+ if (window) {
+ if (window->surface) {
+ SDL_FreeSurface(window->surface);
+ window->surface = NULL;
+ }
+ if (window->shrink_surface) {
+ SDL_FreeSurface(window->shrink_surface);
+ window->shrink_surface = NULL;
+ }
+ if (window->shrink_pixels) {
+ qemu_free(window->shrink_pixels);
+ window->shrink_pixels = NULL;
+ }
+ if (window->onion) {
+ skin_image_unref( &window->onion );
+ window->onion_rotation = SKIN_ROTATION_0;
+ }
+ if (window->scaler) {
+ skin_scaler_free(window->scaler);
+ window->scaler = NULL;
+ }
+ layout_done( &window->layout );
+ qemu_free(window);
+ }
+}
+
+void
+skin_window_set_onion( SkinWindow* window,
+ SkinImage* onion,
+ SkinRotation onion_rotation,
+ int onion_alpha )
+{
+ ADisplay* disp;
+ SkinImage* old = window->onion;
+
+ window->onion = skin_image_ref(onion);
+ window->onion_rotation = onion_rotation;
+ window->onion_alpha = onion_alpha;
+
+ skin_image_unref( &old );
+
+ disp = window->layout.displays;
+
+ if (disp != NULL)
+ display_set_onion( disp, window->onion, onion_rotation, onion_alpha );
+}
+
+static void
+skin_window_update_shrink( SkinWindow* window, SkinRect* rect )
+{
+ skin_scaler_scale( window->scaler, window->shrink_surface, window->surface,
+ rect->pos.x, rect->pos.y, rect->size.w, rect->size.h );
+}
+
+void
+skin_window_set_scale( SkinWindow* window, double scale )
+{
+ window->shrink = (scale != 1.0);
+ window->shrink_scale = scale;
+
+ skin_window_reset( window, window->layout.slayout );
+}
+
+void
+skin_window_redraw( SkinWindow* window, SkinRect* rect )
+{
+ if (window != NULL && window->surface != NULL) {
+ Layout* layout = &window->layout;
+
+ if (rect == NULL)
+ rect = &layout->rect;
+
+ {
+ SkinRect r;
+
+ if ( skin_rect_intersect( &r, rect, &layout->rect ) ) {
+ SDL_Rect rd;
+ rd.x = r.pos.x;
+ rd.y = r.pos.y;
+ rd.w = r.size.w;
+ rd.h = r.size.h;
+
+ SDL_FillRect( window->surface, &rd, layout->color );
+ }
+ }
+
+ {
+ Background* back = layout->backgrounds;
+ Background* end = back + layout->num_backgrounds;
+ for ( ; back < end; back++ )
+ background_redraw( back, rect, window->surface );
+ }
+
+ {
+ ADisplay* disp = layout->displays;
+ ADisplay* end = disp + layout->num_displays;
+ for ( ; disp < end; disp++ )
+ display_redraw( disp, rect, window->surface );
+ }
+
+ {
+ Button* button = layout->buttons;
+ Button* end = button + layout->num_buttons;
+ for ( ; button < end; button++ )
+ button_redraw( button, rect, window->surface );
+ }
+
+ if ( window->ball.tracking )
+ ball_state_redraw( &window->ball, rect, window->surface );
+
+ if (window->shrink)
+ skin_window_update_shrink( window, rect );
+ else
+ {
+ SDL_Rect rd;
+ rd.x = rect->pos.x;
+ rd.y = rect->pos.y;
+ rd.w = rect->size.w;
+ rd.h = rect->size.h;
+
+ SDL_UpdateRects( window->surface, 1, &rd );
+ }
+ }
+}
+
+void
+skin_window_toggle_fullscreen( SkinWindow* window )
+{
+ if (window && window->surface) {
+ SDL_WM_ToggleFullScreen(window->surface);
+ window->fullscreen = !window->fullscreen;
+ skin_window_redraw( window, NULL );
+ }
+}
+
+void
+skin_window_get_display( SkinWindow* window, ADisplayInfo *info )
+{
+ ADisplay* disp = window->layout.displays;
+
+ if (disp != NULL) {
+ info->width = disp->datasize.w;
+ info->height = disp->datasize.h;
+ info->rotation = disp->rotation;
+ info->data = disp->data;
+ } else {
+ info->width = 0;
+ info->height = 0;
+ info->rotation = SKIN_ROTATION_0;
+ info->data = NULL;
+ }
+}
+
+
+void
+skin_window_process_event( SkinWindow* window, SDL_Event* ev )
+{
+ Button* button;
+ int mx, my;
+
+ if (!window->surface)
+ return;
+
+ switch (ev->type) {
+ case SDL_MOUSEBUTTONDOWN:
+ if ( window->ball.tracking ) {
+ skin_window_trackball_press( window, 1 );
+ break;
+ }
+
+ mx = ev->button.x;
+ my = ev->button.y;
+ if ( window->shrink ) {
+ mx /= window->shrink_scale;
+ my /= window->shrink_scale;
+ }
+ skin_window_move_mouse( window, mx, my );
+ skin_window_find_finger( window, mx, my );
+#if 0
+ printf("down: x=%d y=%d fx=%d fy=%d fis=%d\n",
+ ev->button.x, ev->button.y, window->finger.pos.x,
+ window->finger.pos.y, window->finger.inside);
+#endif
+ if (window->finger.inside) {
+ window->finger.tracking = 1;
+ add_finger_event(window->finger.pos.x, window->finger.pos.y, 1);
+ } else {
+ window->button.pressed = NULL;
+ button = window->button.hover;
+ if(button) {
+ button->down += 1;
+ skin_window_redraw( window, &button->rect );
+ window->button.pressed = button;
+ if(button->keycode) {
+ send_key_event(button->keycode, 1);
+ }
+ }
+ }
+ break;
+
+ case SDL_MOUSEBUTTONUP:
+ if ( window->ball.tracking ) {
+ skin_window_trackball_press( window, 0 );
+ break;
+ }
+ button = window->button.pressed;
+ mx = ev->button.x;
+ my = ev->button.y;
+ if ( window->shrink ) {
+ mx /= window->shrink_scale;
+ my /= window->shrink_scale;
+ }
+ if (button)
+ {
+ button->down = 0;
+ skin_window_redraw( window, &button->rect );
+ if(button->keycode) {
+ send_key_event(button->keycode, 0);
+ }
+ window->button.pressed = NULL;
+ window->button.hover = NULL;
+ skin_window_move_mouse( window, mx, my );
+ }
+ else if (window->finger.tracking)
+ {
+ skin_window_move_mouse( window, mx, my );
+ window->finger.tracking = 0;
+ add_finger_event( window->finger.pos.x, window->finger.pos.y, 0);
+ }
+ break;
+
+ case SDL_MOUSEMOTION:
+ if ( window->ball.tracking ) {
+ skin_window_trackball_move( window, ev->motion.xrel, ev->motion.yrel );
+ break;
+ }
+ mx = ev->button.x;
+ my = ev->button.y;
+ if ( window->shrink ) {
+ mx /= window->shrink_scale;
+ my /= window->shrink_scale;
+ }
+ if ( !window->button.pressed )
+ {
+ skin_window_move_mouse( window, mx, my );
+ if ( window->finger.tracking ) {
+ add_finger_event( window->finger.pos.x, window->finger.pos.y, 1 );
+ }
+ }
+ break;
+ }
+}
+
+static ADisplay*
+skin_window_display( SkinWindow* window )
+{
+ return window->layout.displays;
+}
+
+void
+skin_window_update_display( SkinWindow* window, int x, int y, int w, int h )
+{
+ ADisplay* disp = skin_window_display(window);
+
+ if ( !window->surface )
+ return;
+
+ if (disp != NULL) {
+ SkinRect r;
+ r.pos.x = x;
+ r.pos.y = y;
+ r.size.w = w;
+ r.size.h = h;
+
+ skin_rect_rotate( &r, &r, disp->rotation );
+ r.pos.x += disp->origin.x;
+ r.pos.y += disp->origin.y;
+
+ if (window->shrink)
+ skin_window_redraw( window, &r );
+ else
+ display_redraw( disp, &r, window->surface );
+ }
+}
diff --git a/skins/skin_window.h b/skins/skin_window.h
new file mode 100644
index 0000000..5ca1568
--- /dev/null
+++ b/skins/skin_window.h
@@ -0,0 +1,60 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _SKIN_WINDOW_H
+#define _SKIN_WINDOW_H
+
+#include "skin_file.h"
+#include "skin_trackball.h"
+#include "android_utils.h"
+
+#include "vl.h"
+#include <SDL.h>
+
+typedef struct SkinWindow SkinWindow;
+
+extern SkinWindow* skin_window_create( SkinLayout* layout,
+ int x,
+ int y,
+ double scale,
+ int no_display );
+
+extern int skin_window_reset ( SkinWindow* window, SkinLayout* layout );
+extern void skin_window_free ( SkinWindow* window );
+extern void skin_window_redraw( SkinWindow* window, SkinRect* rect );
+extern void skin_window_process_event( SkinWindow* window, SDL_Event* ev );
+
+extern void skin_window_set_onion( SkinWindow* window,
+ SkinImage* onion,
+ SkinRotation rotation,
+ int alpha );
+
+extern void skin_window_set_scale( SkinWindow* window,
+ double scale );
+
+extern void skin_window_set_title( SkinWindow* window,
+ const char* title );
+
+extern void skin_window_set_trackball( SkinWindow* window, SkinTrackBall* ball );
+extern void skin_window_toggle_trackball( SkinWindow* window );
+extern void skin_window_toggle_fullscreen( SkinWindow* window );
+
+typedef struct {
+ int width;
+ int height;
+ SkinRotation rotation;
+ void* data;
+} ADisplayInfo;
+
+extern void skin_window_get_display( SkinWindow* window, ADisplayInfo *info );
+extern void skin_window_update_display( SkinWindow* window, int x, int y, int w, int h );
+
+#endif /* _SKIN_WINDOW_H */
diff --git a/slirp/bootp.c b/slirp/bootp.c
index 62cbcfd..79f5f9f 100644
--- a/slirp/bootp.c
+++ b/slirp/bootp.c
@@ -38,6 +38,8 @@ typedef struct {
BOOTPClient bootp_clients[NB_ADDR];
+const char *bootp_filename;
+
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
#ifdef DEBUG
@@ -125,7 +127,7 @@ static void dhcp_decode(const uint8_t *buf, int size,
static void bootp_reply(struct bootp_t *bp)
{
BOOTPClient *bc;
- struct mbuf *m;
+ MBuf m;
struct bootp_t *rbp;
struct sockaddr_in saddr, daddr;
struct in_addr dns_addr;
@@ -145,7 +147,7 @@ static void bootp_reply(struct bootp_t *bp)
/* XXX: this is a hack to get the client mac address */
memcpy(client_ethaddr, bp->bp_hwaddr, 6);
- if ((m = m_get()) == NULL)
+ if ((m = mbuf_alloc()) == NULL)
return;
m->m_data += if_maxlinkhdr;
rbp = (struct bootp_t *)m->m_data;
@@ -168,6 +170,9 @@ static void bootp_reply(struct bootp_t *bp)
goto new_addr;
}
}
+ if (bootp_filename)
+ snprintf((char*)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);
@@ -244,9 +249,9 @@ static void bootp_reply(struct bootp_t *bp)
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
}
-void bootp_input(struct mbuf *m)
+void bootp_input(MBuf m)
{
- struct bootp_t *bp = mtod(m, struct bootp_t *);
+ struct bootp_t *bp = MBUF_TO(m, struct bootp_t *);
if (bp->bp_op == BOOTP_REQUEST) {
bootp_reply(bp);
diff --git a/slirp/bootp.h b/slirp/bootp.h
index e48f53f..1fb42fa 100644
--- a/slirp/bootp.h
+++ b/slirp/bootp.h
@@ -110,4 +110,4 @@ struct bootp_t {
uint8_t bp_vend[DHCP_OPT_LEN];
};
-void bootp_input(struct mbuf *m);
+void bootp_input(MBuf m);
diff --git a/slirp/cksum.c b/slirp/cksum.c
index f8f7512..9474b9e 100644
--- a/slirp/cksum.c
+++ b/slirp/cksum.c
@@ -48,7 +48,7 @@
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);}
-int cksum(struct mbuf *m, int len)
+int cksum(MBuf m, int len)
{
register u_int16_t *w;
register int sum = 0;
@@ -66,7 +66,7 @@ int cksum(struct mbuf *m, int len)
if (m->m_len == 0)
goto cont;
- w = mtod(m, u_int16_t *);
+ w = MBUF_TO(m, u_int16_t *);
mlen = m->m_len;
diff --git a/slirp/ctl.h b/slirp/ctl.h
index 4a8576d..854ae9a 100644
--- a/slirp/ctl.h
+++ b/slirp/ctl.h
@@ -2,6 +2,9 @@
#define CTL_EXEC 1
#define CTL_ALIAS 2
#define CTL_DNS 3
+/* NOTE: DNS_ADDR_MAX addresses, starting from CTL_DNS, are reserved */
+
+#define CTL_IS_DNS(x) ((unsigned)((x)-CTL_DNS) < (unsigned)dns_addr_count)
#define CTL_SPECIAL "10.0.2.0"
#define CTL_LOCAL "10.0.2.15"
diff --git a/slirp/debug.c b/slirp/debug.c
index d3d8c57..a46626b 100644
--- a/slirp/debug.c
+++ b/slirp/debug.c
@@ -42,7 +42,7 @@ debug_init(file, dbg)
fflush(dfd);
slirp_debug = dbg;
} else {
- lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n",
+ fprintf(stderr, "Error: Debugging file \"%s\" could not be opened: %s\r\n",
file, strerror(errno));
}
}
@@ -268,30 +268,6 @@ icmpstats()
}
void
-mbufstats()
-{
- struct mbuf *m;
- int i;
-
- lprint(" \r\n");
-
- lprint("Mbuf stats:\r\n");
-
- lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max);
-
- i = 0;
- for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next)
- i++;
- lprint(" %6d mbufs on free list\r\n", i);
-
- i = 0;
- for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next)
- i++;
- lprint(" %6d mbufs on used list\r\n", i);
- lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued);
-}
-
-void
sockstats()
{
char buff[256];
diff --git a/slirp/if.c b/slirp/if.c
index 94132ca..b589c42 100644
--- a/slirp/if.c
+++ b/slirp/if.c
@@ -22,7 +22,7 @@ struct mbuf *next_m; /* Pointer to next mbuf to output */
void
ifs_insque(ifm, ifmhead)
- struct mbuf *ifm, *ifmhead;
+ MBuf ifm, ifmhead;
{
ifm->ifs_next = ifmhead->ifs_next;
ifmhead->ifs_next = ifm;
@@ -32,7 +32,7 @@ ifs_insque(ifm, ifmhead)
void
ifs_remque(ifm)
- struct mbuf *ifm;
+ MBuf ifm;
{
ifm->ifs_prev->ifs_next = ifm->ifs_next;
ifm->ifs_next->ifs_prev = ifm->ifs_prev;
@@ -159,9 +159,9 @@ if_input(ttyp)
void
if_output(so, ifm)
struct socket *so;
- struct mbuf *ifm;
+ MBuf ifm;
{
- struct mbuf *ifq;
+ MBuf ifq;
int on_fastq = 1;
DEBUG_CALL("if_output");
@@ -266,7 +266,7 @@ diddit:
void
if_start(void)
{
- struct mbuf *ifm, *ifqt;
+ MBuf ifm, *ifqt;
DEBUG_CALL("if_start");
@@ -315,7 +315,7 @@ if_start(void)
/* Encapsulate the packet for sending */
if_encap(ifm->m_data, ifm->m_len);
- m_free(ifm);
+ mbuf_free(ifm);
if (if_queued)
goto again;
diff --git a/slirp/if.h b/slirp/if.h
index 5d96a90..f22f161 100644
--- a/slirp/if.h
+++ b/slirp/if.h
@@ -25,7 +25,7 @@ extern int if_thresh; /* Number of packets queued before we start sending
extern struct mbuf if_fastq; /* fast queue (for interactive data) */
extern struct mbuf if_batchq; /* queue for non-interactive data */
-extern struct mbuf *next_m;
+extern MBuf next_m;
#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm))
diff --git a/slirp/ip_icmp.c b/slirp/ip_icmp.c
index b67a373..2d50629 100644
--- a/slirp/ip_icmp.c
+++ b/slirp/ip_icmp.c
@@ -63,7 +63,7 @@ static int icmp_flush[19] = {
/* INFO (15) */ 0,
/* INFO REPLY (16) */ 0,
/* ADDR MASK (17) */ 0,
-/* ADDR MASK REPLY (18) */ 0
+/* ADDR MASK REPLY (18) */ 0
};
/*
@@ -71,20 +71,20 @@ static int icmp_flush[19] = {
*/
void
icmp_input(m, hlen)
- struct mbuf *m;
+ MBuf m;
int hlen;
{
register struct icmp *icp;
- register struct ip *ip=mtod(m, struct ip *);
+ register struct ip *ip=MBUF_TO(m, struct ip *);
int icmplen=ip->ip_len;
/* int code; */
-
+
DEBUG_CALL("icmp_input");
DEBUG_ARG("m = %lx", (long )m);
DEBUG_ARG("m_len = %d", m->m_len);
icmpstat.icps_received++;
-
+
/*
* Locate icmp structure in mbuf, and check
* that its not corrupted and of at least minimum length.
@@ -92,20 +92,20 @@ icmp_input(m, hlen)
if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */
icmpstat.icps_tooshort++;
freeit:
- m_freem(m);
+ mbuf_free(m);
goto end_error;
}
m->m_len -= hlen;
m->m_data += hlen;
- icp = mtod(m, struct icmp *);
+ icp = MBUF_TO(m, struct icmp *);
if (cksum(m, icmplen)) {
icmpstat.icps_checksum++;
goto freeit;
}
m->m_len += hlen;
m->m_data -= hlen;
-
+
/* icmpstat.icps_inhist[icp->icmp_type]++; */
/* code = icp->icmp_code; */
@@ -121,10 +121,10 @@ icmp_input(m, hlen)
struct sockaddr_in addr;
if ((so = socreate()) == NULL) goto freeit;
if(udp_attach(so) == -1) {
- DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
+ DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n",
errno,strerror(errno)));
sofree(so);
- m_free(m);
+ mbuf_free(m);
goto end_error;
}
so->so_m = m;
@@ -135,20 +135,17 @@ icmp_input(m, hlen)
so->so_iptos = ip->ip_tos;
so->so_type = IPPROTO_ICMP;
so->so_state = SS_ISFCONNECTED;
-
+
/* Send the packet */
addr.sin_family = AF_INET;
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
/* It's an alias */
- switch(ntohl(so->so_faddr.s_addr) & 0xff) {
- case CTL_DNS:
- addr.sin_addr = dns_addr;
- break;
- case CTL_ALIAS:
- default:
- addr.sin_addr = loopback_addr;
- break;
- }
+ int low = ntohl(so->so_faddr.s_addr) & 0xff;
+
+ if (low >= CTL_DNS && low < CTL_DNS + dns_addr_count)
+ addr.sin_addr = dns_addr[low - CTL_DNS];
+ else
+ addr.sin_addr = loopback_addr;
} else {
addr.sin_addr = so->so_faddr;
}
@@ -157,7 +154,7 @@ icmp_input(m, hlen)
(struct sockaddr *)&addr, sizeof(addr)) == -1) {
DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n",
errno,strerror(errno)));
- icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
+ icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
udp_detach(so);
}
} /* if ip->ip_dst.s_addr == alias_addr.s_addr */
@@ -171,16 +168,16 @@ icmp_input(m, hlen)
case ICMP_MASKREQ:
case ICMP_REDIRECT:
icmpstat.icps_notsupp++;
- m_freem(m);
+ mbuf_free(m);
break;
-
+
default:
icmpstat.icps_badtype++;
- m_freem(m);
+ mbuf_free(m);
} /* swith */
end_error:
- /* m is m_free()'d xor put in a socket xor or given to ip_send */
+ /* m is mbuf_free()'d xor put in a socket xor or given to ip_send */
return;
}
@@ -196,17 +193,17 @@ end_error:
*/
/*
* Send ICMP_UNREACH back to the source regarding msrc.
- * mbuf *msrc is used as a template, but is NOT m_free()'d.
+ * mbuf *msrc is used as a template, but is NOT mbuf_free()'d.
* It is reported as the bad ip packet. The header should
* be fully correct and in host byte order.
- * ICMP fragmentation is illegal. All machines must accept 576 bytes in one
+ * ICMP fragmentation is illegal. All machines must accept 576 bytes in one
* packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548
*/
#define ICMP_MAXDATALEN (IP_MSS-28)
void
icmp_error(msrc, type, code, minsize, message)
- struct mbuf *msrc;
+ MBuf msrc;
u_char type;
u_char code;
int minsize;
@@ -215,7 +212,7 @@ icmp_error(msrc, type, code, minsize, message)
unsigned hlen, shlen, s_ip_len;
register struct ip *ip;
register struct icmp *icp;
- register struct mbuf *m;
+ register MBuf m;
DEBUG_CALL("icmp_error");
DEBUG_ARG("msrc = %lx", (long )msrc);
@@ -225,8 +222,8 @@ icmp_error(msrc, type, code, minsize, message)
/* check msrc */
if(!msrc) goto end_error;
- ip = mtod(msrc, struct ip *);
-#if DEBUG
+ ip = MBUF_TO(msrc, struct ip *);
+#if DEBUG
{ char bufa[20], bufb[20];
strcpy(bufa, inet_ntoa(ip->ip_src));
strcpy(bufb, inet_ntoa(ip->ip_dst));
@@ -247,29 +244,29 @@ icmp_error(msrc, type, code, minsize, message)
}
/* make a copy */
- if(!(m=m_get())) goto end_error; /* get mbuf */
+ if(!(m=mbuf_alloc())) goto end_error; /* get mbuf */
{ int new_m_size;
new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN;
- if(new_m_size>m->m_size) m_inc(m, new_m_size);
+ if(new_m_size>m->m_size) mbuf_ensure(m, new_m_size);
}
memcpy(m->m_data, msrc->m_data, msrc->m_len);
m->m_len = msrc->m_len; /* copy msrc to m */
/* make the header of the reply packet */
- ip = mtod(m, struct ip *);
+ ip = MBUF_TO(m, struct ip *);
hlen= sizeof(struct ip ); /* no options in reply */
-
+
/* fill in icmp */
- m->m_data += hlen;
+ m->m_data += hlen;
m->m_len -= hlen;
- icp = mtod(m, struct icmp *);
+ icp = MBUF_TO(m, struct icmp *);
if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */
else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */
s_ip_len=ICMP_MAXDATALEN;
- m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */
+ m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */
/* min. size = 8+sizeof(struct ip)+8 */
@@ -304,7 +301,7 @@ icmp_error(msrc, type, code, minsize, message)
/* fill in ip */
ip->ip_hl = hlen >> 2;
ip->ip_len = m->m_len;
-
+
ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */
ip->ip_ttl = MAXTTL;
@@ -313,7 +310,7 @@ icmp_error(msrc, type, code, minsize, message)
ip->ip_src = alias_addr;
(void ) ip_output((struct socket *)NULL, m);
-
+
icmpstat.icps_reflect++;
end_error:
@@ -326,9 +323,9 @@ end_error:
*/
void
icmp_reflect(m)
- struct mbuf *m;
+ MBuf m;
{
- register struct ip *ip = mtod(m, struct ip *);
+ register struct ip *ip = MBUF_TO(m, struct ip *);
int hlen = ip->ip_hl << 2;
int optlen = hlen - sizeof(struct ip );
register struct icmp *icp;
@@ -339,7 +336,7 @@ icmp_reflect(m)
*/
m->m_data += hlen;
m->m_len -= hlen;
- icp = mtod(m, struct icmp *);
+ icp = MBUF_TO(m, struct icmp *);
icp->icmp_cksum = 0;
icp->icmp_cksum = cksum(m, ip->ip_len - hlen);
diff --git a/slirp/ip_icmp.h b/slirp/ip_icmp.h
index 8c9b5a1..42740db 100644
--- a/slirp/ip_icmp.h
+++ b/slirp/ip_icmp.h
@@ -157,8 +157,8 @@ struct icmp {
(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
-void icmp_input _P((struct mbuf *, int));
-void icmp_error _P((struct mbuf *, u_char, u_char, int, char *));
-void icmp_reflect _P((struct mbuf *));
+void icmp_input _P((MBuf , int));
+void icmp_error _P((MBuf , u_char, u_char, int, char *));
+void icmp_reflect _P((MBuf ));
#endif
diff --git a/slirp/ip_input.c b/slirp/ip_input.c
index 4f5bfd9..cc320de 100644
--- a/slirp/ip_input.c
+++ b/slirp/ip_input.c
@@ -69,7 +69,7 @@ ip_init()
*/
void
ip_input(m)
- struct mbuf *m;
+ MBuf m;
{
register struct ip *ip;
int hlen;
@@ -85,7 +85,7 @@ ip_input(m)
return;
}
- ip = mtod(m, struct ip *);
+ ip = MBUF_TO(m, struct ip *);
if (ip->ip_v != IPVERSION) {
ipstat.ips_badvers++;
@@ -130,7 +130,7 @@ ip_input(m)
}
/* Should drop packet if mbuf too long? hmmm... */
if (m->m_len > ip->ip_len)
- m_adj(m, ip->ip_len - m->m_len);
+ mbuf_trim(m, ip->ip_len - m->m_len);
/* check ip_ttl for a correct ICMP reply */
if(ip->ip_ttl==0 || ip->ip_ttl==1) {
@@ -197,7 +197,7 @@ ip_input(m)
if (ip == 0)
return;
ipstat.ips_reassembled++;
- m = dtom(ip);
+ m = MBUF_FROM(ip);
} else
if (fp)
ip_freef(fp);
@@ -221,11 +221,11 @@ ip_input(m)
break;
default:
ipstat.ips_noproto++;
- m_free(m);
+ mbuf_free(m);
}
return;
bad:
- m_freem(m);
+ mbuf_free(m);
return;
}
@@ -240,7 +240,7 @@ ip_reass(ip, fp)
register struct ipasfrag *ip;
register struct ipq *fp;
{
- register struct mbuf *m = dtom(ip);
+ register MBuf m = MBUF_FROM(ip);
register struct ipasfrag *q;
int hlen = ip->ip_hl << 2;
int i, next;
@@ -262,9 +262,9 @@ ip_reass(ip, fp)
* If first fragment to arrive, create a reassembly queue.
*/
if (fp == 0) {
- struct mbuf *t;
- if ((t = m_get()) == NULL) goto dropfrag;
- fp = mtod(t, struct ipq *);
+ MBuf t;
+ if ((t = mbuf_alloc()) == NULL) goto dropfrag;
+ fp = MBUF_TO(t, struct ipq *);
insque_32(fp, &ipq);
fp->ipq_ttl = IPFRAGTTL;
fp->ipq_p = ip->ip_p;
@@ -295,7 +295,7 @@ ip_reass(ip, fp)
if (i > 0) {
if (i >= ip->ip_len)
goto dropfrag;
- m_adj(dtom(ip), i);
+ mbuf_trim(MBUF_FROM(ip), i);
ip->ip_off += i;
ip->ip_len -= i;
}
@@ -310,11 +310,11 @@ ip_reass(ip, fp)
if (i < q->ip_len) {
q->ip_len -= i;
q->ip_off += i;
- m_adj(dtom(q), i);
+ mbuf_trim(MBUF_FROM(q), i);
break;
}
q = (struct ipasfrag *) q->ipf_next;
- m_freem(dtom((struct ipasfrag *) q->ipf_prev));
+ mbuf_free(MBUF_FROM((struct ipasfrag *) q->ipf_prev));
ip_deq((struct ipasfrag *) q->ipf_prev);
}
@@ -338,14 +338,14 @@ insert:
* Reassembly is complete; concatenate fragments.
*/
q = (struct ipasfrag *) fp->ipq_next;
- m = dtom(q);
+ m = MBUF_FROM(q);
q = (struct ipasfrag *) q->ipf_next;
while (q != (struct ipasfrag *)fp) {
- struct mbuf *t;
- t = dtom(q);
+ MBuf t;
+ t = MBUF_FROM(q);
q = (struct ipasfrag *) q->ipf_next;
- m_cat(m, t);
+ mbuf_append(m, t);
}
/*
@@ -377,8 +377,8 @@ insert:
((struct ip *)ip)->ip_src = fp->ipq_src;
((struct ip *)ip)->ip_dst = fp->ipq_dst;
remque_32(fp);
- (void) m_free(dtom(fp));
- m = dtom(ip);
+ (void) mbuf_free(MBUF_FROM(fp));
+ m = MBUF_FROM(ip);
m->m_len += (ip->ip_hl << 2);
m->m_data -= (ip->ip_hl << 2);
@@ -386,7 +386,7 @@ insert:
dropfrag:
ipstat.ips_fragdropped++;
- m_freem(m);
+ mbuf_free(m);
return (0);
}
@@ -404,10 +404,10 @@ ip_freef(fp)
q = p) {
p = (struct ipasfrag *) q->ipf_next;
ip_deq(q);
- m_freem(dtom(q));
+ mbuf_free(MBUF_FROM(q));
}
remque_32(fp);
- (void) m_free(dtom(fp));
+ (void) mbuf_free(MBUF_FROM(fp));
}
/*
@@ -475,9 +475,9 @@ ip_slowtimo()
int
ip_dooptions(m)
- struct mbuf *m;
+ MBuf m;
{
- register struct ip *ip = mtod(m, struct ip *);
+ register struct ip *ip = MBUF_TO(m, struct ip *);
register u_char *cp;
register struct ip_timestamp *ipt;
register struct in_ifaddr *ia;
@@ -679,11 +679,11 @@ bad:
*/
void
ip_stripoptions(m, mopt)
- register struct mbuf *m;
- struct mbuf *mopt;
+ register MBuf m;
+ MBuf mopt;
{
register int i;
- struct ip *ip = mtod(m, struct ip *);
+ struct ip *ip = MBUF_TO(m, struct ip *);
register caddr_t opts;
int olen;
diff --git a/slirp/ip_output.c b/slirp/ip_output.c
index f3dc9b7..42d789c 100644
--- a/slirp/ip_output.c
+++ b/slirp/ip_output.c
@@ -55,10 +55,10 @@ u_int16_t ip_id;
int
ip_output(so, m0)
struct socket *so;
- struct mbuf *m0;
+ MBuf m0;
{
register struct ip *ip;
- register struct mbuf *m = m0;
+ register MBuf m = m0;
register int hlen = sizeof(struct ip );
int len, off, error = 0;
@@ -72,7 +72,7 @@ ip_output(so, m0)
* hlen = len;
* }
*/
- ip = mtod(m, struct ip *);
+ ip = MBUF_TO(m, struct ip *);
/*
* Fill in IP header.
*/
@@ -124,7 +124,7 @@ ip_output(so, m0)
{
int mhlen, firstlen = len;
- struct mbuf **mnext = &m->m_nextpkt;
+ MBuf *mnext = &m->m_nextpkt;
/*
* Loop through length of segment after first fragment,
@@ -134,14 +134,14 @@ ip_output(so, m0)
mhlen = sizeof (struct ip);
for (off = hlen + len; off < (u_int16_t)ip->ip_len; off += len) {
register struct ip *mhip;
- m = m_get();
+ m = mbuf_alloc();
if (m == 0) {
error = -1;
ipstat.ips_odropped++;
goto sendorfree;
}
m->m_data += if_maxlinkhdr;
- mhip = mtod(m, struct ip *);
+ mhip = MBUF_TO(m, struct ip *);
*mhip = *ip;
/* No options */
@@ -160,7 +160,7 @@ ip_output(so, m0)
mhip->ip_off |= IP_MF;
mhip->ip_len = htons((u_int16_t)(len + mhlen));
- if (m_copy(m, m0, off, len) < 0) {
+ if (mbuf_copy(m, m0, off, len) < 0) {
error = -1;
goto sendorfree;
}
@@ -177,7 +177,7 @@ ip_output(so, m0)
* and updating header, then send each fragment (in order).
*/
m = m0;
- m_adj(m, hlen + firstlen - (u_int16_t)ip->ip_len);
+ mbuf_trim(m, hlen + firstlen - (u_int16_t)ip->ip_len);
ip->ip_len = htons((u_int16_t)m->m_len);
ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF));
ip->ip_sum = 0;
@@ -189,7 +189,7 @@ sendorfree:
if (error == 0)
if_output(so, m);
else
- m_freem(m);
+ mbuf_free(m);
}
if (error == 0)
@@ -200,6 +200,6 @@ done:
return (error);
bad:
- m_freem(m0);
+ mbuf_free(m0);
goto done;
}
diff --git a/slirp/libslirp.h b/slirp/libslirp.h
index a9260af..3ce34b7 100644
--- a/slirp/libslirp.h
+++ b/slirp/libslirp.h
@@ -1,6 +1,7 @@
#ifndef _LIBSLIRP_H
#define _LIBSLIRP_H
+#include <stdint.h>
#ifdef _WIN32
#include <winsock2.h>
int inet_aton(const char *cp, struct in_addr *ia);
@@ -15,7 +16,7 @@ extern "C" {
void slirp_init(void);
-void slirp_select_fill(int *pnfds,
+void slirp_select_fill(int *pnfds,
fd_set *readfds, fd_set *writefds, fd_set *xfds);
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds);
@@ -26,10 +27,13 @@ void slirp_input(const uint8_t *pkt, int pkt_len);
int slirp_can_output(void);
void slirp_output(const uint8_t *pkt, int pkt_len);
-int slirp_redir(int is_udp, int host_port,
+int slirp_redir(int is_udp, int host_port,
struct in_addr guest_addr, int guest_port);
-int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
- int guest_port);
+
+int slirp_unredir(int is_udp, int host_port);
+
+int slirp_add_dns_server(struct in_addr dns_addr);
+int slirp_get_system_dns_servers(void);
extern const char *tftp_prefix;
extern char slirp_hostname[33];
diff --git a/slirp/main.h b/slirp/main.h
index 181b6ae..49dad00 100644
--- a/slirp/main.h
+++ b/slirp/main.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
+ *
+ * Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
@@ -28,6 +28,8 @@ extern int ctty_closed;
*/
#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y)
+#define DNS_ADDR_MAX 4
+
extern char *slirp_tty;
extern char *exec_shell;
extern u_int curtime;
@@ -37,7 +39,8 @@ extern struct in_addr special_addr;
extern struct in_addr alias_addr;
extern struct in_addr our_addr;
extern struct in_addr loopback_addr;
-extern struct in_addr dns_addr;
+extern struct in_addr dns_addr[DNS_ADDR_MAX];
+extern int dns_addr_count;
extern char *username;
extern char *socket_path;
extern int towrite_max;
diff --git a/slirp/mbuf.c b/slirp/mbuf.c
index 3769baf..efc8141 100644
--- a/slirp/mbuf.c
+++ b/slirp/mbuf.c
@@ -17,16 +17,28 @@
#include <slirp.h>
-struct mbuf *mbutl;
-char *mclrefcnt;
-int mbuf_alloced = 0;
-struct mbuf m_freelist, m_usedlist;
-int mbuf_thresh = 30;
-int mbuf_max = 0;
-int msize;
+static int mbuf_alloced = 0;
+static MBufRec m_freelist, m_usedlist;
+static int mbuf_thresh = 30;
+static int mbuf_max = 0;
+static int msize;
+
+/*
+ * How much room is in the mbuf, from m_data to the end of the mbuf
+ */
+#define M_ROOM(m) ((m->m_flags & M_EXT)? \
+ (((m)->m_ext + (m)->m_size) - (m)->m_data) \
+ : \
+ (((m)->m_dat + (m)->m_size) - (m)->m_data))
+
+/*
+ * How much free room there is
+ */
+#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
+
void
-m_init()
+mbuf_init()
{
m_freelist.m_next = m_freelist.m_prev = &m_freelist;
m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist;
@@ -40,10 +52,27 @@ msize_init()
* Find a nice value for msize
* XXX if_maxlinkhdr already in mtu
*/
- msize = (if_mtu>if_mru?if_mtu:if_mru) +
+ msize = (if_mtu > if_mru ? if_mtu : if_mru) +
if_maxlinkhdr + sizeof(struct m_hdr ) + 6;
}
+static void
+mbuf_insque(MBuf m, MBuf head)
+{
+ m->m_next = head->m_next;
+ m->m_prev = head;
+ head->m_next = m;
+ m->m_next->m_prev = m;
+}
+
+static void
+mbuf_remque(MBuf m)
+{
+ m->m_prev->m_next = m->m_next;
+ m->m_next->m_prev = m->m_prev;
+ m->m_next = m->m_prev = m;
+}
+
/*
* Get an mbuf from the free list, if there are none
* malloc one
@@ -52,16 +81,16 @@ msize_init()
* free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE,
* which tells m_free to actually free() it
*/
-struct mbuf *
-m_get()
+MBuf
+mbuf_alloc(void)
{
- register struct mbuf *m;
+ register MBuf m;
int flags = 0;
- DEBUG_CALL("m_get");
+ DEBUG_CALL("mbuf_alloc");
if (m_freelist.m_next == &m_freelist) {
- m = (struct mbuf *)malloc(msize);
+ m = (MBuf) malloc(msize);
if (m == NULL) goto end_error;
mbuf_alloced++;
if (mbuf_alloced > mbuf_thresh)
@@ -70,36 +99,35 @@ m_get()
mbuf_max = mbuf_alloced;
} else {
m = m_freelist.m_next;
- remque(m);
+ mbuf_remque(m);
}
/* Insert it in the used list */
- insque(m,&m_usedlist);
+ mbuf_insque(m,&m_usedlist);
m->m_flags = (flags | M_USEDLIST);
/* Initialise it */
- m->m_size = msize - sizeof(struct m_hdr);
- m->m_data = m->m_dat;
- m->m_len = 0;
- m->m_nextpkt = 0;
- m->m_prevpkt = 0;
+ m->m_size = msize - sizeof(struct m_hdr);
+ m->m_data = m->m_dat;
+ m->m_len = 0;
+ m->m_next2 = NULL;
+ m->m_prev2 = NULL;
end_error:
DEBUG_ARG("m = %lx", (long )m);
return m;
}
void
-m_free(m)
- struct mbuf *m;
+mbuf_free(MBuf m)
{
- DEBUG_CALL("m_free");
+ DEBUG_CALL("mbuf_free");
DEBUG_ARG("m = %lx", (long )m);
if(m) {
/* Remove from m_usedlist */
if (m->m_flags & M_USEDLIST)
- remque(m);
+ mbuf_remque(m);
/* If it's M_EXT, free() it */
if (m->m_flags & M_EXT)
@@ -112,7 +140,7 @@ m_free(m)
free(m);
mbuf_alloced--;
} else if ((m->m_flags & M_FREELIST) == 0) {
- insque(m,&m_freelist);
+ mbuf_insque(m,&m_freelist);
m->m_flags = M_FREELIST; /* Clobber other flags */
}
} /* if(m) */
@@ -124,74 +152,62 @@ m_free(m)
* an M_EXT data segment
*/
void
-m_cat(m, n)
- register struct mbuf *m, *n;
+mbuf_append(MBuf m, MBuf n)
{
/*
* If there's no room, realloc
*/
if (M_FREEROOM(m) < n->m_len)
- m_inc(m,m->m_size+MINCSIZE);
+ mbuf_ensure(m, m->m_size+MINCSIZE);
memcpy(m->m_data+m->m_len, n->m_data, n->m_len);
m->m_len += n->m_len;
- m_free(n);
+ mbuf_free(n);
}
/* make m size bytes large */
void
-m_inc(m, size)
- struct mbuf *m;
- int size;
+mbuf_ensure(MBuf m, int size)
{
int datasize;
/* some compiles throw up on gotos. This one we can fake. */
- if(m->m_size>size) return;
-
- if (m->m_flags & M_EXT) {
- datasize = m->m_data - m->m_ext;
- m->m_ext = (char *)realloc(m->m_ext,size);
-/* if (m->m_ext == NULL)
- * return (struct mbuf *)NULL;
- */
- m->m_data = m->m_ext + datasize;
- } else {
- char *dat;
- datasize = m->m_data - m->m_dat;
- dat = (char *)malloc(size);
-/* if (dat == NULL)
- * return (struct mbuf *)NULL;
- */
- memcpy(dat, m->m_dat, m->m_size);
-
- m->m_ext = dat;
- m->m_data = m->m_ext + datasize;
- m->m_flags |= M_EXT;
- }
-
- m->m_size = size;
+ if(m->m_size > size) return;
+
+ if (m->m_flags & M_EXT) {
+ datasize = m->m_data - m->m_ext;
+ m->m_ext = (char *)realloc(m->m_ext,size);
+ m->m_data = m->m_ext + datasize;
+ } else {
+ char *dat;
+ datasize = m->m_data - m->m_dat;
+ dat = (char *)malloc(size);
+ memcpy(dat, m->m_dat, m->m_size);
+ m->m_ext = dat;
+ m->m_data = m->m_ext + datasize;
+ m->m_flags |= M_EXT;
+ }
+
+ m->m_size = size;
}
void
-m_adj(m, len)
- struct mbuf *m;
- int len;
+mbuf_trim(MBuf m, int len)
{
if (m == NULL)
return;
if (len >= 0) {
/* Trim from head */
m->m_data += len;
- m->m_len -= len;
+ m->m_len -= len;
} else {
/* Trim from tail */
- len = -len;
+ len = -len;
m->m_len -= len;
}
}
@@ -201,9 +217,7 @@ m_adj(m, len)
* Copy len bytes from m, starting off bytes into n
*/
int
-m_copy(n, m, off, len)
- struct mbuf *n, *m;
- int off, len;
+mbuf_copy(MBuf n, MBuf m, int off, int len)
{
if (len > M_FREEROOM(n))
return -1;
@@ -213,34 +227,61 @@ m_copy(n, m, off, len)
return 0;
}
+int
+mbuf_freeroom( MBuf m )
+{
+ return M_FREEROOM(m);
+}
/*
* Given a pointer into an mbuf, return the mbuf
* XXX This is a kludge, I should eliminate the need for it
* Fortunately, it's not used often
*/
-struct mbuf *
-dtom(dat)
- void *dat;
+MBuf
+mbuf_from(void* dat)
{
- struct mbuf *m;
+ MBuf m;
- DEBUG_CALL("dtom");
+ DEBUG_CALL("mbuf_from");
DEBUG_ARG("dat = %lx", (long )dat);
/* bug corrected for M_EXT buffers */
for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) {
if (m->m_flags & M_EXT) {
- if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) )
- return m;
+ if( (unsigned)((char*)dat - m->m_ext) < (unsigned)m->m_size )
+ goto Exit;
} else {
- if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) )
- return m;
+ if( (unsigned)((char *)dat - m->m_dat) < (unsigned)m->m_size )
+ goto Exit;
}
}
+ m = NULL;
+ DEBUG_ERROR((dfd, "mbuf_from failed"));
+Exit:
+ return m;
+}
+
+void
+mbufstats()
+{
+ MBuf m;
+ int i;
- DEBUG_ERROR((dfd, "dtom failed"));
+ lprint(" \r\n");
- return (struct mbuf *)0;
-}
+ lprint("Mbuf stats:\r\n");
+ lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max);
+
+ i = 0;
+ for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next)
+ i++;
+ lprint(" %6d mbufs on free list\r\n", i);
+
+ i = 0;
+ for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next)
+ i++;
+ lprint(" %6d mbufs on used list\r\n", i);
+ lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued);
+}
diff --git a/slirp/mbuf.h b/slirp/mbuf.h
index 8cc292b..ed83372 100644
--- a/slirp/mbuf.h
+++ b/slirp/mbuf.h
@@ -37,111 +37,85 @@
#ifndef _MBUF_H_
#define _MBUF_H_
-#define m_freem m_free
-
-
#define MINCSIZE 4096 /* Amount to increase mbuf if too small */
-/*
- * Macros for type conversion
- * mtod(m,t) - convert mbuf pointer to data pointer of correct type
- * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX)
- */
-#define mtod(m,t) ((t)(m)->m_data)
-/* #define dtom(x) ((struct mbuf *)((int)(x) & ~(M_SIZE-1))) */
+/* flags for the mh_flags field */
+#define M_EXT 0x01 /* m_ext points to more (malloced) data */
+#define M_FREELIST 0x02 /* mbuf is on free list */
+#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */
+#define M_DOFREE 0x08 /* when mbuf_free is called on the mbuf, free()
+ * it rather than putting it on the free list */
+
/* XXX About mbufs for slirp:
* Only one mbuf is ever used in a chain, for each "cell" of data.
* m_nextpkt points to the next packet, if fragmented.
* If the data is too large, the M_EXT is used, and a larger block
- * is alloced. Therefore, m_free[m] must check for M_EXT and if set
+ * is alloced. Therefore, mbuf_free[m] must check for M_EXT and if set
* free the m_ext. This is inefficient memory-wise, but who cares.
*/
/* XXX should union some of these! */
/* header at beginning of each mbuf: */
-struct m_hdr {
- struct mbuf *mh_next; /* Linked list of mbufs */
- struct mbuf *mh_prev;
- struct mbuf *mh_nextpkt; /* Next packet in queue/record */
- struct mbuf *mh_prevpkt; /* Flags aren't used in the output queue */
- int mh_flags; /* Misc flags */
-
- int mh_size; /* Size of data */
- struct socket *mh_so;
-
- caddr_t mh_data; /* Location of data */
- int mh_len; /* Amount of data in this mbuf */
-};
-/*
- * How much room is in the mbuf, from m_data to the end of the mbuf
+/**
+ * m_next, m_prev :: used to place the MBuf in free/used linked lists
+ * m_next2, m_prev2 :: used to place the same MBuf in other linked lists
+ * m_flags :: bit flags describing this MBuf
+ * m_size :: total size of MBuf buffer
+ * m_so :: socket this MBuf is attached to
+ * m_data :: pointer to current cursor in MBuf buffer
+ * m_len :: amount of data recorded in this MBuf
*/
-#define M_ROOM(m) ((m->m_flags & M_EXT)? \
- (((m)->m_ext + (m)->m_size) - (m)->m_data) \
- : \
- (((m)->m_dat + (m)->m_size) - (m)->m_data))
+#define MBUF_HEADER \
+ struct mbuf* m_next; \
+ struct mbuf* m_prev; \
+ struct mbuf* m_next2; \
+ struct mbuf* m_prev2; \
+ int m_flags; \
+ int m_size; \
+ struct socket* m_so; \
+ caddr_t m_data; \
+ int m_len;
-/*
- * How much free room there is
- */
-#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len)
-#define M_TRAILINGSPACE M_FREEROOM
+struct m_hdr {
+ MBUF_HEADER
+};
-struct mbuf {
- struct m_hdr m_hdr;
+typedef struct mbuf {
+ MBUF_HEADER
union M_dat {
- char m_dat_[1]; /* ANSI don't like 0 sized arrays */
- char *m_ext_;
+ char m_dat_[1]; /* ANSI doesn't like 0 sized arrays */
+ char* m_ext_;
} M_dat;
-};
+} MBufRec, *MBuf;
-#define m_next m_hdr.mh_next
-#define m_prev m_hdr.mh_prev
-#define m_nextpkt m_hdr.mh_nextpkt
-#define m_prevpkt m_hdr.mh_prevpkt
-#define m_flags m_hdr.mh_flags
-#define m_len m_hdr.mh_len
-#define m_data m_hdr.mh_data
-#define m_size m_hdr.mh_size
+#define m_nextpkt m_next2
+#define m_prevpkt m_prev2
#define m_dat M_dat.m_dat_
#define m_ext M_dat.m_ext_
-#define m_so m_hdr.mh_so
#define ifq_prev m_prev
#define ifq_next m_next
-#define ifs_prev m_prevpkt
-#define ifs_next m_nextpkt
-#define ifq_so m_so
-#define M_EXT 0x01 /* m_ext points to more (malloced) data */
-#define M_FREELIST 0x02 /* mbuf is on free list */
-#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */
-#define M_DOFREE 0x08 /* when m_free is called on the mbuf, free()
- * it rather than putting it on the free list */
+#define ifs_prev m_prev2
+#define ifs_next m_next2
-/*
- * Mbuf statistics. XXX
- */
+#define ifq_so m_so
-struct mbstat {
- int mbs_alloced; /* Number of mbufs allocated */
-
-};
+void mbuf_init (void);
+void msize_init (void);
+MBuf mbuf_alloc (void);
+void mbuf_free (MBuf m);
+void mbuf_append(MBuf m1, MBuf m2);
+void mbuf_ensure(MBuf m, int size);
+void mbuf_trim (MBuf m, int len);
+int mbuf_copy (MBuf m, MBuf n, int n_offset, int n_length);
+
+#define MBUF_TO(m,t) ((t)(m)->m_data)
+#define MBUF_FROM(d) mbuf_from(d)
+MBuf mbuf_from (void *);
-extern struct mbstat mbstat;
-extern int mbuf_alloced;
-extern struct mbuf m_freelist, m_usedlist;
-extern int mbuf_max;
-
-void m_init _P((void));
-void msize_init _P((void));
-struct mbuf * m_get _P((void));
-void m_free _P((struct mbuf *));
-void m_cat _P((register struct mbuf *, register struct mbuf *));
-void m_inc _P((struct mbuf *, int));
-void m_adj _P((struct mbuf *, int));
-int m_copy _P((struct mbuf *, struct mbuf *, int, int));
-struct mbuf * dtom _P((void *));
+int mbuf_freeroom( MBuf m );
#endif
diff --git a/slirp/misc.c b/slirp/misc.c
index 2c42fd1..beffeee 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -1,77 +1,22 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
- *
+ *
* Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
#define WANT_SYS_IOCTL_H
#include <slirp.h>
+#define SLIRP_COMPILATION
+#include "sockets.h"
u_int curtime, time_fasttimo, last_slowtimo, detach_time;
u_int detach_wait = 600000; /* 10 minutes */
-
-#if 0
-int x_port = -1;
-int x_display = 0;
-int x_screen = 0;
-
-int
-show_x(buff, inso)
- char *buff;
- struct socket *inso;
-{
- if (x_port < 0) {
- lprint("X Redir: X not being redirected.\r\n");
- } else {
- lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n",
- inet_ntoa(our_addr), x_port, x_screen);
- lprint("X Redir: In csh/tcsh/etc. type: setenv DISPLAY %s:%d.%d\r\n",
- inet_ntoa(our_addr), x_port, x_screen);
- if (x_display)
- lprint("X Redir: Redirecting to display %d\r\n", x_display);
- }
-
- return CFG_OK;
-}
-
-
-/*
- * XXX Allow more than one X redirection?
- */
-void
-redir_x(inaddr, start_port, display, screen)
- u_int32_t inaddr;
- int start_port;
- int display;
- int screen;
-{
- int i;
-
- if (x_port >= 0) {
- lprint("X Redir: X already being redirected.\r\n");
- show_x(0, 0);
- } else {
- for (i = 6001 + (start_port-1); i <= 6100; i++) {
- if (solisten(htons(i), inaddr, htons(6000 + display), 0)) {
- /* Success */
- x_port = i - 6000;
- x_display = display;
- x_screen = screen;
- show_x(0, 0);
- return;
- }
- }
- lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n");
- }
-}
-#endif
+struct emu_t *tcpemu;
#ifndef HAVE_INET_ATON
int
-inet_aton(cp, ia)
- const char *cp;
- struct in_addr *ia;
+inet_aton(const char* cp, struct in_addr* ia)
{
u_int32_t addr = inet_addr(cp);
if (addr == 0xffffffff)
@@ -89,7 +34,7 @@ getouraddr()
{
char buff[256];
struct hostent *he = NULL;
-
+
if (gethostname(buff,256) == 0)
he = gethostbyname(buff);
if (he)
@@ -106,9 +51,7 @@ struct quehead_32 {
};
inline void
-insque_32(a, b)
- void *a;
- void *b;
+insque_32(void* a, void* b)
{
register struct quehead_32 *element = (struct quehead_32 *) a;
register struct quehead_32 *head = (struct quehead_32 *) b;
@@ -120,8 +63,7 @@ insque_32(a, b)
}
inline void
-remque_32(a)
- void *a;
+remque_32(void* a)
{
register struct quehead_32 *element = (struct quehead_32 *) a;
((struct quehead_32 *)(element->qh_link))->qh_rlink = element->qh_rlink;
@@ -137,8 +79,7 @@ struct quehead {
};
inline void
-insque(a, b)
- void *a, *b;
+insque(void* a, void* b)
{
register struct quehead *element = (struct quehead *) a;
register struct quehead *head = (struct quehead *) b;
@@ -150,8 +91,7 @@ insque(a, b)
}
inline void
-remque(a)
- void *a;
+remque(void* a)
{
register struct quehead *element = (struct quehead *) a;
((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink;
@@ -163,32 +103,6 @@ remque(a)
/* #endif */
-int
-add_exec(ex_ptr, do_pty, exec, addr, port)
- struct ex_list **ex_ptr;
- int do_pty;
- char *exec;
- int addr;
- int port;
-{
- struct ex_list *tmp_ptr;
-
- /* First, check if the port is "bound" */
- for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) {
- if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr)
- return -1;
- }
-
- tmp_ptr = *ex_ptr;
- *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list));
- (*ex_ptr)->ex_fport = port;
- (*ex_ptr)->ex_addr = addr;
- (*ex_ptr)->ex_pty = do_pty;
- (*ex_ptr)->ex_exec = strdup(exec);
- (*ex_ptr)->ex_next = tmp_ptr;
- return 0;
-}
-
#ifndef HAVE_STRERROR
/*
@@ -199,8 +113,7 @@ extern int sys_nerr;
extern char *sys_errlist[];
char *
-strerror(error)
- int error;
+strerror(int error)
{
if (error < sys_nerr)
return sys_errlist[error];
@@ -211,453 +124,45 @@ strerror(error)
#endif
-#ifdef _WIN32
-
-int
-fork_exec(so, ex, do_pty)
- struct socket *so;
- char *ex;
- int do_pty;
-{
- /* not implemented */
- return 0;
-}
-
-#else
-
-int
-slirp_openpty(amaster, aslave)
- int *amaster, *aslave;
-{
- register int master, slave;
-
-#ifdef HAVE_GRANTPT
- char *ptr;
-
- if ((master = open("/dev/ptmx", O_RDWR)) < 0 ||
- grantpt(master) < 0 ||
- unlockpt(master) < 0 ||
- (ptr = ptsname(master)) == NULL) {
- close(master);
- return -1;
- }
-
- if ((slave = open(ptr, O_RDWR)) < 0 ||
- ioctl(slave, I_PUSH, "ptem") < 0 ||
- ioctl(slave, I_PUSH, "ldterm") < 0 ||
- ioctl(slave, I_PUSH, "ttcompat") < 0) {
- close(master);
- close(slave);
- return -1;
- }
-
- *amaster = master;
- *aslave = slave;
- return 0;
-
-#else
-
- static char line[] = "/dev/ptyXX";
- register const char *cp1, *cp2;
-
- for (cp1 = "pqrsPQRS"; *cp1; cp1++) {
- line[8] = *cp1;
- for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) {
- line[9] = *cp2;
- if ((master = open(line, O_RDWR, 0)) == -1) {
- if (errno == ENOENT)
- return (-1); /* out of ptys */
- } else {
- line[5] = 't';
- /* These will fail */
- (void) chown(line, getuid(), 0);
- (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
-#ifdef HAVE_REVOKE
- (void) revoke(line);
-#endif
- if ((slave = open(line, O_RDWR, 0)) != -1) {
- *amaster = master;
- *aslave = slave;
- return 0;
- }
- (void) close(master);
- line[5] = 'p';
- }
- }
- }
- errno = ENOENT; /* out of ptys */
- return (-1);
-#endif
-}
-
-/*
- * XXX This is ugly
- * We create and bind a socket, then fork off to another
- * process, which connects to this socket, after which we
- * exec the wanted program. If something (strange) happens,
- * the accept() call could block us forever.
- *
- * do_pty = 0 Fork/exec inetd style
- * do_pty = 1 Fork/exec using slirp.telnetd
- * do_ptr = 2 Fork/exec using pty
- */
-int
-fork_exec(so, ex, do_pty)
- struct socket *so;
- char *ex;
- int do_pty;
-{
- int s;
- struct sockaddr_in addr;
- int addrlen = sizeof(addr);
- int opt;
- int master;
- char *argv[256];
-#if 0
- char buff[256];
-#endif
- /* don't want to clobber the original */
- char *bptr;
- char *curarg;
- int c, i, ret;
-
- DEBUG_CALL("fork_exec");
- DEBUG_ARG("so = %lx", (long)so);
- DEBUG_ARG("ex = %lx", (long)ex);
- DEBUG_ARG("do_pty = %lx", (long)do_pty);
-
- if (do_pty == 2) {
- if (slirp_openpty(&master, &s) == -1) {
- lprint("Error: openpty failed: %s\n", strerror(errno));
- return 0;
- }
- } else {
- addr.sin_family = AF_INET;
- addr.sin_port = 0;
- addr.sin_addr.s_addr = INADDR_ANY;
-
- if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ||
- bind(s, (struct sockaddr *)&addr, addrlen) < 0 ||
- listen(s, 1) < 0) {
- lprint("Error: inet socket: %s\n", strerror(errno));
- closesocket(s);
-
- return 0;
- }
- }
-
- switch(fork()) {
- case -1:
- lprint("Error: fork failed: %s\n", strerror(errno));
- close(s);
- if (do_pty == 2)
- close(master);
- return 0;
-
- case 0:
- /* Set the DISPLAY */
- if (do_pty == 2) {
- (void) close(master);
-#ifdef TIOCSCTTY /* XXXXX */
- (void) setsid();
- ioctl(s, TIOCSCTTY, (char *)NULL);
-#endif
- } else {
- getsockname(s, (struct sockaddr *)&addr, &addrlen);
- close(s);
- /*
- * Connect to the socket
- * XXX If any of these fail, we're in trouble!
- */
- s = socket(AF_INET, SOCK_STREAM, 0);
- addr.sin_addr = loopback_addr;
- do {
- ret = connect(s, (struct sockaddr *)&addr, addrlen);
- } while (ret < 0 && errno == EINTR);
- }
-
-#if 0
- if (x_port >= 0) {
-#ifdef HAVE_SETENV
- sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
- setenv("DISPLAY", buff, 1);
-#else
- sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
- putenv(buff);
-#endif
- }
-#endif
- dup2(s, 0);
- dup2(s, 1);
- dup2(s, 2);
- for (s = 3; s <= 255; s++)
- close(s);
-
- i = 0;
- bptr = strdup(ex); /* No need to free() this */
- if (do_pty == 1) {
- /* Setup "slirp.telnetd -x" */
- argv[i++] = "slirp.telnetd";
- argv[i++] = "-x";
- argv[i++] = bptr;
- } else
- do {
- /* Change the string into argv[] */
- curarg = bptr;
- while (*bptr != ' ' && *bptr != (char)0)
- bptr++;
- c = *bptr;
- *bptr++ = (char)0;
- argv[i++] = strdup(curarg);
- } while (c);
-
- argv[i] = 0;
- execvp(argv[0], argv);
-
- /* Ooops, failed, let's tell the user why */
- {
- char buff[256];
-
- sprintf(buff, "Error: execvp of %s failed: %s\n",
- argv[0], strerror(errno));
- write(2, buff, strlen(buff)+1);
- }
- close(0); close(1); close(2); /* XXX */
- exit(1);
-
- default:
- if (do_pty == 2) {
- close(s);
- so->s = master;
- } else {
- /*
- * XXX this could block us...
- * XXX Should set a timer here, and if accept() doesn't
- * return after X seconds, declare it a failure
- * The only reason this will block forever is if socket()
- * of connect() fail in the child process
- */
- do {
- so->s = accept(s, (struct sockaddr *)&addr, &addrlen);
- } while (so->s < 0 && errno == EINTR);
- closesocket(s);
- opt = 1;
- setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
- opt = 1;
- setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
- }
- fd_nonblock(so->s);
-
- /* Append the telnet options now */
- if (so->so_m != 0 && do_pty == 1) {
- sbappend(so, so->so_m);
- so->so_m = 0;
- }
-
- return 1;
- }
-}
-#endif
#ifndef HAVE_STRDUP
char *
-strdup(str)
- const char *str;
+strdup(const char* str)
{
char *bptr;
-
- bptr = (char *)malloc(strlen(str)+1);
- strcpy(bptr, str);
-
- return bptr;
-}
-#endif
+ int len = strlen(str);
-#if 0
-void
-snooze_hup(num)
- int num;
-{
- int s, ret;
-#ifndef NO_UNIX_SOCKETS
- struct sockaddr_un sock_un;
-#endif
- struct sockaddr_in sock_in;
- char buff[256];
-
- ret = -1;
- if (slirp_socket_passwd) {
- s = socket(AF_INET, SOCK_STREAM, 0);
- if (s < 0)
- slirp_exit(1);
- sock_in.sin_family = AF_INET;
- sock_in.sin_addr.s_addr = slirp_socket_addr;
- sock_in.sin_port = htons(slirp_socket_port);
- if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0)
- slirp_exit(1); /* just exit...*/
- sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit);
- write(s, buff, strlen(buff)+1);
- }
-#ifndef NO_UNIX_SOCKETS
- else {
- s = socket(AF_UNIX, SOCK_STREAM, 0);
- if (s < 0)
- slirp_exit(1);
- sock_un.sun_family = AF_UNIX;
- strcpy(sock_un.sun_path, socket_path);
- if (connect(s, (struct sockaddr *)&sock_un,
- sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0)
- slirp_exit(1);
- sprintf(buff, "kill none:%d", slirp_socket_unit);
- write(s, buff, strlen(buff)+1);
- }
-#endif
- slirp_exit(0);
-}
-
-
-void
-snooze()
-{
- sigset_t s;
- int i;
-
- /* Don't need our data anymore */
- /* XXX This makes SunOS barf */
-/* brk(0); */
-
- /* Close all fd's */
- for (i = 255; i >= 0; i--)
- close(i);
-
- signal(SIGQUIT, slirp_exit);
- signal(SIGHUP, snooze_hup);
- sigemptyset(&s);
-
- /* Wait for any signal */
- sigsuspend(&s);
-
- /* Just in case ... */
- exit(255);
-}
+ bptr = (char *)malloc(len+1);
+ memcpy(bptr, str, len+1);
-void
-relay(s)
- int s;
-{
- char buf[8192];
- int n;
- fd_set readfds;
- struct ttys *ttyp;
-
- /* Don't need our data anymore */
- /* XXX This makes SunOS barf */
-/* brk(0); */
-
- signal(SIGQUIT, slirp_exit);
- signal(SIGHUP, slirp_exit);
- signal(SIGINT, slirp_exit);
- signal(SIGTERM, slirp_exit);
-
- /* Fudge to get term_raw and term_restore to work */
- if (NULL == (ttyp = tty_attach (0, slirp_tty))) {
- lprint ("Error: tty_attach failed in misc.c:relay()\r\n");
- slirp_exit (1);
- }
- ttyp->fd = 0;
- ttyp->flags |= TTY_CTTY;
- term_raw(ttyp);
-
- while (1) {
- FD_ZERO(&readfds);
-
- FD_SET(0, &readfds);
- FD_SET(s, &readfds);
-
- n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0);
-
- if (n <= 0)
- slirp_exit(0);
-
- if (FD_ISSET(0, &readfds)) {
- n = read(0, buf, 8192);
- if (n <= 0)
- slirp_exit(0);
- n = writen(s, buf, n);
- if (n <= 0)
- slirp_exit(0);
- }
-
- if (FD_ISSET(s, &readfds)) {
- n = read(s, buf, 8192);
- if (n <= 0)
- slirp_exit(0);
- n = writen(0, buf, n);
- if (n <= 0)
- slirp_exit(0);
- }
- }
-
- /* Just in case.... */
- exit(1);
+ return bptr;
}
#endif
+
int (*lprint_print) _P((void *, const char *, va_list));
char *lprint_ptr, *lprint_ptr2, **lprint_arg;
void
-#ifdef __STDC__
lprint(const char *format, ...)
-#else
-lprint(va_alist) va_dcl
-#endif
{
va_list args;
-
-#ifdef __STDC__
- va_start(args, format);
-#else
- char *format;
- va_start(args);
- format = va_arg(args, char *);
-#endif
-#if 0
- /* If we're printing to an sbuf, make sure there's enough room */
- /* XXX +100? */
- if (lprint_sb) {
- if ((lprint_ptr - lprint_sb->sb_wptr) >=
- (lprint_sb->sb_datalen - (strlen(format) + 100))) {
- int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data;
- int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data;
- int deltap = lprint_ptr - lprint_sb->sb_data;
-
- lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data,
- lprint_sb->sb_datalen + TCP_SNDSPACE);
-
- /* Adjust all values */
- lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw;
- lprint_sb->sb_rptr = lprint_sb->sb_data + deltar;
- lprint_ptr = lprint_sb->sb_data + deltap;
-
- lprint_sb->sb_datalen += TCP_SNDSPACE;
- }
- }
-#endif
+
+ va_start(args, format);
if (lprint_print)
lprint_ptr += (*lprint_print)(*lprint_arg, format, args);
-
+
/* Check if they want output to be logged to file as well */
if (lfd) {
- /*
+ /*
* Remove \r's
* otherwise you'll get ^M all over the file
*/
int len = strlen(format);
char *bptr1, *bptr2;
-
+
bptr1 = bptr2 = strdup(format);
-
+
while (len--) {
if (*bptr1 == '\r')
memcpy(bptr1, bptr1+1, len+1);
@@ -671,8 +176,7 @@ lprint(va_alist) va_dcl
}
void
-add_emu(buff)
- char *buff;
+add_emu(char* buff)
{
u_int lport, fport;
u_int8_t tos = 0, emu = 0;
@@ -680,12 +184,12 @@ add_emu(buff)
char *buff3 = buff4;
struct emu_t *emup;
struct socket *so;
-
+
if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) {
lprint("Error: Bad arguments\r\n");
return;
}
-
+
if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) {
lport = 0;
if (sscanf(buff1, "%d", &fport) != 1) {
@@ -693,7 +197,7 @@ add_emu(buff)
return;
}
}
-
+
if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) {
buff3 = 0;
if (sscanf(buff2, "%256s", buff1) != 1) {
@@ -701,7 +205,7 @@ add_emu(buff)
return;
}
}
-
+
if (buff3) {
if (strcmp(buff3, "lowdelay") == 0)
tos = IPTOS_LOWDELAY;
@@ -712,7 +216,7 @@ add_emu(buff)
return;
}
}
-
+
if (strcmp(buff1, "ftp") == 0)
emu = EMU_FTP;
else if (strcmp(buff1, "irc") == 0)
@@ -723,7 +227,7 @@ add_emu(buff)
lprint("Error: Unknown service\r\n");
return;
}
-
+
/* First, check that it isn't already emulated */
for (emup = tcpemu; emup; emup = emup->next) {
if (emup->lport == lport && emup->fport == fport) {
@@ -731,7 +235,7 @@ add_emu(buff)
return;
}
}
-
+
/* link it */
emup = (struct emu_t *)malloc(sizeof (struct emu_t));
emup->lport = (u_int16_t)lport;
@@ -740,7 +244,7 @@ add_emu(buff)
emup->emu = emu;
emup->next = tcpemu;
tcpemu = emup;
-
+
/* And finally, mark all current sessions, if any, as being emulated */
for (so = tcb.so_next; so != &tcb; so = so->so_next) {
if ((lport && lport == ntohs(so->so_lport)) ||
@@ -751,7 +255,7 @@ add_emu(buff)
so->so_iptos = tos;
}
}
-
+
lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport);
}
@@ -765,180 +269,20 @@ add_emu(buff)
*/
int
-vsprintf_len(string, format, args)
- char *string;
- const char *format;
- va_list args;
+vsprintf_len(char* string, const char* format, va_list args)
{
vsprintf(string, format, args);
return strlen(string);
}
int
-#ifdef __STDC__
sprintf_len(char *string, const char *format, ...)
-#else
-sprintf_len(va_alist) va_dcl
-#endif
{
va_list args;
-#ifdef __STDC__
va_start(args, format);
-#else
- char *string;
- char *format;
- va_start(args);
- string = va_arg(args, char *);
- format = va_arg(args, char *);
-#endif
vsprintf(string, format, args);
return strlen(string);
}
#endif
-void
-u_sleep(usec)
- int usec;
-{
- struct timeval t;
- fd_set fdset;
-
- FD_ZERO(&fdset);
-
- t.tv_sec = 0;
- t.tv_usec = usec * 1000;
-
- select(0, &fdset, &fdset, &fdset, &t);
-}
-
-/*
- * Set fd blocking and non-blocking
- */
-
-void
-fd_nonblock(fd)
- int fd;
-{
-#ifdef FIONBIO
- int opt = 1;
-
- ioctlsocket(fd, FIONBIO, &opt);
-#else
- int opt;
-
- opt = fcntl(fd, F_GETFL, 0);
- opt |= O_NONBLOCK;
- fcntl(fd, F_SETFL, opt);
-#endif
-}
-
-void
-fd_block(fd)
- int fd;
-{
-#ifdef FIONBIO
- int opt = 0;
-
- ioctlsocket(fd, FIONBIO, &opt);
-#else
- int opt;
-
- opt = fcntl(fd, F_GETFL, 0);
- opt &= ~O_NONBLOCK;
- fcntl(fd, F_SETFL, opt);
-#endif
-}
-
-
-#if 0
-/*
- * invoke RSH
- */
-int
-rsh_exec(so,ns, user, host, args)
- struct socket *so;
- struct socket *ns;
- char *user;
- char *host;
- char *args;
-{
- int fd[2];
- int fd0[2];
- int s;
- char buff[256];
-
- DEBUG_CALL("rsh_exec");
- DEBUG_ARG("so = %lx", (long)so);
-
- if (pipe(fd)<0) {
- lprint("Error: pipe failed: %s\n", strerror(errno));
- return 0;
- }
-/* #ifdef HAVE_SOCKETPAIR */
-#if 1
- if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) {
- close(fd[0]);
- close(fd[1]);
- lprint("Error: openpty failed: %s\n", strerror(errno));
- return 0;
- }
-#else
- if (slirp_openpty(&fd0[0], &fd0[1]) == -1) {
- close(fd[0]);
- close(fd[1]);
- lprint("Error: openpty failed: %s\n", strerror(errno));
- return 0;
- }
-#endif
-
- switch(fork()) {
- case -1:
- lprint("Error: fork failed: %s\n", strerror(errno));
- close(fd[0]);
- close(fd[1]);
- close(fd0[0]);
- close(fd0[1]);
- return 0;
-
- case 0:
- close(fd[0]);
- close(fd0[0]);
-
- /* Set the DISPLAY */
- if (x_port >= 0) {
-#ifdef HAVE_SETENV
- sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
- setenv("DISPLAY", buff, 1);
-#else
- sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen);
- putenv(buff);
-#endif
- }
-
- dup2(fd0[1], 0);
- dup2(fd0[1], 1);
- dup2(fd[1], 2);
- for (s = 3; s <= 255; s++)
- close(s);
-
- execlp("rsh","rsh","-l", user, host, args, NULL);
-
- /* Ooops, failed, let's tell the user why */
-
- sprintf(buff, "Error: execlp of %s failed: %s\n",
- "rsh", strerror(errno));
- write(2, buff, strlen(buff)+1);
- close(0); close(1); close(2); /* XXX */
- exit(1);
-
- default:
- close(fd[1]);
- close(fd0[1]);
- ns->s=fd[0];
- so->s=fd0[0];
-
- return 1;
- }
-}
-#endif
diff --git a/slirp/misc.h b/slirp/misc.h
index 8e6a606..aa4a0ce 100644
--- a/slirp/misc.h
+++ b/slirp/misc.h
@@ -8,20 +8,11 @@
#ifndef _MISC_H_
#define _MISC_H_
-struct ex_list {
- int ex_pty; /* Do we want a pty? */
- int ex_addr; /* The last byte of the address */
- int ex_fport; /* Port to telnet to */
- char *ex_exec; /* Command line of what to exec */
- struct ex_list *ex_next;
-};
-
-extern struct ex_list *exec_list;
extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait;
extern int (*lprint_print) _P((void *, const char *, va_list));
extern char *lprint_ptr, *lprint_ptr2, **lprint_arg;
-extern struct sbuf *lprint_sb;
+//extern SBuf lprint_sb;
#ifndef HAVE_STRDUP
char *strdup _P((const char *));
@@ -65,23 +56,9 @@ struct emu_t {
extern struct emu_t *tcpemu;
-extern int x_port, x_server, x_display;
-
-int show_x _P((char *, struct socket *));
-void redir_x _P((u_int32_t, int, int, int));
void getouraddr _P((void));
inline void slirp_insque _P((void *, void *));
inline void slirp_remque _P((void *));
-int add_exec _P((struct ex_list **, int, char *, int, int));
-int slirp_openpty _P((int *, int *));
-int fork_exec _P((struct socket *, char *, int));
-void snooze_hup _P((int));
-void snooze _P((void));
-void relay _P((int));
void add_emu _P((char *));
-void u_sleep _P((int));
-void fd_nonblock _P((int));
-void fd_block _P((int));
-int rsh_exec _P((struct socket *, struct socket *, char *, char *, char *));
#endif
diff --git a/slirp/sbuf.c b/slirp/sbuf.c
index d6726c9..3d975f8 100644
--- a/slirp/sbuf.c
+++ b/slirp/sbuf.c
@@ -6,26 +6,17 @@
*/
#include <slirp.h>
-
-/* Done as a macro in socket.h */
-/* int
- * sbspace(struct sockbuff *sb)
- * {
- * return SB_DATALEN - sb->sb_cc;
- * }
- */
+#define SLIRP_COMPILATION
+#include "sockets.h"
void
-sbfree(sb)
- struct sbuf *sb;
+sbuf_free(SBuf sb)
{
free(sb->sb_data);
}
void
-sbdrop(sb, num)
- struct sbuf *sb;
- int num;
+sbuf_drop(SBuf sb, int num)
{
/*
* We can only drop how much we have
@@ -41,28 +32,17 @@ sbdrop(sb, num)
}
void
-sbreserve(sb, size)
- struct sbuf *sb;
- int size;
+sbuf_reserve(SBuf sb, int size)
{
- if (sb->sb_data) {
- /* Already alloced, realloc if necessary */
- if (sb->sb_datalen != size) {
- sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
- sb->sb_cc = 0;
- if (sb->sb_wptr)
- sb->sb_datalen = size;
- else
- sb->sb_datalen = 0;
- }
- } else {
- sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size);
- sb->sb_cc = 0;
- if (sb->sb_wptr)
- sb->sb_datalen = size;
- else
- sb->sb_datalen = 0;
- }
+ if (sb->sb_datalen == size)
+ return;
+
+ sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size);
+ sb->sb_cc = 0;
+ if (sb->sb_wptr)
+ sb->sb_datalen = size;
+ else
+ sb->sb_datalen = 0;
}
/*
@@ -72,20 +52,18 @@ sbreserve(sb, size)
* (the socket is non-blocking, so we won't hang)
*/
void
-sbappend(so, m)
- struct socket *so;
- struct mbuf *m;
+sbuf_append(struct socket *so, MBuf m)
{
int ret = 0;
-
- DEBUG_CALL("sbappend");
+
+ DEBUG_CALL("sbuf_append");
DEBUG_ARG("so = %lx", (long)so);
DEBUG_ARG("m = %lx", (long)m);
DEBUG_ARG("m->m_len = %d", m->m_len);
/* Shouldn't happen, but... e.g. foreign host closes connection */
if (m->m_len <= 0) {
- m_free(m);
+ mbuf_free(m);
return;
}
@@ -95,8 +73,8 @@ sbappend(so, m)
* (The rest of this function is just an optimisation)
*/
if (so->so_urgc) {
- sbappendsb(&so->so_rcv, m);
- m_free(m);
+ sbuf_appendsb(&so->so_rcv, m);
+ mbuf_free(m);
sosendoob(so);
return;
}
@@ -105,9 +83,12 @@ sbappend(so, m)
* We only write if there's nothing in the buffer,
* ottherwise it'll arrive out of order, and hence corrupt
*/
- if (!so->so_rcv.sb_cc)
- ret = send(so->s, m->m_data, m->m_len, 0);
-
+ if (!so->so_rcv.sb_cc) {
+ do {
+ ret = send(so->s, m->m_data, m->m_len, 0);
+ } while (ret == 0 && socket_errno == EINTR);
+ }
+
if (ret <= 0) {
/*
* Nothing was written
@@ -115,18 +96,18 @@ sbappend(so, m)
* we don't need to check because if it has closed,
* it will be detected in the normal way by soread()
*/
- sbappendsb(&so->so_rcv, m);
+ sbuf_appendsb(&so->so_rcv, m);
} else if (ret != m->m_len) {
/*
* Something was written, but not everything..
- * sbappendsb the rest
+ * sbuf_appendsb the rest
*/
m->m_len -= ret;
m->m_data += ret;
- sbappendsb(&so->so_rcv, m);
+ sbuf_appendsb(&so->so_rcv, m);
} /* else */
/* Whatever happened, we free the mbuf */
- m_free(m);
+ mbuf_free(m);
}
/*
@@ -134,9 +115,7 @@ sbappend(so, m)
* The caller is responsible to make sure there's enough room
*/
void
-sbappendsb(sb, m)
- struct sbuf *sb;
- struct mbuf *m;
+sbuf_appendsb(SBuf sb, MBuf m)
{
int len, n, nn;
@@ -161,7 +140,7 @@ sbappendsb(sb, m)
}
}
- sb->sb_cc += n;
+ sb->sb_cc += n;
sb->sb_wptr += n;
if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen)
sb->sb_wptr -= sb->sb_datalen;
@@ -173,11 +152,7 @@ sbappendsb(sb, m)
* done in sbdrop when the data is acked
*/
void
-sbcopy(sb, off, len, to)
- struct sbuf *sb;
- int off;
- int len;
- char *to;
+sbuf_copy(SBuf sb, int off, int len, char* to)
{
char *from;
diff --git a/slirp/sbuf.h b/slirp/sbuf.h
index 161e0bb..05fa01a 100644
--- a/slirp/sbuf.h
+++ b/slirp/sbuf.h
@@ -8,24 +8,30 @@
#ifndef _SBUF_H_
#define _SBUF_H_
-#define sbflush(sb) sbdrop((sb),(sb)->sb_cc)
-#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc)
+#include "mbuf.h"
+#include <stddef.h>
-struct sbuf {
- u_int sb_cc; /* actual chars in buffer */
- u_int sb_datalen; /* Length of data */
- char *sb_wptr; /* write pointer. points to where the next
- * bytes should be written in the sbuf */
- char *sb_rptr; /* read pointer. points to where the next
- * byte should be read from the sbuf */
- char *sb_data; /* Actual data */
-};
+/* a SBuf is a simple circular buffer used to hold RX and TX data in a struct socket
+ */
+
+typedef struct sbuf {
+ unsigned sb_cc; /* actual chars in buffer */
+ unsigned sb_datalen; /* Length of data */
+ char* sb_wptr; /* write pointer. points to where the next
+ * bytes should be written in the sbuf */
+ char* sb_rptr; /* read pointer. points to where the next
+ * byte should be read from the sbuf */
+ char* sb_data; /* Actual data */
+} SBufRec, *SBuf;
+
+void sbuf_free (SBuf sb);
+void sbuf_drop (SBuf sb, int num);
+void sbuf_reserve (SBuf sb, int count);
+void sbuf_append (struct socket *so, MBuf m);
+void sbuf_appendsb(SBuf sb, MBuf m);
+void sbuf_copy (SBuf sb, int offset, int length, char *to);
-void sbfree _P((struct sbuf *));
-void sbdrop _P((struct sbuf *, int));
-void sbreserve _P((struct sbuf *, int));
-void sbappend _P((struct socket *, struct mbuf *));
-void sbappendsb _P((struct sbuf *, struct mbuf *));
-void sbcopy _P((struct sbuf *, int, int, char *));
+#define sbuf_flush(sb) sbuf_drop((sb),(sb)->sb_cc)
+#define sbuf_space(sb) ((sb)->sb_datalen - (sb)->sb_cc)
#endif
diff --git a/slirp/slirp.c b/slirp/slirp.c
index 6ba753e..d6eaac4 100644
--- a/slirp/slirp.c
+++ b/slirp/slirp.c
@@ -1,9 +1,17 @@
#include "slirp.h"
+#include "proxy_common.h"
+#include "android_utils.h" /* for dprint */
+#include "android.h"
+
+#define D(...) VERBOSE_PRINT(slirp,__VA_ARGS__)
+#define DN(...) do { if (VERBOSE_CHECK(slirp)) dprintn(__VA_ARGS__); } while (0)
/* host address */
struct in_addr our_addr;
/* host dns address */
-struct in_addr dns_addr;
+struct in_addr dns_addr[DNS_ADDR_MAX];
+int dns_addr_count;
+
/* host loopback address */
struct in_addr loopback_addr;
@@ -12,36 +20,50 @@ struct in_addr special_addr;
/* virtual address alias for host */
struct in_addr alias_addr;
-const uint8_t special_ethaddr[6] = {
+const uint8_t special_ethaddr[6] = {
0x52, 0x54, 0x00, 0x12, 0x35, 0x00
};
-uint8_t client_ethaddr[6];
+uint8_t client_ethaddr[6] = {
+ 0x52, 0x54, 0x00, 0x12, 0x34, 0x56
+};
int do_slowtimo;
int link_up;
struct timeval tt;
FILE *lfd;
-struct ex_list *exec_list;
/* XXX: suppress those select globals */
fd_set *global_readfds, *global_writefds, *global_xfds;
char slirp_hostname[33];
+int slirp_add_dns_server(struct in_addr new_dns_addr)
+{
+ if (dns_addr_count >= DNS_ADDR_MAX)
+ return -1;
+
+ dns_addr[dns_addr_count++] = new_dns_addr;
+ return 0;
+}
+
+
#ifdef _WIN32
-static int get_dns_addr(struct in_addr *pdns_addr)
+int slirp_get_system_dns_servers()
{
FIXED_INFO *FixedInfo=NULL;
ULONG BufLen;
DWORD ret;
IP_ADDR_STRING *pIPAddr;
struct in_addr tmp_addr;
-
+
+ if (dns_addr_count > 0)
+ return dns_addr_count;
+
FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
BufLen = sizeof(FIXED_INFO);
-
+
if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
if (FixedInfo) {
GlobalFree(FixedInfo);
@@ -49,7 +71,7 @@ static int get_dns_addr(struct in_addr *pdns_addr)
}
FixedInfo = GlobalAlloc(GPTR, BufLen);
}
-
+
if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
if (FixedInfo) {
@@ -58,84 +80,114 @@ static int get_dns_addr(struct in_addr *pdns_addr)
}
return -1;
}
-
+
+ D( "DNS Servers:");
pIPAddr = &(FixedInfo->DnsServerList);
- inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
- *pdns_addr = tmp_addr;
-#if 0
- printf( "DNS Servers:\n" );
- printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String );
-
- pIPAddr = FixedInfo -> DnsServerList.Next;
- while ( pIPAddr ) {
- printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String );
- pIPAddr = pIPAddr ->Next;
+ while (pIPAddr && dns_addr_count < DNS_ADDR_MAX) {
+ D( " %s", pIPAddr->IpAddress.String );
+ inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
+ if (tmp_addr.s_addr == loopback_addr.s_addr)
+ tmp_addr = our_addr;
+ if (dns_addr_count < DNS_ADDR_MAX)
+ dns_addr[dns_addr_count++] = tmp_addr;
+ pIPAddr = pIPAddr->Next;
}
-#endif
+
if (FixedInfo) {
GlobalFree(FixedInfo);
FixedInfo = NULL;
}
- return 0;
+ if (dns_addr_count <= 0)
+ return -1;
+
+ return dns_addr_count;
}
#else
-static int get_dns_addr(struct in_addr *pdns_addr)
+int slirp_get_system_dns_servers(void)
{
char buff[512];
char buff2[256];
FILE *f;
- int found = 0;
struct in_addr tmp_addr;
-
+
+ if (dns_addr_count > 0)
+ return dns_addr_count;
+
+#ifdef CONFIG_DARWIN
+ /* on Darwin /etc/resolv.conf is a symlink to /private/var/run/resolv.conf
+ * in some siutations, the symlink can be destroyed and the system will not
+ * re-create it. Darwin-aware applications will continue to run, but "legacy"
+ * Unix ones will not.
+ */
+ f = fopen("/private/var/run/resolv.conf", "r");
+ if (!f)
+ f = fopen("/etc/resolv.conf", "r"); /* desperate attempt to sanity */
+#else
f = fopen("/etc/resolv.conf", "r");
+#endif
if (!f)
return -1;
- lprint("IP address of your DNS(s): ");
+ DN("emulator: IP address of your DNS(s): ");
while (fgets(buff, 512, f) != NULL) {
if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
if (!inet_aton(buff2, &tmp_addr))
continue;
if (tmp_addr.s_addr == loopback_addr.s_addr)
tmp_addr = our_addr;
- /* If it's the first one, set it to dns_addr */
- if (!found)
- *pdns_addr = tmp_addr;
- else
- lprint(", ");
- if (++found > 3) {
- lprint("(more)");
+ if (dns_addr_count < DNS_ADDR_MAX) {
+ dns_addr[dns_addr_count++] = tmp_addr;
+ if (dns_addr_count > 1)
+ DN(", ");
+ DN("%s", inet_ntoa(tmp_addr));
+ } else {
+ DN("(more)");
break;
- } else
- lprint("%s", inet_ntoa(tmp_addr));
+ }
}
}
+ DN("\n");
fclose(f);
- if (!found)
+
+ if (!dns_addr_count)
return -1;
- return 0;
+
+ return dns_addr_count;
}
#endif
-#ifdef _WIN32
-void slirp_cleanup(void)
-{
- WSACleanup();
-}
-#endif
+extern void slirp_init_shapers();
void slirp_init(void)
{
- // debug_init("/tmp/slirp.log", DEBUG_DEFAULT);
-
-#ifdef _WIN32
+#if DEBUG
+ int slirp_logmask = 0;
+ char slirp_logfile[512];
+
{
- WSADATA Data;
- WSAStartup(MAKEWORD(2,0), &Data);
- atexit(slirp_cleanup);
+ const char* env = getenv( "ANDROID_SLIRP_LOGMASK" );
+ if (env != NULL)
+ slirp_logmask = atoi(env);
+ else if (VERBOSE_CHECK(slirp))
+ slirp_logmask = DEBUG_DEFAULT;
+ }
+
+ {
+ char* p = slirp_logfile;
+ char* end = p + sizeof(slirp_logfile);
+
+ p = bufprint_temp_file( p, end, "slirp.log" );
+ if (p >= end) {
+ dprint( "cannot create slirp log file in temporary directory" );
+ slirp_logmask = 0;
+ }
+ }
+ if (slirp_logmask) {
+ dprint( "sending slirp logs with mask %x to %s", slirp_logmask, slirp_logfile );
+ debug_init( slirp_logfile, slirp_logmask );
}
#endif
@@ -145,19 +197,24 @@ void slirp_init(void)
ip_init();
/* Initialise mbufs *after* setting the MTU */
- m_init();
+ mbuf_init();
/* set default addresses */
inet_aton("127.0.0.1", &loopback_addr);
- if (get_dns_addr(&dns_addr) < 0) {
- dns_addr = loopback_addr;
- fprintf (stderr, "Warning: No DNS servers found\n");
+ if (dns_addr_count == 0) {
+ if (slirp_get_system_dns_servers() < 0) {
+ dns_addr[0] = loopback_addr;
+ dns_addr_count = 1;
+ fprintf (stderr, "Warning: No DNS servers found\n");
+ }
}
inet_aton(CTL_SPECIAL, &special_addr);
alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS);
getouraddr();
+
+ slirp_init_shapers();
}
#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
@@ -180,16 +237,16 @@ static void updtime(void)
static void updtime(void)
{
gettimeofday(&tt, 0);
-
+
curtime = (u_int)tt.tv_sec * (u_int)1000;
curtime += (u_int)tt.tv_usec / (u_int)1000;
-
+
if ((tt.tv_usec % 1000) >= 500)
curtime++;
}
#endif
-void slirp_select_fill(int *pnfds,
+void slirp_select_fill(int *pnfds,
fd_set *readfds, fd_set *writefds, fd_set *xfds)
{
struct socket *so, *so_next;
@@ -201,143 +258,158 @@ void slirp_select_fill(int *pnfds,
global_readfds = NULL;
global_writefds = NULL;
global_xfds = NULL;
-
+
nfds = *pnfds;
- /*
- * First, TCP sockets
- */
- do_slowtimo = 0;
- if (link_up) {
- /*
- * *_slowtimo needs calling if there are IP fragments
- * in the fragment queue, or there are TCP connections active
- */
- do_slowtimo = ((tcb.so_next != &tcb) ||
- ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next));
-
- for (so = tcb.so_next; so != &tcb; so = so_next) {
- so_next = so->so_next;
-
- /*
- * See if we need a tcp_fasttimo
- */
- if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
- time_fasttimo = curtime; /* Flag when we want a fasttimo */
-
- /*
- * NOFDREF can include still connecting to local-host,
- * newly socreated() sockets etc. Don't want to select these.
- */
- if (so->so_state & SS_NOFDREF || so->s == -1)
- continue;
-
- /*
- * Set for reading sockets which are accepting
- */
- if (so->so_state & SS_FACCEPTCONN) {
+ /*
+ * First, TCP sockets
+ */
+ do_slowtimo = 0;
+ if (link_up) {
+ /*
+ * *_slowtimo needs calling if there are IP fragments
+ * in the fragment queue, or there are TCP connections active
+ */
+ do_slowtimo = ((tcb.so_next != &tcb) ||
+ ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next));
+
+ for (so = tcb.so_next; so != &tcb; so = so_next) {
+ so_next = so->so_next;
+
+ /*
+ * See if we need a tcp_fasttimo
+ */
+ if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
+ time_fasttimo = curtime; /* Flag when we want a fasttimo */
+
+ /*
+ * NOFDREF can include still connecting to local-host,
+ * newly socreated() sockets etc. Don't want to select these.
+ */
+ if (so->so_state & SS_NOFDREF || so->s == -1)
+ continue;
+
+ /*
+ * don't register proxified socked connections here
+ */
+ if ((so->so_state & SS_PROXIFIED) != 0)
+ continue;
+
+ /*
+ * Set for reading sockets which are accepting
+ */
+ if (so->so_state & SS_FACCEPTCONN) {
FD_SET(so->s, readfds);
- UPD_NFDS(so->s);
- continue;
- }
-
- /*
- * Set for writing sockets which are connecting
- */
- if (so->so_state & SS_ISFCONNECTING) {
- FD_SET(so->s, writefds);
- UPD_NFDS(so->s);
- continue;
- }
-
- /*
- * Set for writing if we are connected, can send more, and
- * we have something to send
- */
- if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
- FD_SET(so->s, writefds);
- UPD_NFDS(so->s);
- }
-
- /*
- * Set for reading (and urgent data) if we are connected, can
- * receive more, and we have room for it XXX /2 ?
- */
- if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
- FD_SET(so->s, readfds);
- FD_SET(so->s, xfds);
- UPD_NFDS(so->s);
- }
- }
-
- /*
- * UDP sockets
- */
- for (so = udb.so_next; so != &udb; so = so_next) {
- so_next = so->so_next;
-
- /*
- * See if it's timed out
- */
- if (so->so_expire) {
- if (so->so_expire <= curtime) {
- udp_detach(so);
- continue;
- } else
- do_slowtimo = 1; /* Let socket expire */
- }
-
- /*
- * When UDP packets are received from over the
- * link, they're sendto()'d straight away, so
- * no need for setting for writing
- * Limit the number of packets queued by this session
- * to 4. Note that even though we try and limit this
- * to 4 packets, the session could have more queued
- * if the packets needed to be fragmented
- * (XXX <= 4 ?)
- */
- if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
- FD_SET(so->s, readfds);
- UPD_NFDS(so->s);
- }
- }
- }
-
- /*
- * Setup timeout to use minimum CPU usage, especially when idle
- */
-
- /*
- * First, see the timeout needed by *timo
- */
- timeout.tv_sec = 0;
- timeout.tv_usec = -1;
- /*
- * If a slowtimo is needed, set timeout to 500ms from the last
- * slow timeout. If a fast timeout is needed, set timeout within
- * 200ms of when it was requested.
- */
- if (do_slowtimo) {
- /* XXX + 10000 because some select()'s aren't that accurate */
- timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
- if (timeout.tv_usec < 0)
- timeout.tv_usec = 0;
- else if (timeout.tv_usec > 510000)
- timeout.tv_usec = 510000;
-
- /* Can only fasttimo if we also slowtimo */
- if (time_fasttimo) {
- tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
- if (tmp_time < 0)
- tmp_time = 0;
-
- /* Choose the smallest of the 2 */
- if (tmp_time < timeout.tv_usec)
- timeout.tv_usec = (u_int)tmp_time;
- }
- }
+ UPD_NFDS(so->s);
+ continue;
+ }
+
+ /*
+ * Set for writing sockets which are connecting
+ */
+ if (so->so_state & SS_ISFCONNECTING) {
+ FD_SET(so->s, writefds);
+ UPD_NFDS(so->s);
+ continue;
+ }
+
+ /*
+ * Set for writing if we are connected, can send more, and
+ * we have something to send
+ */
+ if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
+ FD_SET(so->s, writefds);
+ UPD_NFDS(so->s);
+ }
+
+ /*
+ * Set for reading (and urgent data) if we are connected, can
+ * receive more, and we have room for it XXX /2 ?
+ */
+ if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
+ FD_SET(so->s, readfds);
+ FD_SET(so->s, xfds);
+ UPD_NFDS(so->s);
+ }
+ }
+
+ /*
+ * UDP sockets
+ */
+ for (so = udb.so_next; so != &udb; so = so_next) {
+ so_next = so->so_next;
+
+ if ((so->so_state & SS_PROXIFIED) != 0)
+ continue;
+
+ /*
+ * See if it's timed out
+ */
+ if (so->so_expire) {
+ if (so->so_expire <= curtime) {
+ udp_detach(so);
+ continue;
+ } else
+ do_slowtimo = 1; /* Let socket expire */
+ }
+
+ /*
+ * When UDP packets are received from over the
+ * link, they're sendto()'d straight away, so
+ * no need for setting for writing
+ * Limit the number of packets queued by this session
+ * to 4. Note that even though we try and limit this
+ * to 4 packets, the session could have more queued
+ * if the packets needed to be fragmented
+ * (XXX <= 4 ?)
+ */
+ if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
+ FD_SET(so->s, readfds);
+ UPD_NFDS(so->s);
+ }
+ }
+ }
+
+ /*
+ * Setup timeout to use minimum CPU usage, especially when idle
+ */
+
+ /*
+ * First, see the timeout needed by *timo
+ */
+ timeout.tv_sec = 0;
+ timeout.tv_usec = -1;
+ /*
+ * If a slowtimo is needed, set timeout to 500ms from the last
+ * slow timeout. If a fast timeout is needed, set timeout within
+ * 200ms of when it was requested.
+ */
+ if (do_slowtimo) {
+ /* XXX + 10000 because some select()'s aren't that accurate */
+ timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
+ if (timeout.tv_usec < 0)
+ timeout.tv_usec = 0;
+ else if (timeout.tv_usec > 510000)
+ timeout.tv_usec = 510000;
+
+ /* Can only fasttimo if we also slowtimo */
+ if (time_fasttimo) {
+ tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
+ if (tmp_time < 0)
+ tmp_time = 0;
+
+ /* Choose the smallest of the 2 */
+ if (tmp_time < timeout.tv_usec)
+ timeout.tv_usec = (u_int)tmp_time;
+ }
+ }
+
+ /*
+ * now, the proxified sockets
+ */
+ proxy_manager_select_fill(&nfds, readfds, writefds, xfds);
+
*pnfds = nfds;
-}
+}
void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
{
@@ -350,9 +422,9 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
/* Update time */
updtime();
-
+
/*
- * See if anything has timed out
+ * See if anything has timed out
*/
if (link_up) {
if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
@@ -365,7 +437,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
last_slowtimo = curtime;
}
}
-
+
/*
* Check sockets
*/
@@ -375,14 +447,21 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
*/
for (so = tcb.so_next; so != &tcb; so = so_next) {
so_next = so->so_next;
-
+
/*
* FD_ISSET is meaningless on these sockets
* (and they can crash the program)
*/
if (so->so_state & SS_NOFDREF || so->s == -1)
continue;
-
+
+ /*
+ * proxified sockets are polled later in this
+ * function.
+ */
+ if ((so->so_state & SS_PROXIFIED) != 0)
+ continue;
+
/*
* Check for URG data
* This will soread as well, so no need to
@@ -402,12 +481,12 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
continue;
} /* else */
ret = soread(so);
-
+
/* Output it if we read something */
if (ret > 0)
tcp_output(sototcpcb(so));
}
-
+
/*
* Check sockets for writing
*/
@@ -418,34 +497,34 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
if (so->so_state & SS_ISFCONNECTING) {
/* Connected */
so->so_state &= ~SS_ISFCONNECTING;
-
- ret = send(so->s, &ret, 0, 0);
+
+ ret = send(so->s, (char*)&ret, 0, 0);
if (ret < 0) {
/* XXXXX Must fix, zero bytes is a NOP */
if (errno == EAGAIN || errno == EWOULDBLOCK ||
errno == EINPROGRESS || errno == ENOTCONN)
continue;
-
+
/* else failed */
so->so_state = SS_NOFDREF;
}
/* else so->so_state &= ~SS_ISFCONNECTING; */
-
+
/*
* Continue tcp_input
*/
- tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
+ tcp_input((MBuf )NULL, sizeof(struct ip), so);
/* continue; */
} else
ret = sowrite(so);
/*
- * XXXXX If we wrote something (a lot), there
+ * XXXXX If we wrote something (a lot), there
* could be a need for a window update.
* In the worst case, the remote will send
* a window probe to get things going again
*/
}
-
+
/*
* Probe a still-connecting, non-blocking socket
* to check if it's still alive
@@ -453,16 +532,16 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
#ifdef PROBE_CONN
if (so->so_state & SS_ISFCONNECTING) {
ret = recv(so->s, (char *)&ret, 0,0);
-
+
if (ret < 0) {
/* XXX */
if (errno == EAGAIN || errno == EWOULDBLOCK ||
errno == EINPROGRESS || errno == ENOTCONN)
continue; /* Still connecting, continue */
-
+
/* else failed */
so->so_state = SS_NOFDREF;
-
+
/* tcp_input will take care of it */
} else {
ret = send(so->s, &ret, 0,0);
@@ -475,13 +554,13 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
so->so_state = SS_NOFDREF;
} else
so->so_state &= ~SS_ISFCONNECTING;
-
+
}
- tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
+ tcp_input((MBuf )NULL, sizeof(struct ip),so);
} /* SS_ISFCONNECTING */
#endif
}
-
+
/*
* Now UDP sockets.
* Incoming packets are sent straight away, they're not buffered.
@@ -489,13 +568,21 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
*/
for (so = udb.so_next; so != &udb; so = so_next) {
so_next = so->so_next;
-
+
+ if ((so->so_state & SS_PROXIFIED) != 0)
+ continue;
+
if (so->s != -1 && FD_ISSET(so->s, readfds)) {
sorecvfrom(so);
}
}
}
-
+
+ /*
+ * Now the proxified sockets
+ */
+ proxy_manager_poll(readfds, writefds, xfds);
+
/*
* See if we can start outputting
*/
@@ -521,7 +608,7 @@ void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)
#define ARPOP_REQUEST 1 /* ARP request */
#define ARPOP_REPLY 2 /* ARP reply */
-struct ethhdr
+struct ethhdr
{
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
unsigned char h_source[ETH_ALEN]; /* source ether addr */
@@ -553,18 +640,13 @@ void arp_input(const uint8_t *pkt, int pkt_len)
struct ethhdr *reh = (struct ethhdr *)arp_reply;
struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
int ar_op;
- struct ex_list *ex_ptr;
ar_op = ntohs(ah->ar_op);
switch(ar_op) {
case ARPOP_REQUEST:
if (!memcmp(ah->ar_tip, &special_addr, 3)) {
- if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS)
+ if ( CTL_IS_DNS(ah->ar_tip[3]) || ah->ar_tip[3] == CTL_ALIAS)
goto arp_ok;
- for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
- if (ex_ptr->ex_addr == ah->ar_tip[3])
- goto arp_ok;
- }
return;
arp_ok:
/* XXX: make an ARP request to have the client address */
@@ -595,19 +677,19 @@ void arp_input(const uint8_t *pkt, int pkt_len)
void slirp_input(const uint8_t *pkt, int pkt_len)
{
- struct mbuf *m;
+ MBuf m;
int proto;
if (pkt_len < ETH_HLEN)
return;
-
+
proto = ntohs(*(uint16_t *)(pkt + 12));
switch(proto) {
case ETH_P_ARP:
arp_input(pkt, pkt_len);
break;
case ETH_P_IP:
- m = m_get();
+ m = mbuf_alloc();
if (!m)
return;
/* Note: we add to align the IP header */
@@ -642,24 +724,26 @@ void if_encap(const uint8_t *ip_data, int ip_data_len)
slirp_output(buf, ip_data_len + ETH_HLEN);
}
-int slirp_redir(int is_udp, int host_port,
+int slirp_redir(int is_udp, int host_port,
struct in_addr guest_addr, int guest_port)
{
if (is_udp) {
- if (!udp_listen(htons(host_port), guest_addr.s_addr,
+ if (!udp_listen(htons(host_port), guest_addr.s_addr,
htons(guest_port), 0))
return -1;
} else {
- if (!solisten(htons(host_port), guest_addr.s_addr,
+ if (!solisten(htons(host_port), guest_addr.s_addr,
htons(guest_port), 0))
return -1;
}
return 0;
}
-int slirp_add_exec(int do_pty, const char *args, int addr_low_byte,
- int guest_port)
+int slirp_unredir(int is_udp, int host_port)
{
- return add_exec(&exec_list, do_pty, (char *)args,
- addr_low_byte, htons(guest_port));
+ if (is_udp)
+ return udp_unlisten( host_port );
+ else
+ return sounlisten( host_port );
}
+
diff --git a/slirp/slirp.h b/slirp/slirp.h
index 1ff68cb..50c0a77 100644
--- a/slirp/slirp.h
+++ b/slirp/slirp.h
@@ -272,28 +272,28 @@ extern int do_echo;
#define DEFAULT_BAUD 115200
/* cksum.c */
-int cksum(struct mbuf *m, int len);
+int cksum(MBuf m, int len);
/* if.c */
void if_init _P((void));
-void if_output _P((struct socket *, struct mbuf *));
+void if_output _P((struct socket *, MBuf ));
/* ip_input.c */
void ip_init _P((void));
-void ip_input _P((struct mbuf *));
+void ip_input _P((MBuf ));
struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *));
void ip_freef _P((struct ipq *));
void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *));
void ip_deq _P((register struct ipasfrag *));
void ip_slowtimo _P((void));
-void ip_stripoptions _P((register struct mbuf *, struct mbuf *));
+void ip_stripoptions _P((register MBuf , MBuf ));
/* ip_output.c */
-int ip_output _P((struct socket *, struct mbuf *));
+int ip_output _P((struct socket *, MBuf ));
/* tcp_input.c */
-int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct mbuf *));
-void tcp_input _P((register struct mbuf *, int, struct socket *));
+int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, MBuf ));
+void tcp_input _P((register MBuf , int, struct socket *));
void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *));
void tcp_xmit_timer _P((register struct tcpcb *, int));
int tcp_mss _P((register struct tcpcb *, u_int));
@@ -305,7 +305,7 @@ void tcp_setpersist _P((register struct tcpcb *));
/* tcp_subr.c */
void tcp_init _P((void));
void tcp_template _P((struct tcpcb *));
-void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct mbuf *, tcp_seq, tcp_seq, int));
+void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register MBuf , tcp_seq, tcp_seq, int));
struct tcpcb * tcp_newtcpcb _P((struct socket *));
struct tcpcb * tcp_close _P((register struct tcpcb *));
void tcp_drain _P((void));
@@ -314,7 +314,7 @@ int tcp_fconnect _P((struct socket *));
void tcp_connect _P((struct socket *));
int tcp_attach _P((struct socket *));
u_int8_t tcp_tos _P((struct socket *));
-int tcp_emu _P((struct socket *, struct mbuf *));
+int tcp_emu _P((struct socket *, MBuf ));
int tcp_ctl _P((struct socket *));
struct tcpcb *tcp_drop(struct tcpcb *tp, int err);
diff --git a/slirp/socket.c b/slirp/socket.c
index 0ae1f87..8ddc95c 100644
--- a/slirp/socket.c
+++ b/slirp/socket.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
+ *
+ * Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
@@ -12,6 +12,9 @@
#ifdef __sun__
#include <sys/filio.h>
#endif
+#define SLIRP_COMPILATION
+#include "sockets.h"
+#include "proxy_common.h"
void
so_init()
@@ -29,19 +32,19 @@ solookup(head, laddr, lport, faddr, fport)
u_int fport;
{
struct socket *so;
-
+
for (so = head->so_next; so != head; so = so->so_next) {
- if (so->so_lport == lport &&
+ if (so->so_lport == lport &&
so->so_laddr.s_addr == laddr.s_addr &&
so->so_faddr.s_addr == faddr.s_addr &&
so->so_fport == fport)
break;
}
-
+
if (so == head)
return (struct socket *)NULL;
return so;
-
+
}
/*
@@ -53,7 +56,7 @@ struct socket *
socreate()
{
struct socket *so;
-
+
so = (struct socket *)malloc(sizeof(struct socket));
if(so) {
memset(so, 0, sizeof(struct socket));
@@ -70,7 +73,10 @@ void
sofree(so)
struct socket *so;
{
- if (so->so_emu==EMU_RSH && so->extra) {
+ if (so->so_state & SS_PROXIFIED)
+ proxy_manager_del(so->s);
+
+ if (so->extra) {
sofree(so->extra);
so->extra=NULL;
}
@@ -78,10 +84,10 @@ sofree(so)
tcp_last_so = &tcb;
else if (so == udp_last_so)
udp_last_so = &udb;
-
- m_free(so->so_m);
-
- if(so->so_next && so->so_prev)
+
+ mbuf_free(so->so_m);
+
+ if(so->so_next && so->so_prev)
remque(so); /* crashes if so is not in a queue */
free(so);
@@ -97,21 +103,21 @@ soread(so)
struct socket *so;
{
int n, nn, lss, total;
- struct sbuf *sb = &so->so_snd;
- int len = sb->sb_datalen - sb->sb_cc;
+ SBuf sb = &so->so_snd;
+ int len = sb->sb_datalen - sb->sb_cc;
struct iovec iov[2];
int mss = so->so_tcpcb->t_maxseg;
-
+
DEBUG_CALL("soread");
DEBUG_ARG("so = %lx", (long )so);
-
- /*
+
+ /*
* No need to check if there's enough room to read.
* soread wouldn't have been called if there weren't
*/
-
+
len = sb->sb_datalen - sb->sb_cc;
-
+
iov[0].iov_base = sb->sb_wptr;
if (sb->sb_wptr < sb->sb_rptr) {
iov[0].iov_len = sb->sb_rptr - sb->sb_wptr;
@@ -150,13 +156,13 @@ soread(so)
n = 1;
}
}
-
+
#ifdef HAVE_READV
nn = readv(so->s, (struct iovec *)iov, n);
DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
#else
nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0);
-#endif
+#endif
if (nn <= 0) {
if (nn < 0 && (errno == EINTR || errno == EAGAIN))
return 0;
@@ -167,7 +173,7 @@ soread(so)
return -1;
}
}
-
+
#ifndef HAVE_READV
/*
* If there was no error, try and read the second time round
@@ -184,10 +190,10 @@ soread(so)
if (ret > 0)
nn += ret;
}
-
+
DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn));
#endif
-
+
/* Update fields */
sb->sb_cc += nn;
sb->sb_wptr += nn;
@@ -195,10 +201,10 @@ soread(so)
sb->sb_wptr -= sb->sb_datalen;
return nn;
}
-
+
/*
* Get urgent data
- *
+ *
* When the socket is created, we set it SO_OOBINLINE,
* so when OOB data arrives, we soread() it and everything
* in the send buffer is sent as urgent data
@@ -211,13 +217,13 @@ sorecvoob(so)
DEBUG_CALL("sorecvoob");
DEBUG_ARG("so = %lx", (long)so);
-
+
/*
* We take a guess at how much urgent data has arrived.
* In most situations, when urgent data arrives, the next
* read() should get all the urgent data. This guess will
* be wrong however if more data arrives just after the
- * urgent data, or the read() doesn't return all the
+ * urgent data, or the read() doesn't return all the
* urgent data.
*/
soread(so);
@@ -235,26 +241,25 @@ int
sosendoob(so)
struct socket *so;
{
- struct sbuf *sb = &so->so_rcv;
- char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
-
- int n, len;
-
+ SBuf sb = &so->so_rcv;
+ char buff[2048]; /* XXX Shouldn't be sending more oob data than this */
+ int n, len;
+
DEBUG_CALL("sosendoob");
DEBUG_ARG("so = %lx", (long)so);
DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc);
-
+
if (so->so_urgc > 2048)
so->so_urgc = 2048; /* XXXX */
-
+
if (sb->sb_rptr < sb->sb_wptr) {
/* We can send it directly */
n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */
so->so_urgc -= n;
-
+
DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
} else {
- /*
+ /*
* Since there's no sendv or sendtov like writev,
* we must copy all data to a linear buffer then
* send it all
@@ -274,34 +279,34 @@ sosendoob(so)
#ifdef DEBUG
if (n != len)
DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n"));
-#endif
+#endif
DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc));
}
-
+
sb->sb_cc -= n;
sb->sb_rptr += n;
if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
sb->sb_rptr -= sb->sb_datalen;
-
+
return n;
}
/*
- * Write data from so_rcv to so's socket,
+ * Write data from so_rcv to so's socket,
* updating all sbuf field as necessary
*/
int
sowrite(so)
struct socket *so;
{
- int n,nn;
- struct sbuf *sb = &so->so_rcv;
- int len = sb->sb_cc;
+ int n,nn;
+ SBuf sb = &so->so_rcv;
+ int len = sb->sb_cc;
struct iovec iov[2];
-
+
DEBUG_CALL("sowrite");
DEBUG_ARG("so = %lx", (long)so);
-
+
if (so->so_urgc) {
sosendoob(so);
if (sb->sb_cc == 0)
@@ -312,9 +317,9 @@ sowrite(so)
* No need to check if there's something to write,
* sowrite wouldn't have been called otherwise
*/
-
+
len = sb->sb_cc;
-
+
iov[0].iov_base = sb->sb_rptr;
if (sb->sb_rptr < sb->sb_wptr) {
iov[0].iov_len = sb->sb_wptr - sb->sb_rptr;
@@ -337,7 +342,7 @@ sowrite(so)
#ifdef HAVE_READV
nn = writev(so->s, (const struct iovec *)iov, n);
-
+
DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn));
#else
nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0);
@@ -345,7 +350,7 @@ sowrite(so)
/* This should never happen, but people tell me it does *shrug* */
if (nn < 0 && (errno == EAGAIN || errno == EINTR))
return 0;
-
+
if (nn <= 0) {
DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n",
so->so_state, errno));
@@ -353,7 +358,7 @@ sowrite(so)
tcp_sockclosed(sototcpcb(so));
return -1;
}
-
+
#ifndef HAVE_READV
if (n == 2 && nn == iov[0].iov_len) {
int ret;
@@ -363,20 +368,20 @@ sowrite(so)
}
DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn));
#endif
-
+
/* Update sbuf */
sb->sb_cc -= nn;
sb->sb_rptr += nn;
if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen))
sb->sb_rptr -= sb->sb_datalen;
-
+
/*
* If in DRAIN mode, and there's no more data, set
* it CANTSENDMORE
*/
if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0)
sofcantsendmore(so);
-
+
return nn;
}
@@ -389,68 +394,68 @@ sorecvfrom(so)
{
struct sockaddr_in addr;
int addrlen = sizeof(struct sockaddr_in);
-
+
DEBUG_CALL("sorecvfrom");
DEBUG_ARG("so = %lx", (long)so);
-
+
if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */
char buff[256];
int len;
-
- len = recvfrom(so->s, buff, 256, 0,
+
+ len = recvfrom(so->s, buff, 256, 0,
(struct sockaddr *)&addr, &addrlen);
/* XXX Check if reply is "correct"? */
-
+
if(len == -1 || len == 0) {
u_char code=ICMP_UNREACH_PORT;
if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
-
+
DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n",
errno,strerror(errno)));
icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
} else {
icmp_reflect(so->so_m);
- so->so_m = 0; /* Don't m_free() it again! */
+ so->so_m = 0; /* Don't mbuf_free() it again! */
}
/* No need for this socket anymore, udp_detach it */
udp_detach(so);
} else { /* A "normal" UDP packet */
- struct mbuf *m;
+ MBuf m;
int len, n;
- if (!(m = m_get())) return;
+ if (!(m = mbuf_alloc())) return;
m->m_data += if_maxlinkhdr;
-
- /*
+
+ /*
* XXX Shouldn't FIONREAD packets destined for port 53,
* but I don't know the max packet size for DNS lookups
*/
- len = M_FREEROOM(m);
+ len = mbuf_freeroom(m);
/* if (so->so_fport != htons(53)) { */
ioctlsocket(so->s, FIONREAD, &n);
-
+
if (n > len) {
n = (m->m_data - m->m_dat) + m->m_len + n + 1;
- m_inc(m, n);
- len = M_FREEROOM(m);
+ mbuf_ensure(m, n);
+ len = mbuf_freeroom(m);
}
/* } */
-
+
m->m_len = recvfrom(so->s, m->m_data, len, 0,
(struct sockaddr *)&addr, &addrlen);
- DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
+ DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n",
m->m_len, errno,strerror(errno)));
if(m->m_len<0) {
u_char code=ICMP_UNREACH_PORT;
if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET;
-
+
DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code));
icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno));
- m_free(m);
+ mbuf_free(m);
} else {
/*
* Hack: domain name lookup will be used the most for UDP,
@@ -466,12 +471,12 @@ sorecvfrom(so)
}
/* if (m->m_len == len) {
- * m_inc(m, MINCSIZE);
+ * mbuf_ensure(m, MINCSIZE);
* m->m_len = 0;
* }
*/
-
- /*
+
+ /*
* If this packet was destined for CTL_ADDR,
* make it look like that's where it came from, done by udp_output
*/
@@ -486,7 +491,7 @@ sorecvfrom(so)
int
sosendto(so, m)
struct socket *so;
- struct mbuf *m;
+ MBuf m;
{
int ret;
struct sockaddr_in addr;
@@ -494,31 +499,28 @@ sosendto(so, m)
DEBUG_CALL("sosendto");
DEBUG_ARG("so = %lx", (long)so);
DEBUG_ARG("m = %lx", (long)m);
-
+
addr.sin_family = AF_INET;
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
/* It's an alias */
- switch(ntohl(so->so_faddr.s_addr) & 0xff) {
- case CTL_DNS:
- addr.sin_addr = dns_addr;
- break;
- case CTL_ALIAS:
- default:
- addr.sin_addr = loopback_addr;
- break;
- }
+ int low = ntohl(so->so_faddr.s_addr) & 0xff;
+
+ if ( CTL_IS_DNS(low) )
+ addr.sin_addr = dns_addr[low - CTL_DNS];
+ else
+ addr.sin_addr = loopback_addr;
} else
addr.sin_addr = so->so_faddr;
addr.sin_port = so->so_fport;
DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
-
+
/* Don't care what port we get */
ret = sendto(so->s, m->m_data, m->m_len, 0,
(struct sockaddr *)&addr, sizeof (struct sockaddr));
if (ret < 0)
return -1;
-
+
/*
* Kill the socket if there's no reply in 4 minutes,
* but only if it's an expirable socket
@@ -548,39 +550,47 @@ solisten(port, laddr, lport, flags)
DEBUG_ARG("laddr = %x", laddr);
DEBUG_ARG("lport = %d", lport);
DEBUG_ARG("flags = %x", flags);
-
+
if ((so = socreate()) == NULL) {
/* free(so); Not sofree() ??? free(NULL) == NOP */
return NULL;
}
-
+
/* Don't tcp_attach... we don't need so_snd nor so_rcv */
if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) {
free(so);
return NULL;
}
insque(so,&tcb);
-
- /*
+
+ /*
* SS_FACCEPTONCE sockets must time out.
*/
if (flags & SS_FACCEPTONCE)
so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2;
-
+
so->so_state = (SS_FACCEPTCONN|flags);
so->so_lport = lport; /* Kept in network format */
+ so->so_hport = port;
so->so_laddr.s_addr = laddr; /* Ditto */
-
+
+ memset( &addr, 0, sizeof(addr) );
addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = port;
-
- if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) ||
- (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) ||
- (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
+
+ if ((s = socket(AF_INET,SOCK_STREAM,0)) < 0) {
+ sofree(so);
+ return NULL;
+ }
+
+ socket_set_xreuseaddr(s);
+
+ if ((socket_set_xreuseaddr(s) < 0) ||
+ (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) ||
(listen(s,1) < 0)) {
int tmperrno = errno; /* Don't clobber the real reason we failed */
-
+
close(s);
sofree(so);
/* Restore the real errno */
@@ -591,8 +601,8 @@ solisten(port, laddr, lport, flags)
#endif
return NULL;
}
- setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
-
+ socket_set_oobinline(s);
+
getsockname(s,(struct sockaddr *)&addr,&addrlen);
so->so_fport = addr.sin_port;
if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
@@ -604,7 +614,32 @@ solisten(port, laddr, lport, flags)
return so;
}
-/*
+
+int
+sounlisten(u_int port)
+{
+ struct socket *so;
+
+ for (so = tcb.so_next; so != &tcb; so = so->so_next) {
+ if (so->so_hport == htons(port)) {
+ break;
+ }
+ }
+
+ if (so == &tcb) {
+ return -1;
+ }
+
+ sofcantrcvmore( so );
+ sofcantsendmore( so );
+ close( so->s );
+ so->s = -1;
+ sofree( so );
+ return 0;
+}
+
+
+/*
* Data is available in so_rcv
* Just write() the data to the socket
* XXX not yet...
@@ -616,7 +651,7 @@ sorwakeup(so)
/* sowrite(so); */
/* FD_CLR(so->s,&writefds); */
}
-
+
/*
* Data has been freed in so_snd
* We have room for a read() if we want to
diff --git a/slirp/socket.h b/slirp/socket.h
index d05354c..54cb21c 100644
--- a/slirp/socket.h
+++ b/slirp/socket.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
+ *
+ * Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
@@ -23,7 +23,7 @@ struct socket {
int s; /* The actual socket */
/* XXX union these with not-yet-used sbuf params */
- struct mbuf *so_m; /* Pointer to the original SYN packet,
+ MBuf so_m; /* Pointer to the original SYN packet,
* for non-blocking connect()'s, and
* PING reply's */
struct tcpiphdr *so_ti; /* Pointer to the original ti within
@@ -33,23 +33,24 @@ struct socket {
struct in_addr so_laddr; /* local host table entry */
u_int16_t so_fport; /* foreign port */
u_int16_t so_lport; /* local port */
-
+ u_int16_t so_hport;
+
u_int8_t so_iptos; /* Type of service */
u_int8_t so_emu; /* Is the socket emulated? */
-
+
u_char so_type; /* Type of socket, UDP or TCP */
int so_state; /* internal state flags SS_*, below */
-
+
struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */
u_int so_expire; /* When the socket will expire */
-
+
int so_queued; /* Number of packets queued from this socket */
int so_nqueued; /* Number of packets queued in a row
* Used to determine when to "downgrade" a session
* from fastq to batchq */
-
- struct sbuf so_rcv; /* Receive buffer */
- struct sbuf so_snd; /* Send buffer */
+
+ SBufRec so_rcv; /* Receive buffer */
+ SBufRec so_snd; /* Send buffer */
void * extra; /* Extra pointer */
};
@@ -70,7 +71,8 @@ struct socket {
#define SS_CTL 0x080
#define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */
#define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */
-
+#define SS_PROXIFIED 0x400 /* Socket is trying to connect through a proxy, only makes sense
+ when SS_ISFCONNECTING is also set */
extern struct socket tcb;
@@ -90,8 +92,9 @@ void sorecvoob _P((struct socket *));
int sosendoob _P((struct socket *));
int sowrite _P((struct socket *));
void sorecvfrom _P((struct socket *));
-int sosendto _P((struct socket *, struct mbuf *));
+int sosendto _P((struct socket *, MBuf ));
struct socket * solisten _P((u_int, u_int32_t, u_int, int));
+int sounlisten _P((u_int port));
void sorwakeup _P((struct socket *));
void sowwakeup _P((struct socket *));
void soisfconnecting _P((register struct socket *));
diff --git a/slirp/tcp.h b/slirp/tcp.h
index cd7e891..769f364 100644
--- a/slirp/tcp.h
+++ b/slirp/tcp.h
@@ -112,7 +112,9 @@ struct tcphdr {
/*
* User-settable options (used with setsockopt).
*/
-/* #define TCP_NODELAY 0x01 */ /* don't delay send to coalesce packets */
+#undef TCP_NODELAY
+#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
+#undef TCP_MAXSEG
/* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */
/*
diff --git a/slirp/tcp_input.c b/slirp/tcp_input.c
index c015161..4621ca2 100644
--- a/slirp/tcp_input.c
+++ b/slirp/tcp_input.c
@@ -37,8 +37,8 @@
/*
* Changes and additions relating to SLiRP
* Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
+ *
+ * Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
@@ -82,9 +82,9 @@ tcp_seq tcp_iss; /* tcp initial send seq # */
tcpstat.tcps_rcvpack++;\
tcpstat.tcps_rcvbyte += (ti)->ti_len;\
if (so->so_emu) { \
- if (tcp_emu((so),(m))) sbappend((so), (m)); \
+ if (tcp_emu((so),(m))) sbuf_append((so), (m)); \
} else \
- sbappend((so), (m)); \
+ sbuf_append((so), (m)); \
/* sorwakeup(so); */ \
} else {\
(flags) = tcp_reass((tp), (ti), (m)); \
@@ -102,9 +102,9 @@ tcp_seq tcp_iss; /* tcp initial send seq # */
tcpstat.tcps_rcvpack++;\
tcpstat.tcps_rcvbyte += (ti)->ti_len;\
if (so->so_emu) { \
- if (tcp_emu((so),(m))) sbappend(so, (m)); \
+ if (tcp_emu((so),(m))) sbuf_append(so, (m)); \
} else \
- sbappend((so), (m)); \
+ sbuf_append((so), (m)); \
/* sorwakeup(so); */ \
} else { \
(flags) = tcp_reass((tp), (ti), (m)); \
@@ -117,12 +117,12 @@ int
tcp_reass(tp, ti, m)
register struct tcpcb *tp;
register struct tcpiphdr *ti;
- struct mbuf *m;
+ MBuf m;
{
register struct tcpiphdr *q;
struct socket *so = tp->t_socket;
int flags;
-
+
/*
* Call with ti==0 after become established to
* force pre-ESTABLISHED data up to user socket.
@@ -152,7 +152,7 @@ tcp_reass(tp, ti, m)
if (i >= ti->ti_len) {
tcpstat.tcps_rcvduppack++;
tcpstat.tcps_rcvdupbyte += ti->ti_len;
- m_freem(m);
+ mbuf_free(m);
/*
* Try to present any queued data
* at the left window edge to the user.
@@ -161,7 +161,7 @@ tcp_reass(tp, ti, m)
*/
goto present; /* ??? */
}
- m_adj(m, i);
+ mbuf_trim(m, i);
ti->ti_len -= i;
ti->ti_seq += i;
}
@@ -182,13 +182,13 @@ tcp_reass(tp, ti, m)
if (i < q->ti_len) {
q->ti_seq += i;
q->ti_len -= i;
- m_adj((struct mbuf *) REASS_MBUF(q), i);
+ mbuf_trim((MBuf ) REASS_MBUF(q), i);
break;
}
q = (struct tcpiphdr *)q->ti_next;
- m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev);
+ m = (MBuf ) REASS_MBUF((struct tcpiphdr *)q->ti_prev);
remque_32((void *)(q->ti_prev));
- m_freem(m);
+ mbuf_free(m);
}
/*
@@ -212,16 +212,16 @@ present:
tp->rcv_nxt += ti->ti_len;
flags = ti->ti_flags & TH_FIN;
remque_32(ti);
- m = (struct mbuf *) REASS_MBUF(ti); /* XXX */
+ m = (MBuf ) REASS_MBUF(ti); /* XXX */
ti = (struct tcpiphdr *)ti->ti_next;
/* if (so->so_state & SS_FCANTRCVMORE) */
if (so->so_state & SS_FCANTSENDMORE)
- m_freem(m);
+ mbuf_free(m);
else {
if (so->so_emu) {
- if (tcp_emu(so,m)) sbappend(so, m);
+ if (tcp_emu(so,m)) sbuf_append(so, m);
} else
- sbappend(so, m);
+ sbuf_append(so, m);
}
} while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt);
/* sorwakeup(so); */
@@ -234,7 +234,7 @@ present:
*/
void
tcp_input(m, iphlen, inso)
- register struct mbuf *m;
+ register MBuf m;
int iphlen;
struct socket *inso;
{
@@ -254,15 +254,15 @@ tcp_input(m, iphlen, inso)
/* int ts_present = 0; */
DEBUG_CALL("tcp_input");
- DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n",
+ DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n",
(long )m, iphlen, (long )inso ));
-
+
/*
* If called with m == 0, then we're continuing the connect
*/
if (m == NULL) {
so = inso;
-
+
/* Re-set a few variables */
tp = sototcpcb(so);
m = so->so_m;
@@ -270,30 +270,30 @@ tcp_input(m, iphlen, inso)
ti = so->so_ti;
tiwin = ti->ti_win;
tiflags = ti->ti_flags;
-
+
goto cont_conn;
}
-
-
+
+
tcpstat.tcps_rcvtotal++;
/*
* Get IP and TCP header together in first mbuf.
* Note: IP leaves IP header in first mbuf.
*/
- ti = mtod(m, struct tcpiphdr *);
+ ti = MBUF_TO(m, struct tcpiphdr *);
if (iphlen > sizeof(struct ip )) {
- ip_stripoptions(m, (struct mbuf *)0);
+ ip_stripoptions(m, (MBuf )0);
iphlen=sizeof(struct ip );
}
/* XXX Check if too short */
-
+
/*
* Save a copy of the IP header in case we want restore it
* for sending an ICMP error message in response.
*/
- ip=mtod(m, struct ip *);
- save_ip = *ip;
+ ip=MBUF_TO(m, struct ip *);
+ save_ip = *ip;
save_ip.ip_len+= iphlen;
/*
@@ -305,7 +305,7 @@ tcp_input(m, iphlen, inso)
ti->ti_len = htons((u_int16_t)tlen);
len = sizeof(struct ip ) + tlen;
/* keep checksum for ICMP reply
- * ti->ti_sum = cksum(m, len);
+ * ti->ti_sum = cksum(m, len);
* if (ti->ti_sum) { */
if(cksum(m, len)) {
tcpstat.tcps_rcvbadsum++;
@@ -325,9 +325,9 @@ tcp_input(m, iphlen, inso)
ti->ti_len = tlen;
if (off > sizeof (struct tcphdr)) {
optlen = off - sizeof (struct tcphdr);
- optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
+ optp = MBUF_TO(m, caddr_t) + sizeof (struct tcpiphdr);
- /*
+ /*
* Do quick retrieval of timestamp options ("options
* prediction?"). If timestamp is the only option and it's
* formatted as recommended in RFC 1323 appendix A, we
@@ -347,7 +347,7 @@ tcp_input(m, iphlen, inso)
*/
}
tiflags = ti->ti_flags;
-
+
/*
* Convert TCP protocol specific fields to host format.
*/
@@ -361,7 +361,7 @@ tcp_input(m, iphlen, inso)
*/
m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
-
+
/*
* Locate pcb for segment.
*/
@@ -385,8 +385,8 @@ findso:
* but should either do a listen or a connect soon.
*
* state == CLOSED means we've done socreate() but haven't
- * attached it to a protocol yet...
- *
+ * attached it to a protocol yet...
+ *
* XXX If a TCB does not exist, and the TH_SYN flag is
* the only flag set, then create a session, mark it
* as if it was LISTENING, and continue...
@@ -394,32 +394,32 @@ findso:
if (so == 0) {
if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)
goto dropwithreset;
-
+
if ((so = socreate()) == NULL)
goto dropwithreset;
if (tcp_attach(so) < 0) {
free(so); /* Not sofree (if it failed, it's not insqued) */
goto dropwithreset;
}
-
- sbreserve(&so->so_snd, tcp_sndspace);
- sbreserve(&so->so_rcv, tcp_rcvspace);
-
+
+ sbuf_reserve(&so->so_snd, tcp_sndspace);
+ sbuf_reserve(&so->so_rcv, tcp_rcvspace);
+
/* tcp_last_so = so; */ /* XXX ? */
/* tp = sototcpcb(so); */
-
+
so->so_laddr = ti->ti_src;
so->so_lport = ti->ti_sport;
so->so_faddr = ti->ti_dst;
so->so_fport = ti->ti_dport;
-
+
if ((so->so_iptos = tcp_tos(so)) == 0)
so->so_iptos = ((struct ip *)ti)->ip_tos;
-
+
tp = sototcpcb(so);
tp->t_state = TCPS_LISTEN;
}
-
+
/*
* If this is a still-connecting socket, this probably
* a retransmit of the SYN. Whether it's a retransmit SYN
@@ -429,13 +429,13 @@ findso:
goto drop;
tp = sototcpcb(so);
-
+
/* XXX Should never fail */
if (tp == 0)
goto dropwithreset;
if (tp->t_state == TCPS_CLOSED)
goto drop;
-
+
/* Unscale the window into a 32-bit value. */
/* if ((tiflags & TH_SYN) == 0)
* tiwin = ti->ti_win << tp->snd_scale;
@@ -458,11 +458,11 @@ findso:
* else do it below (after getting remote address).
*/
if (optp && tp->t_state != TCPS_LISTEN)
- tcp_dooptions(tp, (u_char *)optp, optlen, ti);
+ tcp_dooptions(tp, (u_char *)optp, optlen, ti);
/* , */
/* &ts_present, &ts_val, &ts_ecr); */
- /*
+ /*
* Header prediction: check for the two common cases
* of a uni-directional data xfer. If the packet has
* no control flags, is in-sequence, the window didn't
@@ -486,7 +486,7 @@ findso:
ti->ti_seq == tp->rcv_nxt &&
tiwin && tiwin == tp->snd_wnd &&
tp->snd_nxt == tp->snd_max) {
- /*
+ /*
* If last ACK falls within this segment's sequence numbers,
* record the timestamp.
*/
@@ -506,16 +506,16 @@ findso:
++tcpstat.tcps_predack;
/* if (ts_present)
* tcp_xmit_timer(tp, tcp_now-ts_ecr+1);
- * else
+ * else
*/ if (tp->t_rtt &&
SEQ_GT(ti->ti_ack, tp->t_rtseq))
tcp_xmit_timer(tp, tp->t_rtt);
acked = ti->ti_ack - tp->snd_una;
tcpstat.tcps_rcvackpack++;
tcpstat.tcps_rcvackbyte += acked;
- sbdrop(&so->so_snd, acked);
+ sbuf_drop(&so->so_snd, acked);
tp->snd_una = ti->ti_ack;
- m_freem(m);
+ mbuf_free(m);
/*
* If all outstanding data are acked, stop
@@ -531,14 +531,14 @@ findso:
else if (tp->t_timer[TCPT_PERSIST] == 0)
tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
- /*
+ /*
* There's room in so_snd, sowwakup will read()
* from the socket if we can
*/
/* if (so->so_snd.sb_flags & SB_NOTIFY)
* sowwakeup(so);
*/
- /*
+ /*
* This is called because sowwakeup might have
* put data into so_snd. Since we don't so sowwakeup,
* we don't need this.. XXX???
@@ -550,7 +550,7 @@ findso:
}
} else if (ti->ti_ack == tp->snd_una &&
tp->seg_next == (tcpiphdrp_32)tp &&
- ti->ti_len <= sbspace(&so->so_rcv)) {
+ ti->ti_len <= sbuf_space(&so->so_rcv)) {
/*
* this is a pure, in-sequence data packet
* with nothing on the reassembly queue and
@@ -564,25 +564,25 @@ findso:
* Add data to socket buffer.
*/
if (so->so_emu) {
- if (tcp_emu(so,m)) sbappend(so, m);
+ if (tcp_emu(so,m)) sbuf_append(so, m);
} else
- sbappend(so, m);
-
- /*
+ sbuf_append(so, m);
+
+ /*
* XXX This is called when data arrives. Later, check
* if we can actually write() to the socket
* XXX Need to check? It's be NON_BLOCKING
*/
/* sorwakeup(so); */
-
+
/*
* If this is a short packet, then ACK now - with Nagel
* congestion avoidance sender won't send more until
* he gets an ACK.
- *
+ *
* It is better to not delay acks at all to maximize
* TCP throughput. See RFC 2581.
- */
+ */
tp->t_flags |= TF_ACKNOW;
tcp_output(tp);
return;
@@ -595,7 +595,7 @@ findso:
* but not less than advertised window.
*/
{ int win;
- win = sbspace(&so->so_rcv);
+ win = sbuf_space(&so->so_rcv);
if (win < 0)
win = 0;
tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));
@@ -624,46 +624,26 @@ findso:
goto dropwithreset;
if ((tiflags & TH_SYN) == 0)
goto drop;
-
+
/*
* This has way too many gotos...
* But a bit of spaghetti code never hurt anybody :)
*/
-
+
/*
* If this is destined for the control address, then flag to
* tcp_ctl once connected, otherwise connect
*/
if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) {
int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff;
- if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) {
-#if 0
- if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) {
- /* Command or exec adress */
- so->so_state |= SS_CTL;
- } else
-#endif
- {
- /* May be an add exec */
- struct ex_list *ex_ptr;
- for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
- if(ex_ptr->ex_fport == so->so_fport &&
- lastbyte == ex_ptr->ex_addr) {
- so->so_state |= SS_CTL;
- break;
- }
- }
- }
- if(so->so_state & SS_CTL) goto cont_input;
- }
/* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
}
-
+
if (so->so_emu & EMU_NOCONNECT) {
so->so_emu &= ~EMU_NOCONNECT;
goto cont_input;
}
-
+
if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
u_char code=ICMP_UNREACH_NET;
DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",
@@ -671,7 +651,7 @@ findso:
if(errno == ECONNREFUSED) {
/* ACK the SYN, send RST to refuse the connection */
tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0,
- TH_RST|TH_ACK);
+ TH_RST|TH_ACK);
} else {
if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
HTONL(ti->ti_seq); /* restore tcp header */
@@ -684,7 +664,7 @@ findso:
icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno));
}
tp = tcp_close(tp);
- m_free(m);
+ mbuf_free(m);
} else {
/*
* Haven't connected yet, save the current mbuf
@@ -699,25 +679,26 @@ findso:
}
return;
- cont_conn:
- /* m==NULL
+ cont_conn:
+ /* m==NULL
* Check if the connect succeeded
*/
if (so->so_state & SS_NOFDREF) {
+ DEBUG_MISC((dfd, " tcp_input closing connecting socket %lx\n", (long)so));
tp = tcp_close(tp);
goto dropwithreset;
}
- cont_input:
+ cont_input:
tcp_template(tp);
-
+
if (optp)
tcp_dooptions(tp, (u_char *)optp, optlen, ti);
/* , */
/* &ts_present, &ts_val, &ts_ecr); */
-
+
if (iss)
tp->iss = iss;
- else
+ else
tp->iss = tcp_iss;
tcp_iss += TCP_ISSINCR/2;
tp->irs = ti->ti_seq;
@@ -727,9 +708,10 @@ findso:
tp->t_state = TCPS_SYN_RECEIVED;
tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
tcpstat.tcps_accepts++;
+ DEBUG_MISC((dfd, " tcp_input accept connected socket %lx\n", (long)so));
goto trimthenstep6;
} /* case TCPS_LISTEN */
-
+
/*
* If the state is SYN_SENT:
* if seg contains an ACK, but not for our SYN, drop the input.
@@ -770,7 +752,7 @@ findso:
tcpstat.tcps_connects++;
soisfconnected(so);
tp->t_state = TCPS_ESTABLISHED;
-
+
/* Do window scaling on this connection? */
/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
* (TF_RCVD_SCALE|TF_REQ_SCALE)) {
@@ -779,7 +761,7 @@ findso:
* }
*/
(void) tcp_reass(tp, (struct tcpiphdr *)0,
- (struct mbuf *)0);
+ (MBuf )0);
/*
* if we didn't have to retransmit the SYN,
* use its rtt as our initial srtt & rtt var.
@@ -798,7 +780,7 @@ trimthenstep6:
ti->ti_seq++;
if (ti->ti_len > tp->rcv_wnd) {
todrop = ti->ti_len - tp->rcv_wnd;
- m_adj(m, -todrop);
+ mbuf_trim(m, -todrop);
ti->ti_len = tp->rcv_wnd;
tiflags &= ~TH_FIN;
tcpstat.tcps_rcvpackafterwin++;
@@ -811,10 +793,10 @@ trimthenstep6:
/*
* States other than LISTEN or SYN_SENT.
* First check timestamp, if present.
- * Then check that at least some bytes of segment are within
+ * Then check that at least some bytes of segment are within
* receive window. If segment begins before rcv_nxt,
* drop leading data (and SYN); if nothing left, just ack.
- *
+ *
* RFC 1323 PAWS: If we have a timestamp reply on this segment
* and it's less than ts_recent, drop it.
*/
@@ -849,7 +831,7 @@ trimthenstep6:
if (tiflags & TH_SYN) {
tiflags &= ~TH_SYN;
ti->ti_seq++;
- if (ti->ti_urp > 1)
+ if (ti->ti_urp > 1)
ti->ti_urp--;
else
tiflags &= ~TH_URG;
@@ -866,7 +848,7 @@ trimthenstep6:
* of sequence; drop it.
*/
tiflags &= ~TH_FIN;
-
+
/*
* Send an ACK to resynchronize and drop any data.
* But keep on processing for RST or ACK.
@@ -879,7 +861,7 @@ trimthenstep6:
tcpstat.tcps_rcvpartduppack++;
tcpstat.tcps_rcvpartdupbyte += todrop;
}
- m_adj(m, todrop);
+ mbuf_trim(m, todrop);
ti->ti_seq += todrop;
ti->ti_len -= todrop;
if (ti->ti_urp > todrop)
@@ -936,7 +918,7 @@ trimthenstep6:
goto dropafterack;
} else
tcpstat.tcps_rcvbyteafterwin += todrop;
- m_adj(m, -todrop);
+ mbuf_trim(m, -todrop);
ti->ti_len -= todrop;
tiflags &= ~(TH_PUSH|TH_FIN);
}
@@ -1017,12 +999,12 @@ trimthenstep6:
goto dropwithreset;
tcpstat.tcps_connects++;
tp->t_state = TCPS_ESTABLISHED;
- /*
- * The sent SYN is ack'ed with our sequence number +1
- * The first data byte already in the buffer will get
+ /*
+ * The sent SYN is ack'ed with our sequence number +1
+ * The first data byte already in the buffer will get
* lost if no correction is made. This is only needed for
* SS_CTL since the buffer is empty otherwise.
- * tp->snd_una++; or:
+ * tp->snd_una++; or:
*/
tp->snd_una=ti->ti_ack;
if (so->so_state & SS_CTL) {
@@ -1040,7 +1022,7 @@ trimthenstep6:
} else {
soisfconnected(so);
}
-
+
/* Do window scaling? */
/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
* (TF_RCVD_SCALE|TF_REQ_SCALE)) {
@@ -1048,7 +1030,7 @@ trimthenstep6:
* tp->rcv_scale = tp->request_r_scale;
* }
*/
- (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
+ (void) tcp_reass(tp, (struct tcpiphdr *)0, (MBuf )0);
tp->snd_wl1 = ti->ti_seq - 1;
/* Avoid ack processing; snd_una==ti_ack => dup ack */
goto synrx_to_est;
@@ -1094,7 +1076,7 @@ trimthenstep6:
* the new ssthresh).
*
* Dup acks mean that packets have left the
- * network (they're now cached at the receiver)
+ * network (they're now cached at the receiver)
* so bump cwnd by the amount in the receiver
* to keep a constant cwnd packets in the
* network.
@@ -1159,7 +1141,7 @@ trimthenstep6:
/* if (ts_present)
* tcp_xmit_timer(tp, tcp_now-ts_ecr+1);
* else
- */
+ */
if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
tcp_xmit_timer(tp,tp->t_rtt);
@@ -1191,16 +1173,16 @@ trimthenstep6:
}
if (acked > so->so_snd.sb_cc) {
tp->snd_wnd -= so->so_snd.sb_cc;
- sbdrop(&so->so_snd, (int )so->so_snd.sb_cc);
+ sbuf_drop(&so->so_snd, (int )so->so_snd.sb_cc);
ourfinisacked = 1;
} else {
- sbdrop(&so->so_snd, acked);
+ sbuf_drop(&so->so_snd, acked);
tp->snd_wnd -= acked;
ourfinisacked = 0;
}
/*
* XXX sowwakup is called when data is acked and there's room for
- * for more data... it should read() the socket
+ * for more data... it should read() the socket
*/
/* if (so->so_snd.sb_flags & SB_NOTIFY)
* sowwakeup(so);
@@ -1278,7 +1260,7 @@ step6:
* Don't look at window if no ACK: TAC's send garbage on first SYN.
*/
if ((tiflags & TH_ACK) &&
- (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
+ (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
(tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
(tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) {
/* keep track of pure window updates */
@@ -1313,14 +1295,14 @@ step6:
* If this segment advances the known urgent pointer,
* then mark the data stream. This should not happen
* in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
- * a FIN has been received from the remote side.
+ * a FIN has been received from the remote side.
* In these states we ignore the URG.
*
* According to RFC961 (Assigned Protocols),
* the urgent pointer points to the last octet
* of urgent data. We continue, however,
* to consider it to indicate the first octet
- * of data past the urgent section as the original
+ * of data past the urgent section as the original
* spec states (in one of two places).
*/
if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
@@ -1328,7 +1310,7 @@ step6:
so->so_urgc = so->so_rcv.sb_cc +
(tp->rcv_up - tp->rcv_nxt); /* -1; */
tp->rcv_up = ti->ti_seq + ti->ti_urp;
-
+
}
} else
/*
@@ -1358,7 +1340,7 @@ dodata:
*/
len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt);
} else {
- m_free(m);
+ mbuf_free(m);
tiflags &= ~TH_FIN;
}
@@ -1379,7 +1361,7 @@ dodata:
*/
/* sofcantrcvmore(so); */
sofwdrain(so);
-
+
tp->t_flags |= TF_ACKNOW;
tp->rcv_nxt++;
}
@@ -1393,7 +1375,7 @@ dodata:
case TCPS_ESTABLISHED:
if(so->so_emu == EMU_CTL) /* no shutdown on socket */
tp->t_state = TCPS_LAST_ACK;
- else
+ else
tp->t_state = TCPS_CLOSE_WAIT;
break;
@@ -1407,7 +1389,7 @@ dodata:
/*
* In FIN_WAIT_2 state enter the TIME_WAIT state,
- * starting the time-wait timer, turning off the other
+ * starting the time-wait timer, turning off the other
* standard timers.
*/
case TCPS_FIN_WAIT_2:
@@ -1430,7 +1412,7 @@ dodata:
* If this is a small packet, then ACK now - with Nagel
* congestion avoidance sender won't send more until
* he gets an ACK.
- *
+ *
* See above.
*/
/* if (ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg) {
@@ -1460,13 +1442,13 @@ dropafterack:
*/
if (tiflags & TH_RST)
goto drop;
- m_freem(m);
+ mbuf_free(m);
tp->t_flags |= TF_ACKNOW;
(void) tcp_output(tp);
return;
dropwithreset:
- /* reuses m if m!=NULL, m_free() unnecessary */
+ /* reuses m if m!=NULL, mbuf_free() unnecessary */
if (tiflags & TH_ACK)
tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
else {
@@ -1481,7 +1463,7 @@ drop:
/*
* Drop space held by incoming segment and return.
*/
- m_free(m);
+ mbuf_free(m);
return;
}
@@ -1547,7 +1529,7 @@ tcp_dooptions(tp, cp, cnt, ti)
* memcpy((char *) ts_ecr, (char *)cp + 6, sizeof(*ts_ecr));
* NTOHL(*ts_ecr);
*
- */ /*
+ */ /*
* * A timestamp received in a SYN makes
* * it ok to send timestamp requests and replies.
* */
@@ -1575,13 +1557,13 @@ void
tcp_pulloutofband(so, ti, m)
struct socket *so;
struct tcpiphdr *ti;
- register struct mbuf *m;
+ register MBuf m;
{
int cnt = ti->ti_urp - 1;
-
+
while (cnt >= 0) {
if (m->m_len > cnt) {
- char *cp = mtod(m, caddr_t) + cnt;
+ char *cp = MBUF_TO(m, caddr_t) + cnt;
struct tcpcb *tp = sototcpcb(so);
tp->t_iobc = *cp;
@@ -1615,7 +1597,7 @@ tcp_xmit_timer(tp, rtt)
DEBUG_CALL("tcp_xmit_timer");
DEBUG_ARG("tp = %lx", (long)tp);
DEBUG_ARG("rtt = %d", rtt);
-
+
tcpstat.tcps_rttupdated++;
if (tp->t_srtt != 0) {
/*
@@ -1644,7 +1626,7 @@ tcp_xmit_timer(tp, rtt)
if ((tp->t_rttvar += delta) <= 0)
tp->t_rttvar = 1;
} else {
- /*
+ /*
* No rtt measurement yet - use the unsmoothed rtt.
* Set the variance to half the rtt (so our first
* retransmit happens at 3*rtt).
@@ -1668,7 +1650,7 @@ tcp_xmit_timer(tp, rtt)
*/
TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp),
(short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
-
+
/*
* We received an ack for a packet that wasn't retransmitted;
* it is probably safe to discard any error indications we've
@@ -1702,24 +1684,24 @@ tcp_mss(tp, offer)
{
struct socket *so = tp->t_socket;
int mss;
-
+
DEBUG_CALL("tcp_mss");
DEBUG_ARG("tp = %lx", (long)tp);
DEBUG_ARG("offer = %d", offer);
-
+
mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr);
if (offer)
mss = min(mss, offer);
mss = max(mss, 32);
if (mss < tp->t_maxseg || offer != 0)
tp->t_maxseg = mss;
-
+
tp->snd_cwnd = mss;
-
- sbreserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0));
- sbreserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0));
-
+
+ sbuf_reserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0));
+ sbuf_reserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0));
+
DEBUG_MISC((dfd, " returning mss = %d\n", mss));
-
+
return mss;
}
diff --git a/slirp/tcp_output.c b/slirp/tcp_output.c
index b79bcf1..95246aa 100644
--- a/slirp/tcp_output.c
+++ b/slirp/tcp_output.c
@@ -74,7 +74,7 @@ tcp_output(tp)
register struct socket *so = tp->t_socket;
register long len, win;
int off, flags, error;
- register struct mbuf *m;
+ register MBuf m;
register struct tcpiphdr *ti;
u_char opt[MAX_TCPOPTLEN];
unsigned optlen, hdrlen;
@@ -166,7 +166,7 @@ again:
if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
flags &= ~TH_FIN;
- win = sbspace(&so->so_rcv);
+ win = sbuf_space(&so->so_rcv);
/*
* Sender silly window avoidance. If connection is idle
@@ -348,7 +348,7 @@ send:
tcpstat.tcps_sndbyte += len;
}
- m = m_get();
+ m = mbuf_alloc();
if (m == NULL) {
/* error = ENOBUFS; */
error = 1;
@@ -363,11 +363,11 @@ send:
*/
/* if (len <= MHLEN - hdrlen - max_linkhdr) { */
- sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen);
+ sbuf_copy(&so->so_snd, off, (int) len, MBUF_TO(m, caddr_t) + hdrlen);
m->m_len += len;
/* } else {
- * m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len);
+ * m->m_next = mbuf_copy(so->so_snd.sb_mb, off, (int) len);
* if (m->m_next == 0)
* len = 0;
* }
@@ -390,7 +390,7 @@ send:
else
tcpstat.tcps_sndwinup++;
- m = m_get();
+ m = mbuf_alloc();
if (m == NULL) {
/* error = ENOBUFS; */
error = 1;
@@ -400,7 +400,7 @@ send:
m->m_len = hdrlen;
}
- ti = mtod(m, struct tcpiphdr *);
+ ti = MBUF_TO(m, struct tcpiphdr *);
memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr));
@@ -547,7 +547,7 @@ send:
error = ip_output(so, m);
/* #else
- * error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route,
+ * error = ip_output(m, (MBuf )0, &tp->t_inpcb->inp_route,
* so->so_options & SO_DONTROUTE);
* #endif
*/
diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c
index e66987e..b42e6ea 100644
--- a/slirp/tcp_subr.c
+++ b/slirp/tcp_subr.c
@@ -37,13 +37,16 @@
/*
* Changes and additions relating to SLiRP
* Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
+ *
+ * Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
#define WANT_SYS_IOCTL_H
#include <slirp.h>
+#define SLIRP_COMPILATION
+#include "sockets.h"
+#include "proxy_common.h"
/* patchable/settable parameters for tcp */
int tcp_mssdflt = TCP_MSS;
@@ -60,11 +63,11 @@ tcp_init()
{
tcp_iss = 1; /* wrong */
tcb.so_next = tcb.so_prev = &tcb;
-
+
/* tcp_rcvspace = our Window we advertise to the remote */
tcp_rcvspace = TCP_RCVSPACE;
tcp_sndspace = TCP_SNDSPACE;
-
+
/* Make sure tcp_sndspace is at least 2*MSS */
if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)))
tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr));
@@ -92,7 +95,7 @@ tcp_template(tp)
n->ti_dst = so->so_laddr;
n->ti_sport = so->so_fport;
n->ti_dport = so->so_lport;
-
+
n->ti_seq = 0;
n->ti_ack = 0;
n->ti_x2 = 0;
@@ -120,7 +123,7 @@ void
tcp_respond(tp, ti, m, ack, seq, flags)
struct tcpcb *tp;
register struct tcpiphdr *ti;
- register struct mbuf *m;
+ register MBuf m;
tcp_seq ack, seq;
int flags;
{
@@ -134,11 +137,11 @@ tcp_respond(tp, ti, m, ack, seq, flags)
DEBUG_ARG("ack = %u", ack);
DEBUG_ARG("seq = %u", seq);
DEBUG_ARG("flags = %x", flags);
-
+
if (tp)
- win = sbspace(&tp->t_socket->so_rcv);
+ win = sbuf_space(&tp->t_socket->so_rcv);
if (m == 0) {
- if ((m = m_get()) == NULL)
+ if ((m = mbuf_alloc()) == NULL)
return;
#ifdef TCP_COMPAT_42
tlen = 1;
@@ -146,16 +149,16 @@ tcp_respond(tp, ti, m, ack, seq, flags)
tlen = 0;
#endif
m->m_data += if_maxlinkhdr;
- *mtod(m, struct tcpiphdr *) = *ti;
- ti = mtod(m, struct tcpiphdr *);
+ *MBUF_TO(m, struct tcpiphdr *) = *ti;
+ ti = MBUF_TO(m, struct tcpiphdr *);
flags = TH_ACK;
} else {
- /*
+ /*
* ti points into m so the next line is just making
* the mbuf point to ti
*/
m->m_data = (caddr_t)ti;
-
+
m->m_len = sizeof (struct tcpiphdr);
tlen = 0;
#define xchg(a,b,type) { type t; t=a; a=b; b=t; }
@@ -183,11 +186,11 @@ tcp_respond(tp, ti, m, ack, seq, flags)
ti->ti_sum = cksum(m, tlen);
((struct ip *)ti)->ip_len = tlen;
- if(flags & TH_RST)
+ if(flags & TH_RST)
((struct ip *)ti)->ip_ttl = MAXTTL;
- else
+ else
((struct ip *)ti)->ip_ttl = ip_defttl;
-
+
(void) ip_output((struct socket *)0, m);
}
@@ -201,18 +204,18 @@ tcp_newtcpcb(so)
struct socket *so;
{
register struct tcpcb *tp;
-
+
tp = (struct tcpcb *)malloc(sizeof(*tp));
if (tp == NULL)
return ((struct tcpcb *)0);
-
+
memset((char *) tp, 0, sizeof(struct tcpcb));
tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp;
tp->t_maxseg = tcp_mssdflt;
-
+
tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0;
tp->t_socket = so;
-
+
/*
* Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no
* rtt estimate. Set rttvar so that srtt + 2 * rttvar gives
@@ -222,14 +225,14 @@ tcp_newtcpcb(so)
tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2;
tp->t_rttmin = TCPTV_MIN;
- TCPT_RANGESET(tp->t_rxtcur,
+ TCPT_RANGESET(tp->t_rxtcur,
((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1,
TCPTV_MIN, TCPTV_REXMTMAX);
tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT;
tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT;
tp->t_state = TCPS_CLOSED;
-
+
so->so_tcpcb = tp;
return (tp);
@@ -240,7 +243,7 @@ tcp_newtcpcb(so)
* the specified error. If connection is synchronized,
* then send a RST to peer.
*/
-struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
+struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
{
/* tcp_drop(tp, errno)
register struct tcpcb *tp;
@@ -251,7 +254,7 @@ struct tcpcb *tcp_drop(struct tcpcb *tp, int err)
DEBUG_CALL("tcp_drop");
DEBUG_ARG("tp = %lx", (long)tp);
DEBUG_ARG("errno = %d", errno);
-
+
if (TCPS_HAVERCVDSYN(tp->t_state)) {
tp->t_state = TCPS_CLOSED;
(void) tcp_output(tp);
@@ -277,22 +280,22 @@ tcp_close(tp)
{
register struct tcpiphdr *t;
struct socket *so = tp->t_socket;
- register struct mbuf *m;
+ register MBuf m;
DEBUG_CALL("tcp_close");
DEBUG_ARG("tp = %lx", (long )tp);
-
+
/* free the reassembly queue, if any */
t = (struct tcpiphdr *) tp->seg_next;
while (t != (struct tcpiphdr *)tp) {
t = (struct tcpiphdr *)t->ti_next;
- m = (struct mbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev);
+ m = (MBuf ) REASS_MBUF((struct tcpiphdr *)t->ti_prev);
remque_32((struct tcpiphdr *) t->ti_prev);
- m_freem(m);
+ mbuf_free(m);
}
/* It's static */
/* if (tp->t_template)
- * (void) m_free(dtom(tp->t_template));
+ * (void) mbuf_free(MBUF_FROM(tp->t_template));
*/
/* free(tp, M_PCB); */
free(tp);
@@ -302,8 +305,8 @@ tcp_close(tp)
if (so == tcp_last_so)
tcp_last_so = &tcb;
closesocket(so->s);
- sbfree(&so->so_rcv);
- sbfree(&so->so_snd);
+ sbuf_free(&so->so_rcv);
+ sbuf_free(&so->so_snd);
sofree(so);
tcpstat.tcps_closed++;
return ((struct tcpcb *)0);
@@ -356,7 +359,7 @@ tcp_sockclosed(tp)
DEBUG_CALL("tcp_sockclosed");
DEBUG_ARG("tp = %lx", (long)tp);
-
+
switch (tp->t_state) {
case TCPS_CLOSED:
@@ -382,56 +385,80 @@ tcp_sockclosed(tp)
tcp_output(tp);
}
-/*
+static void
+tcp_proxy_event( struct socket* so,
+ ProxyEvent event )
+{
+ so->so_state &= ~SS_PROXIFIED;
+
+ if (event == PROXY_EVENT_CONNECTED) {
+ so->so_state &= ~(SS_ISFCONNECTING);
+ }
+ else {
+ so->so_state = SS_NOFDREF;
+ }
+
+ /* continue the connect */
+ tcp_input(NULL, sizeof(struct ip), so);
+}
+
+/*
* Connect to a host on the Internet
* Called by tcp_input
* Only do a connect, the tcp fields will be set in tcp_input
* return 0 if there's a result of the connect,
* else return -1 means we're still connecting
* The return value is almost always -1 since the socket is
- * nonblocking. Connect returns after the SYN is sent, and does
+ * nonblocking. Connect returns after the SYN is sent, and does
* not wait for ACK+SYN.
*/
int tcp_fconnect(so)
struct socket *so;
{
int ret=0;
-
+ int try_proxy = 0;
+
DEBUG_CALL("tcp_fconnect");
DEBUG_ARG("so = %lx", (long )so);
if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) {
- int opt, s=so->s;
+ int s=so->s;
struct sockaddr_in addr;
- fd_nonblock(s);
- opt = 1;
- setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt ));
- opt = 1;
- setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt ));
-
+ socket_set_nonblock(s);
+ socket_set_xreuseaddr(s);
+ socket_set_oobinline(s);
+
addr.sin_family = AF_INET;
if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) {
/* It's an alias */
- switch(ntohl(so->so_faddr.s_addr) & 0xff) {
- case CTL_DNS:
- addr.sin_addr = dns_addr;
- break;
- case CTL_ALIAS:
- default:
- addr.sin_addr = loopback_addr;
- break;
- }
- } else
+ int last_byte = ntohl(so->so_faddr.s_addr) & 0xff;
+
+ if (CTL_IS_DNS(last_byte))
+ addr.sin_addr = dns_addr[last_byte - CTL_DNS];
+ else
+ addr.sin_addr = loopback_addr;
+ } else {
addr.sin_addr = so->so_faddr;
+ try_proxy = 1;
+ }
addr.sin_port = so->so_fport;
-
+
DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, "
- "addr.sin_addr.s_addr=%.16s\n",
- ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
+ "addr.sin_addr.s_addr=%.16s\n",
+ ntohs(addr.sin_port), inet_ntoa(addr.sin_addr)));
+
+ if (try_proxy) {
+ if (!proxy_manager_add(s, &addr, so, (ProxyEventFunc) tcp_proxy_event)) {
+ soisfconnecting(so);
+ so->so_state |= SS_PROXIFIED;
+ return 0;
+ }
+ }
+
/* We don't care what port we get */
ret = connect(s,(struct sockaddr *)&addr,sizeof (addr));
-
+
/*
* If it's not in progress, it failed, so we just return 0,
* without clearing SS_NOFDREF
@@ -444,16 +471,16 @@ int tcp_fconnect(so)
/*
* Accept the socket and connect to the local-host
- *
+ *
* We have a problem. The correct thing to do would be
* to first connect to the local-host, and only if the
* connection is accepted, then do an accept() here.
- * But, a) we need to know who's trying to connect
+ * But, a) we need to know who's trying to connect
* to the socket to be able to SYN the local-host, and
* b) we are already connected to the foreign host by
* the time it gets to accept(), so... We simply accept
* here and SYN the local-host.
- */
+ */
void
tcp_connect(inso)
struct socket *inso;
@@ -462,11 +489,11 @@ tcp_connect(inso)
struct sockaddr_in addr;
int addrlen = sizeof(struct sockaddr_in);
struct tcpcb *tp;
- int s, opt;
+ int s;
DEBUG_CALL("tcp_connect");
DEBUG_ARG("inso = %lx", (long)inso);
-
+
/*
* If it's an SS_ACCEPTONCE socket, no need to socreate()
* another socket, just use the accept() socket.
@@ -487,38 +514,37 @@ tcp_connect(inso)
so->so_laddr = inso->so_laddr;
so->so_lport = inso->so_lport;
}
-
+
(void) tcp_mss(sototcpcb(so), 0);
if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) {
tcp_close(sototcpcb(so)); /* This will sofree() as well */
return;
}
- fd_nonblock(s);
- opt = 1;
- setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
- opt = 1;
- setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int));
-
+ socket_set_nonblock(s);
+ socket_set_xreuseaddr(s);
+ socket_set_oobinline(s);
+ socket_set_lowlatency(s);
+
so->so_fport = addr.sin_port;
so->so_faddr = addr.sin_addr;
/* Translate connections from localhost to the real hostname */
if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr)
so->so_faddr = alias_addr;
-
+
/* Close the accept() socket, set right state */
if (inso->so_state & SS_FACCEPTONCE) {
- closesocket(so->s); /* If we only accept once, close the accept() socket */
+ socket_close(so->s); /* If we only accept once, close the accept() socket */
so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */
/* if it's not FACCEPTONCE, it's already NOFDREF */
}
so->s = s;
-
+
so->so_iptos = tcp_tos(so);
tp = sototcpcb(so);
tcp_template(tp);
-
+
/* Compute window scaling to request. */
/* while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
* (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
@@ -527,10 +553,10 @@ tcp_connect(inso)
/* soisconnecting(so); */ /* NOFDREF used instead */
tcpstat.tcps_connattempt++;
-
+
tp->t_state = TCPS_SYN_SENT;
tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
- tp->iss = tcp_iss;
+ tp->iss = tcp_iss;
tcp_iss += TCP_ISSINCR/2;
tcp_sendseqinit(tp);
tcp_output(tp);
@@ -545,7 +571,7 @@ tcp_attach(so)
{
if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL)
return -1;
-
+
insque(so, &tcb);
return 0;
@@ -570,8 +596,7 @@ struct tos_t tcptos[] = {
{0, 0, 0, 0}
};
-struct emu_t *tcpemu = 0;
-
+
/*
* Return TOS according to the above table
*/
@@ -581,7 +606,7 @@ tcp_tos(so)
{
int i = 0;
struct emu_t *emup;
-
+
while(tcptos[i].tos) {
if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) ||
(tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) {
@@ -590,16 +615,7 @@ tcp_tos(so)
}
i++;
}
-
- /* Nope, lets see if there's a user-added one */
- for (emup = tcpemu; emup; emup = emup->next) {
- if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) ||
- (emup->lport && (ntohs(so->so_lport) == emup->lport))) {
- so->so_emu = emup->emu;
- return emup->tos;
- }
- }
-
+
return 0;
}
@@ -610,54 +626,54 @@ int do_echo = -1;
* This includes ftp (the data connection is
* initiated by the server) and IRC (DCC CHAT and
* DCC SEND) for now
- *
+ *
* NOTE: It's possible to crash SLiRP by sending it
* unstandard strings to emulate... if this is a problem,
* more checks are needed here
*
* XXX Assumes the whole command came in one packet
- *
+ *
* XXX Some ftp clients will have their TOS set to
* LOWDELAY and so Nagel will kick in. Because of this,
* we'll get the first letter, followed by the rest, so
* we simply scan for ORT instead of PORT...
* DCC doesn't have this problem because there's other stuff
* in the packet before the DCC command.
- *
- * Return 1 if the mbuf m is still valid and should be
- * sbappend()ed
- *
- * NOTE: if you return 0 you MUST m_free() the mbuf!
+ *
+ * Return 1 if the mbuf m is still valid and should be
+ * sbuf_append()ed
+ *
+ * NOTE: if you return 0 you MUST mbuf_free() the mbuf!
*/
int
tcp_emu(so, m)
struct socket *so;
- struct mbuf *m;
+ MBuf m;
{
u_int n1, n2, n3, n4, n5, n6;
char buff[256];
u_int32_t laddr;
u_int lport;
char *bptr;
-
+
DEBUG_CALL("tcp_emu");
DEBUG_ARG("so = %lx", (long)so);
DEBUG_ARG("m = %lx", (long)m);
-
+
switch(so->so_emu) {
int x, i;
-
+
case EMU_IDENT:
/*
* Identification protocol as per rfc-1413
*/
-
+
{
struct socket *tmpso;
struct sockaddr_in addr;
int addrlen = sizeof(struct sockaddr_in);
- struct sbuf *so_rcv = &so->so_rcv;
-
+ SBuf so_rcv = &so->so_rcv;
+
memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
so_rcv->sb_wptr += m->m_len;
so_rcv->sb_rptr += m->m_len;
@@ -683,337 +699,41 @@ tcp_emu(so, m)
so_rcv->sb_rptr = so_rcv->sb_data;
so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc;
}
- m_free(m);
+ mbuf_free(m);
return 0;
}
-
-#if 0
- case EMU_RLOGIN:
- /*
- * Rlogin emulation
- * First we accumulate all the initial option negotiation,
- * then fork_exec() rlogin according to the options
- */
- {
- int i, i2, n;
- char *ptr;
- char args[100];
- char term[100];
- struct sbuf *so_snd = &so->so_snd;
- struct sbuf *so_rcv = &so->so_rcv;
-
- /* First check if they have a priveladged port, or too much data has arrived */
- if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
- (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
- memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
- so_snd->sb_wptr += 18;
- so_snd->sb_cc += 18;
- tcp_sockclosed(sototcpcb(so));
- m_free(m);
- return 0;
- }
-
- /* Append the current data */
- memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
- so_rcv->sb_wptr += m->m_len;
- so_rcv->sb_rptr += m->m_len;
- m_free(m);
-
- /*
- * Check if we have all the initial options,
- * and build argument list to rlogin while we're here
- */
- n = 0;
- ptr = so_rcv->sb_data;
- args[0] = 0;
- term[0] = 0;
- while (ptr < so_rcv->sb_wptr) {
- if (*ptr++ == 0) {
- n++;
- if (n == 2) {
- sprintf(args, "rlogin -l %s %s",
- ptr, inet_ntoa(so->so_faddr));
- } else if (n == 3) {
- i2 = so_rcv->sb_wptr - ptr;
- for (i = 0; i < i2; i++) {
- if (ptr[i] == '/') {
- ptr[i] = 0;
-#ifdef HAVE_SETENV
- sprintf(term, "%s", ptr);
-#else
- sprintf(term, "TERM=%s", ptr);
-#endif
- ptr[i] = '/';
- break;
- }
- }
- }
- }
- }
-
- if (n != 4)
- return 0;
-
- /* We have it, set our term variable and fork_exec() */
-#ifdef HAVE_SETENV
- setenv("TERM", term, 1);
-#else
- putenv(term);
-#endif
- fork_exec(so, args, 2);
- term[0] = 0;
- so->so_emu = 0;
-
- /* And finally, send the client a 0 character */
- so_snd->sb_wptr[0] = 0;
- so_snd->sb_wptr++;
- so_snd->sb_cc++;
-
- return 0;
- }
-
- case EMU_RSH:
- /*
- * rsh emulation
- * First we accumulate all the initial option negotiation,
- * then rsh_exec() rsh according to the options
- */
- {
- int n;
- char *ptr;
- char *user;
- char *args;
- struct sbuf *so_snd = &so->so_snd;
- struct sbuf *so_rcv = &so->so_rcv;
-
- /* First check if they have a priveladged port, or too much data has arrived */
- if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 ||
- (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) {
- memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
- so_snd->sb_wptr += 18;
- so_snd->sb_cc += 18;
- tcp_sockclosed(sototcpcb(so));
- m_free(m);
- return 0;
- }
-
- /* Append the current data */
- memcpy(so_rcv->sb_wptr, m->m_data, m->m_len);
- so_rcv->sb_wptr += m->m_len;
- so_rcv->sb_rptr += m->m_len;
- m_free(m);
-
- /*
- * Check if we have all the initial options,
- * and build argument list to rlogin while we're here
- */
- n = 0;
- ptr = so_rcv->sb_data;
- user="";
- args="";
- if (so->extra==NULL) {
- struct socket *ns;
- struct tcpcb* tp;
- int port=atoi(ptr);
- if (port <= 0) return 0;
- if (port > 1023 || port < 512) {
- memcpy(so_snd->sb_wptr, "Permission denied\n", 18);
- so_snd->sb_wptr += 18;
- so_snd->sb_cc += 18;
- tcp_sockclosed(sototcpcb(so));
- return 0;
- }
- if ((ns=socreate()) == NULL)
- return 0;
- if (tcp_attach(ns)<0) {
- free(ns);
- return 0;
- }
-
- ns->so_laddr=so->so_laddr;
- ns->so_lport=htons(port);
-
- (void) tcp_mss(sototcpcb(ns), 0);
- ns->so_faddr=so->so_faddr;
- ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */
-
- if (ns->so_faddr.s_addr == 0 ||
- ns->so_faddr.s_addr == loopback_addr.s_addr)
- ns->so_faddr = alias_addr;
-
- ns->so_iptos = tcp_tos(ns);
- tp = sototcpcb(ns);
-
- tcp_template(tp);
-
- /* Compute window scaling to request. */
- /* while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
- * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat)
- * tp->request_r_scale++;
- */
-
- /*soisfconnecting(ns);*/
-
- tcpstat.tcps_connattempt++;
-
- tp->t_state = TCPS_SYN_SENT;
- tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
- tp->iss = tcp_iss;
- tcp_iss += TCP_ISSINCR/2;
- tcp_sendseqinit(tp);
- tcp_output(tp);
- so->extra=ns;
- }
- while (ptr < so_rcv->sb_wptr) {
- if (*ptr++ == 0) {
- n++;
- if (n == 2) {
- user=ptr;
- } else if (n == 3) {
- args=ptr;
- }
- }
- }
-
- if (n != 4)
- return 0;
-
- rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args);
- so->so_emu = 0;
- so->extra=NULL;
-
- /* And finally, send the client a 0 character */
- so_snd->sb_wptr[0] = 0;
- so_snd->sb_wptr++;
- so_snd->sb_cc++;
-
- return 0;
- }
-
- case EMU_CTL:
- {
- int num;
- struct sbuf *so_snd = &so->so_snd;
- struct sbuf *so_rcv = &so->so_rcv;
-
- /*
- * If there is binary data here, we save it in so->so_m
- */
- if (!so->so_m) {
- int rxlen;
- char *rxdata;
- rxdata=mtod(m, char *);
- for (rxlen=m->m_len; rxlen; rxlen--) {
- if (*rxdata++ & 0x80) {
- so->so_m = m;
- return 0;
- }
- }
- } /* if(so->so_m==NULL) */
-
- /*
- * Append the line
- */
- sbappendsb(so_rcv, m);
-
- /* To avoid going over the edge of the buffer, we reset it */
- if (so_snd->sb_cc == 0)
- so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data;
-
- /*
- * A bit of a hack:
- * If the first packet we get here is 1 byte long, then it
- * was done in telnet character mode, therefore we must echo
- * the characters as they come. Otherwise, we echo nothing,
- * because in linemode, the line is already echoed
- * XXX two or more control connections won't work
- */
- if (do_echo == -1) {
- if (m->m_len == 1) do_echo = 1;
- else do_echo = 0;
- }
- if (do_echo) {
- sbappendsb(so_snd, m);
- m_free(m);
- tcp_output(sototcpcb(so)); /* XXX */
- } else
- m_free(m);
-
- num = 0;
- while (num < so->so_rcv.sb_cc) {
- if (*(so->so_rcv.sb_rptr + num) == '\n' ||
- *(so->so_rcv.sb_rptr + num) == '\r') {
- int n;
-
- *(so_rcv->sb_rptr + num) = 0;
- if (ctl_password && !ctl_password_ok) {
- /* Need a password */
- if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) {
- if (strcmp(buff, ctl_password) == 0) {
- ctl_password_ok = 1;
- n = sprintf(so_snd->sb_wptr,
- "Password OK.\r\n");
- goto do_prompt;
- }
- }
- n = sprintf(so_snd->sb_wptr,
- "Error: Password required, log on with \"pass PASSWORD\"\r\n");
- goto do_prompt;
- }
- cfg_quitting = 0;
- n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF);
- if (!cfg_quitting) {
- /* Register the printed data */
-do_prompt:
- so_snd->sb_cc += n;
- so_snd->sb_wptr += n;
- /* Add prompt */
- n = sprintf(so_snd->sb_wptr, "Slirp> ");
- so_snd->sb_cc += n;
- so_snd->sb_wptr += n;
- }
- /* Drop so_rcv data */
- so_rcv->sb_cc = 0;
- so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data;
- tcp_output(sototcpcb(so)); /* Send the reply */
- }
- num++;
- }
- return 0;
- }
-#endif
case EMU_FTP: /* ftp */
*(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */
if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) {
/*
* Need to emulate the PORT command
- */
- x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]",
+ */
+ x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]",
&n1, &n2, &n3, &n4, &n5, &n6, buff);
if (x < 6)
return 1;
-
+
laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
lport = htons((n5 << 8) | (n6));
-
+
if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
return 1;
-
+
n6 = ntohs(so->so_fport);
-
+
n5 = (n6 >> 8) & 0xff;
n6 &= 0xff;
-
+
laddr = ntohl(so->so_faddr.s_addr);
-
+
n1 = ((laddr >> 24) & 0xff);
n2 = ((laddr >> 16) & 0xff);
n3 = ((laddr >> 8) & 0xff);
n4 = (laddr & 0xff);
-
+
m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s",
+ m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s",
n1, n2, n3, n4, n5, n6, x==7?buff:"");
return 1;
} else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) {
@@ -1024,34 +744,34 @@ do_prompt:
&n1, &n2, &n3, &n4, &n5, &n6, buff);
if (x < 6)
return 1;
-
+
laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4));
lport = htons((n5 << 8) | (n6));
-
+
if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL)
return 1;
-
+
n6 = ntohs(so->so_fport);
-
+
n5 = (n6 >> 8) & 0xff;
n6 &= 0xff;
-
+
laddr = ntohl(so->so_faddr.s_addr);
-
+
n1 = ((laddr >> 24) & 0xff);
n2 = ((laddr >> 16) & 0xff);
n3 = ((laddr >> 8) & 0xff);
n4 = (laddr & 0xff);
-
+
m->m_len = bptr - m->m_data; /* Adjust length */
m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s",
n1, n2, n3, n4, n5, n6, x==7?buff:"");
-
+
return 1;
}
-
+
return 1;
-
+
case EMU_KSH:
/*
* The kshell (Kerberos rsh) and shell services both pass
@@ -1070,7 +790,7 @@ do_prompt:
(so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL)
m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1;
return 1;
-
+
case EMU_IRC:
/*
* Need to emulate DCC CHAT, DCC SEND and DCC MOVE
@@ -1078,12 +798,12 @@ do_prompt:
*(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */
if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL)
return 1;
-
+
/* The %256s is for the broken mIRC */
if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) {
if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
return 1;
-
+
m->m_len = bptr - m->m_data; /* Adjust length */
m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n",
(unsigned long)ntohl(so->so_faddr.s_addr),
@@ -1091,15 +811,15 @@ do_prompt:
} else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
return 1;
-
+
m->m_len = bptr - m->m_data; /* Adjust length */
- m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n",
+ m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n",
buff, (unsigned long)ntohl(so->so_faddr.s_addr),
ntohs(so->so_fport), n1, 1);
} else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) {
if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL)
return 1;
-
+
m->m_len = bptr - m->m_data; /* Adjust length */
m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n",
buff, (unsigned long)ntohl(so->so_faddr.s_addr),
@@ -1108,7 +828,7 @@ do_prompt:
return 1;
case EMU_REALAUDIO:
- /*
+ /*
* RealAudio emulation - JP. We must try to parse the incoming
* data and try to find the two characters that contain the
* port number. Then we redirect an udp port and replace the
@@ -1116,45 +836,45 @@ do_prompt:
*
* The 1.0 beta versions of the player are not supported
* any more.
- *
+ *
* A typical packet for player version 1.0 (release version):
- *
- * 0000:50 4E 41 00 05
+ *
+ * 0000:50 4E 41 00 05
* 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P
* 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH
* 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v
* 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB
- *
+ *
* Now the port number 0x1BD7 is found at offset 0x04 of the
* Now the port number 0x1BD7 is found at offset 0x04 of the
* second packet. This time we received five bytes first and
* then the rest. You never know how many bytes you get.
*
* A typical packet for player version 2.0 (beta):
- *
+ *
* 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á.
* 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0
* 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/
* 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas
* 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B
- *
+ *
* Port number 0x1BC1 is found at offset 0x0d.
- *
+ *
* This is just a horrible switch statement. Variable ra tells
* us where we're going.
*/
-
+
bptr = m->m_data;
while (bptr < m->m_data + m->m_len) {
u_short p;
static int ra = 0;
- char ra_tbl[4];
-
+ char ra_tbl[4];
+
ra_tbl[0] = 0x50;
ra_tbl[1] = 0x4e;
ra_tbl[2] = 0x41;
ra_tbl[3] = 0;
-
+
switch (ra) {
case 0:
case 2:
@@ -1164,7 +884,7 @@ do_prompt:
continue;
}
break;
-
+
case 1:
/*
* We may get 0x50 several times, ignore them
@@ -1178,15 +898,15 @@ do_prompt:
continue;
}
break;
-
- case 4:
- /*
+
+ case 4:
+ /*
* skip version number
*/
bptr++;
break;
-
- case 5:
+
+ case 5:
/*
* The difference between versions 1.0 and
* 2.0 is here. For future versions of
@@ -1196,19 +916,19 @@ do_prompt:
bptr += 8;
else
bptr += 4;
- break;
-
+ break;
+
case 6:
/* This is the field containing the port
* number that RA-player is listening to.
*/
- lport = (((u_char*)bptr)[0] << 8)
+ lport = (((u_char*)bptr)[0] << 8)
+ ((u_char *)bptr)[1];
- if (lport < 6970)
+ if (lport < 6970)
lport += 256; /* don't know why */
if (lport < 6970 || lport > 7170)
return 1; /* failed */
-
+
/* try to get udp port between 6970 - 7170 */
for (p = 6970; p < 7071; p++) {
if (udp_listen( htons(p),
@@ -1222,17 +942,17 @@ do_prompt:
p = 0;
*(u_char *)bptr++ = (p >> 8) & 0xff;
*(u_char *)bptr++ = p & 0xff;
- ra = 0;
+ ra = 0;
return 1; /* port redirected, we're done */
- break;
-
+ break;
+
default:
- ra = 0;
+ ra = 0;
}
ra++;
}
- return 1;
-
+ return 1;
+
default:
/* Ooops, not emulated, won't call tcp_emu again */
so->so_emu = 0;
@@ -1249,15 +969,15 @@ int
tcp_ctl(so)
struct socket *so;
{
- struct sbuf *sb = &so->so_snd;
+ SBuf sb = &so->so_snd;
int command;
struct ex_list *ex_ptr;
int do_pty;
// struct socket *tmpso;
-
+
DEBUG_CALL("tcp_ctl");
DEBUG_ARG("so = %lx", (long )so);
-
+
#if 0
/*
* Check if they're authorised
@@ -1267,58 +987,20 @@ tcp_ctl(so)
sb->sb_wptr += sb->sb_cc;
return 0;
}
-#endif
+#endif
command = (ntohl(so->so_faddr.s_addr) & 0xff);
-
+
switch(command) {
- default: /* Check for exec's */
-
- /*
- * Check if it's pty_exec
- */
- for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
- if (ex_ptr->ex_fport == so->so_fport &&
- command == ex_ptr->ex_addr) {
- do_pty = ex_ptr->ex_pty;
- goto do_exec;
- }
- }
-
+ default:
/*
* Nothing bound..
*/
/* tcp_fconnect(so); */
-
- /* FALLTHROUGH */
+
case CTL_ALIAS:
sb->sb_cc = sprintf(sb->sb_wptr,
"Error: No application configured.\r\n");
sb->sb_wptr += sb->sb_cc;
return(0);
-
- do_exec:
- DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec));
- return(fork_exec(so, ex_ptr->ex_exec, do_pty));
-
-#if 0
- case CTL_CMD:
- for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) {
- if (tmpso->so_emu == EMU_CTL &&
- !(tmpso->so_tcpcb?
- (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK))
- :0)) {
- /* Ooops, control connection already active */
- sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n");
- sb->sb_wptr += sb->sb_cc;
- return 0;
- }
- }
- so->so_emu = EMU_CTL;
- ctl_password_ok = 0;
- sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> ");
- sb->sb_wptr += sb->sb_cc;
- do_echo=-1;
- return(2);
-#endif
}
}
diff --git a/slirp/tcp_timer.c b/slirp/tcp_timer.c
index d3146db..ad03098 100644
--- a/slirp/tcp_timer.c
+++ b/slirp/tcp_timer.c
@@ -305,10 +305,10 @@ tcp_timers(tp, timer)
* The keepalive packet must have nonzero length
* to get a 4.2 host to respond.
*/
- tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
+ tcp_respond(tp, &tp->t_template, (MBuf )NULL,
tp->rcv_nxt - 1, tp->snd_una - 1, 0);
#else
- tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
+ tcp_respond(tp, &tp->t_template, (MBuf )NULL,
tp->rcv_nxt, tp->snd_una - 1, 0);
#endif
tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
diff --git a/slirp/tcp_var.h b/slirp/tcp_var.h
index 0d6cd24..b30a15d 100644
--- a/slirp/tcp_var.h
+++ b/slirp/tcp_var.h
@@ -37,6 +37,7 @@
#ifndef _TCP_VAR_H_
#define _TCP_VAR_H_
+#include "mbuf.h"
#include "tcpip.h"
#include "tcp_timer.h"
@@ -172,14 +173,14 @@ struct tcpcb {
/* XXX
* We want to avoid doing m_pullup on incoming packets but that
- * means avoiding dtom on the tcp reassembly code. That in turn means
+ * means avoiding MBUF_FROM on the tcp reassembly code. That in turn means
* keeping an mbuf pointer in the reassembly queue (since we might
* have a cluster). As a quick hack, the source & destination
* port numbers (which are no longer needed once we've located the
* tcpcb) are overlayed with an mbuf pointer.
*/
#if SIZEOF_CHAR_P == 4
-typedef struct mbuf *mbufp_32;
+typedef MBuf mbufp_32;
#else
typedef u_int32_t mbufp_32;
#endif
diff --git a/slirp/tftp.c b/slirp/tftp.c
index c9946d6..8af404a 100644
--- a/slirp/tftp.c
+++ b/slirp/tftp.c
@@ -1,8 +1,8 @@
/*
* tftp.c - a simple, read-only tftp server for qemu
- *
+ *
* Copyright (c) 2004 Magnus Damm <damm@opensource.se>
- *
+ *
* 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
@@ -27,10 +27,10 @@
struct tftp_session {
int in_use;
unsigned char filename[TFTP_FILENAME_MAX];
-
+
struct in_addr client_ip;
u_int16_t client_port;
-
+
int timestamp;
};
@@ -102,8 +102,15 @@ static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr,
{
int fd;
int bytes_read = 0;
+ char buffer[1024];
+ int n;
+
+ n = snprintf(buffer, sizeof(buffer), "%s/%s",
+ tftp_prefix, spt->filename);
+ if (n >= sizeof(buffer))
+ return -1;
- fd = open(spt->filename, O_RDONLY | O_BINARY);
+ fd = open(buffer, O_RDONLY | O_BINARY);
if (fd < 0) {
return -1;
@@ -120,16 +127,55 @@ static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr,
return bytes_read;
}
-static int tftp_send_error(struct tftp_session *spt,
+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;
+ MBuf m;
+ struct tftp_t *tp;
+ int n = 0;
+
+ m = mbuf_alloc();
+
+ 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((char*)tp->x.tp_buf + n, "%s", key) + 1;
+ n += sprintf((char*)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)
{
struct sockaddr_in saddr, daddr;
- struct mbuf *m;
+ MBuf m;
struct tftp_t *tp;
int nobytes;
- m = m_get();
+ m = mbuf_alloc();
if (!m) {
return -1;
@@ -140,10 +186,10 @@ static int tftp_send_error(struct tftp_session *spt,
m->m_data += if_maxlinkhdr;
tp = (void *)m->m_data;
m->m_data += sizeof(struct udpiphdr);
-
+
tp->tp_op = htons(TFTP_ERROR);
tp->x.tp_error.tp_error_code = htons(errorcode);
- strcpy(tp->x.tp_error.tp_msg, msg);
+ strcpy((char*)tp->x.tp_error.tp_msg, msg);
saddr.sin_addr = recv_tp->ip.ip_dst;
saddr.sin_port = recv_tp->udp.uh_dport;
@@ -153,7 +199,7 @@ static int tftp_send_error(struct tftp_session *spt,
nobytes = 2;
- m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
+ m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) -
sizeof(struct ip) - sizeof(struct udphdr);
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
@@ -163,12 +209,12 @@ static int tftp_send_error(struct tftp_session *spt,
return 0;
}
-static int tftp_send_data(struct tftp_session *spt,
+static int tftp_send_data(struct tftp_session *spt,
u_int16_t block_nr,
struct tftp_t *recv_tp)
{
struct sockaddr_in saddr, daddr;
- struct mbuf *m;
+ MBuf m;
struct tftp_t *tp;
int nobytes;
@@ -176,7 +222,7 @@ static int tftp_send_data(struct tftp_session *spt,
return -1;
}
- m = m_get();
+ m = mbuf_alloc();
if (!m) {
return -1;
@@ -187,7 +233,7 @@ static int tftp_send_data(struct tftp_session *spt,
m->m_data += if_maxlinkhdr;
tp = (void *)m->m_data;
m->m_data += sizeof(struct udpiphdr);
-
+
tp->tp_op = htons(TFTP_DATA);
tp->x.tp_data.tp_block_nr = htons(block_nr);
@@ -200,7 +246,7 @@ static int tftp_send_data(struct tftp_session *spt,
nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512);
if (nobytes < 0) {
- m_free(m);
+ mbuf_free(m);
/* send "file not found" error back */
@@ -209,7 +255,7 @@ static int tftp_send_data(struct tftp_session *spt,
return -1;
}
- m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
+ m->m_len = sizeof(struct tftp_t) - (512 - nobytes) -
sizeof(struct ip) - sizeof(struct udphdr);
udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
@@ -251,52 +297,95 @@ static void tftp_handle_rrq(struct tftp_t *tp, int pktlen)
else {
return;
}
-
+
if (src[k] == '\0') {
break;
}
}
-
+
if (k >= n) {
return;
}
-
+
k++;
-
+
/* check mode */
if ((n - k) < 6) {
return;
}
-
+
if (memcmp(&src[k], "octet\0", 6) != 0) {
tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
return;
}
+ k += 6; /* skipping octet */
+
/* do sanity checks on the filename */
if ((spt->filename[0] != '/')
- || (spt->filename[strlen(spt->filename) - 1] == '/')
- || strstr(spt->filename, "/../")) {
+ || (spt->filename[strlen((const char*)spt->filename) - 1] == '/')
+ || strstr((const char*)spt->filename, "/../")) {
tftp_send_error(spt, 2, "Access violation", tp);
return;
}
/* 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;
}
/* check if the file exists */
-
+
if (tftp_read_data(spt, 0, spt->filename, 0) < 0) {
tftp_send_error(spt, 1, "File not found", tp);
return;
}
+ if (src[n - 1] != 0) {
+ tftp_send_error(spt, 2, "Access violation", tp);
+ return;
+ }
+
+ while (k < n) {
+ const char *key, *value;
+
+ key = (const char*)src + k;
+ k += strlen(key) + 1;
+
+ if (k >= n) {
+ tftp_send_error(spt, 2, "Access violation", tp);
+ return;
+ }
+
+ value = (const char*)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);
}
@@ -310,14 +399,14 @@ static void tftp_handle_ack(struct tftp_t *tp, int pktlen)
return;
}
- if (tftp_send_data(&tftp_sessions[s],
- ntohs(tp->x.tp_data.tp_block_nr) + 1,
+ if (tftp_send_data(&tftp_sessions[s],
+ ntohs(tp->x.tp_data.tp_block_nr) + 1,
tp) < 0) {
return;
}
}
-void tftp_input(struct mbuf *m)
+void tftp_input(MBuf m)
{
struct tftp_t *tp = (struct tftp_t *)m->m_data;
diff --git a/slirp/tftp.h b/slirp/tftp.h
index f0560b6..06018a7 100644
--- a/slirp/tftp.h
+++ b/slirp/tftp.h
@@ -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
@@ -29,4 +30,4 @@ struct tftp_t {
} x;
};
-void tftp_input(struct mbuf *m);
+void tftp_input(MBuf m);
diff --git a/slirp/udp.c b/slirp/udp.c
index 0d70970..d96251d 100644
--- a/slirp/udp.c
+++ b/slirp/udp.c
@@ -37,8 +37,8 @@
/*
* Changes and additions relating to SLiRP
* Copyright (c) 1995 Danny Gasparovski.
- *
- * Please read the file COPYRIGHT for the
+ *
+ * Please read the file COPYRIGHT for the
* terms and conditions of the copyright.
*/
@@ -66,26 +66,26 @@ udp_init()
{
udb.so_next = udb.so_prev = &udb;
}
-/* m->m_data points at ip packet header
- * m->m_len length ip packet
+/* m->m_data points at ip packet header
+ * m->m_len length ip packet
* ip->ip_len length data (IPDU)
*/
void
udp_input(m, iphlen)
- register struct mbuf *m;
+ register MBuf m;
int iphlen;
{
register struct ip *ip;
register struct udphdr *uh;
-/* struct mbuf *opts = 0;*/
+/* MBuf opts = 0;*/
int len;
- struct ip save_ip;
+ struct ip save_ip;
struct socket *so;
-
+
DEBUG_CALL("udp_input");
DEBUG_ARG("m = %lx", (long)m);
DEBUG_ARG("iphlen = %d", iphlen);
-
+
udpstat.udps_ipackets++;
/*
@@ -95,14 +95,14 @@ udp_input(m, iphlen)
* with options still present.
*/
if(iphlen > sizeof(struct ip)) {
- ip_stripoptions(m, (struct mbuf *)0);
+ ip_stripoptions(m, (MBuf )0);
iphlen = sizeof(struct ip);
}
/*
* Get IP and UDP header together in first mbuf.
*/
- ip = mtod(m, struct ip *);
+ ip = MBUF_TO(m, struct ip *);
uh = (struct udphdr *)((caddr_t)ip + iphlen);
/*
@@ -116,15 +116,15 @@ udp_input(m, iphlen)
udpstat.udps_badlen++;
goto bad;
}
- m_adj(m, len - ip->ip_len);
+ mbuf_trim(m, len - ip->ip_len);
ip->ip_len = len;
}
-
+
/*
* Save a copy of the IP header in case we want restore it
* for sending an ICMP error message in response.
*/
- save_ip = *ip;
+ save_ip = *ip;
save_ip.ip_len+= iphlen; /* tcp_input subtracts this */
/*
@@ -136,8 +136,8 @@ udp_input(m, iphlen)
((struct ipovly *)ip)->ih_x1 = 0;
((struct ipovly *)ip)->ih_len = uh->uh_ulen;
/* keep uh_sum for ICMP reply
- * uh->uh_sum = cksum(m, len + sizeof (struct ip));
- * if (uh->uh_sum) {
+ * uh->uh_sum = cksum(m, len + sizeof (struct ip));
+ * if (uh->uh_sum) {
*/
if(cksum(m, len + sizeof(struct ip))) {
udpstat.udps_badsum++;
@@ -168,7 +168,7 @@ udp_input(m, iphlen)
if (so->so_lport != uh->uh_sport ||
so->so_laddr.s_addr != ip->ip_src.s_addr) {
struct socket *tmp;
-
+
for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) {
if (tmp->so_lport == uh->uh_sport &&
tmp->so_laddr.s_addr == ip->ip_src.s_addr) {
@@ -185,7 +185,7 @@ udp_input(m, iphlen)
udp_last_so = so;
}
}
-
+
if (so == NULL) {
/*
* If there's no socket for this packet,
@@ -193,31 +193,32 @@ udp_input(m, iphlen)
*/
if ((so = socreate()) == NULL) goto bad;
if(udp_attach(so) == -1) {
- DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
+ DEBUG_MISC((dfd," udp_attach errno = %d-%s\n",
errno,strerror(errno)));
sofree(so);
goto bad;
}
-
+
/*
* Setup fields
*/
/* 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;
-
+
/*
* XXXXX Here, check if it's in udpexec_list,
* and if it is, do the fork_exec() etc.
*/
}
- iphlen += sizeof(struct udphdr);
+ 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;
@@ -232,10 +233,10 @@ udp_input(m, iphlen)
m->m_data -= iphlen;
*ip=save_ip;
DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno)));
- icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
+ icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno));
}
- m_free(so->so_m); /* used for ICMP if error on sorecvfrom */
+ mbuf_free(so->so_m); /* used for ICMP if error on sorecvfrom */
/* restore the orig mbuf packet */
m->m_len += iphlen;
@@ -245,12 +246,12 @@ udp_input(m, iphlen)
return;
bad:
- m_freem(m);
- /* if (opts) m_freem(opts); */
+ mbuf_free(m);
+ /* if (opts) mbuf_free(opts); */
return;
}
-int udp_output2(struct socket *so, struct mbuf *m,
+int udp_output2(struct socket *so, MBuf m,
struct sockaddr_in *saddr, struct sockaddr_in *daddr,
int iptos)
{
@@ -268,12 +269,12 @@ int udp_output2(struct socket *so, struct mbuf *m,
*/
m->m_data -= sizeof(struct udpiphdr);
m->m_len += sizeof(struct udpiphdr);
-
+
/*
* Fill in mbuf with extended UDP header
* and addresses and length put into network format.
*/
- ui = mtod(m, struct udpiphdr *);
+ ui = MBUF_TO(m, struct udpiphdr *);
ui->ui_next = ui->ui_prev = 0;
ui->ui_x1 = 0;
ui->ui_pr = IPPROTO_UDP;
@@ -297,15 +298,15 @@ int udp_output2(struct socket *so, struct mbuf *m,
((struct ip *)ui)->ip_ttl = ip_defttl;
((struct ip *)ui)->ip_tos = iptos;
-
+
udpstat.udps_opackets++;
-
+
error = ip_output(so, m);
-
+
return (error);
}
-int udp_output(struct socket *so, struct mbuf *m,
+int udp_output(struct socket *so, MBuf m,
struct sockaddr_in *addr)
{
@@ -319,7 +320,7 @@ int udp_output(struct socket *so, struct mbuf *m,
}
daddr.sin_addr = so->so_laddr;
daddr.sin_port = so->so_lport;
-
+
return udp_output2(so, m, &saddr, &daddr, so->so_iptos);
}
@@ -328,7 +329,7 @@ udp_attach(so)
struct socket *so;
{
struct sockaddr_in addr;
-
+
if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) {
/*
* Here, we bind() the socket. Although not really needed
@@ -361,7 +362,7 @@ udp_detach(so)
struct socket *so;
{
closesocket(so->s);
- /* if (so->so_m) m_free(so->so_m); done by sofree */
+ /* if (so->so_m) mbuf_free(so->so_m); done by sofree */
sofree(so);
}
@@ -379,7 +380,7 @@ udp_tos(so)
struct socket *so;
{
int i = 0;
-
+
while(udptos[i].tos) {
if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) ||
(udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) {
@@ -388,7 +389,7 @@ udp_tos(so)
}
i++;
}
-
+
return 0;
}
@@ -402,7 +403,7 @@ udp_tos(so)
void
udp_emu(so, m)
struct socket *so;
- struct mbuf *m;
+ MBuf m;
{
struct sockaddr_in addr;
int addrlen = sizeof(addr);
@@ -411,17 +412,17 @@ udp_emu(so, m)
CTL_MSG *nmsg;
char buff[sizeof(CTL_MSG)];
u_char type;
-
+
struct talk_request {
struct talk_request *next;
struct socket *udp_so;
struct socket *tcp_so;
} *req;
-
- static struct talk_request *req_tbl = 0;
-
+
+ static struct talk_request *req_tbl = 0;
+
#endif
-
+
struct cu_header {
uint16_t d_family; // destination family
uint16_t d_port; // destination port
@@ -448,7 +449,7 @@ struct cu_header {
*/
if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
return;
-
+
#define IS_OLD (so->so_emu == EMU_TALK)
#define COPY_MSG(dest, src) { dest->type = src->type; \
@@ -465,24 +466,24 @@ struct cu_header {
if (IS_OLD) { /* old talk */
- omsg = mtod(m, CTL_MSG_OLD*);
+ omsg = MBUF_TO(m, CTL_MSG_OLD*);
nmsg = (CTL_MSG *) buff;
type = omsg->type;
OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port;
OTOSIN(omsg, ctl_addr)->sin_addr = our_addr;
strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD);
- } else { /* new talk */
+ } else { /* new talk */
omsg = (CTL_MSG_OLD *) buff;
- nmsg = mtod(m, CTL_MSG *);
+ nmsg = MBUF_TO(m, CTL_MSG *);
type = nmsg->type;
OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port;
OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr;
strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD);
}
-
- if (type == LOOK_UP)
+
+ if (type == LOOK_UP)
return; /* for LOOK_UP this is enough */
-
+
if (IS_OLD) { /* make a copy of the message */
COPY_MSG(nmsg, omsg);
nmsg->vers = 1;
@@ -501,75 +502,75 @@ struct cu_header {
* ports, 517 and 518. This is why we have two copies
* of the message, one in old talk and one in new talk
* format.
- */
+ */
if (type == ANNOUNCE) {
int s;
u_short temp_port;
-
+
for(req = req_tbl; req; req = req->next)
if (so == req->udp_so)
break; /* found it */
-
+
if (!req) { /* no entry for so, create new */
req = (struct talk_request *)
malloc(sizeof(struct talk_request));
req->udp_so = so;
- req->tcp_so = solisten(0,
- OTOSIN(omsg, addr)->sin_addr.s_addr,
+ req->tcp_so = solisten(0,
+ OTOSIN(omsg, addr)->sin_addr.s_addr,
OTOSIN(omsg, addr)->sin_port,
SS_FACCEPTONCE);
req->next = req_tbl;
req_tbl = req;
- }
-
+ }
+
/* replace port number in addr field */
addrlen = sizeof(addr);
- getsockname(req->tcp_so->s,
+ getsockname(req->tcp_so->s,
(struct sockaddr *) &addr,
- &addrlen);
+ &addrlen);
OTOSIN(omsg, addr)->sin_port = addr.sin_port;
OTOSIN(omsg, addr)->sin_addr = our_addr;
OTOSIN(nmsg, addr)->sin_port = addr.sin_port;
- OTOSIN(nmsg, addr)->sin_addr = our_addr;
-
+ OTOSIN(nmsg, addr)->sin_addr = our_addr;
+
/* send LEAVE_INVITEs */
temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
OTOSIN(omsg, ctl_addr)->sin_port = 0;
OTOSIN(nmsg, ctl_addr)->sin_port = 0;
- omsg->type = nmsg->type = LEAVE_INVITE;
-
+ omsg->type = nmsg->type = LEAVE_INVITE;
+
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
addr.sin_addr = our_addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(517);
- sendto(s, (char *)omsg, sizeof(*omsg), 0,
+ sendto(s, (char *)omsg, sizeof(*omsg), 0,
(struct sockaddr *)&addr, sizeof(addr));
addr.sin_port = htons(518);
sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
(struct sockaddr *) &addr, sizeof(addr));
closesocket(s) ;
- omsg->type = nmsg->type = ANNOUNCE;
+ omsg->type = nmsg->type = ANNOUNCE;
OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
}
-
- /*
+
+ /*
* If it is a DELETE message, we send a copy to the
* local daemons. Then we delete the entry corresponding
* to our socket from the request table.
*/
-
+
if (type == DELETE) {
struct talk_request *temp_req, *req_next;
int s;
u_short temp_port;
-
+
temp_port = OTOSIN(omsg, ctl_addr)->sin_port;
OTOSIN(omsg, ctl_addr)->sin_port = 0;
OTOSIN(nmsg, ctl_addr)->sin_port = 0;
-
+
s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
addr.sin_addr = our_addr;
addr.sin_family = AF_INET;
@@ -580,7 +581,7 @@ struct cu_header {
sendto(s, (char *)nmsg, sizeof(*nmsg), 0,
(struct sockaddr *)&addr, sizeof(addr));
closesocket(s);
-
+
OTOSIN(omsg, ctl_addr)->sin_port = temp_port;
OTOSIN(nmsg, ctl_addr)->sin_port = temp_port;
@@ -603,26 +604,26 @@ struct cu_header {
}
}
}
-
- return;
+
+ return;
#endif
-
+
case EMU_CUSEEME:
-
+
/*
* Cu-SeeMe emulation.
* Hopefully the packet is more that 16 bytes long. We don't
* do any other tests, just replace the address and port
* fields.
- */
+ */
if (m->m_len >= sizeof (*cu_head)) {
if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0)
return;
- cu_head = mtod(m, struct cu_header *);
+ cu_head = MBUF_TO(m, struct cu_header *);
cu_head->s_port = addr.sin_port;
cu_head->so_addr = our_addr.s_addr;
}
-
+
return;
}
}
@@ -636,14 +637,15 @@ udp_listen(port, laddr, lport, flags)
{
struct sockaddr_in addr;
struct socket *so;
- int addrlen = sizeof(struct sockaddr_in), opt = 1;
-
+ int addrlen = sizeof(struct sockaddr_in);
+
if ((so = socreate()) == NULL) {
free(so);
return NULL;
}
so->s = socket(AF_INET,SOCK_DGRAM,0);
so->so_expire = curtime + SO_EXPIRE;
+ so->so_hport = port;
insque(so,&udb);
addr.sin_family = AF_INET;
@@ -654,22 +656,44 @@ udp_listen(port, laddr, lport, flags)
udp_detach(so);
return NULL;
}
- setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int));
-/* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */
-
+ socket_set_xreuseaddr(so->s);
+
getsockname(so->s,(struct sockaddr *)&addr,&addrlen);
so->so_fport = addr.sin_port;
if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr)
so->so_faddr = alias_addr;
else
so->so_faddr = addr.sin_addr;
-
+
so->so_lport = lport;
so->so_laddr.s_addr = laddr;
if (flags != SS_FACCEPTONCE)
so->so_expire = 0;
-
+
so->so_state = SS_ISFCONNECTED;
-
+
return so;
}
+
+int udp_unlisten (u_int port)
+{
+ struct socket *so;
+
+ for (so = udb.so_next; so != &udb; so = so->so_next) {
+ if (so->so_hport == htons(port)) {
+ break;
+ }
+ }
+
+ if (so == &udb)
+ return -1;
+
+ sofcantrcvmore( so );
+ sofcantsendmore( so );
+ close( so->s );
+ so->s = -1;
+ sofree( so );
+ return 0;
+}
+
+
diff --git a/slirp/udp.h b/slirp/udp.h
index 24c11bb..f59925d 100644
--- a/slirp/udp.h
+++ b/slirp/udp.h
@@ -97,14 +97,15 @@ extern struct socket udb;
struct mbuf;
void udp_init _P((void));
-void udp_input _P((register struct mbuf *, int));
-int udp_output _P((struct socket *, struct mbuf *, struct sockaddr_in *));
+void udp_input _P((register MBuf , int));
+int udp_output _P((struct socket *, MBuf , struct sockaddr_in *));
int udp_attach _P((struct socket *));
void udp_detach _P((struct socket *));
u_int8_t udp_tos _P((struct socket *));
-void udp_emu _P((struct socket *, struct mbuf *));
+void udp_emu _P((struct socket *, MBuf ));
struct socket * udp_listen _P((u_int, u_int32_t, u_int, int));
-int udp_output2(struct socket *so, struct mbuf *m,
+int udp_unlisten _P((u_int));
+int udp_output2(struct socket *so, MBuf m,
struct sockaddr_in *saddr, struct sockaddr_in *daddr,
int iptos);
#endif
diff --git a/sockets.c b/sockets.c
new file mode 100644
index 0000000..3a5e96d
--- /dev/null
+++ b/sockets.c
@@ -0,0 +1,449 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "sockets.h"
+#include "vl.h"
+#include <fcntl.h>
+#include "android_debug.h"
+
+/* QSOCKET_CALL is used to deal with the fact that EINTR happens pretty
+ * easily in QEMU since we use SIGALRM to implement periodic timers
+ */
+#ifdef _WIN32
+# define QSOCKET_CALL(_ret,_cmd) \
+ do { _ret = (_cmd); } while ( _ret < 0 && WSAGetLastError() == WSAEINTR )
+#else
+# define QSOCKET_CALL(_ret,_cmd) \
+ do { _ret = (_cmd); } while ( _ret < 0 && errno == EINTR )
+#endif
+
+#ifdef _WIN32
+const char* socket_strerr(void)
+{
+ int err = WSAGetLastError();
+ switch (err) {
+ case WSA_INVALID_HANDLE:
+ return "invalid handle";
+ case WSA_NOT_ENOUGH_MEMORY:
+ return "not enough memory";
+ case WSA_INVALID_PARAMETER:
+ return "invalid parameter";
+ case WSA_OPERATION_ABORTED:
+ return "operation aborted";
+ case WSA_IO_INCOMPLETE:
+ return "incomplete i/o";
+ case WSA_IO_PENDING:
+ return "pending i/o";
+ case WSAEINTR:
+ return "interrupted";
+ case WSAEBADF:
+ return "bad file descriptor";
+ case WSAEACCES:
+ return "permission denied";
+ case WSAEFAULT:
+ return "bad address";
+ case WSAEINVAL:
+ return "invalid argument";
+ case WSAEMFILE:
+ return "too many opened files";
+ case WSAEWOULDBLOCK:
+ return "resource temporarily unavailable";
+ case WSAEINPROGRESS:
+ return "operation in progress";
+ case WSAEALREADY:
+ return "operation already in progress";
+ case WSAENOTSOCK:
+ return "socket operation not on socket";
+ case WSAEDESTADDRREQ:
+ return "destination address required";
+ case WSAEMSGSIZE:
+ return "message too long";
+ case WSAEPROTOTYPE:
+ return "wrong protocol for socket type";
+ case WSAENOPROTOOPT:
+ return "bad option for protocol";
+ case WSAEPROTONOSUPPORT:
+ return "protocol not supported";
+ case WSAEADDRINUSE:
+ return "address already in use";
+ case WSAEADDRNOTAVAIL:
+ return "address not available";
+ case WSAENETDOWN:
+ return "network is down";
+ case WSAENETUNREACH:
+ return "network unreachable";
+ case WSAENETRESET:
+ return "network dropped connection on reset";
+ case WSAECONNABORTED:
+ return "connection aborted";
+ case WSAECONNRESET:
+ return "connection reset by peer";
+ case WSAENOBUFS:
+ return "no buffer space available";
+ case WSAETIMEDOUT:
+ return "connection timed out";
+ case WSAECONNREFUSED:
+ return "connection refused";
+ case WSAEHOSTDOWN:
+ return "host is down";
+ case WSAEHOSTUNREACH:
+ return "no route to host";
+ default:
+ return "unknown/TODO";
+ }
+}
+#endif
+
+int socket_get_type(int fd)
+{
+ int opt = -1;
+ int optlen = sizeof(opt);
+ getsockopt(fd, SOL_SOCKET, SO_TYPE, (void*)&opt, (void*)&optlen );
+ return opt;
+}
+
+int socket_set_nonblock(int fd)
+{
+#ifdef _WIN32
+ unsigned long opt = 1;
+ return ioctlsocket(fd, FIONBIO, &opt);
+#else
+ return fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
+}
+
+int socket_set_blocking(int fd)
+{
+#ifdef _WIN32
+ unsigned long opt = 0;
+ return ioctlsocket(fd, FIONBIO, &opt);
+#else
+ return fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
+}
+
+
+int socket_set_xreuseaddr(int fd)
+{
+#ifdef _WIN32
+ /* on Windows, SO_REUSEADDR is used to indicate that several programs can
+ * bind to the same port. this is completely different from the Unix
+ * semantics. instead of SO_EXCLUSIVEADDR to ensure that explicitely prevent
+ * this.
+ */
+ BOOL flag = 1;
+ return setsockopt( fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (const char*)&flag, sizeof(flag) );
+#else
+ int flag = 1;
+ return setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&flag, sizeof(flag) );
+#endif
+}
+
+
+int socket_set_oobinline(int fd)
+{
+#ifdef _WIN32
+ BOOL flag = 1;
+#else
+ int flag = 1;
+#endif
+ /* enable low-latency */
+ return setsockopt( fd, SOL_SOCKET, SO_OOBINLINE, (const char*)&flag, sizeof(flag) );
+}
+
+
+int socket_set_lowlatency(int fd)
+{
+#ifdef _WIN32
+ BOOL flag = 1;
+#else
+ int flag = 1;
+#endif
+ /* enable low-latency */
+ return setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&flag, sizeof(flag) );
+}
+
+
+#ifdef _WIN32
+#include <stdlib.h>
+
+static void socket_cleanup(void)
+{
+ WSACleanup();
+}
+
+int socket_init(void)
+{
+ WSADATA Data;
+ int ret, err;
+
+ ret = WSAStartup(MAKEWORD(2,2), &Data);
+ if (ret != 0) {
+ err = WSAGetLastError();
+ return -1;
+ }
+ atexit(socket_cleanup);
+ return 0;
+}
+
+#else /* !_WIN32 */
+
+int socket_init(void)
+{
+ return 0; /* nothing to do on Unix */
+}
+
+#endif /* !_WIN32 */
+
+#ifdef _WIN32
+
+static void
+socket_close_handler( void* _fd )
+{
+ int fd = (int)_fd;
+ int ret;
+ char buff[64];
+
+ /* we want to drain the read side of the socket before closing it */
+ do {
+ ret = recv( fd, buff, sizeof(buff), 0 );
+ } while (ret < 0 && socket_errno == EINTR);
+
+ if (ret < 0 && socket_errno == EWOULDBLOCK)
+ return;
+
+ qemu_set_fd_handler( fd, NULL, NULL, NULL );
+ closesocket( fd );
+}
+
+void
+socket_close( int fd )
+{
+ shutdown( fd, SD_BOTH );
+ /* we want to drain the socket before closing it */
+ qemu_set_fd_handler( fd, socket_close_handler, NULL, (void*)fd );
+}
+
+#else /* !_WIN32 */
+
+#include <unistd.h>
+
+void
+socket_close( int fd )
+{
+ shutdown( fd, SHUT_RDWR );
+ close( fd );
+}
+
+#endif /* !_WIN32 */
+
+
+static int
+socket_bind_server( int s, const struct sockaddr* addr, socklen_t addrlen, int type )
+{
+ int ret;
+
+ socket_set_xreuseaddr(s);
+
+ QSOCKET_CALL(ret, bind(s, addr, addrlen));
+ if ( ret < 0 ) {
+ dprint("could not bind server socket: %s", socket_errstr());
+ socket_close(s);
+ return -1;
+ }
+
+ if (type == SOCK_STREAM) {
+ QSOCKET_CALL( ret, listen(s, 4) );
+ if ( ret < 0 ) {
+ dprint("could not listen server socket: %s", socket_errstr());
+ socket_close(s);
+ return -1;
+ }
+ }
+ return s;
+}
+
+
+static int
+socket_connect_client( int s, const struct sockaddr* addr, socklen_t addrlen )
+{
+ int ret;
+
+ QSOCKET_CALL(ret, connect(s, addr, addrlen));
+ if ( ret < 0 ) {
+ dprint( "could not connect client socket: %s\n", socket_errstr() );
+ socket_close(s);
+ return -1;
+ }
+
+ socket_set_nonblock( s );
+ return s;
+}
+
+
+static int
+socket_in_server( int address, int port, int type )
+{
+ struct sockaddr_in addr;
+ int s;
+
+ memset( &addr, 0, sizeof(addr) );
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = htonl(address);
+
+ s = socket(PF_INET, type, 0);
+ if (s < 0) return -1;
+
+ return socket_bind_server( s, (struct sockaddr*) &addr, sizeof(addr), type );
+}
+
+
+static int
+socket_in_client( struct sockaddr_in* addr, int type )
+{
+ int s;
+
+ s = socket(addr->sin_family, type, 0);
+ if (s < 0) return -1;
+
+ return socket_connect_client( s, (struct sockaddr*) addr, sizeof(*addr) );
+}
+
+
+int
+socket_loopback_server( int port, int type )
+{
+ return socket_in_server( INADDR_LOOPBACK, port, type );
+}
+
+int
+socket_loopback_client( int port, int type )
+{
+ struct sockaddr_in addr;
+ memset( &addr, 0, sizeof(addr) );
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+
+ return socket_in_client( &addr, type );
+}
+
+
+int
+socket_network_client( const char* host, int port, int type )
+{
+ struct hostent* hp;
+ struct sockaddr_in addr;
+
+ hp = gethostbyname(host);
+ if (hp == 0) return -1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = hp->h_addrtype;
+ addr.sin_port = htons(port);
+ memcpy( &addr.sin_addr, hp->h_addr, hp->h_length );
+
+ return socket_in_client( &addr, type );
+}
+
+
+int
+socket_anyaddr_server( int port, int type )
+{
+ return socket_in_server( INADDR_ANY, port, type );
+}
+
+int
+socket_accept_any( int server_fd )
+{
+ int fd;
+
+ QSOCKET_CALL(fd, accept( server_fd, NULL, 0 ));
+ if (fd < 0) {
+ dprint( "could not accept client connection from fd %d: %s",
+ server_fd, socket_errstr() );
+ return -1;
+ }
+
+ /* set to non-blocking */
+ socket_set_nonblock( fd );
+ return fd;
+}
+
+
+#ifndef _WIN32
+
+#include <sys/un.h>
+
+static int
+socket_unix_prepare_address( struct sockaddr_un* addr, const char* name )
+{
+ size_t namelen = strlen(name);
+ size_t offset = offsetof(struct sockaddr_un, sun_path);
+
+ if (offset + namelen + 1 > sizeof(*addr)) {
+ fprintf(stderr, "unix socket path too long\n");
+ return -1;
+ }
+ memset( addr, 0, sizeof(*addr) );
+ addr->sun_family = AF_LOCAL;
+ memcpy( addr->sun_path, name, namelen+1 );
+ return offset + namelen + 1;
+}
+
+int
+socket_unix_server( const char* name, int type )
+{
+ struct sockaddr_un addr;
+ int addrlen;
+ int s, ret;
+
+ do {
+ s = socket(AF_LOCAL, type, 0);
+ } while (s < 0 && socket_errno == EINTR);
+ if (s < 0) return -1;
+
+ addrlen = socket_unix_prepare_address( &addr, name );
+ if (addrlen < 0) {
+ socket_close(s);
+ return -1;
+ }
+
+ do {
+ ret = unlink( addr.sun_path );
+ } while (ret < 0 && errno == EINTR);
+
+ return socket_bind_server( s, (struct sockaddr*) &addr, (socklen_t)addrlen, type );
+}
+
+int
+socket_unix_client( const char* name, int type )
+{
+ struct sockaddr_un addr;
+ int addrlen;
+ int s;
+
+ do {
+ s = socket(AF_LOCAL, type, 0);
+ } while (s < 0 && socket_errno == EINTR);
+ if (s < 0) return -1;
+
+ addrlen = socket_unix_prepare_address( &addr, name );
+ if (addrlen < 0) {
+ socket_close(s);
+ return -1;
+ }
+
+ return socket_connect_client( s, (struct sockaddr*) &addr, (socklen_t)addrlen );
+}
+#endif
+
diff --git a/sockets.h b/sockets.h
new file mode 100644
index 0000000..c1f6d80
--- /dev/null
+++ b/sockets.h
@@ -0,0 +1,73 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+/* headers to use the BSD sockets */
+#ifndef QEMU_SOCKET_H
+#define QEMU_SOCKET_H
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+#define socket_errno WSAGetLastError()
+#define socket_errstr() socket_strerr()
+
+#undef EINTR
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EINTR WSAEINTR
+#define EINPROGRESS WSAEINPROGRESS
+
+extern const char* socket_strerr(void);
+
+#else
+
+/* if this code is included from slirp/ sources, don't include the
+ * system header files because this might conflict with some of the
+ * slirp definitions
+ */
+#include <errno.h>
+#ifndef SLIRP_COMPILATION
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#endif
+
+#define socket_errno errno
+#define socket_errstr() strerror(errno)
+
+#endif /* !_WIN32 */
+
+int socket_init( void );
+
+int socket_get_type(int fd);
+
+/* set SO_REUSEADDR on Unix, SO_EXCLUSIVEADDR on Windows */
+int socket_set_xreuseaddr(int fd);
+int socket_set_nonblock(int fd);
+int socket_set_blocking(int fd);
+int socket_set_lowlatency(int fd);
+int socket_set_oobinline(int fd);
+void socket_close(int fd);
+
+int socket_loopback_server( int port, int type );
+int socket_loopback_client( int port, int type );
+#ifndef _WIN32
+int socket_unix_server( const char* name, int type );
+int socket_unix_client( const char* name, int type );
+#endif
+int socket_network_client( const char* host, int port, int type );
+int socket_anyaddr_server( int port, int type );
+int socket_accept_any( int server_fd );
+
+#endif /* QEMU_SOCKET_H */
diff --git a/softmmu_header.h b/softmmu_header.h
index d5b3deb..25062a7 100644
--- a/softmmu_header.h
+++ b/softmmu_header.h
@@ -108,7 +108,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr, DATA_TYPE v, int is_user);
#if (DATA_SIZE <= 4) && (TARGET_LONG_BITS == 32) && defined(__i386__) && \
- (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU)
+ (ACCESS_TYPE <= 1) && defined(ASM_SOFTMMU) && (__GNUC__ < 4)
#define CPU_TLB_ENTRY_BITS 4
@@ -150,7 +150,7 @@ static inline RES_TYPE glue(glue(ld, USUFFIX), MEMSUFFIX)(target_ulong ptr)
"m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)),
"i" (CPU_MEM_INDEX),
"m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX))
- : "%eax", "%ecx", "%edx", "memory", "cc");
+ : "%eax", "%edx", "memory", "cc");
return res;
}
@@ -197,13 +197,14 @@ static inline int glue(glue(lds, SUFFIX), MEMSUFFIX)(target_ulong ptr)
"m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_read)),
"i" (CPU_MEM_INDEX),
"m" (*(uint8_t *)&glue(glue(__ld, SUFFIX), MMUSUFFIX))
- : "%eax", "%ecx", "%edx", "memory", "cc");
+ : "%eax", "%edx", "memory", "cc");
return res;
}
#endif
-static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE v)
+static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE val)
{
+ RES_TYPE v = val;
asm volatile ("movl %0, %%edx\n"
"movl %0, %%eax\n"
"shrl %3, %%edx\n"
@@ -240,16 +241,14 @@ static inline void glue(glue(st, SUFFIX), MEMSUFFIX)(target_ulong ptr, RES_TYPE
"2:\n"
:
: "r" (ptr),
-/* NOTE: 'q' would be needed as constraint, but we could not use it
- with T1 ! */
- "r" (v),
+ "q" (v),
"i" ((CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS),
"i" (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS),
"i" (TARGET_PAGE_MASK | (DATA_SIZE - 1)),
"m" (*(uint32_t *)offsetof(CPUState, tlb_table[CPU_MEM_INDEX][0].addr_write)),
"i" (CPU_MEM_INDEX),
"m" (*(uint8_t *)&glue(glue(__st, SUFFIX), MMUSUFFIX))
- : "%eax", "%ecx", "%edx", "memory", "cc");
+ : "%eax", "%edx", "memory", "cc");
}
#else
diff --git a/softmmu_template.h b/softmmu_template.h
index 1c12c42..3f0edbf 100644
--- a/softmmu_template.h
+++ b/softmmu_template.h
@@ -94,11 +94,18 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
if (tlb_addr & ~TARGET_PAGE_MASK) {
/* IO access */
if ((addr & (DATA_SIZE - 1)) != 0)
- goto do_unaligned_access;
- res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
- } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
+ {
+ retaddr = GETPC();
+#ifdef IO_ALIGNED_ONLY
+ do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr);
+#endif
+ res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(addr, is_user, retaddr);
+ }
+ else
+ res = glue(io_read, SUFFIX)(physaddr, tlb_addr);
+ }
+ else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
/* slow unaligned access (it spans two pages or IO) */
- do_unaligned_access:
retaddr = GETPC();
#ifdef ALIGNED_ONLY
do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr);
@@ -118,7 +125,7 @@ DATA_TYPE REGPARM(1) glue(glue(__ld, SUFFIX), MMUSUFFIX)(target_ulong addr,
} else {
/* the page is not in the TLB : fill it */
retaddr = GETPC();
-#ifdef ALIGNED_ONLY
+#ifdef zzALIGNED_ONLY
if ((addr & (DATA_SIZE - 1)) != 0)
do_unaligned_access(addr, READ_ACCESS_TYPE, is_user, retaddr);
#endif
@@ -217,7 +224,8 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
target_ulong tlb_addr;
void *retaddr;
int index;
-
+
+ env->mem_write_vaddr = addr;
index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
redo:
tlb_addr = env->tlb_table[is_user][index].addr_write;
@@ -225,12 +233,18 @@ void REGPARM(2) glue(glue(__st, SUFFIX), MMUSUFFIX)(target_ulong addr,
physaddr = addr + env->tlb_table[is_user][index].addend;
if (tlb_addr & ~TARGET_PAGE_MASK) {
/* IO access */
- if ((addr & (DATA_SIZE - 1)) != 0)
- goto do_unaligned_access;
retaddr = GETPC();
- glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr);
- } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
- do_unaligned_access:
+ if ((addr & (DATA_SIZE - 1)) != 0)
+ {
+#ifdef IO_ALIGNED_ONLY
+ do_unaligned_acess(addr, 1, is_user, retaddr);
+#endif
+ glue(glue(slow_st, SUFFIX), MMUSUFFIX)(addr, val, is_user, retaddr);
+ }
+ else
+ glue(io_write, SUFFIX)(physaddr, val, tlb_addr, retaddr);
+ }
+ else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) {
retaddr = GETPC();
#ifdef ALIGNED_ONLY
do_unaligned_access(addr, 1, is_user, retaddr);
diff --git a/sparc-dis.c b/sparc-dis.c
deleted file mode 100644
index 2be874a..0000000
--- a/sparc-dis.c
+++ /dev/null
@@ -1,3265 +0,0 @@
-/* Print SPARC instructions.
- Copyright 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2002 Free Software Foundation, Inc.
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-#include <stdlib.h>
-#include "dis-asm.h"
-
-/* The SPARC opcode table (and other related data) is defined in
- the opcodes library in sparc-opc.c. If you change anything here, make
- sure you fix up that file, and vice versa. */
-
- /* FIXME-someday: perhaps the ,a's and such should be embedded in the
- instruction's name rather than the args. This would make gas faster, pinsn
- slower, but would mess up some macros a bit. xoxorich. */
-
-/* List of instruction sets variations.
- These values are such that each element is either a superset of a
- preceding each one or they conflict in which case SPARC_OPCODE_CONFLICT_P
- returns non-zero.
- The values are indices into `sparc_opcode_archs' defined in sparc-opc.c.
- Don't change this without updating sparc-opc.c. */
-
-enum sparc_opcode_arch_val {
- SPARC_OPCODE_ARCH_V6 = 0,
- SPARC_OPCODE_ARCH_V7,
- SPARC_OPCODE_ARCH_V8,
- SPARC_OPCODE_ARCH_SPARCLET,
- SPARC_OPCODE_ARCH_SPARCLITE,
- /* v9 variants must appear last */
- SPARC_OPCODE_ARCH_V9,
- SPARC_OPCODE_ARCH_V9A, /* v9 with ultrasparc additions */
- SPARC_OPCODE_ARCH_V9B, /* v9 with ultrasparc and cheetah additions */
- SPARC_OPCODE_ARCH_BAD /* error return from sparc_opcode_lookup_arch */
-};
-
-/* The highest architecture in the table. */
-#define SPARC_OPCODE_ARCH_MAX (SPARC_OPCODE_ARCH_BAD - 1)
-
-/* Given an enum sparc_opcode_arch_val, return the bitmask to use in
- insn encoding/decoding. */
-#define SPARC_OPCODE_ARCH_MASK(arch) (1 << (arch))
-
-/* Given a valid sparc_opcode_arch_val, return non-zero if it's v9. */
-#define SPARC_OPCODE_ARCH_V9_P(arch) ((arch) >= SPARC_OPCODE_ARCH_V9)
-
-/* Table of cpu variants. */
-
-struct sparc_opcode_arch {
- const char *name;
- /* Mask of sparc_opcode_arch_val's supported.
- EG: For v7 this would be
- (SPARC_OPCODE_ARCH_MASK (..._V6) | SPARC_OPCODE_ARCH_MASK (..._V7)).
- These are short's because sparc_opcode.architecture is. */
- short supported;
-};
-
-extern const struct sparc_opcode_arch sparc_opcode_archs[];
-
-/* Given architecture name, look up it's sparc_opcode_arch_val value. */
-extern enum sparc_opcode_arch_val sparc_opcode_lookup_arch
- PARAMS ((const char *));
-
-/* Return the bitmask of supported architectures for ARCH. */
-#define SPARC_OPCODE_SUPPORTED(ARCH) (sparc_opcode_archs[ARCH].supported)
-
-/* Non-zero if ARCH1 conflicts with ARCH2.
- IE: ARCH1 as a supported bit set that ARCH2 doesn't, and vice versa. */
-#define SPARC_OPCODE_CONFLICT_P(ARCH1, ARCH2) \
-(((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \
- != SPARC_OPCODE_SUPPORTED (ARCH1)) \
- && ((SPARC_OPCODE_SUPPORTED (ARCH1) & SPARC_OPCODE_SUPPORTED (ARCH2)) \
- != SPARC_OPCODE_SUPPORTED (ARCH2)))
-
-/* Structure of an opcode table entry. */
-
-struct sparc_opcode {
- const char *name;
- unsigned long match; /* Bits that must be set. */
- unsigned long lose; /* Bits that must not be set. */
- const char *args;
- /* This was called "delayed" in versions before the flags. */
- char flags;
- short architecture; /* Bitmask of sparc_opcode_arch_val's. */
-};
-
-#define F_DELAYED 1 /* Delayed branch */
-#define F_ALIAS 2 /* Alias for a "real" instruction */
-#define F_UNBR 4 /* Unconditional branch */
-#define F_CONDBR 8 /* Conditional branch */
-#define F_JSR 16 /* Subroutine call */
-#define F_FLOAT 32 /* Floating point instruction (not a branch) */
-#define F_FBR 64 /* Floating point branch */
-/* FIXME: Add F_ANACHRONISTIC flag for v9. */
-
-/*
-
-All sparc opcodes are 32 bits, except for the `set' instruction (really a
-macro), which is 64 bits. It is handled as a special case.
-
-The match component is a mask saying which bits must match a particular
-opcode in order for an instruction to be an instance of that opcode.
-
-The args component is a string containing one character for each operand of the
-instruction.
-
-Kinds of operands:
- # Number used by optimizer. It is ignored.
- 1 rs1 register.
- 2 rs2 register.
- d rd register.
- e frs1 floating point register.
- v frs1 floating point register (double/even).
- V frs1 floating point register (quad/multiple of 4).
- f frs2 floating point register.
- B frs2 floating point register (double/even).
- R frs2 floating point register (quad/multiple of 4).
- g frsd floating point register.
- H frsd floating point register (double/even).
- J frsd floating point register (quad/multiple of 4).
- b crs1 coprocessor register
- c crs2 coprocessor register
- D crsd coprocessor register
- m alternate space register (asr) in rd
- M alternate space register (asr) in rs1
- h 22 high bits.
- X 5 bit unsigned immediate
- Y 6 bit unsigned immediate
- 3 SIAM mode (3 bits). (v9b)
- K MEMBAR mask (7 bits). (v9)
- j 10 bit Immediate. (v9)
- I 11 bit Immediate. (v9)
- i 13 bit Immediate.
- n 22 bit immediate.
- k 2+14 bit PC relative immediate. (v9)
- G 19 bit PC relative immediate. (v9)
- l 22 bit PC relative immediate.
- L 30 bit PC relative immediate.
- a Annul. The annul bit is set.
- A Alternate address space. Stored as 8 bits.
- C Coprocessor state register.
- F floating point state register.
- p Processor state register.
- N Branch predict clear ",pn" (v9)
- T Branch predict set ",pt" (v9)
- z %icc. (v9)
- Z %xcc. (v9)
- q Floating point queue.
- r Single register that is both rs1 and rd.
- O Single register that is both rs2 and rd.
- Q Coprocessor queue.
- S Special case.
- t Trap base register.
- w Window invalid mask register.
- y Y register.
- u sparclet coprocessor registers in rd position
- U sparclet coprocessor registers in rs1 position
- E %ccr. (v9)
- s %fprs. (v9)
- P %pc. (v9)
- W %tick. (v9)
- o %asi. (v9)
- 6 %fcc0. (v9)
- 7 %fcc1. (v9)
- 8 %fcc2. (v9)
- 9 %fcc3. (v9)
- ! Privileged Register in rd (v9)
- ? Privileged Register in rs1 (v9)
- * Prefetch function constant. (v9)
- x OPF field (v9 impdep).
- 0 32/64 bit immediate for set or setx (v9) insns
- _ Ancillary state register in rd (v9a)
- / Ancillary state register in rs1 (v9a)
-
-The following chars are unused: (note: ,[] are used as punctuation)
-[45]
-
-*/
-
-#define OP2(x) (((x)&0x7) << 22) /* op2 field of format2 insns */
-#define OP3(x) (((x)&0x3f) << 19) /* op3 field of format3 insns */
-#define OP(x) ((unsigned)((x)&0x3) << 30) /* op field of all insns */
-#define OPF(x) (((x)&0x1ff) << 5) /* opf field of float insns */
-#define OPF_LOW5(x) OPF((x)&0x1f) /* v9 */
-#define F3F(x, y, z) (OP(x) | OP3(y) | OPF(z)) /* format3 float insns */
-#define F3I(x) (((x)&0x1) << 13) /* immediate field of format 3 insns */
-#define F2(x, y) (OP(x) | OP2(y)) /* format 2 insns */
-#define F3(x, y, z) (OP(x) | OP3(y) | F3I(z)) /* format3 insns */
-#define F1(x) (OP(x))
-#define DISP30(x) ((x)&0x3fffffff)
-#define ASI(x) (((x)&0xff) << 5) /* asi field of format3 insns */
-#define RS2(x) ((x)&0x1f) /* rs2 field */
-#define SIMM13(x) ((x)&0x1fff) /* simm13 field */
-#define RD(x) (((x)&0x1f) << 25) /* destination register field */
-#define RS1(x) (((x)&0x1f) << 14) /* rs1 field */
-#define ASI_RS2(x) (SIMM13(x))
-#define MEMBAR(x) ((x)&0x7f)
-#define SLCPOP(x) (((x)&0x7f) << 6) /* sparclet cpop */
-
-#define ANNUL (1<<29)
-#define BPRED (1<<19) /* v9 */
-#define IMMED F3I(1)
-#define RD_G0 RD(~0)
-#define RS1_G0 RS1(~0)
-#define RS2_G0 RS2(~0)
-
-extern const struct sparc_opcode sparc_opcodes[];
-extern const int sparc_num_opcodes;
-
-extern int sparc_encode_asi PARAMS ((const char *));
-extern const char *sparc_decode_asi PARAMS ((int));
-extern int sparc_encode_membar PARAMS ((const char *));
-extern const char *sparc_decode_membar PARAMS ((int));
-extern int sparc_encode_prefetch PARAMS ((const char *));
-extern const char *sparc_decode_prefetch PARAMS ((int));
-extern int sparc_encode_sparclet_cpreg PARAMS ((const char *));
-extern const char *sparc_decode_sparclet_cpreg PARAMS ((int));
-
-/* Some defines to make life easy. */
-#define MASK_V6 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V6)
-#define MASK_V7 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V7)
-#define MASK_V8 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8)
-#define MASK_SPARCLET SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET)
-#define MASK_SPARCLITE SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE)
-#define MASK_V9 SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9)
-#define MASK_V9A SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A)
-#define MASK_V9B SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B)
-
-/* Bit masks of architectures supporting the insn. */
-
-#define v6 (MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET \
- | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B)
-/* v6 insns not supported on the sparclet */
-#define v6notlet (MASK_V6 | MASK_V7 | MASK_V8 \
- | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B)
-#define v7 (MASK_V7 | MASK_V8 | MASK_SPARCLET \
- | MASK_SPARCLITE | MASK_V9 | MASK_V9A | MASK_V9B)
-/* Although not all insns are implemented in hardware, sparclite is defined
- to be a superset of v8. Unimplemented insns trap and are then theoretically
- implemented in software.
- It's not clear that the same is true for sparclet, although the docs
- suggest it is. Rather than complicating things, the sparclet assembler
- recognizes all v8 insns. */
-#define v8 (MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE \
- | MASK_V9 | MASK_V9A | MASK_V9B)
-#define sparclet (MASK_SPARCLET)
-#define sparclite (MASK_SPARCLITE)
-#define v9 (MASK_V9 | MASK_V9A | MASK_V9B)
-#define v9a (MASK_V9A | MASK_V9B)
-#define v9b (MASK_V9B)
-/* v6 insns not supported by v9 */
-#define v6notv9 (MASK_V6 | MASK_V7 | MASK_V8 \
- | MASK_SPARCLET | MASK_SPARCLITE)
-/* v9a instructions which would appear to be aliases to v9's impdep's
- otherwise */
-#define v9notv9a (MASK_V9)
-
-/* Table of opcode architectures.
- The order is defined in opcode/sparc.h. */
-
-const struct sparc_opcode_arch sparc_opcode_archs[] = {
- { "v6", MASK_V6 },
- { "v7", MASK_V6 | MASK_V7 },
- { "v8", MASK_V6 | MASK_V7 | MASK_V8 },
- { "sparclet", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLET },
- { "sparclite", MASK_V6 | MASK_V7 | MASK_V8 | MASK_SPARCLITE },
- /* ??? Don't some v8 priviledged insns conflict with v9? */
- { "v9", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 },
- /* v9 with ultrasparc additions */
- { "v9a", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A },
- /* v9 with cheetah additions */
- { "v9b", MASK_V6 | MASK_V7 | MASK_V8 | MASK_V9 | MASK_V9A | MASK_V9B },
- { NULL, 0 }
-};
-
-/* Given NAME, return it's architecture entry. */
-
-enum sparc_opcode_arch_val
-sparc_opcode_lookup_arch (name)
- const char *name;
-{
- const struct sparc_opcode_arch *p;
-
- for (p = &sparc_opcode_archs[0]; p->name; ++p)
- {
- if (strcmp (name, p->name) == 0)
- return (enum sparc_opcode_arch_val) (p - &sparc_opcode_archs[0]);
- }
-
- return SPARC_OPCODE_ARCH_BAD;
-}
-
-/* Branch condition field. */
-#define COND(x) (((x)&0xf)<<25)
-
-/* v9: Move (MOVcc and FMOVcc) condition field. */
-#define MCOND(x,i_or_f) ((((i_or_f)&1)<<18)|(((x)>>11)&(0xf<<14))) /* v9 */
-
-/* v9: Move register (MOVRcc and FMOVRcc) condition field. */
-#define RCOND(x) (((x)&0x7)<<10) /* v9 */
-
-#define CONDA (COND(0x8))
-#define CONDCC (COND(0xd))
-#define CONDCS (COND(0x5))
-#define CONDE (COND(0x1))
-#define CONDG (COND(0xa))
-#define CONDGE (COND(0xb))
-#define CONDGU (COND(0xc))
-#define CONDL (COND(0x3))
-#define CONDLE (COND(0x2))
-#define CONDLEU (COND(0x4))
-#define CONDN (COND(0x0))
-#define CONDNE (COND(0x9))
-#define CONDNEG (COND(0x6))
-#define CONDPOS (COND(0xe))
-#define CONDVC (COND(0xf))
-#define CONDVS (COND(0x7))
-
-#define CONDNZ CONDNE
-#define CONDZ CONDE
-#define CONDGEU CONDCC
-#define CONDLU CONDCS
-
-#define FCONDA (COND(0x8))
-#define FCONDE (COND(0x9))
-#define FCONDG (COND(0x6))
-#define FCONDGE (COND(0xb))
-#define FCONDL (COND(0x4))
-#define FCONDLE (COND(0xd))
-#define FCONDLG (COND(0x2))
-#define FCONDN (COND(0x0))
-#define FCONDNE (COND(0x1))
-#define FCONDO (COND(0xf))
-#define FCONDU (COND(0x7))
-#define FCONDUE (COND(0xa))
-#define FCONDUG (COND(0x5))
-#define FCONDUGE (COND(0xc))
-#define FCONDUL (COND(0x3))
-#define FCONDULE (COND(0xe))
-
-#define FCONDNZ FCONDNE
-#define FCONDZ FCONDE
-
-#define ICC (0) /* v9 */
-#define XCC (1<<12) /* v9 */
-#define FCC(x) (((x)&0x3)<<11) /* v9 */
-#define FBFCC(x) (((x)&0x3)<<20) /* v9 */
-
-/* The order of the opcodes in the table is significant:
-
- * The assembler requires that all instances of the same mnemonic must
- be consecutive. If they aren't, the assembler will bomb at runtime.
-
- * The disassembler should not care about the order of the opcodes.
-
-*/
-
-/* Entries for commutative arithmetic operations. */
-/* ??? More entries can make use of this. */
-#define COMMUTEOP(opcode, op3, arch_mask) \
-{ opcode, F3(2, op3, 0), F3(~2, ~op3, ~0)|ASI(~0), "1,2,d", 0, arch_mask }, \
-{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "1,i,d", 0, arch_mask }, \
-{ opcode, F3(2, op3, 1), F3(~2, ~op3, ~1), "i,1,d", 0, arch_mask }
-
-const struct sparc_opcode sparc_opcodes[] = {
-
-{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", 0, v6 },
-{ "ld", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", 0, v6 }, /* ld [rs1+%g0],d */
-{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", 0, v6 },
-{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", 0, v6 },
-{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", 0, v6 },
-{ "ld", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ld [rs1+0],d */
-{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0), "[1+2],g", 0, v6 },
-{ "ld", F3(3, 0x20, 0), F3(~3, ~0x20, ~0)|RS2_G0, "[1],g", 0, v6 }, /* ld [rs1+%g0],d */
-{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[1+i],g", 0, v6 },
-{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1), "[i+1],g", 0, v6 },
-{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|RS1_G0, "[i],g", 0, v6 },
-{ "ld", F3(3, 0x20, 1), F3(~3, ~0x20, ~1)|SIMM13(~0), "[1],g", 0, v6 }, /* ld [rs1+0],d */
-
-{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RD(~0), "[1+2],F", 0, v6 },
-{ "ld", F3(3, 0x21, 0), F3(~3, ~0x21, ~0)|RS2_G0|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+%g0],d */
-{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[1+i],F", 0, v6 },
-{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RD(~0), "[i+1],F", 0, v6 },
-{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~0),"[i],F", 0, v6 },
-{ "ld", F3(3, 0x21, 1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~0),"[1],F", 0, v6 }, /* ld [rs1+0],d */
-
-{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2],D", 0, v6notv9 },
-{ "ld", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1],D", 0, v6notv9 }, /* ld [rs1+%g0],d */
-{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i],D", 0, v6notv9 },
-{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1],D", 0, v6notv9 },
-{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i],D", 0, v6notv9 },
-{ "ld", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ld [rs1+0],d */
-{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0), "[1+2],C", 0, v6notv9 },
-{ "ld", F3(3, 0x31, 0), F3(~3, ~0x31, ~0)|RS2_G0, "[1],C", 0, v6notv9 }, /* ld [rs1+%g0],d */
-{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[1+i],C", 0, v6notv9 },
-{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1), "[i+1],C", 0, v6notv9 },
-{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|RS1_G0, "[i],C", 0, v6notv9 },
-{ "ld", F3(3, 0x31, 1), F3(~3, ~0x31, ~1)|SIMM13(~0), "[1],C", 0, v6notv9 }, /* ld [rs1+0],d */
-
-/* The v9 LDUW is the same as the old 'ld' opcode, it is not the same as the
- 'ld' pseudo-op in v9. */
-{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0), "[1+2],d", F_ALIAS, v9 },
-{ "lduw", F3(3, 0x00, 0), F3(~3, ~0x00, ~0)|RS2_G0, "[1],d", F_ALIAS, v9 }, /* ld [rs1+%g0],d */
-{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[1+i],d", F_ALIAS, v9 },
-{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1), "[i+1],d", F_ALIAS, v9 },
-{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|RS1_G0, "[i],d", F_ALIAS, v9 },
-{ "lduw", F3(3, 0x00, 1), F3(~3, ~0x00, ~1)|SIMM13(~0), "[1],d", F_ALIAS, v9 }, /* ld [rs1+0],d */
-
-{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI(~0), "[1+2],d", 0, v6 },
-{ "ldd", F3(3, 0x03, 0), F3(~3, ~0x03, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldd [rs1+%g0],d */
-{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[1+i],d", 0, v6 },
-{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1), "[i+1],d", 0, v6 },
-{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|RS1_G0, "[i],d", 0, v6 },
-{ "ldd", F3(3, 0x03, 1), F3(~3, ~0x03, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldd [rs1+0],d */
-{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI(~0), "[1+2],H", 0, v6 },
-{ "ldd", F3(3, 0x23, 0), F3(~3, ~0x23, ~0)|ASI_RS2(~0), "[1],H", 0, v6 }, /* ldd [rs1+%g0],d */
-{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[1+i],H", 0, v6 },
-{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1), "[i+1],H", 0, v6 },
-{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|RS1_G0, "[i],H", 0, v6 },
-{ "ldd", F3(3, 0x23, 1), F3(~3, ~0x23, ~1)|SIMM13(~0), "[1],H", 0, v6 }, /* ldd [rs1+0],d */
-
-{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI(~0), "[1+2],D", 0, v6notv9 },
-{ "ldd", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|ASI_RS2(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+%g0],d */
-{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i],D", 0, v6notv9 },
-{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1],D", 0, v6notv9 },
-{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i],D", 0, v6notv9 },
-{ "ldd", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1],D", 0, v6notv9 }, /* ldd [rs1+0],d */
-
-{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI(~0), "[1+2],J", 0, v9 },
-{ "ldq", F3(3, 0x22, 0), F3(~3, ~0x22, ~0)|ASI_RS2(~0), "[1],J", 0, v9 }, /* ldd [rs1+%g0],d */
-{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[1+i],J", 0, v9 },
-{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1), "[i+1],J", 0, v9 },
-{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|RS1_G0, "[i],J", 0, v9 },
-{ "ldq", F3(3, 0x22, 1), F3(~3, ~0x22, ~1)|SIMM13(~0), "[1],J", 0, v9 }, /* ldd [rs1+0],d */
-
-{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI(~0), "[1+2],d", 0, v6 },
-{ "ldsb", F3(3, 0x09, 0), F3(~3, ~0x09, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsb [rs1+%g0],d */
-{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[1+i],d", 0, v6 },
-{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1), "[i+1],d", 0, v6 },
-{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|RS1_G0, "[i],d", 0, v6 },
-{ "ldsb", F3(3, 0x09, 1), F3(~3, ~0x09, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsb [rs1+0],d */
-
-{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldsh [rs1+%g0],d */
-{ "ldsh", F3(3, 0x0a, 0), F3(~3, ~0x0a, ~0)|ASI(~0), "[1+2],d", 0, v6 },
-{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[1+i],d", 0, v6 },
-{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1), "[i+1],d", 0, v6 },
-{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|RS1_G0, "[i],d", 0, v6 },
-{ "ldsh", F3(3, 0x0a, 1), F3(~3, ~0x0a, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldsh [rs1+0],d */
-
-{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI(~0), "[1+2],d", 0, v6 },
-{ "ldstub", F3(3, 0x0d, 0), F3(~3, ~0x0d, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldstub [rs1+%g0],d */
-{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[1+i],d", 0, v6 },
-{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1), "[i+1],d", 0, v6 },
-{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|RS1_G0, "[i],d", 0, v6 },
-{ "ldstub", F3(3, 0x0d, 1), F3(~3, ~0x0d, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldstub [rs1+0],d */
-
-{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI(~0), "[1+2],d", 0, v9 },
-{ "ldsw", F3(3, 0x08, 0), F3(~3, ~0x08, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldsw [rs1+%g0],d */
-{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[1+i],d", 0, v9 },
-{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1), "[i+1],d", 0, v9 },
-{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|RS1_G0, "[i],d", 0, v9 },
-{ "ldsw", F3(3, 0x08, 1), F3(~3, ~0x08, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldsw [rs1+0],d */
-
-{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI(~0), "[1+2],d", 0, v6 },
-{ "ldub", F3(3, 0x01, 0), F3(~3, ~0x01, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* ldub [rs1+%g0],d */
-{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[1+i],d", 0, v6 },
-{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1), "[i+1],d", 0, v6 },
-{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|RS1_G0, "[i],d", 0, v6 },
-{ "ldub", F3(3, 0x01, 1), F3(~3, ~0x01, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* ldub [rs1+0],d */
-
-{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI(~0), "[1+2],d", 0, v6 },
-{ "lduh", F3(3, 0x02, 0), F3(~3, ~0x02, ~0)|ASI_RS2(~0), "[1],d", 0, v6 }, /* lduh [rs1+%g0],d */
-{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[1+i],d", 0, v6 },
-{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1), "[i+1],d", 0, v6 },
-{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|RS1_G0, "[i],d", 0, v6 },
-{ "lduh", F3(3, 0x02, 1), F3(~3, ~0x02, ~1)|SIMM13(~0), "[1],d", 0, v6 }, /* lduh [rs1+0],d */
-
-{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI(~0), "[1+2],d", 0, v9 },
-{ "ldx", F3(3, 0x0b, 0), F3(~3, ~0x0b, ~0)|ASI_RS2(~0), "[1],d", 0, v9 }, /* ldx [rs1+%g0],d */
-{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[1+i],d", 0, v9 },
-{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1), "[i+1],d", 0, v9 },
-{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|RS1_G0, "[i],d", 0, v9 },
-{ "ldx", F3(3, 0x0b, 1), F3(~3, ~0x0b, ~1)|SIMM13(~0), "[1],d", 0, v9 }, /* ldx [rs1+0],d */
-
-{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RD(~1), "[1+2],F", 0, v9 },
-{ "ldx", F3(3, 0x21, 0)|RD(1), F3(~3, ~0x21, ~0)|RS2_G0|RD(~1), "[1],F", 0, v9 }, /* ld [rs1+%g0],d */
-{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[1+i],F", 0, v9 },
-{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RD(~1), "[i+1],F", 0, v9 },
-{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|RS1_G0|RD(~1), "[i],F", 0, v9 },
-{ "ldx", F3(3, 0x21, 1)|RD(1), F3(~3, ~0x21, ~1)|SIMM13(~0)|RD(~1),"[1],F", 0, v9 }, /* ld [rs1+0],d */
-
-{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", 0, v6 },
-{ "lda", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lda [rs1+%g0],d */
-{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", 0, v9 },
-{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", 0, v9 },
-{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", 0, v9 },
-{ "lda", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
-{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0), "[1+2]A,g", 0, v9 },
-{ "lda", F3(3, 0x30, 0), F3(~3, ~0x30, ~0)|RS2_G0, "[1]A,g", 0, v9 }, /* lda [rs1+%g0],d */
-{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[1+i]o,g", 0, v9 },
-{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1), "[i+1]o,g", 0, v9 },
-{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|RS1_G0, "[i]o,g", 0, v9 },
-{ "lda", F3(3, 0x30, 1), F3(~3, ~0x30, ~1)|SIMM13(~0), "[1]o,g", 0, v9 }, /* ld [rs1+0],d */
-
-{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0), "[1+2]A,d", 0, v6 },
-{ "ldda", F3(3, 0x13, 0), F3(~3, ~0x13, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldda [rs1+%g0],d */
-{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[1+i]o,d", 0, v9 },
-{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1), "[i+1]o,d", 0, v9 },
-{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|RS1_G0, "[i]o,d", 0, v9 },
-{ "ldda", F3(3, 0x13, 1), F3(~3, ~0x13, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
-
-{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0), "[1+2]A,H", 0, v9 },
-{ "ldda", F3(3, 0x33, 0), F3(~3, ~0x33, ~0)|RS2_G0, "[1]A,H", 0, v9 }, /* ldda [rs1+%g0],d */
-{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[1+i]o,H", 0, v9 },
-{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1), "[i+1]o,H", 0, v9 },
-{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|RS1_G0, "[i]o,H", 0, v9 },
-{ "ldda", F3(3, 0x33, 1), F3(~3, ~0x33, ~1)|SIMM13(~0), "[1]o,H", 0, v9 }, /* ld [rs1+0],d */
-
-{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0), "[1+2]A,J", 0, v9 },
-{ "ldqa", F3(3, 0x32, 0), F3(~3, ~0x32, ~0)|RS2_G0, "[1]A,J", 0, v9 }, /* ldd [rs1+%g0],d */
-{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[1+i]o,J", 0, v9 },
-{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1), "[i+1]o,J", 0, v9 },
-{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|RS1_G0, "[i]o,J", 0, v9 },
-{ "ldqa", F3(3, 0x32, 1), F3(~3, ~0x32, ~1)|SIMM13(~0), "[1]o,J", 0, v9 }, /* ldd [rs1+0],d */
-
-{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0), "[1+2]A,d", 0, v6 },
-{ "ldsba", F3(3, 0x19, 0), F3(~3, ~0x19, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsba [rs1+%g0],d */
-{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[1+i]o,d", 0, v9 },
-{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1), "[i+1]o,d", 0, v9 },
-{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|RS1_G0, "[i]o,d", 0, v9 },
-{ "ldsba", F3(3, 0x19, 1), F3(~3, ~0x19, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
-
-{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0), "[1+2]A,d", 0, v6 },
-{ "ldsha", F3(3, 0x1a, 0), F3(~3, ~0x1a, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldsha [rs1+%g0],d */
-{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[1+i]o,d", 0, v9 },
-{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1), "[i+1]o,d", 0, v9 },
-{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|RS1_G0, "[i]o,d", 0, v9 },
-{ "ldsha", F3(3, 0x1a, 1), F3(~3, ~0x1a, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
-
-{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0), "[1+2]A,d", 0, v6 },
-{ "ldstuba", F3(3, 0x1d, 0), F3(~3, ~0x1d, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* ldstuba [rs1+%g0],d */
-{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[1+i]o,d", 0, v9 },
-{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1), "[i+1]o,d", 0, v9 },
-{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|RS1_G0, "[i]o,d", 0, v9 },
-{ "ldstuba", F3(3, 0x1d, 1), F3(~3, ~0x1d, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
-
-{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0), "[1+2]A,d", 0, v9 },
-{ "ldswa", F3(3, 0x18, 0), F3(~3, ~0x18, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */
-{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[1+i]o,d", 0, v9 },
-{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1), "[i+1]o,d", 0, v9 },
-{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|RS1_G0, "[i]o,d", 0, v9 },
-{ "ldswa", F3(3, 0x18, 1), F3(~3, ~0x18, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
-
-{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0), "[1+2]A,d", 0, v6 },
-{ "lduba", F3(3, 0x11, 0), F3(~3, ~0x11, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduba [rs1+%g0],d */
-{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[1+i]o,d", 0, v9 },
-{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1), "[i+1]o,d", 0, v9 },
-{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|RS1_G0, "[i]o,d", 0, v9 },
-{ "lduba", F3(3, 0x11, 1), F3(~3, ~0x11, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
-
-{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0), "[1+2]A,d", 0, v6 },
-{ "lduha", F3(3, 0x12, 0), F3(~3, ~0x12, ~0)|RS2_G0, "[1]A,d", 0, v6 }, /* lduha [rs1+%g0],d */
-{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[1+i]o,d", 0, v9 },
-{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1), "[i+1]o,d", 0, v9 },
-{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|RS1_G0, "[i]o,d", 0, v9 },
-{ "lduha", F3(3, 0x12, 1), F3(~3, ~0x12, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
-
-{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0), "[1+2]A,d", F_ALIAS, v9 }, /* lduwa === lda */
-{ "lduwa", F3(3, 0x10, 0), F3(~3, ~0x10, ~0)|RS2_G0, "[1]A,d", F_ALIAS, v9 }, /* lda [rs1+%g0],d */
-{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[1+i]o,d", F_ALIAS, v9 },
-{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1), "[i+1]o,d", F_ALIAS, v9 },
-{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|RS1_G0, "[i]o,d", F_ALIAS, v9 },
-{ "lduwa", F3(3, 0x10, 1), F3(~3, ~0x10, ~1)|SIMM13(~0), "[1]o,d", F_ALIAS, v9 }, /* ld [rs1+0],d */
-
-{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0), "[1+2]A,d", 0, v9 },
-{ "ldxa", F3(3, 0x1b, 0), F3(~3, ~0x1b, ~0)|RS2_G0, "[1]A,d", 0, v9 }, /* lda [rs1+%g0],d */
-{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[1+i]o,d", 0, v9 },
-{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1), "[i+1]o,d", 0, v9 },
-{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|RS1_G0, "[i]o,d", 0, v9 },
-{ "ldxa", F3(3, 0x1b, 1), F3(~3, ~0x1b, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* ld [rs1+0],d */
-
-{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", 0, v6 },
-{ "st", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* st d,[rs1+%g0] */
-{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", 0, v6 },
-{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", 0, v6 },
-{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", 0, v6 },
-{ "st", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* st d,[rs1+0] */
-{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI(~0), "g,[1+2]", 0, v6 },
-{ "st", F3(3, 0x24, 0), F3(~3, ~0x24, ~0)|ASI_RS2(~0), "g,[1]", 0, v6 }, /* st d[rs1+%g0] */
-{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[1+i]", 0, v6 },
-{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1), "g,[i+1]", 0, v6 },
-{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|RS1_G0, "g,[i]", 0, v6 },
-{ "st", F3(3, 0x24, 1), F3(~3, ~0x24, ~1)|SIMM13(~0), "g,[1]", 0, v6 }, /* st d,[rs1+0] */
-
-{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 },
-{ "st", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */
-{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[1+i]", 0, v6notv9 },
-{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "D,[i+1]", 0, v6notv9 },
-{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "D,[i]", 0, v6notv9 },
-{ "st", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* st d,[rs1+0] */
-{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI(~0), "C,[1+2]", 0, v6notv9 },
-{ "st", F3(3, 0x35, 0), F3(~3, ~0x35, ~0)|ASI_RS2(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+%g0] */
-{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[1+i]", 0, v6notv9 },
-{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1), "C,[i+1]", 0, v6notv9 },
-{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|RS1_G0, "C,[i]", 0, v6notv9 },
-{ "st", F3(3, 0x35, 1), F3(~3, ~0x35, ~1)|SIMM13(~0), "C,[1]", 0, v6notv9 }, /* st d,[rs1+0] */
-
-{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI(~0), "F,[1+2]", 0, v6 },
-{ "st", F3(3, 0x25, 0), F3(~3, ~0x25, ~0)|RD_G0|ASI_RS2(~0), "F,[1]", 0, v6 }, /* st d,[rs1+%g0] */
-{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[1+i]", 0, v6 },
-{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0, "F,[i+1]", 0, v6 },
-{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|RS1_G0, "F,[i]", 0, v6 },
-{ "st", F3(3, 0x25, 1), F3(~3, ~0x25, ~1)|RD_G0|SIMM13(~0), "F,[1]", 0, v6 }, /* st d,[rs1+0] */
-
-{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 },
-{ "stw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */
-{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 },
-{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 },
-{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 },
-{ "stw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */
-{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 },
-{ "stsw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */
-{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 },
-{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 },
-{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 },
-{ "stsw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */
-{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v9 },
-{ "stuw", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+%g0] */
-{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v9 },
-{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v9 },
-{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v9 },
-{ "stuw", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v9 }, /* st d,[rs1+0] */
-
-{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 },
-{ "spill", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+%g0] */
-{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[1+i]", F_ALIAS, v6 },
-{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1), "d,[i+1]", F_ALIAS, v6 },
-{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 },
-{ "spill", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* st d,[rs1+0] */
-
-{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", 0, v6 },
-{ "sta", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* sta d,[rs1+%g0] */
-{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", 0, v9 },
-{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", 0, v9 },
-{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", 0, v9 },
-{ "sta", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* st d,[rs1+0] */
-
-{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0), "g,[1+2]A", 0, v9 },
-{ "sta", F3(3, 0x34, 0), F3(~3, ~0x34, ~0)|RS2(~0), "g,[1]A", 0, v9 }, /* sta d,[rs1+%g0] */
-{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[1+i]o", 0, v9 },
-{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1), "g,[i+1]o", 0, v9 },
-{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|RS1_G0, "g,[i]o", 0, v9 },
-{ "sta", F3(3, 0x34, 1), F3(~3, ~0x34, ~1)|SIMM13(~0), "g,[1]o", 0, v9 }, /* st d,[rs1+0] */
-
-{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 },
-{ "stwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */
-{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 },
-{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 },
-{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 },
-{ "stwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */
-{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 },
-{ "stswa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */
-{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 },
-{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 },
-{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 },
-{ "stswa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */
-{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0), "d,[1+2]A", F_ALIAS, v9 },
-{ "stuwa", F3(3, 0x14, 0), F3(~3, ~0x14, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v9 }, /* sta d,[rs1+%g0] */
-{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[1+i]o", F_ALIAS, v9 },
-{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1), "d,[i+1]o", F_ALIAS, v9 },
-{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 },
-{ "stuwa", F3(3, 0x14, 1), F3(~3, ~0x14, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* st d,[rs1+0] */
-
-{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", 0, v6 },
-{ "stb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+%g0] */
-{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", 0, v6 },
-{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", 0, v6 },
-{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", 0, v6 },
-{ "stb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* stb d,[rs1+0] */
-
-{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 },
-{ "stsb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */
-{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 },
-{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 },
-{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 },
-{ "stsb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */
-{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 },
-{ "stub", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+%g0] */
-{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[1+i]", F_ALIAS, v6 },
-{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1), "d,[i+1]", F_ALIAS, v6 },
-{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 },
-{ "stub", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* stb d,[rs1+0] */
-
-{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", 0, v6 },
-{ "stba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stba d,[rs1+%g0] */
-{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", 0, v9 },
-{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", 0, v9 },
-{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", 0, v9 },
-{ "stba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stb d,[rs1+0] */
-
-{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 },
-{ "stsba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */
-{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 },
-{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 },
-{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 },
-{ "stsba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */
-{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0), "d,[1+2]A", F_ALIAS, v6 },
-{ "stuba", F3(3, 0x15, 0), F3(~3, ~0x15, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stba d,[rs1+%g0] */
-{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[1+i]o", F_ALIAS, v9 },
-{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1), "d,[i+1]o", F_ALIAS, v9 },
-{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 },
-{ "stuba", F3(3, 0x15, 1), F3(~3, ~0x15, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* stb d,[rs1+0] */
-
-{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", 0, v6 },
-{ "std", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* std d,[rs1+%g0] */
-{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", 0, v6 },
-{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", 0, v6 },
-{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", 0, v6 },
-{ "std", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* std d,[rs1+0] */
-
-{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "q,[1+2]", 0, v6notv9 },
-{ "std", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */
-{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[1+i]", 0, v6notv9 },
-{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "q,[i+1]", 0, v6notv9 },
-{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "q,[i]", 0, v6notv9 },
-{ "std", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */
-{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI(~0), "H,[1+2]", 0, v6 },
-{ "std", F3(3, 0x27, 0), F3(~3, ~0x27, ~0)|ASI_RS2(~0), "H,[1]", 0, v6 }, /* std d,[rs1+%g0] */
-{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[1+i]", 0, v6 },
-{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1), "H,[i+1]", 0, v6 },
-{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|RS1_G0, "H,[i]", 0, v6 },
-{ "std", F3(3, 0x27, 1), F3(~3, ~0x27, ~1)|SIMM13(~0), "H,[1]", 0, v6 }, /* std d,[rs1+0] */
-
-{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "Q,[1+2]", 0, v6notv9 },
-{ "std", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */
-{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[1+i]", 0, v6notv9 },
-{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "Q,[i+1]", 0, v6notv9 },
-{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "Q,[i]", 0, v6notv9 },
-{ "std", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "Q,[1]", 0, v6notv9 }, /* std d,[rs1+0] */
-{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI(~0), "D,[1+2]", 0, v6notv9 },
-{ "std", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|ASI_RS2(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+%g0] */
-{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[1+i]", 0, v6notv9 },
-{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "D,[i+1]", 0, v6notv9 },
-{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "D,[i]", 0, v6notv9 },
-{ "std", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "D,[1]", 0, v6notv9 }, /* std d,[rs1+0] */
-
-{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 },
-{ "spilld", F3(3, 0x07, 0), F3(~3, ~0x07, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+%g0] */
-{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[1+i]", F_ALIAS, v6 },
-{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1), "d,[i+1]", F_ALIAS, v6 },
-{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 },
-{ "spilld", F3(3, 0x07, 1), F3(~3, ~0x07, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* std d,[rs1+0] */
-
-{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0), "d,[1+2]A", 0, v6 },
-{ "stda", F3(3, 0x17, 0), F3(~3, ~0x17, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stda d,[rs1+%g0] */
-{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[1+i]o", 0, v9 },
-{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1), "d,[i+1]o", 0, v9 },
-{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|RS1_G0, "d,[i]o", 0, v9 },
-{ "stda", F3(3, 0x17, 1), F3(~3, ~0x17, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* std d,[rs1+0] */
-{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0), "H,[1+2]A", 0, v9 },
-{ "stda", F3(3, 0x37, 0), F3(~3, ~0x37, ~0)|RS2(~0), "H,[1]A", 0, v9 }, /* stda d,[rs1+%g0] */
-{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[1+i]o", 0, v9 },
-{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1), "H,[i+1]o", 0, v9 },
-{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|RS1_G0, "H,[i]o", 0, v9 },
-{ "stda", F3(3, 0x37, 1), F3(~3, ~0x37, ~1)|SIMM13(~0), "H,[1]o", 0, v9 }, /* std d,[rs1+0] */
-
-{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", 0, v6 },
-{ "sth", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+%g0] */
-{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", 0, v6 },
-{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", 0, v6 },
-{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", 0, v6 },
-{ "sth", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", 0, v6 }, /* sth d,[rs1+0] */
-
-{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 },
-{ "stsh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */
-{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 },
-{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 },
-{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 },
-{ "stsh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */
-{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI(~0), "d,[1+2]", F_ALIAS, v6 },
-{ "stuh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|ASI_RS2(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+%g0] */
-{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[1+i]", F_ALIAS, v6 },
-{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1), "d,[i+1]", F_ALIAS, v6 },
-{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RS1_G0, "d,[i]", F_ALIAS, v6 },
-{ "stuh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|SIMM13(~0), "d,[1]", F_ALIAS, v6 }, /* sth d,[rs1+0] */
-
-{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", 0, v6 },
-{ "stha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", 0, v6 }, /* stha ,[rs1+%g0] */
-{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", 0, v9 },
-{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", 0, v9 },
-{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", 0, v9 },
-{ "stha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* sth d,[rs1+0] */
-
-{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 },
-{ "stsha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */
-{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 },
-{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 },
-{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 },
-{ "stsha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */
-{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0), "d,[1+2]A", F_ALIAS, v6 },
-{ "stuha", F3(3, 0x16, 0), F3(~3, ~0x16, ~0)|RS2(~0), "d,[1]A", F_ALIAS, v6 }, /* stha ,[rs1+%g0] */
-{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[1+i]o", F_ALIAS, v9 },
-{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1), "d,[i+1]o", F_ALIAS, v9 },
-{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|RS1_G0, "d,[i]o", F_ALIAS, v9 },
-{ "stuha", F3(3, 0x16, 1), F3(~3, ~0x16, ~1)|SIMM13(~0), "d,[1]o", F_ALIAS, v9 }, /* sth d,[rs1+0] */
-
-{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI(~0), "d,[1+2]", 0, v9 },
-{ "stx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|ASI_RS2(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+%g0] */
-{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[1+i]", 0, v9 },
-{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1), "d,[i+1]", 0, v9 },
-{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RS1_G0, "d,[i]", 0, v9 },
-{ "stx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|SIMM13(~0), "d,[1]", 0, v9 }, /* stx d,[rs1+0] */
-
-{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI(~0)|RD(~1), "F,[1+2]", 0, v9 },
-{ "stx", F3(3, 0x25, 0)|RD(1), F3(~3, ~0x25, ~0)|ASI_RS2(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+%g0] */
-{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[1+i]", 0, v9 },
-{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RD(~1), "F,[i+1]", 0, v9 },
-{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|RS1_G0|RD(~1), "F,[i]", 0, v9 },
-{ "stx", F3(3, 0x25, 1)|RD(1), F3(~3, ~0x25, ~1)|SIMM13(~0)|RD(~1),"F,[1]", 0, v9 }, /* stx d,[rs1+0] */
-
-{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0), "d,[1+2]A", 0, v9 },
-{ "stxa", F3(3, 0x1e, 0), F3(~3, ~0x1e, ~0)|RS2(~0), "d,[1]A", 0, v9 }, /* stxa d,[rs1+%g0] */
-{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[1+i]o", 0, v9 },
-{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1), "d,[i+1]o", 0, v9 },
-{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|RS1_G0, "d,[i]o", 0, v9 },
-{ "stxa", F3(3, 0x1e, 1), F3(~3, ~0x1e, ~1)|SIMM13(~0), "d,[1]o", 0, v9 }, /* stx d,[rs1+0] */
-
-{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI(~0), "J,[1+2]", 0, v9 },
-{ "stq", F3(3, 0x26, 0), F3(~3, ~0x26, ~0)|ASI_RS2(~0), "J,[1]", 0, v9 }, /* stq [rs1+%g0] */
-{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[1+i]", 0, v9 },
-{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1), "J,[i+1]", 0, v9 },
-{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|RS1_G0, "J,[i]", 0, v9 },
-{ "stq", F3(3, 0x26, 1), F3(~3, ~0x26, ~1)|SIMM13(~0), "J,[1]", 0, v9 }, /* stq [rs1+0] */
-
-{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI(~0), "J,[1+2]A", 0, v9 },
-{ "stqa", F3(3, 0x36, 0), F3(~3, ~0x36, ~0)|ASI_RS2(~0), "J,[1]A", 0, v9 }, /* stqa [rs1+%g0] */
-{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[1+i]o", 0, v9 },
-{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1), "J,[i+1]o", 0, v9 },
-{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|RS1_G0, "J,[i]o", 0, v9 },
-{ "stqa", F3(3, 0x36, 1), F3(~3, ~0x36, ~1)|SIMM13(~0), "J,[1]o", 0, v9 }, /* stqa [rs1+0] */
-
-{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI(~0), "[1+2],d", 0, v7 },
-{ "swap", F3(3, 0x0f, 0), F3(~3, ~0x0f, ~0)|ASI_RS2(~0), "[1],d", 0, v7 }, /* swap [rs1+%g0],d */
-{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[1+i],d", 0, v7 },
-{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1), "[i+1],d", 0, v7 },
-{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|RS1_G0, "[i],d", 0, v7 },
-{ "swap", F3(3, 0x0f, 1), F3(~3, ~0x0f, ~1)|SIMM13(~0), "[1],d", 0, v7 }, /* swap [rs1+0],d */
-
-{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0), "[1+2]A,d", 0, v7 },
-{ "swapa", F3(3, 0x1f, 0), F3(~3, ~0x1f, ~0)|RS2(~0), "[1]A,d", 0, v7 }, /* swapa [rs1+%g0],d */
-{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[1+i]o,d", 0, v9 },
-{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1), "[i+1]o,d", 0, v9 },
-{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|RS1_G0, "[i]o,d", 0, v9 },
-{ "swapa", F3(3, 0x1f, 1), F3(~3, ~0x1f, ~1)|SIMM13(~0), "[1]o,d", 0, v9 }, /* swap [rs1+0],d */
-
-{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "restore", F3(2, 0x3d, 0), F3(~2, ~0x3d, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v6 }, /* restore %g0,%g0,%g0 */
-{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1), "1,i,d", 0, v6 },
-{ "restore", F3(2, 0x3d, 1), F3(~2, ~0x3d, ~1)|RD_G0|RS1_G0|SIMM13(~0), "", 0, v6 }, /* restore %g0,0,%g0 */
-
-{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* rett rs1+rs2 */
-{ "rett", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1,%g0 */
-{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* rett rs1+X */
-{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */
-{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X+rs1 */
-{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* rett X */
-{ "rett", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* rett rs1+0 */
-
-{ "save", F3(2, 0x3c, 0), F3(~2, ~0x3c, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "save", F3(2, 0x3c, 1), F3(~2, ~0x3c, ~1), "1,i,d", 0, v6 },
-{ "save", 0x81e00000, ~0x81e00000, "", F_ALIAS, v6 },
-
-{ "ret", F3(2, 0x38, 1)|RS1(0x1f)|SIMM13(8), F3(~2, ~0x38, ~1)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %i7+8,%g0 */
-{ "retl", F3(2, 0x38, 1)|RS1(0x0f)|SIMM13(8), F3(~2, ~0x38, ~1)|RS1(~0x0f)|SIMM13(~8), "", F_UNBR|F_DELAYED, v6 }, /* jmpl %o7+8,%g0 */
-
-{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI(~0), "1+2,d", F_JSR|F_DELAYED, v6 },
-{ "jmpl", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|ASI_RS2(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,d */
-{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|SIMM13(~0), "1,d", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,d */
-{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RS1_G0, "i,d", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,d */
-{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "1+i,d", F_JSR|F_DELAYED, v6 },
-{ "jmpl", F3(2, 0x38, 1), F3(~2, ~0x38, ~1), "i+1,d", F_JSR|F_DELAYED, v6 },
-
-{ "done", F3(2, 0x3e, 0)|RD(0), F3(~2, ~0x3e, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 },
-{ "retry", F3(2, 0x3e, 0)|RD(1), F3(~2, ~0x3e, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 },
-{ "saved", F3(2, 0x31, 0)|RD(0), F3(~2, ~0x31, ~0)|RD(~0)|RS1_G0|SIMM13(~0), "", 0, v9 },
-{ "restored", F3(2, 0x31, 0)|RD(1), F3(~2, ~0x31, ~0)|RD(~1)|RS1_G0|SIMM13(~0), "", 0, v9 },
-{ "sir", F3(2, 0x30, 1)|RD(0xf), F3(~2, ~0x30, ~1)|RD(~0xf)|RS1_G0, "i", 0, v9 },
-
-{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", 0, v8 },
-{ "flush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", 0, v8 }, /* flush rs1+%g0 */
-{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", 0, v8 }, /* flush rs1+0 */
-{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", 0, v8 }, /* flush %g0+i */
-{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", 0, v8 },
-{ "flush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", 0, v8 },
-
-/* IFLUSH was renamed to FLUSH in v8. */
-{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI(~0), "1+2", F_ALIAS, v6 },
-{ "iflush", F3(2, 0x3b, 0), F3(~2, ~0x3b, ~0)|ASI_RS2(~0), "1", F_ALIAS, v6 }, /* flush rs1+%g0 */
-{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|SIMM13(~0), "1", F_ALIAS, v6 }, /* flush rs1+0 */
-{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1)|RS1_G0, "i", F_ALIAS, v6 },
-{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "1+i", F_ALIAS, v6 },
-{ "iflush", F3(2, 0x3b, 1), F3(~2, ~0x3b, ~1), "i+1", F_ALIAS, v6 },
-
-{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI(~0), "1+2", 0, v9 },
-{ "return", F3(2, 0x39, 0), F3(~2, ~0x39, ~0)|ASI_RS2(~0), "1", 0, v9 }, /* return rs1+%g0 */
-{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|SIMM13(~0), "1", 0, v9 }, /* return rs1+0 */
-{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1)|RS1_G0, "i", 0, v9 }, /* return %g0+i */
-{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "1+i", 0, v9 },
-{ "return", F3(2, 0x39, 1), F3(~2, ~0x39, ~1), "i+1", 0, v9 },
-
-{ "flushw", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "", 0, v9 },
-
-{ "membar", F3(2, 0x28, 1)|RS1(0xf), F3(~2, ~0x28, ~1)|RD_G0|RS1(~0xf)|SIMM13(~127), "K", 0, v9 },
-{ "stbar", F3(2, 0x28, 0)|RS1(0xf), F3(~2, ~0x28, ~0)|RD_G0|RS1(~0xf)|SIMM13(~0), "", 0, v8 },
-
-{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0), "[1+2],*", 0, v9 },
-{ "prefetch", F3(3, 0x2d, 0), F3(~3, ~0x2d, ~0)|RS2_G0, "[1],*", 0, v9 }, /* prefetch [rs1+%g0],prefetch_fcn */
-{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[1+i],*", 0, v9 },
-{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1), "[i+1],*", 0, v9 },
-{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|RS1_G0, "[i],*", 0, v9 },
-{ "prefetch", F3(3, 0x2d, 1), F3(~3, ~0x2d, ~1)|SIMM13(~0), "[1],*", 0, v9 }, /* prefetch [rs1+0],prefetch_fcn */
-{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0), "[1+2]A,*", 0, v9 },
-{ "prefetcha", F3(3, 0x3d, 0), F3(~3, ~0x3d, ~0)|RS2_G0, "[1]A,*", 0, v9 }, /* prefetcha [rs1+%g0],prefetch_fcn */
-{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[1+i]o,*", 0, v9 },
-{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1), "[i+1]o,*", 0, v9 },
-{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|RS1_G0, "[i]o,*", 0, v9 },
-{ "prefetcha", F3(3, 0x3d, 1), F3(~3, ~0x3d, ~1)|SIMM13(~0), "[1]o,*", 0, v9 }, /* prefetcha [rs1+0],d */
-
-{ "sll", F3(2, 0x25, 0), F3(~2, ~0x25, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 },
-{ "sll", F3(2, 0x25, 1), F3(~2, ~0x25, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 },
-{ "sra", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 },
-{ "sra", F3(2, 0x27, 1), F3(~2, ~0x27, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 },
-{ "srl", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|(0x7f<<5), "1,2,d", 0, v6 },
-{ "srl", F3(2, 0x26, 1), F3(~2, ~0x26, ~1)|(1<<12)|(0x7f<<5), "1,X,d", 0, v6 },
-
-{ "sllx", F3(2, 0x25, 0)|(1<<12), F3(~2, ~0x25, ~0)|(0x7f<<5), "1,2,d", 0, v9 },
-{ "sllx", F3(2, 0x25, 1)|(1<<12), F3(~2, ~0x25, ~1)|(0x3f<<6), "1,Y,d", 0, v9 },
-{ "srax", F3(2, 0x27, 0)|(1<<12), F3(~2, ~0x27, ~0)|(0x7f<<5), "1,2,d", 0, v9 },
-{ "srax", F3(2, 0x27, 1)|(1<<12), F3(~2, ~0x27, ~1)|(0x3f<<6), "1,Y,d", 0, v9 },
-{ "srlx", F3(2, 0x26, 0)|(1<<12), F3(~2, ~0x26, ~0)|(0x7f<<5), "1,2,d", 0, v9 },
-{ "srlx", F3(2, 0x26, 1)|(1<<12), F3(~2, ~0x26, ~1)|(0x3f<<6), "1,Y,d", 0, v9 },
-
-{ "mulscc", F3(2, 0x24, 0), F3(~2, ~0x24, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "mulscc", F3(2, 0x24, 1), F3(~2, ~0x24, ~1), "1,i,d", 0, v6 },
-
-{ "divscc", F3(2, 0x1d, 0), F3(~2, ~0x1d, ~0)|ASI(~0), "1,2,d", 0, sparclite },
-{ "divscc", F3(2, 0x1d, 1), F3(~2, ~0x1d, ~1), "1,i,d", 0, sparclite },
-
-{ "scan", F3(2, 0x2c, 0), F3(~2, ~0x2c, ~0)|ASI(~0), "1,2,d", 0, sparclet|sparclite },
-{ "scan", F3(2, 0x2c, 1), F3(~2, ~0x2c, ~1), "1,i,d", 0, sparclet|sparclite },
-
-{ "popc", F3(2, 0x2e, 0), F3(~2, ~0x2e, ~0)|RS1_G0|ASI(~0),"2,d", 0, v9 },
-{ "popc", F3(2, 0x2e, 1), F3(~2, ~0x2e, ~1)|RS1_G0, "i,d", 0, v9 },
-
-{ "clr", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RD_G0|RS1_G0|ASI_RS2(~0), "d", F_ALIAS, v6 }, /* or %g0,%g0,d */
-{ "clr", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0|SIMM13(~0), "d", F_ALIAS, v6 }, /* or %g0,0,d */
-{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 },
-{ "clr", F3(3, 0x04, 0), F3(~3, ~0x04, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+%g0] */
-{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 },
-{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 },
-{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 },
-{ "clr", F3(3, 0x04, 1), F3(~3, ~0x04, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* st %g0,[rs1+0] */
-
-{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 },
-{ "clrb", F3(3, 0x05, 0), F3(~3, ~0x05, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+%g0] */
-{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 },
-{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 },
-{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 },
-{ "clrb", F3(3, 0x05, 1), F3(~3, ~0x05, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* stb %g0,[rs1+0] */
-
-{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v6 },
-{ "clrh", F3(3, 0x06, 0), F3(~3, ~0x06, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+%g0] */
-{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[1+i]", F_ALIAS, v6 },
-{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0, "[i+1]", F_ALIAS, v6 },
-{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v6 },
-{ "clrh", F3(3, 0x06, 1), F3(~3, ~0x06, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v6 }, /* sth %g0,[rs1+0] */
-
-{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI(~0), "[1+2]", F_ALIAS, v9 },
-{ "clrx", F3(3, 0x0e, 0), F3(~3, ~0x0e, ~0)|RD_G0|ASI_RS2(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+%g0] */
-{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[1+i]", F_ALIAS, v9 },
-{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0, "[i+1]", F_ALIAS, v9 },
-{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|RS1_G0, "[i]", F_ALIAS, v9 },
-{ "clrx", F3(3, 0x0e, 1), F3(~3, ~0x0e, ~1)|RD_G0|SIMM13(~0), "[1]", F_ALIAS, v9 }, /* stx %g0,[rs1+0] */
-
-{ "orcc", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "1,i,d", 0, v6 },
-{ "orcc", F3(2, 0x12, 1), F3(~2, ~0x12, ~1), "i,1,d", 0, v6 },
-
-/* This is not a commutative instruction. */
-{ "orncc", F3(2, 0x16, 0), F3(~2, ~0x16, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "orncc", F3(2, 0x16, 1), F3(~2, ~0x16, ~1), "1,i,d", 0, v6 },
-
-/* This is not a commutative instruction. */
-{ "orn", F3(2, 0x06, 0), F3(~2, ~0x06, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "orn", F3(2, 0x06, 1), F3(~2, ~0x06, ~1), "1,i,d", 0, v6 },
-
-{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|ASI_RS2(~0), "1", 0, v6 }, /* orcc rs1, %g0, %g0 */
-{ "tst", F3(2, 0x12, 0), F3(~2, ~0x12, ~0)|RD_G0|RS1_G0|ASI(~0), "2", 0, v6 }, /* orcc %g0, rs2, %g0 */
-{ "tst", F3(2, 0x12, 1), F3(~2, ~0x12, ~1)|RD_G0|SIMM13(~0), "1", 0, v6 }, /* orcc rs1, 0, %g0 */
-
-{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", 0, v8 }, /* wr r,r,%asrX */
-{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", 0, v8 }, /* wr r,i,%asrX */
-{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */
-{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", 0, v6 }, /* wr r,r,%y */
-{ "wr", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", 0, v6 }, /* wr r,i,%y */
-{ "wr", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */
-{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", 0, v6notv9 }, /* wr r,r,%psr */
-{ "wr", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", 0, v6notv9 }, /* wr r,i,%psr */
-{ "wr", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */
-{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", 0, v6notv9 }, /* wr r,r,%wim */
-{ "wr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", 0, v6notv9 }, /* wr r,i,%wim */
-{ "wr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */
-{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", 0, v6notv9 }, /* wr r,r,%tbr */
-{ "wr", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", 0, v6notv9 }, /* wr r,i,%tbr */
-{ "wr", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */
-
-{ "wr", F3(2, 0x30, 0)|RD(2), F3(~2, ~0x30, ~0)|RD(~2)|ASI(~0), "1,2,E", 0, v9 }, /* wr r,r,%ccr */
-{ "wr", F3(2, 0x30, 1)|RD(2), F3(~2, ~0x30, ~1)|RD(~2), "1,i,E", 0, v9 }, /* wr r,i,%ccr */
-{ "wr", F3(2, 0x30, 0)|RD(3), F3(~2, ~0x30, ~0)|RD(~3)|ASI(~0), "1,2,o", 0, v9 }, /* wr r,r,%asi */
-{ "wr", F3(2, 0x30, 1)|RD(3), F3(~2, ~0x30, ~1)|RD(~3), "1,i,o", 0, v9 }, /* wr r,i,%asi */
-{ "wr", F3(2, 0x30, 0)|RD(6), F3(~2, ~0x30, ~0)|RD(~6)|ASI(~0), "1,2,s", 0, v9 }, /* wr r,r,%fprs */
-{ "wr", F3(2, 0x30, 1)|RD(6), F3(~2, ~0x30, ~1)|RD(~6), "1,i,s", 0, v9 }, /* wr r,i,%fprs */
-
-{ "wr", F3(2, 0x30, 0)|RD(16), F3(~2, ~0x30, ~0)|RD(~16)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pcr */
-{ "wr", F3(2, 0x30, 1)|RD(16), F3(~2, ~0x30, ~1)|RD(~16), "1,i,_", 0, v9a }, /* wr r,i,%pcr */
-{ "wr", F3(2, 0x30, 0)|RD(17), F3(~2, ~0x30, ~0)|RD(~17)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%pic */
-{ "wr", F3(2, 0x30, 1)|RD(17), F3(~2, ~0x30, ~1)|RD(~17), "1,i,_", 0, v9a }, /* wr r,i,%pic */
-{ "wr", F3(2, 0x30, 0)|RD(18), F3(~2, ~0x30, ~0)|RD(~18)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%dcr */
-{ "wr", F3(2, 0x30, 1)|RD(18), F3(~2, ~0x30, ~1)|RD(~18), "1,i,_", 0, v9a }, /* wr r,i,%dcr */
-{ "wr", F3(2, 0x30, 0)|RD(19), F3(~2, ~0x30, ~0)|RD(~19)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%gsr */
-{ "wr", F3(2, 0x30, 1)|RD(19), F3(~2, ~0x30, ~1)|RD(~19), "1,i,_", 0, v9a }, /* wr r,i,%gsr */
-{ "wr", F3(2, 0x30, 0)|RD(20), F3(~2, ~0x30, ~0)|RD(~20)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%set_softint */
-{ "wr", F3(2, 0x30, 1)|RD(20), F3(~2, ~0x30, ~1)|RD(~20), "1,i,_", 0, v9a }, /* wr r,i,%set_softint */
-{ "wr", F3(2, 0x30, 0)|RD(21), F3(~2, ~0x30, ~0)|RD(~21)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%clear_softint */
-{ "wr", F3(2, 0x30, 1)|RD(21), F3(~2, ~0x30, ~1)|RD(~21), "1,i,_", 0, v9a }, /* wr r,i,%clear_softint */
-{ "wr", F3(2, 0x30, 0)|RD(22), F3(~2, ~0x30, ~0)|RD(~22)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%softint */
-{ "wr", F3(2, 0x30, 1)|RD(22), F3(~2, ~0x30, ~1)|RD(~22), "1,i,_", 0, v9a }, /* wr r,i,%softint */
-{ "wr", F3(2, 0x30, 0)|RD(23), F3(~2, ~0x30, ~0)|RD(~23)|ASI(~0), "1,2,_", 0, v9a }, /* wr r,r,%tick_cmpr */
-{ "wr", F3(2, 0x30, 1)|RD(23), F3(~2, ~0x30, ~1)|RD(~23), "1,i,_", 0, v9a }, /* wr r,i,%tick_cmpr */
-{ "wr", F3(2, 0x30, 0)|RD(24), F3(~2, ~0x30, ~0)|RD(~24)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick */
-{ "wr", F3(2, 0x30, 1)|RD(24), F3(~2, ~0x30, ~1)|RD(~24), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick */
-{ "wr", F3(2, 0x30, 0)|RD(25), F3(~2, ~0x30, ~0)|RD(~25)|ASI(~0), "1,2,_", 0, v9b }, /* wr r,r,%sys_tick_cmpr */
-{ "wr", F3(2, 0x30, 1)|RD(25), F3(~2, ~0x30, ~1)|RD(~25), "1,i,_", 0, v9b }, /* wr r,i,%sys_tick_cmpr */
-
-{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", 0, v8 }, /* rd %asrX,r */
-{ "rd", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", 0, v6 }, /* rd %y,r */
-{ "rd", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", 0, v6notv9 }, /* rd %psr,r */
-{ "rd", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", 0, v6notv9 }, /* rd %wim,r */
-{ "rd", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", 0, v6notv9 }, /* rd %tbr,r */
-
-{ "rd", F3(2, 0x28, 0)|RS1(2), F3(~2, ~0x28, ~0)|RS1(~2)|SIMM13(~0), "E,d", 0, v9 }, /* rd %ccr,r */
-{ "rd", F3(2, 0x28, 0)|RS1(3), F3(~2, ~0x28, ~0)|RS1(~3)|SIMM13(~0), "o,d", 0, v9 }, /* rd %asi,r */
-{ "rd", F3(2, 0x28, 0)|RS1(4), F3(~2, ~0x28, ~0)|RS1(~4)|SIMM13(~0), "W,d", 0, v9 }, /* rd %tick,r */
-{ "rd", F3(2, 0x28, 0)|RS1(5), F3(~2, ~0x28, ~0)|RS1(~5)|SIMM13(~0), "P,d", 0, v9 }, /* rd %pc,r */
-{ "rd", F3(2, 0x28, 0)|RS1(6), F3(~2, ~0x28, ~0)|RS1(~6)|SIMM13(~0), "s,d", 0, v9 }, /* rd %fprs,r */
-
-{ "rd", F3(2, 0x28, 0)|RS1(16), F3(~2, ~0x28, ~0)|RS1(~16)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pcr,r */
-{ "rd", F3(2, 0x28, 0)|RS1(17), F3(~2, ~0x28, ~0)|RS1(~17)|SIMM13(~0), "/,d", 0, v9a }, /* rd %pic,r */
-{ "rd", F3(2, 0x28, 0)|RS1(18), F3(~2, ~0x28, ~0)|RS1(~18)|SIMM13(~0), "/,d", 0, v9a }, /* rd %dcr,r */
-{ "rd", F3(2, 0x28, 0)|RS1(19), F3(~2, ~0x28, ~0)|RS1(~19)|SIMM13(~0), "/,d", 0, v9a }, /* rd %gsr,r */
-{ "rd", F3(2, 0x28, 0)|RS1(22), F3(~2, ~0x28, ~0)|RS1(~22)|SIMM13(~0), "/,d", 0, v9a }, /* rd %softint,r */
-{ "rd", F3(2, 0x28, 0)|RS1(23), F3(~2, ~0x28, ~0)|RS1(~23)|SIMM13(~0), "/,d", 0, v9a }, /* rd %tick_cmpr,r */
-{ "rd", F3(2, 0x28, 0)|RS1(24), F3(~2, ~0x28, ~0)|RS1(~24)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick,r */
-{ "rd", F3(2, 0x28, 0)|RS1(25), F3(~2, ~0x28, ~0)|RS1(~25)|SIMM13(~0), "/,d", 0, v9b }, /* rd %sys_tick_cmpr,r */
-
-{ "rdpr", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|SIMM13(~0), "?,d", 0, v9 }, /* rdpr %priv,r */
-{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0), "1,2,!", 0, v9 }, /* wrpr r1,r2,%priv */
-{ "wrpr", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|SIMM13(~0), "1,!", 0, v9 }, /* wrpr r1,%priv */
-{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "1,i,!", 0, v9 }, /* wrpr r1,i,%priv */
-{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1), "i,1,!", F_ALIAS, v9 }, /* wrpr i,r1,%priv */
-{ "wrpr", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RS1(~0), "i,!", 0, v9 }, /* wrpr i,%priv */
-
-/* ??? This group seems wrong. A three operand move? */
-{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI(~0), "1,2,m", F_ALIAS, v8 }, /* wr r,r,%asrX */
-{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "1,i,m", F_ALIAS, v8 }, /* wr r,i,%asrX */
-{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI(~0), "1,2,y", F_ALIAS, v6 }, /* wr r,r,%y */
-{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "1,i,y", F_ALIAS, v6 }, /* wr r,i,%y */
-{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI(~0), "1,2,p", F_ALIAS, v6notv9 }, /* wr r,r,%psr */
-{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "1,i,p", F_ALIAS, v6notv9 }, /* wr r,i,%psr */
-{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI(~0), "1,2,w", F_ALIAS, v6notv9 }, /* wr r,r,%wim */
-{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "1,i,w", F_ALIAS, v6notv9 }, /* wr r,i,%wim */
-{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI(~0), "1,2,t", F_ALIAS, v6notv9 }, /* wr r,r,%tbr */
-{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "1,i,t", F_ALIAS, v6notv9 }, /* wr r,i,%tbr */
-
-{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|SIMM13(~0), "M,d", F_ALIAS, v8 }, /* rd %asr1,r */
-{ "mov", F3(2, 0x28, 0), F3(~2, ~0x28, ~0)|RS1_G0|SIMM13(~0), "y,d", F_ALIAS, v6 }, /* rd %y,r */
-{ "mov", F3(2, 0x29, 0), F3(~2, ~0x29, ~0)|RS1_G0|SIMM13(~0), "p,d", F_ALIAS, v6notv9 }, /* rd %psr,r */
-{ "mov", F3(2, 0x2a, 0), F3(~2, ~0x2a, ~0)|RS1_G0|SIMM13(~0), "w,d", F_ALIAS, v6notv9 }, /* rd %wim,r */
-{ "mov", F3(2, 0x2b, 0), F3(~2, ~0x2b, ~0)|RS1_G0|SIMM13(~0), "t,d", F_ALIAS, v6notv9 }, /* rd %tbr,r */
-
-{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|ASI_RS2(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,%g0,%asrX */
-{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1), "i,m", F_ALIAS, v8 }, /* wr %g0,i,%asrX */
-{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|SIMM13(~0), "1,m", F_ALIAS, v8 }, /* wr rs1,0,%asrX */
-{ "mov", F3(2, 0x30, 0), F3(~2, ~0x30, ~0)|RD_G0|ASI_RS2(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,%g0,%y */
-{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0, "i,y", F_ALIAS, v6 }, /* wr %g0,i,%y */
-{ "mov", F3(2, 0x30, 1), F3(~2, ~0x30, ~1)|RD_G0|SIMM13(~0), "1,y", F_ALIAS, v6 }, /* wr rs1,0,%y */
-{ "mov", F3(2, 0x31, 0), F3(~2, ~0x31, ~0)|RD_G0|ASI_RS2(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%psr */
-{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0, "i,p", F_ALIAS, v6notv9 }, /* wr %g0,i,%psr */
-{ "mov", F3(2, 0x31, 1), F3(~2, ~0x31, ~1)|RD_G0|SIMM13(~0), "1,p", F_ALIAS, v6notv9 }, /* wr rs1,0,%psr */
-{ "mov", F3(2, 0x32, 0), F3(~2, ~0x32, ~0)|RD_G0|ASI_RS2(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%wim */
-{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0, "i,w", F_ALIAS, v6notv9 }, /* wr %g0,i,%wim */
-{ "mov", F3(2, 0x32, 1), F3(~2, ~0x32, ~1)|RD_G0|SIMM13(~0), "1,w", F_ALIAS, v6notv9 }, /* wr rs1,0,%wim */
-{ "mov", F3(2, 0x33, 0), F3(~2, ~0x33, ~0)|RD_G0|ASI_RS2(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,%g0,%tbr */
-{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0, "i,t", F_ALIAS, v6notv9 }, /* wr %g0,i,%tbr */
-{ "mov", F3(2, 0x33, 1), F3(~2, ~0x33, ~1)|RD_G0|SIMM13(~0), "1,t", F_ALIAS, v6notv9 }, /* wr rs1,0,%tbr */
-
-{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|RS1_G0|ASI(~0), "2,d", 0, v6 }, /* or %g0,rs2,d */
-{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|RS1_G0, "i,d", 0, v6 }, /* or %g0,i,d */
-{ "mov", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI_RS2(~0), "1,d", 0, v6 }, /* or rs1,%g0,d */
-{ "mov", F3(2, 0x02, 1), F3(~2, ~0x02, ~1)|SIMM13(~0), "1,d", 0, v6 }, /* or rs1,0,d */
-
-{ "or", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "1,i,d", 0, v6 },
-{ "or", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,1,d", 0, v6 },
-
-{ "bset", F3(2, 0x02, 0), F3(~2, ~0x02, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* or rd,rs2,rd */
-{ "bset", F3(2, 0x02, 1), F3(~2, ~0x02, ~1), "i,r", F_ALIAS, v6 }, /* or rd,i,rd */
-
-/* This is not a commutative instruction. */
-{ "andn", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "andn", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "1,i,d", 0, v6 },
-
-/* This is not a commutative instruction. */
-{ "andncc", F3(2, 0x15, 0), F3(~2, ~0x15, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "andncc", F3(2, 0x15, 1), F3(~2, ~0x15, ~1), "1,i,d", 0, v6 },
-
-{ "bclr", F3(2, 0x05, 0), F3(~2, ~0x05, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* andn rd,rs2,rd */
-{ "bclr", F3(2, 0x05, 1), F3(~2, ~0x05, ~1), "i,r", F_ALIAS, v6 }, /* andn rd,i,rd */
-
-{ "cmp", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|RD_G0|ASI(~0), "1,2", 0, v6 }, /* subcc rs1,rs2,%g0 */
-{ "cmp", F3(2, 0x14, 1), F3(~2, ~0x14, ~1)|RD_G0, "1,i", 0, v6 }, /* subcc rs1,i,%g0 */
-
-{ "sub", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "sub", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "1,i,d", 0, v6 },
-
-{ "subcc", F3(2, 0x14, 0), F3(~2, ~0x14, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "subcc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "1,i,d", 0, v6 },
-
-{ "subx", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 },
-{ "subx", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v6notv9 },
-{ "subc", F3(2, 0x0c, 0), F3(~2, ~0x0c, ~0)|ASI(~0), "1,2,d", 0, v9 },
-{ "subc", F3(2, 0x0c, 1), F3(~2, ~0x0c, ~1), "1,i,d", 0, v9 },
-
-{ "subxcc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v6notv9 },
-{ "subxcc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v6notv9 },
-{ "subccc", F3(2, 0x1c, 0), F3(~2, ~0x1c, ~0)|ASI(~0), "1,2,d", 0, v9 },
-{ "subccc", F3(2, 0x1c, 1), F3(~2, ~0x1c, ~1), "1,i,d", 0, v9 },
-
-{ "and", F3(2, 0x01, 0), F3(~2, ~0x01, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "1,i,d", 0, v6 },
-{ "and", F3(2, 0x01, 1), F3(~2, ~0x01, ~1), "i,1,d", 0, v6 },
-
-{ "andcc", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "1,i,d", 0, v6 },
-{ "andcc", F3(2, 0x11, 1), F3(~2, ~0x11, ~1), "i,1,d", 0, v6 },
-
-{ "dec", F3(2, 0x04, 1)|SIMM13(0x1), F3(~2, ~0x04, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* sub rd,1,rd */
-{ "dec", F3(2, 0x04, 1), F3(~2, ~0x04, ~1), "i,r", F_ALIAS, v8 }, /* sub rd,imm,rd */
-{ "deccc", F3(2, 0x14, 1)|SIMM13(0x1), F3(~2, ~0x14, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* subcc rd,1,rd */
-{ "deccc", F3(2, 0x14, 1), F3(~2, ~0x14, ~1), "i,r", F_ALIAS, v8 }, /* subcc rd,imm,rd */
-{ "inc", F3(2, 0x00, 1)|SIMM13(0x1), F3(~2, ~0x00, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* add rd,1,rd */
-{ "inc", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,r", F_ALIAS, v8 }, /* add rd,imm,rd */
-{ "inccc", F3(2, 0x10, 1)|SIMM13(0x1), F3(~2, ~0x10, ~1)|SIMM13(~0x0001), "r", F_ALIAS, v6 }, /* addcc rd,1,rd */
-{ "inccc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,r", F_ALIAS, v8 }, /* addcc rd,imm,rd */
-
-{ "btst", F3(2, 0x11, 0), F3(~2, ~0x11, ~0)|RD_G0|ASI(~0), "1,2", F_ALIAS, v6 }, /* andcc rs1,rs2,%g0 */
-{ "btst", F3(2, 0x11, 1), F3(~2, ~0x11, ~1)|RD_G0, "i,1", F_ALIAS, v6 }, /* andcc rs1,i,%g0 */
-
-{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "2,d", F_ALIAS, v6 }, /* sub %g0,rs2,rd */
-{ "neg", F3(2, 0x04, 0), F3(~2, ~0x04, ~0)|RS1_G0|ASI(~0), "O", F_ALIAS, v6 }, /* sub %g0,rd,rd */
-
-{ "add", F3(2, 0x00, 0), F3(~2, ~0x00, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "1,i,d", 0, v6 },
-{ "add", F3(2, 0x00, 1), F3(~2, ~0x00, ~1), "i,1,d", 0, v6 },
-{ "addcc", F3(2, 0x10, 0), F3(~2, ~0x10, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "1,i,d", 0, v6 },
-{ "addcc", F3(2, 0x10, 1), F3(~2, ~0x10, ~1), "i,1,d", 0, v6 },
-
-{ "addx", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v6notv9 },
-{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v6notv9 },
-{ "addx", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v6notv9 },
-{ "addc", F3(2, 0x08, 0), F3(~2, ~0x08, ~0)|ASI(~0), "1,2,d", 0, v9 },
-{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "1,i,d", 0, v9 },
-{ "addc", F3(2, 0x08, 1), F3(~2, ~0x08, ~1), "i,1,d", 0, v9 },
-
-{ "addxcc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v6notv9 },
-{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v6notv9 },
-{ "addxcc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v6notv9 },
-{ "addccc", F3(2, 0x18, 0), F3(~2, ~0x18, ~0)|ASI(~0), "1,2,d", 0, v9 },
-{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "1,i,d", 0, v9 },
-{ "addccc", F3(2, 0x18, 1), F3(~2, ~0x18, ~1), "i,1,d", 0, v9 },
-
-{ "smul", F3(2, 0x0b, 0), F3(~2, ~0x0b, ~0)|ASI(~0), "1,2,d", 0, v8 },
-{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "1,i,d", 0, v8 },
-{ "smul", F3(2, 0x0b, 1), F3(~2, ~0x0b, ~1), "i,1,d", 0, v8 },
-{ "smulcc", F3(2, 0x1b, 0), F3(~2, ~0x1b, ~0)|ASI(~0), "1,2,d", 0, v8 },
-{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "1,i,d", 0, v8 },
-{ "smulcc", F3(2, 0x1b, 1), F3(~2, ~0x1b, ~1), "i,1,d", 0, v8 },
-{ "umul", F3(2, 0x0a, 0), F3(~2, ~0x0a, ~0)|ASI(~0), "1,2,d", 0, v8 },
-{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "1,i,d", 0, v8 },
-{ "umul", F3(2, 0x0a, 1), F3(~2, ~0x0a, ~1), "i,1,d", 0, v8 },
-{ "umulcc", F3(2, 0x1a, 0), F3(~2, ~0x1a, ~0)|ASI(~0), "1,2,d", 0, v8 },
-{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "1,i,d", 0, v8 },
-{ "umulcc", F3(2, 0x1a, 1), F3(~2, ~0x1a, ~1), "i,1,d", 0, v8 },
-{ "sdiv", F3(2, 0x0f, 0), F3(~2, ~0x0f, ~0)|ASI(~0), "1,2,d", 0, v8 },
-{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "1,i,d", 0, v8 },
-{ "sdiv", F3(2, 0x0f, 1), F3(~2, ~0x0f, ~1), "i,1,d", 0, v8 },
-{ "sdivcc", F3(2, 0x1f, 0), F3(~2, ~0x1f, ~0)|ASI(~0), "1,2,d", 0, v8 },
-{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "1,i,d", 0, v8 },
-{ "sdivcc", F3(2, 0x1f, 1), F3(~2, ~0x1f, ~1), "i,1,d", 0, v8 },
-{ "udiv", F3(2, 0x0e, 0), F3(~2, ~0x0e, ~0)|ASI(~0), "1,2,d", 0, v8 },
-{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "1,i,d", 0, v8 },
-{ "udiv", F3(2, 0x0e, 1), F3(~2, ~0x0e, ~1), "i,1,d", 0, v8 },
-{ "udivcc", F3(2, 0x1e, 0), F3(~2, ~0x1e, ~0)|ASI(~0), "1,2,d", 0, v8 },
-{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "1,i,d", 0, v8 },
-{ "udivcc", F3(2, 0x1e, 1), F3(~2, ~0x1e, ~1), "i,1,d", 0, v8 },
-
-{ "mulx", F3(2, 0x09, 0), F3(~2, ~0x09, ~0)|ASI(~0), "1,2,d", 0, v9 },
-{ "mulx", F3(2, 0x09, 1), F3(~2, ~0x09, ~1), "1,i,d", 0, v9 },
-{ "sdivx", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, v9 },
-{ "sdivx", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, v9 },
-{ "udivx", F3(2, 0x0d, 0), F3(~2, ~0x0d, ~0)|ASI(~0), "1,2,d", 0, v9 },
-{ "udivx", F3(2, 0x0d, 1), F3(~2, ~0x0d, ~1), "1,i,d", 0, v9 },
-
-{ "call", F1(0x1), F1(~0x1), "L", F_JSR|F_DELAYED, v6 },
-{ "call", F1(0x1), F1(~0x1), "L,#", F_JSR|F_DELAYED, v6 },
-
-{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%o7 */
-{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI(~0), "1+2,#", F_JSR|F_DELAYED, v6 },
-{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%o7 */
-{ "call", F3(2, 0x38, 0)|RD(0xf), F3(~2, ~0x38, ~0)|RD(~0xf)|ASI_RS2(~0), "1,#", F_JSR|F_DELAYED, v6 },
-{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+i,%o7 */
-{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "1+i,#", F_JSR|F_DELAYED, v6 },
-{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1", F_JSR|F_DELAYED, v6 }, /* jmpl i+rs1,%o7 */
-{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf), "i+1,#", F_JSR|F_DELAYED, v6 },
-{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i", F_JSR|F_DELAYED, v6 }, /* jmpl %g0+i,%o7 */
-{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|RS1_G0, "i,#", F_JSR|F_DELAYED, v6 },
-{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1", F_JSR|F_DELAYED, v6 }, /* jmpl rs1+0,%o7 */
-{ "call", F3(2, 0x38, 1)|RD(0xf), F3(~2, ~0x38, ~1)|RD(~0xf)|SIMM13(~0), "1,#", F_JSR|F_DELAYED, v6 },
-
-
-/* Conditional instructions.
-
- Because this part of the table was such a mess earlier, I have
- macrofied it so that all the branches and traps are generated from
- a single-line description of each condition value. John Gilmore. */
-
-/* Define branches -- one annulled, one without, etc. */
-#define br(opcode, mask, lose, flags) \
- { opcode, (mask)|ANNUL, (lose), ",a l", (flags), v6 }, \
- { opcode, (mask) , (lose)|ANNUL, "l", (flags), v6 }
-
-#define brx(opcode, mask, lose, flags) /* v9 */ \
- { opcode, (mask)|(2<<20)|BPRED, ANNUL|(lose), "Z,G", (flags), v9 }, \
- { opcode, (mask)|(2<<20)|BPRED, ANNUL|(lose), ",T Z,G", (flags), v9 }, \
- { opcode, (mask)|(2<<20)|BPRED|ANNUL, (lose), ",a Z,G", (flags), v9 }, \
- { opcode, (mask)|(2<<20)|BPRED|ANNUL, (lose), ",a,T Z,G", (flags), v9 }, \
- { opcode, (mask)|(2<<20), ANNUL|BPRED|(lose), ",N Z,G", (flags), v9 }, \
- { opcode, (mask)|(2<<20)|ANNUL, BPRED|(lose), ",a,N Z,G", (flags), v9 }, \
- { opcode, (mask)|BPRED, ANNUL|(lose)|(2<<20), "z,G", (flags), v9 }, \
- { opcode, (mask)|BPRED, ANNUL|(lose)|(2<<20), ",T z,G", (flags), v9 }, \
- { opcode, (mask)|BPRED|ANNUL, (lose)|(2<<20), ",a z,G", (flags), v9 }, \
- { opcode, (mask)|BPRED|ANNUL, (lose)|(2<<20), ",a,T z,G", (flags), v9 }, \
- { opcode, (mask), ANNUL|BPRED|(lose)|(2<<20), ",N z,G", (flags), v9 }, \
- { opcode, (mask)|ANNUL, BPRED|(lose)|(2<<20), ",a,N z,G", (flags), v9 }
-
-/* Define four traps: reg+reg, reg + immediate, immediate alone, reg alone. */
-#define tr(opcode, mask, lose, flags) \
- { opcode, (mask)|(2<<11)|IMMED, (lose)|RS1_G0, "Z,i", (flags), v9 }, /* %g0 + imm */ \
- { opcode, (mask)|(2<<11)|IMMED, (lose), "Z,1+i", (flags), v9 }, /* rs1 + imm */ \
- { opcode, (mask)|(2<<11), IMMED|(lose), "Z,1+2", (flags), v9 }, /* rs1 + rs2 */ \
- { opcode, (mask)|(2<<11), IMMED|(lose)|RS2_G0, "Z,1", (flags), v9 }, /* rs1 + %g0 */ \
- { opcode, (mask)|IMMED, (lose)|RS1_G0, "z,i", (flags)|F_ALIAS, v9 }, /* %g0 + imm */ \
- { opcode, (mask)|IMMED, (lose), "z,1+i", (flags)|F_ALIAS, v9 }, /* rs1 + imm */ \
- { opcode, (mask), IMMED|(lose), "z,1+2", (flags)|F_ALIAS, v9 }, /* rs1 + rs2 */ \
- { opcode, (mask), IMMED|(lose)|RS2_G0, "z,1", (flags)|F_ALIAS, v9 }, /* rs1 + %g0 */ \
- { opcode, (mask)|IMMED, (lose)|RS1_G0, "i", (flags), v6 }, /* %g0 + imm */ \
- { opcode, (mask)|IMMED, (lose), "1+i", (flags), v6 }, /* rs1 + imm */ \
- { opcode, (mask), IMMED|(lose), "1+2", (flags), v6 }, /* rs1 + rs2 */ \
- { opcode, (mask), IMMED|(lose)|RS2_G0, "1", (flags), v6 } /* rs1 + %g0 */
-
-/* v9: We must put `brx' before `br', to ensure that we never match something
- v9: against an expression unless it is an expression. Otherwise, we end
- v9: up with undefined symbol tables entries, because they get added, but
- v9: are not deleted if the pattern fails to match. */
-
-/* Define both branches and traps based on condition mask */
-#define cond(bop, top, mask, flags) \
- brx(bop, F2(0, 1)|(mask), F2(~0, ~1)|((~mask)&COND(~0)), F_DELAYED|(flags)), /* v9 */ \
- br(bop, F2(0, 2)|(mask), F2(~0, ~2)|((~mask)&COND(~0)), F_DELAYED|(flags)), \
- tr(top, F3(2, 0x3a, 0)|(mask), F3(~2, ~0x3a, 0)|((~mask)&COND(~0)), ((flags) & ~(F_UNBR|F_CONDBR)))
-
-/* Define all the conditions, all the branches, all the traps. */
-
-/* Standard branch, trap mnemonics */
-cond ("b", "ta", CONDA, F_UNBR),
-/* Alternative form (just for assembly, not for disassembly) */
-cond ("ba", "t", CONDA, F_UNBR|F_ALIAS),
-
-cond ("bcc", "tcc", CONDCC, F_CONDBR),
-cond ("bcs", "tcs", CONDCS, F_CONDBR),
-cond ("be", "te", CONDE, F_CONDBR),
-cond ("beq", "teq", CONDE, F_CONDBR|F_ALIAS),
-cond ("bg", "tg", CONDG, F_CONDBR),
-cond ("bgt", "tgt", CONDG, F_CONDBR|F_ALIAS),
-cond ("bge", "tge", CONDGE, F_CONDBR),
-cond ("bgeu", "tgeu", CONDGEU, F_CONDBR|F_ALIAS), /* for cc */
-cond ("bgu", "tgu", CONDGU, F_CONDBR),
-cond ("bl", "tl", CONDL, F_CONDBR),
-cond ("blt", "tlt", CONDL, F_CONDBR|F_ALIAS),
-cond ("ble", "tle", CONDLE, F_CONDBR),
-cond ("bleu", "tleu", CONDLEU, F_CONDBR),
-cond ("blu", "tlu", CONDLU, F_CONDBR|F_ALIAS), /* for cs */
-cond ("bn", "tn", CONDN, F_CONDBR),
-cond ("bne", "tne", CONDNE, F_CONDBR),
-cond ("bneg", "tneg", CONDNEG, F_CONDBR),
-cond ("bnz", "tnz", CONDNZ, F_CONDBR|F_ALIAS), /* for ne */
-cond ("bpos", "tpos", CONDPOS, F_CONDBR),
-cond ("bvc", "tvc", CONDVC, F_CONDBR),
-cond ("bvs", "tvs", CONDVS, F_CONDBR),
-cond ("bz", "tz", CONDZ, F_CONDBR|F_ALIAS), /* for e */
-
-#undef cond
-#undef br
-#undef brr /* v9 */
-#undef tr
-
-#define brr(opcode, mask, lose, flags) /* v9 */ \
- { opcode, (mask)|BPRED, ANNUL|(lose), "1,k", F_DELAYED|(flags), v9 }, \
- { opcode, (mask)|BPRED, ANNUL|(lose), ",T 1,k", F_DELAYED|(flags), v9 }, \
- { opcode, (mask)|BPRED|ANNUL, (lose), ",a 1,k", F_DELAYED|(flags), v9 }, \
- { opcode, (mask)|BPRED|ANNUL, (lose), ",a,T 1,k", F_DELAYED|(flags), v9 }, \
- { opcode, (mask), ANNUL|BPRED|(lose), ",N 1,k", F_DELAYED|(flags), v9 }, \
- { opcode, (mask)|ANNUL, BPRED|(lose), ",a,N 1,k", F_DELAYED|(flags), v9 }
-
-#define condr(bop, mask, flags) /* v9 */ \
- brr(bop, F2(0, 3)|COND(mask), F2(~0, ~3)|COND(~(mask)), (flags)) /* v9 */
-
-/* v9 */ condr("brnz", 0x5, F_CONDBR),
-/* v9 */ condr("brz", 0x1, F_CONDBR),
-/* v9 */ condr("brgez", 0x7, F_CONDBR),
-/* v9 */ condr("brlz", 0x3, F_CONDBR),
-/* v9 */ condr("brlez", 0x2, F_CONDBR),
-/* v9 */ condr("brgz", 0x6, F_CONDBR),
-
-#undef condr /* v9 */
-#undef brr /* v9 */
-
-#define movr(opcode, mask, flags) /* v9 */ \
- { opcode, F3(2, 0x2f, 0)|RCOND(mask), F3(~2, ~0x2f, ~0)|RCOND(~(mask)), "1,2,d", (flags), v9 }, \
- { opcode, F3(2, 0x2f, 1)|RCOND(mask), F3(~2, ~0x2f, ~1)|RCOND(~(mask)), "1,j,d", (flags), v9 }
-
-#define fmrrs(opcode, mask, lose, flags) /* v9 */ \
- { opcode, (mask), (lose), "1,f,g", (flags) | F_FLOAT, v9 }
-#define fmrrd(opcode, mask, lose, flags) /* v9 */ \
- { opcode, (mask), (lose), "1,B,H", (flags) | F_FLOAT, v9 }
-#define fmrrq(opcode, mask, lose, flags) /* v9 */ \
- { opcode, (mask), (lose), "1,R,J", (flags) | F_FLOAT, v9 }
-
-#define fmovrs(mop, mask, flags) /* v9 */ \
- fmrrs(mop, F3(2, 0x35, 0)|OPF_LOW5(5)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~5)|RCOND(~(mask)), (flags)) /* v9 */
-#define fmovrd(mop, mask, flags) /* v9 */ \
- fmrrd(mop, F3(2, 0x35, 0)|OPF_LOW5(6)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~6)|RCOND(~(mask)), (flags)) /* v9 */
-#define fmovrq(mop, mask, flags) /* v9 */ \
- fmrrq(mop, F3(2, 0x35, 0)|OPF_LOW5(7)|RCOND(mask), F3(~2, ~0x35, 0)|OPF_LOW5(~7)|RCOND(~(mask)), (flags)) /* v9 */
-
-/* v9 */ movr("movrne", 0x5, 0),
-/* v9 */ movr("movre", 0x1, 0),
-/* v9 */ movr("movrgez", 0x7, 0),
-/* v9 */ movr("movrlz", 0x3, 0),
-/* v9 */ movr("movrlez", 0x2, 0),
-/* v9 */ movr("movrgz", 0x6, 0),
-/* v9 */ movr("movrnz", 0x5, F_ALIAS),
-/* v9 */ movr("movrz", 0x1, F_ALIAS),
-
-/* v9 */ fmovrs("fmovrsne", 0x5, 0),
-/* v9 */ fmovrs("fmovrse", 0x1, 0),
-/* v9 */ fmovrs("fmovrsgez", 0x7, 0),
-/* v9 */ fmovrs("fmovrslz", 0x3, 0),
-/* v9 */ fmovrs("fmovrslez", 0x2, 0),
-/* v9 */ fmovrs("fmovrsgz", 0x6, 0),
-/* v9 */ fmovrs("fmovrsnz", 0x5, F_ALIAS),
-/* v9 */ fmovrs("fmovrsz", 0x1, F_ALIAS),
-
-/* v9 */ fmovrd("fmovrdne", 0x5, 0),
-/* v9 */ fmovrd("fmovrde", 0x1, 0),
-/* v9 */ fmovrd("fmovrdgez", 0x7, 0),
-/* v9 */ fmovrd("fmovrdlz", 0x3, 0),
-/* v9 */ fmovrd("fmovrdlez", 0x2, 0),
-/* v9 */ fmovrd("fmovrdgz", 0x6, 0),
-/* v9 */ fmovrd("fmovrdnz", 0x5, F_ALIAS),
-/* v9 */ fmovrd("fmovrdz", 0x1, F_ALIAS),
-
-/* v9 */ fmovrq("fmovrqne", 0x5, 0),
-/* v9 */ fmovrq("fmovrqe", 0x1, 0),
-/* v9 */ fmovrq("fmovrqgez", 0x7, 0),
-/* v9 */ fmovrq("fmovrqlz", 0x3, 0),
-/* v9 */ fmovrq("fmovrqlez", 0x2, 0),
-/* v9 */ fmovrq("fmovrqgz", 0x6, 0),
-/* v9 */ fmovrq("fmovrqnz", 0x5, F_ALIAS),
-/* v9 */ fmovrq("fmovrqz", 0x1, F_ALIAS),
-
-#undef movr /* v9 */
-#undef fmovr /* v9 */
-#undef fmrr /* v9 */
-
-#define movicc(opcode, cond, flags) /* v9 */ \
- { opcode, F3(2, 0x2c, 0)|MCOND(cond,1)|ICC, F3(~2, ~0x2c, ~0)|MCOND(~cond,~1)|XCC|(1<<11), "z,2,d", flags, v9 }, \
- { opcode, F3(2, 0x2c, 1)|MCOND(cond,1)|ICC, F3(~2, ~0x2c, ~1)|MCOND(~cond,~1)|XCC|(1<<11), "z,I,d", flags, v9 }, \
- { opcode, F3(2, 0x2c, 0)|MCOND(cond,1)|XCC, F3(~2, ~0x2c, ~0)|MCOND(~cond,~1)|(1<<11), "Z,2,d", flags, v9 }, \
- { opcode, F3(2, 0x2c, 1)|MCOND(cond,1)|XCC, F3(~2, ~0x2c, ~1)|MCOND(~cond,~1)|(1<<11), "Z,I,d", flags, v9 }
-
-#define movfcc(opcode, fcond, flags) /* v9 */ \
- { opcode, F3(2, 0x2c, 0)|FCC(0)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~0)|F3(~2, ~0x2c, ~0), "6,2,d", flags, v9 }, \
- { opcode, F3(2, 0x2c, 1)|FCC(0)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~0)|F3(~2, ~0x2c, ~1), "6,I,d", flags, v9 }, \
- { opcode, F3(2, 0x2c, 0)|FCC(1)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~1)|F3(~2, ~0x2c, ~0), "7,2,d", flags, v9 }, \
- { opcode, F3(2, 0x2c, 1)|FCC(1)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~1)|F3(~2, ~0x2c, ~1), "7,I,d", flags, v9 }, \
- { opcode, F3(2, 0x2c, 0)|FCC(2)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~2)|F3(~2, ~0x2c, ~0), "8,2,d", flags, v9 }, \
- { opcode, F3(2, 0x2c, 1)|FCC(2)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~2)|F3(~2, ~0x2c, ~1), "8,I,d", flags, v9 }, \
- { opcode, F3(2, 0x2c, 0)|FCC(3)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~3)|F3(~2, ~0x2c, ~0), "9,2,d", flags, v9 }, \
- { opcode, F3(2, 0x2c, 1)|FCC(3)|MCOND(fcond,0), MCOND(~fcond,~0)|FCC(~3)|F3(~2, ~0x2c, ~1), "9,I,d", flags, v9 }
-
-#define movcc(opcode, cond, fcond, flags) /* v9 */ \
- movfcc (opcode, fcond, flags), /* v9 */ \
- movicc (opcode, cond, flags) /* v9 */
-
-/* v9 */ movcc ("mova", CONDA, FCONDA, 0),
-/* v9 */ movicc ("movcc", CONDCC, 0),
-/* v9 */ movicc ("movgeu", CONDGEU, F_ALIAS),
-/* v9 */ movicc ("movcs", CONDCS, 0),
-/* v9 */ movicc ("movlu", CONDLU, F_ALIAS),
-/* v9 */ movcc ("move", CONDE, FCONDE, 0),
-/* v9 */ movcc ("movg", CONDG, FCONDG, 0),
-/* v9 */ movcc ("movge", CONDGE, FCONDGE, 0),
-/* v9 */ movicc ("movgu", CONDGU, 0),
-/* v9 */ movcc ("movl", CONDL, FCONDL, 0),
-/* v9 */ movcc ("movle", CONDLE, FCONDLE, 0),
-/* v9 */ movicc ("movleu", CONDLEU, 0),
-/* v9 */ movfcc ("movlg", FCONDLG, 0),
-/* v9 */ movcc ("movn", CONDN, FCONDN, 0),
-/* v9 */ movcc ("movne", CONDNE, FCONDNE, 0),
-/* v9 */ movicc ("movneg", CONDNEG, 0),
-/* v9 */ movcc ("movnz", CONDNZ, FCONDNZ, F_ALIAS),
-/* v9 */ movfcc ("movo", FCONDO, 0),
-/* v9 */ movicc ("movpos", CONDPOS, 0),
-/* v9 */ movfcc ("movu", FCONDU, 0),
-/* v9 */ movfcc ("movue", FCONDUE, 0),
-/* v9 */ movfcc ("movug", FCONDUG, 0),
-/* v9 */ movfcc ("movuge", FCONDUGE, 0),
-/* v9 */ movfcc ("movul", FCONDUL, 0),
-/* v9 */ movfcc ("movule", FCONDULE, 0),
-/* v9 */ movicc ("movvc", CONDVC, 0),
-/* v9 */ movicc ("movvs", CONDVS, 0),
-/* v9 */ movcc ("movz", CONDZ, FCONDZ, F_ALIAS),
-
-#undef movicc /* v9 */
-#undef movfcc /* v9 */
-#undef movcc /* v9 */
-
-#define FM_SF 1 /* v9 - values for fpsize */
-#define FM_DF 2 /* v9 */
-#define FM_QF 3 /* v9 */
-
-#define fmovicc(opcode, fpsize, cond, flags) /* v9 */ \
-{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z,f,g", flags, v9 }, \
-{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z,f,g", flags, v9 }
-
-#define fmovfcc(opcode, fpsize, fcond, flags) /* v9 */ \
-{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6,f,g", flags, v9 }, \
-{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7,f,g", flags, v9 }, \
-{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8,f,g", flags, v9 }, \
-{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9,f,g", flags, v9 }
-
-/* FIXME: use fmovicc/fmovfcc? */ /* v9 */
-#define fmovcc(opcode, fpsize, cond, fcond, flags) /* v9 */ \
-{ opcode, F3F(2, 0x35, 0x100+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x100+fpsize))|MCOND(~cond,~0), "z,f,g", flags | F_FLOAT, v9 }, \
-{ opcode, F3F(2, 0x35, 0x000+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x000+fpsize))|MCOND(~fcond,~0), "6,f,g", flags | F_FLOAT, v9 }, \
-{ opcode, F3F(2, 0x35, 0x180+fpsize)|MCOND(cond,0), F3F(~2, ~0x35, ~(0x180+fpsize))|MCOND(~cond,~0), "Z,f,g", flags | F_FLOAT, v9 }, \
-{ opcode, F3F(2, 0x35, 0x040+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x040+fpsize))|MCOND(~fcond,~0), "7,f,g", flags | F_FLOAT, v9 }, \
-{ opcode, F3F(2, 0x35, 0x080+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x080+fpsize))|MCOND(~fcond,~0), "8,f,g", flags | F_FLOAT, v9 }, \
-{ opcode, F3F(2, 0x35, 0x0c0+fpsize)|MCOND(fcond,0), F3F(~2, ~0x35, ~(0x0c0+fpsize))|MCOND(~fcond,~0), "9,f,g", flags | F_FLOAT, v9 }
-
-/* v9 */ fmovcc ("fmovda", FM_DF, CONDA, FCONDA, 0),
-/* v9 */ fmovcc ("fmovqa", FM_QF, CONDA, FCONDA, 0),
-/* v9 */ fmovcc ("fmovsa", FM_SF, CONDA, FCONDA, 0),
-/* v9 */ fmovicc ("fmovdcc", FM_DF, CONDCC, 0),
-/* v9 */ fmovicc ("fmovqcc", FM_QF, CONDCC, 0),
-/* v9 */ fmovicc ("fmovscc", FM_SF, CONDCC, 0),
-/* v9 */ fmovicc ("fmovdcs", FM_DF, CONDCS, 0),
-/* v9 */ fmovicc ("fmovqcs", FM_QF, CONDCS, 0),
-/* v9 */ fmovicc ("fmovscs", FM_SF, CONDCS, 0),
-/* v9 */ fmovcc ("fmovde", FM_DF, CONDE, FCONDE, 0),
-/* v9 */ fmovcc ("fmovqe", FM_QF, CONDE, FCONDE, 0),
-/* v9 */ fmovcc ("fmovse", FM_SF, CONDE, FCONDE, 0),
-/* v9 */ fmovcc ("fmovdg", FM_DF, CONDG, FCONDG, 0),
-/* v9 */ fmovcc ("fmovqg", FM_QF, CONDG, FCONDG, 0),
-/* v9 */ fmovcc ("fmovsg", FM_SF, CONDG, FCONDG, 0),
-/* v9 */ fmovcc ("fmovdge", FM_DF, CONDGE, FCONDGE, 0),
-/* v9 */ fmovcc ("fmovqge", FM_QF, CONDGE, FCONDGE, 0),
-/* v9 */ fmovcc ("fmovsge", FM_SF, CONDGE, FCONDGE, 0),
-/* v9 */ fmovicc ("fmovdgeu", FM_DF, CONDGEU, F_ALIAS),
-/* v9 */ fmovicc ("fmovqgeu", FM_QF, CONDGEU, F_ALIAS),
-/* v9 */ fmovicc ("fmovsgeu", FM_SF, CONDGEU, F_ALIAS),
-/* v9 */ fmovicc ("fmovdgu", FM_DF, CONDGU, 0),
-/* v9 */ fmovicc ("fmovqgu", FM_QF, CONDGU, 0),
-/* v9 */ fmovicc ("fmovsgu", FM_SF, CONDGU, 0),
-/* v9 */ fmovcc ("fmovdl", FM_DF, CONDL, FCONDL, 0),
-/* v9 */ fmovcc ("fmovql", FM_QF, CONDL, FCONDL, 0),
-/* v9 */ fmovcc ("fmovsl", FM_SF, CONDL, FCONDL, 0),
-/* v9 */ fmovcc ("fmovdle", FM_DF, CONDLE, FCONDLE, 0),
-/* v9 */ fmovcc ("fmovqle", FM_QF, CONDLE, FCONDLE, 0),
-/* v9 */ fmovcc ("fmovsle", FM_SF, CONDLE, FCONDLE, 0),
-/* v9 */ fmovicc ("fmovdleu", FM_DF, CONDLEU, 0),
-/* v9 */ fmovicc ("fmovqleu", FM_QF, CONDLEU, 0),
-/* v9 */ fmovicc ("fmovsleu", FM_SF, CONDLEU, 0),
-/* v9 */ fmovfcc ("fmovdlg", FM_DF, FCONDLG, 0),
-/* v9 */ fmovfcc ("fmovqlg", FM_QF, FCONDLG, 0),
-/* v9 */ fmovfcc ("fmovslg", FM_SF, FCONDLG, 0),
-/* v9 */ fmovicc ("fmovdlu", FM_DF, CONDLU, F_ALIAS),
-/* v9 */ fmovicc ("fmovqlu", FM_QF, CONDLU, F_ALIAS),
-/* v9 */ fmovicc ("fmovslu", FM_SF, CONDLU, F_ALIAS),
-/* v9 */ fmovcc ("fmovdn", FM_DF, CONDN, FCONDN, 0),
-/* v9 */ fmovcc ("fmovqn", FM_QF, CONDN, FCONDN, 0),
-/* v9 */ fmovcc ("fmovsn", FM_SF, CONDN, FCONDN, 0),
-/* v9 */ fmovcc ("fmovdne", FM_DF, CONDNE, FCONDNE, 0),
-/* v9 */ fmovcc ("fmovqne", FM_QF, CONDNE, FCONDNE, 0),
-/* v9 */ fmovcc ("fmovsne", FM_SF, CONDNE, FCONDNE, 0),
-/* v9 */ fmovicc ("fmovdneg", FM_DF, CONDNEG, 0),
-/* v9 */ fmovicc ("fmovqneg", FM_QF, CONDNEG, 0),
-/* v9 */ fmovicc ("fmovsneg", FM_SF, CONDNEG, 0),
-/* v9 */ fmovcc ("fmovdnz", FM_DF, CONDNZ, FCONDNZ, F_ALIAS),
-/* v9 */ fmovcc ("fmovqnz", FM_QF, CONDNZ, FCONDNZ, F_ALIAS),
-/* v9 */ fmovcc ("fmovsnz", FM_SF, CONDNZ, FCONDNZ, F_ALIAS),
-/* v9 */ fmovfcc ("fmovdo", FM_DF, FCONDO, 0),
-/* v9 */ fmovfcc ("fmovqo", FM_QF, FCONDO, 0),
-/* v9 */ fmovfcc ("fmovso", FM_SF, FCONDO, 0),
-/* v9 */ fmovicc ("fmovdpos", FM_DF, CONDPOS, 0),
-/* v9 */ fmovicc ("fmovqpos", FM_QF, CONDPOS, 0),
-/* v9 */ fmovicc ("fmovspos", FM_SF, CONDPOS, 0),
-/* v9 */ fmovfcc ("fmovdu", FM_DF, FCONDU, 0),
-/* v9 */ fmovfcc ("fmovqu", FM_QF, FCONDU, 0),
-/* v9 */ fmovfcc ("fmovsu", FM_SF, FCONDU, 0),
-/* v9 */ fmovfcc ("fmovdue", FM_DF, FCONDUE, 0),
-/* v9 */ fmovfcc ("fmovque", FM_QF, FCONDUE, 0),
-/* v9 */ fmovfcc ("fmovsue", FM_SF, FCONDUE, 0),
-/* v9 */ fmovfcc ("fmovdug", FM_DF, FCONDUG, 0),
-/* v9 */ fmovfcc ("fmovqug", FM_QF, FCONDUG, 0),
-/* v9 */ fmovfcc ("fmovsug", FM_SF, FCONDUG, 0),
-/* v9 */ fmovfcc ("fmovduge", FM_DF, FCONDUGE, 0),
-/* v9 */ fmovfcc ("fmovquge", FM_QF, FCONDUGE, 0),
-/* v9 */ fmovfcc ("fmovsuge", FM_SF, FCONDUGE, 0),
-/* v9 */ fmovfcc ("fmovdul", FM_DF, FCONDUL, 0),
-/* v9 */ fmovfcc ("fmovqul", FM_QF, FCONDUL, 0),
-/* v9 */ fmovfcc ("fmovsul", FM_SF, FCONDUL, 0),
-/* v9 */ fmovfcc ("fmovdule", FM_DF, FCONDULE, 0),
-/* v9 */ fmovfcc ("fmovqule", FM_QF, FCONDULE, 0),
-/* v9 */ fmovfcc ("fmovsule", FM_SF, FCONDULE, 0),
-/* v9 */ fmovicc ("fmovdvc", FM_DF, CONDVC, 0),
-/* v9 */ fmovicc ("fmovqvc", FM_QF, CONDVC, 0),
-/* v9 */ fmovicc ("fmovsvc", FM_SF, CONDVC, 0),
-/* v9 */ fmovicc ("fmovdvs", FM_DF, CONDVS, 0),
-/* v9 */ fmovicc ("fmovqvs", FM_QF, CONDVS, 0),
-/* v9 */ fmovicc ("fmovsvs", FM_SF, CONDVS, 0),
-/* v9 */ fmovcc ("fmovdz", FM_DF, CONDZ, FCONDZ, F_ALIAS),
-/* v9 */ fmovcc ("fmovqz", FM_QF, CONDZ, FCONDZ, F_ALIAS),
-/* v9 */ fmovcc ("fmovsz", FM_SF, CONDZ, FCONDZ, F_ALIAS),
-
-#undef fmovicc /* v9 */
-#undef fmovfcc /* v9 */
-#undef fmovcc /* v9 */
-#undef FM_DF /* v9 */
-#undef FM_QF /* v9 */
-#undef FM_SF /* v9 */
-
-/* Coprocessor branches. */
-#define CBR(opcode, mask, lose, flags, arch) \
- { opcode, (mask), ANNUL|(lose), "l", flags|F_DELAYED, arch }, \
- { opcode, (mask)|ANNUL, (lose), ",a l", flags|F_DELAYED, arch }
-
-/* Floating point branches. */
-#define FBR(opcode, mask, lose, flags) \
- { opcode, (mask), ANNUL|(lose), "l", flags|F_DELAYED|F_FBR, v6 }, \
- { opcode, (mask)|ANNUL, (lose), ",a l", flags|F_DELAYED|F_FBR, v6 }
-
-/* V9 extended floating point branches. */
-#define FBRX(opcode, mask, lose, flags) /* v9 */ \
- { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), "6,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(0)|(mask)|BPRED, ANNUL|FBFCC(~0)|(lose), ",T 6,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a 6,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(0)|(mask)|BPRED|ANNUL, FBFCC(~0)|(lose), ",a,T 6,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(0)|(mask), ANNUL|BPRED|FBFCC(~0)|(lose), ",N 6,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(0)|(mask)|ANNUL, BPRED|FBFCC(~0)|(lose), ",a,N 6,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(1)|(mask)|BPRED, ANNUL|FBFCC(~1)|(lose), "7,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(1)|(mask)|BPRED, ANNUL|FBFCC(~1)|(lose), ",T 7,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(1)|(mask)|BPRED|ANNUL, FBFCC(~1)|(lose), ",a 7,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(1)|(mask)|BPRED|ANNUL, FBFCC(~1)|(lose), ",a,T 7,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(1)|(mask), ANNUL|BPRED|FBFCC(~1)|(lose), ",N 7,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(1)|(mask)|ANNUL, BPRED|FBFCC(~1)|(lose), ",a,N 7,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(2)|(mask)|BPRED, ANNUL|FBFCC(~2)|(lose), "8,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(2)|(mask)|BPRED, ANNUL|FBFCC(~2)|(lose), ",T 8,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(2)|(mask)|BPRED|ANNUL, FBFCC(~2)|(lose), ",a 8,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(2)|(mask)|BPRED|ANNUL, FBFCC(~2)|(lose), ",a,T 8,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(2)|(mask), ANNUL|BPRED|FBFCC(~2)|(lose), ",N 8,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(2)|(mask)|ANNUL, BPRED|FBFCC(~2)|(lose), ",a,N 8,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(3)|(mask)|BPRED, ANNUL|FBFCC(~3)|(lose), "9,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(3)|(mask)|BPRED, ANNUL|FBFCC(~3)|(lose), ",T 9,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a 9,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(3)|(mask)|BPRED|ANNUL, FBFCC(~3)|(lose), ",a,T 9,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(3)|(mask), ANNUL|BPRED|FBFCC(~3)|(lose), ",N 9,G", flags|F_DELAYED|F_FBR, v9 }, \
- { opcode, FBFCC(3)|(mask)|ANNUL, BPRED|FBFCC(~3)|(lose), ",a,N 9,G", flags|F_DELAYED|F_FBR, v9 }
-
-/* v9: We must put `FBRX' before `FBR', to ensure that we never match
- v9: something against an expression unless it is an expression. Otherwise,
- v9: we end up with undefined symbol tables entries, because they get added,
- v9: but are not deleted if the pattern fails to match. */
-
-#define CONDFC(fop, cop, mask, flags) \
- FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \
- FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \
- CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6notlet)
-
-#define CONDFCL(fop, cop, mask, flags) \
- FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \
- FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags), \
- CBR(cop, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)), flags, v6)
-
-#define CONDF(fop, mask, flags) \
- FBRX(fop, F2(0, 5)|COND(mask), F2(~0, ~5)|COND(~(mask)), flags), /* v9 */ \
- FBR(fop, F2(0, 6)|COND(mask), F2(~0, ~6)|COND(~(mask)), flags)
-
-CONDFC ("fb", "cb", 0x8, F_UNBR),
-CONDFCL ("fba", "cba", 0x8, F_UNBR|F_ALIAS),
-CONDFC ("fbe", "cb0", 0x9, F_CONDBR),
-CONDF ("fbz", 0x9, F_CONDBR|F_ALIAS),
-CONDFC ("fbg", "cb2", 0x6, F_CONDBR),
-CONDFC ("fbge", "cb02", 0xb, F_CONDBR),
-CONDFC ("fbl", "cb1", 0x4, F_CONDBR),
-CONDFC ("fble", "cb01", 0xd, F_CONDBR),
-CONDFC ("fblg", "cb12", 0x2, F_CONDBR),
-CONDFCL ("fbn", "cbn", 0x0, F_UNBR),
-CONDFC ("fbne", "cb123", 0x1, F_CONDBR),
-CONDF ("fbnz", 0x1, F_CONDBR|F_ALIAS),
-CONDFC ("fbo", "cb012", 0xf, F_CONDBR),
-CONDFC ("fbu", "cb3", 0x7, F_CONDBR),
-CONDFC ("fbue", "cb03", 0xa, F_CONDBR),
-CONDFC ("fbug", "cb23", 0x5, F_CONDBR),
-CONDFC ("fbuge", "cb023", 0xc, F_CONDBR),
-CONDFC ("fbul", "cb13", 0x3, F_CONDBR),
-CONDFC ("fbule", "cb013", 0xe, F_CONDBR),
-
-#undef CONDFC
-#undef CONDFCL
-#undef CONDF
-#undef CBR
-#undef FBR
-#undef FBRX /* v9 */
-
-{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI(~0), "1+2", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+rs2,%g0 */
-{ "jmp", F3(2, 0x38, 0), F3(~2, ~0x38, ~0)|RD_G0|ASI_RS2(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+%g0,%g0 */
-{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "1+i", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+i,%g0 */
-{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0, "i+1", F_UNBR|F_DELAYED, v6 }, /* jmpl i+rs1,%g0 */
-{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|RS1_G0, "i", F_UNBR|F_DELAYED, v6 }, /* jmpl %g0+i,%g0 */
-{ "jmp", F3(2, 0x38, 1), F3(~2, ~0x38, ~1)|RD_G0|SIMM13(~0), "1", F_UNBR|F_DELAYED, v6 }, /* jmpl rs1+0,%g0 */
-
-{ "nop", F2(0, 4), 0xfeffffff, "", 0, v6 }, /* sethi 0, %g0 */
-
-{ "set", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v6 },
-{ "setuw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 },
-{ "setsw", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,d", F_ALIAS, v9 },
-{ "setx", F2(0x0, 0x4), F2(~0x0, ~0x4), "S0,1,d", F_ALIAS, v9 },
-
-{ "sethi", F2(0x0, 0x4), F2(~0x0, ~0x4), "h,d", 0, v6 },
-
-{ "taddcc", F3(2, 0x20, 0), F3(~2, ~0x20, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "1,i,d", 0, v6 },
-{ "taddcc", F3(2, 0x20, 1), F3(~2, ~0x20, ~1), "i,1,d", 0, v6 },
-{ "taddcctv", F3(2, 0x22, 0), F3(~2, ~0x22, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "1,i,d", 0, v6 },
-{ "taddcctv", F3(2, 0x22, 1), F3(~2, ~0x22, ~1), "i,1,d", 0, v6 },
-
-{ "tsubcc", F3(2, 0x21, 0), F3(~2, ~0x21, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "tsubcc", F3(2, 0x21, 1), F3(~2, ~0x21, ~1), "1,i,d", 0, v6 },
-{ "tsubcctv", F3(2, 0x23, 0), F3(~2, ~0x23, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "tsubcctv", F3(2, 0x23, 1), F3(~2, ~0x23, ~1), "1,i,d", 0, v6 },
-
-{ "unimp", F2(0x0, 0x0), 0xffc00000, "n", 0, v6notv9 },
-{ "illtrap", F2(0, 0), F2(~0, ~0)|RD_G0, "n", 0, v9 },
-
-/* This *is* a commutative instruction. */
-{ "xnor", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "1,i,d", 0, v6 },
-{ "xnor", F3(2, 0x07, 1), F3(~2, ~0x07, ~1), "i,1,d", 0, v6 },
-/* This *is* a commutative instruction. */
-{ "xnorcc", F3(2, 0x17, 0), F3(~2, ~0x17, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "1,i,d", 0, v6 },
-{ "xnorcc", F3(2, 0x17, 1), F3(~2, ~0x17, ~1), "i,1,d", 0, v6 },
-{ "xor", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "1,i,d", 0, v6 },
-{ "xor", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,1,d", 0, v6 },
-{ "xorcc", F3(2, 0x13, 0), F3(~2, ~0x13, ~0)|ASI(~0), "1,2,d", 0, v6 },
-{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "1,i,d", 0, v6 },
-{ "xorcc", F3(2, 0x13, 1), F3(~2, ~0x13, ~1), "i,1,d", 0, v6 },
-
-{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "1,d", F_ALIAS, v6 }, /* xnor rs1,%0,rd */
-{ "not", F3(2, 0x07, 0), F3(~2, ~0x07, ~0)|ASI(~0), "r", F_ALIAS, v6 }, /* xnor rd,%0,rd */
-
-{ "btog", F3(2, 0x03, 0), F3(~2, ~0x03, ~0)|ASI(~0), "2,r", F_ALIAS, v6 }, /* xor rd,rs2,rd */
-{ "btog", F3(2, 0x03, 1), F3(~2, ~0x03, ~1), "i,r", F_ALIAS, v6 }, /* xor rd,i,rd */
-
-/* FPop1 and FPop2 are not instructions. Don't accept them. */
-
-{ "fdtoi", F3F(2, 0x34, 0x0d2), F3F(~2, ~0x34, ~0x0d2)|RS1_G0, "B,g", F_FLOAT, v6 },
-{ "fstoi", F3F(2, 0x34, 0x0d1), F3F(~2, ~0x34, ~0x0d1)|RS1_G0, "f,g", F_FLOAT, v6 },
-{ "fqtoi", F3F(2, 0x34, 0x0d3), F3F(~2, ~0x34, ~0x0d3)|RS1_G0, "R,g", F_FLOAT, v8 },
-
-{ "fdtox", F3F(2, 0x34, 0x082), F3F(~2, ~0x34, ~0x082)|RS1_G0, "B,g", F_FLOAT, v9 },
-{ "fstox", F3F(2, 0x34, 0x081), F3F(~2, ~0x34, ~0x081)|RS1_G0, "f,g", F_FLOAT, v9 },
-{ "fqtox", F3F(2, 0x34, 0x083), F3F(~2, ~0x34, ~0x083)|RS1_G0, "R,g", F_FLOAT, v9 },
-
-{ "fitod", F3F(2, 0x34, 0x0c8), F3F(~2, ~0x34, ~0x0c8)|RS1_G0, "f,H", F_FLOAT, v6 },
-{ "fitos", F3F(2, 0x34, 0x0c4), F3F(~2, ~0x34, ~0x0c4)|RS1_G0, "f,g", F_FLOAT, v6 },
-{ "fitoq", F3F(2, 0x34, 0x0cc), F3F(~2, ~0x34, ~0x0cc)|RS1_G0, "f,J", F_FLOAT, v8 },
-
-{ "fxtod", F3F(2, 0x34, 0x088), F3F(~2, ~0x34, ~0x088)|RS1_G0, "f,H", F_FLOAT, v9 },
-{ "fxtos", F3F(2, 0x34, 0x084), F3F(~2, ~0x34, ~0x084)|RS1_G0, "f,g", F_FLOAT, v9 },
-{ "fxtoq", F3F(2, 0x34, 0x08c), F3F(~2, ~0x34, ~0x08c)|RS1_G0, "f,J", F_FLOAT, v9 },
-
-{ "fdtoq", F3F(2, 0x34, 0x0ce), F3F(~2, ~0x34, ~0x0ce)|RS1_G0, "B,J", F_FLOAT, v8 },
-{ "fdtos", F3F(2, 0x34, 0x0c6), F3F(~2, ~0x34, ~0x0c6)|RS1_G0, "B,g", F_FLOAT, v6 },
-{ "fqtod", F3F(2, 0x34, 0x0cb), F3F(~2, ~0x34, ~0x0cb)|RS1_G0, "R,H", F_FLOAT, v8 },
-{ "fqtos", F3F(2, 0x34, 0x0c7), F3F(~2, ~0x34, ~0x0c7)|RS1_G0, "R,g", F_FLOAT, v8 },
-{ "fstod", F3F(2, 0x34, 0x0c9), F3F(~2, ~0x34, ~0x0c9)|RS1_G0, "f,H", F_FLOAT, v6 },
-{ "fstoq", F3F(2, 0x34, 0x0cd), F3F(~2, ~0x34, ~0x0cd)|RS1_G0, "f,J", F_FLOAT, v8 },
-
-{ "fdivd", F3F(2, 0x34, 0x04e), F3F(~2, ~0x34, ~0x04e), "v,B,H", F_FLOAT, v6 },
-{ "fdivq", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT, v8 },
-{ "fdivx", F3F(2, 0x34, 0x04f), F3F(~2, ~0x34, ~0x04f), "V,R,J", F_FLOAT|F_ALIAS, v8 },
-{ "fdivs", F3F(2, 0x34, 0x04d), F3F(~2, ~0x34, ~0x04d), "e,f,g", F_FLOAT, v6 },
-{ "fmuld", F3F(2, 0x34, 0x04a), F3F(~2, ~0x34, ~0x04a), "v,B,H", F_FLOAT, v6 },
-{ "fmulq", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT, v8 },
-{ "fmulx", F3F(2, 0x34, 0x04b), F3F(~2, ~0x34, ~0x04b), "V,R,J", F_FLOAT|F_ALIAS, v8 },
-{ "fmuls", F3F(2, 0x34, 0x049), F3F(~2, ~0x34, ~0x049), "e,f,g", F_FLOAT, v6 },
-
-{ "fdmulq", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT, v8 },
-{ "fdmulx", F3F(2, 0x34, 0x06e), F3F(~2, ~0x34, ~0x06e), "v,B,J", F_FLOAT|F_ALIAS, v8 },
-{ "fsmuld", F3F(2, 0x34, 0x069), F3F(~2, ~0x34, ~0x069), "e,f,H", F_FLOAT, v8 },
-
-{ "fsqrtd", F3F(2, 0x34, 0x02a), F3F(~2, ~0x34, ~0x02a)|RS1_G0, "B,H", F_FLOAT, v7 },
-{ "fsqrtq", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT, v8 },
-{ "fsqrtx", F3F(2, 0x34, 0x02b), F3F(~2, ~0x34, ~0x02b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v8 },
-{ "fsqrts", F3F(2, 0x34, 0x029), F3F(~2, ~0x34, ~0x029)|RS1_G0, "f,g", F_FLOAT, v7 },
-
-{ "fabsd", F3F(2, 0x34, 0x00a), F3F(~2, ~0x34, ~0x00a)|RS1_G0, "B,H", F_FLOAT, v9 },
-{ "fabsq", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT, v9 },
-{ "fabsx", F3F(2, 0x34, 0x00b), F3F(~2, ~0x34, ~0x00b)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 },
-{ "fabss", F3F(2, 0x34, 0x009), F3F(~2, ~0x34, ~0x009)|RS1_G0, "f,g", F_FLOAT, v6 },
-{ "fmovd", F3F(2, 0x34, 0x002), F3F(~2, ~0x34, ~0x002)|RS1_G0, "B,H", F_FLOAT, v9 },
-{ "fmovq", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT, v9 },
-{ "fmovx", F3F(2, 0x34, 0x003), F3F(~2, ~0x34, ~0x003)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 },
-{ "fmovs", F3F(2, 0x34, 0x001), F3F(~2, ~0x34, ~0x001)|RS1_G0, "f,g", F_FLOAT, v6 },
-{ "fnegd", F3F(2, 0x34, 0x006), F3F(~2, ~0x34, ~0x006)|RS1_G0, "B,H", F_FLOAT, v9 },
-{ "fnegq", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT, v9 },
-{ "fnegx", F3F(2, 0x34, 0x007), F3F(~2, ~0x34, ~0x007)|RS1_G0, "R,J", F_FLOAT|F_ALIAS, v9 },
-{ "fnegs", F3F(2, 0x34, 0x005), F3F(~2, ~0x34, ~0x005)|RS1_G0, "f,g", F_FLOAT, v6 },
-
-{ "faddd", F3F(2, 0x34, 0x042), F3F(~2, ~0x34, ~0x042), "v,B,H", F_FLOAT, v6 },
-{ "faddq", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT, v8 },
-{ "faddx", F3F(2, 0x34, 0x043), F3F(~2, ~0x34, ~0x043), "V,R,J", F_FLOAT|F_ALIAS, v8 },
-{ "fadds", F3F(2, 0x34, 0x041), F3F(~2, ~0x34, ~0x041), "e,f,g", F_FLOAT, v6 },
-{ "fsubd", F3F(2, 0x34, 0x046), F3F(~2, ~0x34, ~0x046), "v,B,H", F_FLOAT, v6 },
-{ "fsubq", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT, v8 },
-{ "fsubx", F3F(2, 0x34, 0x047), F3F(~2, ~0x34, ~0x047), "V,R,J", F_FLOAT|F_ALIAS, v8 },
-{ "fsubs", F3F(2, 0x34, 0x045), F3F(~2, ~0x34, ~0x045), "e,f,g", F_FLOAT, v6 },
-
-#define CMPFCC(x) (((x)&0x3)<<25)
-
-{ "fcmpd", F3F(2, 0x35, 0x052), F3F(~2, ~0x35, ~0x052)|RD_G0, "v,B", F_FLOAT, v6 },
-{ "fcmpd", CMPFCC(0)|F3F(2, 0x35, 0x052), CMPFCC(~0)|F3F(~2, ~0x35, ~0x052), "6,v,B", F_FLOAT, v9 },
-{ "fcmpd", CMPFCC(1)|F3F(2, 0x35, 0x052), CMPFCC(~1)|F3F(~2, ~0x35, ~0x052), "7,v,B", F_FLOAT, v9 },
-{ "fcmpd", CMPFCC(2)|F3F(2, 0x35, 0x052), CMPFCC(~2)|F3F(~2, ~0x35, ~0x052), "8,v,B", F_FLOAT, v9 },
-{ "fcmpd", CMPFCC(3)|F3F(2, 0x35, 0x052), CMPFCC(~3)|F3F(~2, ~0x35, ~0x052), "9,v,B", F_FLOAT, v9 },
-{ "fcmped", F3F(2, 0x35, 0x056), F3F(~2, ~0x35, ~0x056)|RD_G0, "v,B", F_FLOAT, v6 },
-{ "fcmped", CMPFCC(0)|F3F(2, 0x35, 0x056), CMPFCC(~0)|F3F(~2, ~0x35, ~0x056), "6,v,B", F_FLOAT, v9 },
-{ "fcmped", CMPFCC(1)|F3F(2, 0x35, 0x056), CMPFCC(~1)|F3F(~2, ~0x35, ~0x056), "7,v,B", F_FLOAT, v9 },
-{ "fcmped", CMPFCC(2)|F3F(2, 0x35, 0x056), CMPFCC(~2)|F3F(~2, ~0x35, ~0x056), "8,v,B", F_FLOAT, v9 },
-{ "fcmped", CMPFCC(3)|F3F(2, 0x35, 0x056), CMPFCC(~3)|F3F(~2, ~0x35, ~0x056), "9,v,B", F_FLOAT, v9 },
-{ "fcmpq", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT, v8 },
-{ "fcmpq", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT, v9 },
-{ "fcmpq", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT, v9 },
-{ "fcmpq", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT, v9 },
-{ "fcmpq", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT, v9 },
-{ "fcmpeq", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT, v8 },
-{ "fcmpeq", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT, v9 },
-{ "fcmpeq", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT, v9 },
-{ "fcmpeq", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT, v9 },
-{ "fcmpeq", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT, v9 },
-{ "fcmpx", F3F(2, 0x35, 0x053), F3F(~2, ~0x35, ~0x053)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 },
-{ "fcmpx", CMPFCC(0)|F3F(2, 0x35, 0x053), CMPFCC(~0)|F3F(~2, ~0x35, ~0x053), "6,V,R", F_FLOAT|F_ALIAS, v9 },
-{ "fcmpx", CMPFCC(1)|F3F(2, 0x35, 0x053), CMPFCC(~1)|F3F(~2, ~0x35, ~0x053), "7,V,R", F_FLOAT|F_ALIAS, v9 },
-{ "fcmpx", CMPFCC(2)|F3F(2, 0x35, 0x053), CMPFCC(~2)|F3F(~2, ~0x35, ~0x053), "8,V,R", F_FLOAT|F_ALIAS, v9 },
-{ "fcmpx", CMPFCC(3)|F3F(2, 0x35, 0x053), CMPFCC(~3)|F3F(~2, ~0x35, ~0x053), "9,V,R", F_FLOAT|F_ALIAS, v9 },
-{ "fcmpex", F3F(2, 0x35, 0x057), F3F(~2, ~0x35, ~0x057)|RD_G0, "V,R", F_FLOAT|F_ALIAS, v8 },
-{ "fcmpex", CMPFCC(0)|F3F(2, 0x35, 0x057), CMPFCC(~0)|F3F(~2, ~0x35, ~0x057), "6,V,R", F_FLOAT|F_ALIAS, v9 },
-{ "fcmpex", CMPFCC(1)|F3F(2, 0x35, 0x057), CMPFCC(~1)|F3F(~2, ~0x35, ~0x057), "7,V,R", F_FLOAT|F_ALIAS, v9 },
-{ "fcmpex", CMPFCC(2)|F3F(2, 0x35, 0x057), CMPFCC(~2)|F3F(~2, ~0x35, ~0x057), "8,V,R", F_FLOAT|F_ALIAS, v9 },
-{ "fcmpex", CMPFCC(3)|F3F(2, 0x35, 0x057), CMPFCC(~3)|F3F(~2, ~0x35, ~0x057), "9,V,R", F_FLOAT|F_ALIAS, v9 },
-{ "fcmps", F3F(2, 0x35, 0x051), F3F(~2, ~0x35, ~0x051)|RD_G0, "e,f", F_FLOAT, v6 },
-{ "fcmps", CMPFCC(0)|F3F(2, 0x35, 0x051), CMPFCC(~0)|F3F(~2, ~0x35, ~0x051), "6,e,f", F_FLOAT, v9 },
-{ "fcmps", CMPFCC(1)|F3F(2, 0x35, 0x051), CMPFCC(~1)|F3F(~2, ~0x35, ~0x051), "7,e,f", F_FLOAT, v9 },
-{ "fcmps", CMPFCC(2)|F3F(2, 0x35, 0x051), CMPFCC(~2)|F3F(~2, ~0x35, ~0x051), "8,e,f", F_FLOAT, v9 },
-{ "fcmps", CMPFCC(3)|F3F(2, 0x35, 0x051), CMPFCC(~3)|F3F(~2, ~0x35, ~0x051), "9,e,f", F_FLOAT, v9 },
-{ "fcmpes", F3F(2, 0x35, 0x055), F3F(~2, ~0x35, ~0x055)|RD_G0, "e,f", F_FLOAT, v6 },
-{ "fcmpes", CMPFCC(0)|F3F(2, 0x35, 0x055), CMPFCC(~0)|F3F(~2, ~0x35, ~0x055), "6,e,f", F_FLOAT, v9 },
-{ "fcmpes", CMPFCC(1)|F3F(2, 0x35, 0x055), CMPFCC(~1)|F3F(~2, ~0x35, ~0x055), "7,e,f", F_FLOAT, v9 },
-{ "fcmpes", CMPFCC(2)|F3F(2, 0x35, 0x055), CMPFCC(~2)|F3F(~2, ~0x35, ~0x055), "8,e,f", F_FLOAT, v9 },
-{ "fcmpes", CMPFCC(3)|F3F(2, 0x35, 0x055), CMPFCC(~3)|F3F(~2, ~0x35, ~0x055), "9,e,f", F_FLOAT, v9 },
-
-/* These Extended FPop (FIFO) instructions are new in the Fujitsu
- MB86934, replacing the CPop instructions from v6 and later
- processors. */
-
-#define EFPOP1_2(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op)|RS1_G0, args, 0, sparclite }
-#define EFPOP1_3(name, op, args) { name, F3F(2, 0x36, op), F3F(~2, ~0x36, ~op), args, 0, sparclite }
-#define EFPOP2_2(name, op, args) { name, F3F(2, 0x37, op), F3F(~2, ~0x37, ~op)|RD_G0, args, 0, sparclite }
-
-EFPOP1_2 ("efitod", 0x0c8, "f,H"),
-EFPOP1_2 ("efitos", 0x0c4, "f,g"),
-EFPOP1_2 ("efdtoi", 0x0d2, "B,g"),
-EFPOP1_2 ("efstoi", 0x0d1, "f,g"),
-EFPOP1_2 ("efstod", 0x0c9, "f,H"),
-EFPOP1_2 ("efdtos", 0x0c6, "B,g"),
-EFPOP1_2 ("efmovs", 0x001, "f,g"),
-EFPOP1_2 ("efnegs", 0x005, "f,g"),
-EFPOP1_2 ("efabss", 0x009, "f,g"),
-EFPOP1_2 ("efsqrtd", 0x02a, "B,H"),
-EFPOP1_2 ("efsqrts", 0x029, "f,g"),
-EFPOP1_3 ("efaddd", 0x042, "v,B,H"),
-EFPOP1_3 ("efadds", 0x041, "e,f,g"),
-EFPOP1_3 ("efsubd", 0x046, "v,B,H"),
-EFPOP1_3 ("efsubs", 0x045, "e,f,g"),
-EFPOP1_3 ("efdivd", 0x04e, "v,B,H"),
-EFPOP1_3 ("efdivs", 0x04d, "e,f,g"),
-EFPOP1_3 ("efmuld", 0x04a, "v,B,H"),
-EFPOP1_3 ("efmuls", 0x049, "e,f,g"),
-EFPOP1_3 ("efsmuld", 0x069, "e,f,H"),
-EFPOP2_2 ("efcmpd", 0x052, "v,B"),
-EFPOP2_2 ("efcmped", 0x056, "v,B"),
-EFPOP2_2 ("efcmps", 0x051, "e,f"),
-EFPOP2_2 ("efcmpes", 0x055, "e,f"),
-
-#undef EFPOP1_2
-#undef EFPOP1_3
-#undef EFPOP2_2
-
-/* These are marked F_ALIAS, so that they won't conflict with sparclite insns
- present. Otherwise, the F_ALIAS flag is ignored. */
-{ "cpop1", F3(2, 0x36, 0), F3(~2, ~0x36, ~1), "[1+2],d", F_ALIAS, v6notv9 },
-{ "cpop2", F3(2, 0x37, 0), F3(~2, ~0x37, ~1), "[1+2],d", F_ALIAS, v6notv9 },
-
-/* sparclet specific insns */
-
-COMMUTEOP ("umac", 0x3e, sparclet),
-COMMUTEOP ("smac", 0x3f, sparclet),
-COMMUTEOP ("umacd", 0x2e, sparclet),
-COMMUTEOP ("smacd", 0x2f, sparclet),
-COMMUTEOP ("umuld", 0x09, sparclet),
-COMMUTEOP ("smuld", 0x0d, sparclet),
-
-{ "shuffle", F3(2, 0x2d, 0), F3(~2, ~0x2d, ~0)|ASI(~0), "1,2,d", 0, sparclet },
-{ "shuffle", F3(2, 0x2d, 1), F3(~2, ~0x2d, ~1), "1,i,d", 0, sparclet },
-
-/* The manual isn't completely accurate on these insns. The `rs2' field is
- treated as being 6 bits to account for 6 bit immediates to cpush. It is
- assumed that it is intended that bit 5 is 0 when rs2 contains a reg. */
-#define BIT5 (1<<5)
-{ "crdcxt", F3(2, 0x36, 0)|SLCPOP(4), F3(~2, ~0x36, ~0)|SLCPOP(~4)|BIT5|RS2(~0), "U,d", 0, sparclet },
-{ "cwrcxt", F3(2, 0x36, 0)|SLCPOP(3), F3(~2, ~0x36, ~0)|SLCPOP(~3)|BIT5|RS2(~0), "1,u", 0, sparclet },
-{ "cpush", F3(2, 0x36, 0)|SLCPOP(0), F3(~2, ~0x36, ~0)|SLCPOP(~0)|BIT5|RD(~0), "1,2", 0, sparclet },
-{ "cpush", F3(2, 0x36, 1)|SLCPOP(0), F3(~2, ~0x36, ~1)|SLCPOP(~0)|RD(~0), "1,Y", 0, sparclet },
-{ "cpusha", F3(2, 0x36, 0)|SLCPOP(1), F3(~2, ~0x36, ~0)|SLCPOP(~1)|BIT5|RD(~0), "1,2", 0, sparclet },
-{ "cpusha", F3(2, 0x36, 1)|SLCPOP(1), F3(~2, ~0x36, ~1)|SLCPOP(~1)|RD(~0), "1,Y", 0, sparclet },
-{ "cpull", F3(2, 0x36, 0)|SLCPOP(2), F3(~2, ~0x36, ~0)|SLCPOP(~2)|BIT5|RS1(~0)|RS2(~0), "d", 0, sparclet },
-#undef BIT5
-
-/* sparclet coprocessor branch insns */
-#define SLCBCC2(opcode, mask, lose) \
- { opcode, (mask), ANNUL|(lose), "l", F_DELAYED|F_CONDBR, sparclet }, \
- { opcode, (mask)|ANNUL, (lose), ",a l", F_DELAYED|F_CONDBR, sparclet }
-#define SLCBCC(opcode, mask) \
- SLCBCC2(opcode, F2(0, 7)|COND(mask), F2(~0, ~7)|COND(~(mask)))
-
-/* cbn,cba can't be defined here because they're defined elsewhere and GAS
- requires all mnemonics of the same name to be consecutive. */
-/*SLCBCC("cbn", 0), - already defined */
-SLCBCC("cbe", 1),
-SLCBCC("cbf", 2),
-SLCBCC("cbef", 3),
-SLCBCC("cbr", 4),
-SLCBCC("cber", 5),
-SLCBCC("cbfr", 6),
-SLCBCC("cbefr", 7),
-/*SLCBCC("cba", 8), - already defined */
-SLCBCC("cbne", 9),
-SLCBCC("cbnf", 10),
-SLCBCC("cbnef", 11),
-SLCBCC("cbnr", 12),
-SLCBCC("cbner", 13),
-SLCBCC("cbnfr", 14),
-SLCBCC("cbnefr", 15),
-
-#undef SLCBCC2
-#undef SLCBCC
-
-{ "casa", F3(3, 0x3c, 0), F3(~3, ~0x3c, ~0), "[1]A,2,d", 0, v9 },
-{ "casa", F3(3, 0x3c, 1), F3(~3, ~0x3c, ~1), "[1]o,2,d", 0, v9 },
-{ "casxa", F3(3, 0x3e, 0), F3(~3, ~0x3e, ~0), "[1]A,2,d", 0, v9 },
-{ "casxa", F3(3, 0x3e, 1), F3(~3, ~0x3e, ~1), "[1]o,2,d", 0, v9 },
-
-/* v9 synthetic insns */
-{ "iprefetch", F2(0, 1)|(2<<20)|BPRED, F2(~0, ~1)|(1<<20)|ANNUL|COND(~0), "G", 0, v9 }, /* bn,a,pt %xcc,label */
-{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* sra rs1,%g0,rd */
-{ "signx", F3(2, 0x27, 0), F3(~2, ~0x27, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* sra rd,%g0,rd */
-{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "1,d", F_ALIAS, v9 }, /* srl rs1,%g0,rd */
-{ "clruw", F3(2, 0x26, 0), F3(~2, ~0x26, ~0)|(1<<12)|ASI(~0)|RS2_G0, "r", F_ALIAS, v9 }, /* srl rd,%g0,rd */
-{ "cas", F3(3, 0x3c, 0)|ASI(0x80), F3(~3, ~0x3c, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P,rs2,rd */
-{ "casl", F3(3, 0x3c, 0)|ASI(0x88), F3(~3, ~0x3c, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casa [rs1]ASI_P_L,rs2,rd */
-{ "casx", F3(3, 0x3e, 0)|ASI(0x80), F3(~3, ~0x3e, ~0)|ASI(~0x80), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P,rs2,rd */
-{ "casxl", F3(3, 0x3e, 0)|ASI(0x88), F3(~3, ~0x3e, ~0)|ASI(~0x88), "[1],2,d", F_ALIAS, v9 }, /* casxa [rs1]ASI_P_L,rs2,rd */
-
-/* Ultrasparc extensions */
-{ "shutdown", F3F(2, 0x36, 0x080), F3F(~2, ~0x36, ~0x080)|RD_G0|RS1_G0|RS2_G0, "", 0, v9a },
-
-/* FIXME: Do we want to mark these as F_FLOAT, or something similar? */
-{ "fpadd16", F3F(2, 0x36, 0x050), F3F(~2, ~0x36, ~0x050), "v,B,H", 0, v9a },
-{ "fpadd16s", F3F(2, 0x36, 0x051), F3F(~2, ~0x36, ~0x051), "e,f,g", 0, v9a },
-{ "fpadd32", F3F(2, 0x36, 0x052), F3F(~2, ~0x36, ~0x052), "v,B,H", 0, v9a },
-{ "fpadd32s", F3F(2, 0x36, 0x053), F3F(~2, ~0x36, ~0x053), "e,f,g", 0, v9a },
-{ "fpsub16", F3F(2, 0x36, 0x054), F3F(~2, ~0x36, ~0x054), "v,B,H", 0, v9a },
-{ "fpsub16s", F3F(2, 0x36, 0x055), F3F(~2, ~0x36, ~0x055), "e,f,g", 0, v9a },
-{ "fpsub32", F3F(2, 0x36, 0x056), F3F(~2, ~0x36, ~0x056), "v,B,H", 0, v9a },
-{ "fpsub32s", F3F(2, 0x36, 0x057), F3F(~2, ~0x36, ~0x057), "e,f,g", 0, v9a },
-
-{ "fpack32", F3F(2, 0x36, 0x03a), F3F(~2, ~0x36, ~0x03a), "v,B,H", 0, v9a },
-{ "fpack16", F3F(2, 0x36, 0x03b), F3F(~2, ~0x36, ~0x03b)|RS1_G0, "B,g", 0, v9a },
-{ "fpackfix", F3F(2, 0x36, 0x03d), F3F(~2, ~0x36, ~0x03d)|RS1_G0, "B,g", 0, v9a },
-{ "fexpand", F3F(2, 0x36, 0x04d), F3F(~2, ~0x36, ~0x04d)|RS1_G0, "f,H", 0, v9a },
-{ "fpmerge", F3F(2, 0x36, 0x04b), F3F(~2, ~0x36, ~0x04b), "e,f,H", 0, v9a },
-
-/* Note that the mixing of 32/64 bit regs is intentional. */
-{ "fmul8x16", F3F(2, 0x36, 0x031), F3F(~2, ~0x36, ~0x031), "e,B,H", 0, v9a },
-{ "fmul8x16au", F3F(2, 0x36, 0x033), F3F(~2, ~0x36, ~0x033), "e,f,H", 0, v9a },
-{ "fmul8x16al", F3F(2, 0x36, 0x035), F3F(~2, ~0x36, ~0x035), "e,f,H", 0, v9a },
-{ "fmul8sux16", F3F(2, 0x36, 0x036), F3F(~2, ~0x36, ~0x036), "v,B,H", 0, v9a },
-{ "fmul8ulx16", F3F(2, 0x36, 0x037), F3F(~2, ~0x36, ~0x037), "v,B,H", 0, v9a },
-{ "fmuld8sux16", F3F(2, 0x36, 0x038), F3F(~2, ~0x36, ~0x038), "e,f,H", 0, v9a },
-{ "fmuld8ulx16", F3F(2, 0x36, 0x039), F3F(~2, ~0x36, ~0x039), "e,f,H", 0, v9a },
-
-{ "alignaddr", F3F(2, 0x36, 0x018), F3F(~2, ~0x36, ~0x018), "1,2,d", 0, v9a },
-{ "alignaddrl", F3F(2, 0x36, 0x01a), F3F(~2, ~0x36, ~0x01a), "1,2,d", 0, v9a },
-{ "faligndata", F3F(2, 0x36, 0x048), F3F(~2, ~0x36, ~0x048), "v,B,H", 0, v9a },
-
-{ "fzero", F3F(2, 0x36, 0x060), F3F(~2, ~0x36, ~0x060), "H", 0, v9a },
-{ "fzeros", F3F(2, 0x36, 0x061), F3F(~2, ~0x36, ~0x061), "g", 0, v9a },
-{ "fone", F3F(2, 0x36, 0x07e), F3F(~2, ~0x36, ~0x07e), "H", 0, v9a },
-{ "fones", F3F(2, 0x36, 0x07f), F3F(~2, ~0x36, ~0x07f), "g", 0, v9a },
-{ "fsrc1", F3F(2, 0x36, 0x074), F3F(~2, ~0x36, ~0x074), "v,H", 0, v9a },
-{ "fsrc1s", F3F(2, 0x36, 0x075), F3F(~2, ~0x36, ~0x075), "e,g", 0, v9a },
-{ "fsrc2", F3F(2, 0x36, 0x078), F3F(~2, ~0x36, ~0x078), "B,H", 0, v9a },
-{ "fsrc2s", F3F(2, 0x36, 0x079), F3F(~2, ~0x36, ~0x079), "f,g", 0, v9a },
-{ "fnot1", F3F(2, 0x36, 0x06a), F3F(~2, ~0x36, ~0x06a), "v,H", 0, v9a },
-{ "fnot1s", F3F(2, 0x36, 0x06b), F3F(~2, ~0x36, ~0x06b), "e,g", 0, v9a },
-{ "fnot2", F3F(2, 0x36, 0x066), F3F(~2, ~0x36, ~0x066), "B,H", 0, v9a },
-{ "fnot2s", F3F(2, 0x36, 0x067), F3F(~2, ~0x36, ~0x067), "f,g", 0, v9a },
-{ "for", F3F(2, 0x36, 0x07c), F3F(~2, ~0x36, ~0x07c), "v,B,H", 0, v9a },
-{ "fors", F3F(2, 0x36, 0x07d), F3F(~2, ~0x36, ~0x07d), "e,f,g", 0, v9a },
-{ "fnor", F3F(2, 0x36, 0x062), F3F(~2, ~0x36, ~0x062), "v,B,H", 0, v9a },
-{ "fnors", F3F(2, 0x36, 0x063), F3F(~2, ~0x36, ~0x063), "e,f,g", 0, v9a },
-{ "fand", F3F(2, 0x36, 0x070), F3F(~2, ~0x36, ~0x070), "v,B,H", 0, v9a },
-{ "fands", F3F(2, 0x36, 0x071), F3F(~2, ~0x36, ~0x071), "e,f,g", 0, v9a },
-{ "fnand", F3F(2, 0x36, 0x06e), F3F(~2, ~0x36, ~0x06e), "v,B,H", 0, v9a },
-{ "fnands", F3F(2, 0x36, 0x06f), F3F(~2, ~0x36, ~0x06f), "e,f,g", 0, v9a },
-{ "fxor", F3F(2, 0x36, 0x06c), F3F(~2, ~0x36, ~0x06c), "v,B,H", 0, v9a },
-{ "fxors", F3F(2, 0x36, 0x06d), F3F(~2, ~0x36, ~0x06d), "e,f,g", 0, v9a },
-{ "fxnor", F3F(2, 0x36, 0x072), F3F(~2, ~0x36, ~0x072), "v,B,H", 0, v9a },
-{ "fxnors", F3F(2, 0x36, 0x073), F3F(~2, ~0x36, ~0x073), "e,f,g", 0, v9a },
-{ "fornot1", F3F(2, 0x36, 0x07a), F3F(~2, ~0x36, ~0x07a), "v,B,H", 0, v9a },
-{ "fornot1s", F3F(2, 0x36, 0x07b), F3F(~2, ~0x36, ~0x07b), "e,f,g", 0, v9a },
-{ "fornot2", F3F(2, 0x36, 0x076), F3F(~2, ~0x36, ~0x076), "v,B,H", 0, v9a },
-{ "fornot2s", F3F(2, 0x36, 0x077), F3F(~2, ~0x36, ~0x077), "e,f,g", 0, v9a },
-{ "fandnot1", F3F(2, 0x36, 0x068), F3F(~2, ~0x36, ~0x068), "v,B,H", 0, v9a },
-{ "fandnot1s", F3F(2, 0x36, 0x069), F3F(~2, ~0x36, ~0x069), "e,f,g", 0, v9a },
-{ "fandnot2", F3F(2, 0x36, 0x064), F3F(~2, ~0x36, ~0x064), "v,B,H", 0, v9a },
-{ "fandnot2s", F3F(2, 0x36, 0x065), F3F(~2, ~0x36, ~0x065), "e,f,g", 0, v9a },
-
-{ "fcmpgt16", F3F(2, 0x36, 0x028), F3F(~2, ~0x36, ~0x028), "v,B,d", 0, v9a },
-{ "fcmpgt32", F3F(2, 0x36, 0x02c), F3F(~2, ~0x36, ~0x02c), "v,B,d", 0, v9a },
-{ "fcmple16", F3F(2, 0x36, 0x020), F3F(~2, ~0x36, ~0x020), "v,B,d", 0, v9a },
-{ "fcmple32", F3F(2, 0x36, 0x024), F3F(~2, ~0x36, ~0x024), "v,B,d", 0, v9a },
-{ "fcmpne16", F3F(2, 0x36, 0x022), F3F(~2, ~0x36, ~0x022), "v,B,d", 0, v9a },
-{ "fcmpne32", F3F(2, 0x36, 0x026), F3F(~2, ~0x36, ~0x026), "v,B,d", 0, v9a },
-{ "fcmpeq16", F3F(2, 0x36, 0x02a), F3F(~2, ~0x36, ~0x02a), "v,B,d", 0, v9a },
-{ "fcmpeq32", F3F(2, 0x36, 0x02e), F3F(~2, ~0x36, ~0x02e), "v,B,d", 0, v9a },
-
-{ "edge8", F3F(2, 0x36, 0x000), F3F(~2, ~0x36, ~0x000), "1,2,d", 0, v9a },
-{ "edge8l", F3F(2, 0x36, 0x002), F3F(~2, ~0x36, ~0x002), "1,2,d", 0, v9a },
-{ "edge16", F3F(2, 0x36, 0x004), F3F(~2, ~0x36, ~0x004), "1,2,d", 0, v9a },
-{ "edge16l", F3F(2, 0x36, 0x006), F3F(~2, ~0x36, ~0x006), "1,2,d", 0, v9a },
-{ "edge32", F3F(2, 0x36, 0x008), F3F(~2, ~0x36, ~0x008), "1,2,d", 0, v9a },
-{ "edge32l", F3F(2, 0x36, 0x00a), F3F(~2, ~0x36, ~0x00a), "1,2,d", 0, v9a },
-
-{ "pdist", F3F(2, 0x36, 0x03e), F3F(~2, ~0x36, ~0x03e), "v,B,H", 0, v9a },
-
-{ "array8", F3F(2, 0x36, 0x010), F3F(~2, ~0x36, ~0x010), "1,2,d", 0, v9a },
-{ "array16", F3F(2, 0x36, 0x012), F3F(~2, ~0x36, ~0x012), "1,2,d", 0, v9a },
-{ "array32", F3F(2, 0x36, 0x014), F3F(~2, ~0x36, ~0x014), "1,2,d", 0, v9a },
-
-/* Cheetah instructions */
-{ "edge8n", F3F(2, 0x36, 0x001), F3F(~2, ~0x36, ~0x001), "1,2,d", 0, v9b },
-{ "edge8ln", F3F(2, 0x36, 0x003), F3F(~2, ~0x36, ~0x003), "1,2,d", 0, v9b },
-{ "edge16n", F3F(2, 0x36, 0x005), F3F(~2, ~0x36, ~0x005), "1,2,d", 0, v9b },
-{ "edge16ln", F3F(2, 0x36, 0x007), F3F(~2, ~0x36, ~0x007), "1,2,d", 0, v9b },
-{ "edge32n", F3F(2, 0x36, 0x009), F3F(~2, ~0x36, ~0x009), "1,2,d", 0, v9b },
-{ "edge32ln", F3F(2, 0x36, 0x00b), F3F(~2, ~0x36, ~0x00b), "1,2,d", 0, v9b },
-
-{ "bmask", F3F(2, 0x36, 0x019), F3F(~2, ~0x36, ~0x019), "1,2,d", 0, v9b },
-{ "bshuffle", F3F(2, 0x36, 0x04c), F3F(~2, ~0x36, ~0x04c), "v,B,H", 0, v9b },
-
-{ "siam", F3F(2, 0x36, 0x081), F3F(~2, ~0x36, ~0x081)|RD_G0|RS1_G0|RS2(~7), "3", 0, v9b },
-
-/* More v9 specific insns, these need to come last so they do not clash
- with v9a instructions such as "edge8" which looks like impdep1. */
-
-#define IMPDEP(name, code) \
-{ name, F3(2, code, 0), F3(~2, ~code, ~0)|ASI(~0), "1,2,d", 0, v9notv9a }, \
-{ name, F3(2, code, 1), F3(~2, ~code, ~1), "1,i,d", 0, v9notv9a }, \
-{ name, F3(2, code, 0), F3(~2, ~code, ~0), "x,1,2,d", 0, v9notv9a }, \
-{ name, F3(2, code, 0), F3(~2, ~code, ~0), "x,e,f,g", 0, v9notv9a }
-
-IMPDEP ("impdep1", 0x36),
-IMPDEP ("impdep2", 0x37),
-
-#undef IMPDEP
-
-};
-
-const int sparc_num_opcodes = ((sizeof sparc_opcodes)/(sizeof sparc_opcodes[0]));
-
-/* Utilities for argument parsing. */
-
-typedef struct
-{
- int value;
- const char *name;
-} arg;
-
-/* Look up NAME in TABLE. */
-
-static int lookup_name PARAMS ((const arg *, const char *));
-static const char *lookup_value PARAMS ((const arg *, int));
-
-static int
-lookup_name (table, name)
- const arg *table;
- const char *name;
-{
- const arg *p;
-
- for (p = table; p->name; ++p)
- if (strcmp (name, p->name) == 0)
- return p->value;
-
- return -1;
-}
-
-/* Look up VALUE in TABLE. */
-
-static const char *
-lookup_value (table, value)
- const arg *table;
- int value;
-{
- const arg *p;
-
- for (p = table; p->name; ++p)
- if (value == p->value)
- return p->name;
-
- return (char *) 0;
-}
-
-/* Handle ASI's. */
-
-static const arg asi_table_v8[] =
-{
- { 0x00, "#ASI_M_RES00" },
- { 0x01, "#ASI_M_UNA01" },
- { 0x02, "#ASI_M_MXCC" },
- { 0x03, "#ASI_M_FLUSH_PROBE" },
- { 0x04, "#ASI_M_MMUREGS" },
- { 0x05, "#ASI_M_TLBDIAG" },
- { 0x06, "#ASI_M_DIAGS" },
- { 0x07, "#ASI_M_IODIAG" },
- { 0x08, "#ASI_M_USERTXT" },
- { 0x09, "#ASI_M_KERNELTXT" },
- { 0x0A, "#ASI_M_USERDATA" },
- { 0x0B, "#ASI_M_KERNELDATA" },
- { 0x0C, "#ASI_M_TXTC_TAG" },
- { 0x0D, "#ASI_M_TXTC_DATA" },
- { 0x0E, "#ASI_M_DATAC_TAG" },
- { 0x0F, "#ASI_M_DATAC_DATA" },
- { 0x10, "#ASI_M_FLUSH_PAGE" },
- { 0x11, "#ASI_M_FLUSH_SEG" },
- { 0x12, "#ASI_M_FLUSH_REGION" },
- { 0x13, "#ASI_M_FLUSH_CTX" },
- { 0x14, "#ASI_M_FLUSH_USER" },
- { 0x17, "#ASI_M_BCOPY" },
- { 0x18, "#ASI_M_IFLUSH_PAGE" },
- { 0x19, "#ASI_M_IFLUSH_SEG" },
- { 0x1A, "#ASI_M_IFLUSH_REGION" },
- { 0x1B, "#ASI_M_IFLUSH_CTX" },
- { 0x1C, "#ASI_M_IFLUSH_USER" },
- { 0x1F, "#ASI_M_BFILL" },
- { 0x20, "#ASI_M_BYPASS" },
- { 0x29, "#ASI_M_FBMEM" },
- { 0x2A, "#ASI_M_VMEUS" },
- { 0x2B, "#ASI_M_VMEPS" },
- { 0x2C, "#ASI_M_VMEUT" },
- { 0x2D, "#ASI_M_VMEPT" },
- { 0x2E, "#ASI_M_SBUS" },
- { 0x2F, "#ASI_M_CTL" },
- { 0x31, "#ASI_M_FLUSH_IWHOLE" },
- { 0x36, "#ASI_M_IC_FLCLEAR" },
- { 0x37, "#ASI_M_DC_FLCLEAR" },
- { 0x39, "#ASI_M_DCDR" },
- { 0x40, "#ASI_M_VIKING_TMP1" },
- { 0x41, "#ASI_M_VIKING_TMP2" },
- { 0x4c, "#ASI_M_ACTION" },
- { 0, 0 }
-};
-
-static const arg asi_table_v9[] =
-{
- /* These are in the v9 architecture manual. */
- /* The shorter versions appear first, they're here because Sun's as has them.
- Sun's as uses #ASI_P_L instead of #ASI_PL (which appears in the
- UltraSPARC architecture manual). */
- { 0x04, "#ASI_N" },
- { 0x0c, "#ASI_N_L" },
- { 0x10, "#ASI_AIUP" },
- { 0x11, "#ASI_AIUS" },
- { 0x18, "#ASI_AIUP_L" },
- { 0x19, "#ASI_AIUS_L" },
- { 0x80, "#ASI_P" },
- { 0x81, "#ASI_S" },
- { 0x82, "#ASI_PNF" },
- { 0x83, "#ASI_SNF" },
- { 0x88, "#ASI_P_L" },
- { 0x89, "#ASI_S_L" },
- { 0x8a, "#ASI_PNF_L" },
- { 0x8b, "#ASI_SNF_L" },
- { 0x04, "#ASI_NUCLEUS" },
- { 0x0c, "#ASI_NUCLEUS_LITTLE" },
- { 0x10, "#ASI_AS_IF_USER_PRIMARY" },
- { 0x11, "#ASI_AS_IF_USER_SECONDARY" },
- { 0x18, "#ASI_AS_IF_USER_PRIMARY_LITTLE" },
- { 0x19, "#ASI_AS_IF_USER_SECONDARY_LITTLE" },
- { 0x80, "#ASI_PRIMARY" },
- { 0x81, "#ASI_SECONDARY" },
- { 0x82, "#ASI_PRIMARY_NOFAULT" },
- { 0x83, "#ASI_SECONDARY_NOFAULT" },
- { 0x88, "#ASI_PRIMARY_LITTLE" },
- { 0x89, "#ASI_SECONDARY_LITTLE" },
- { 0x8a, "#ASI_PRIMARY_NOFAULT_LITTLE" },
- { 0x8b, "#ASI_SECONDARY_NOFAULT_LITTLE" },
- /* These are UltraSPARC extensions. */
- /* FIXME: There are dozens of them. Not sure we want them all.
- Most are for kernel building but some are for vis type stuff. */
- { 0, 0 }
-};
-
-/* Return the name for ASI value VALUE or NULL if not found. */
-
-static const char *
-sparc_decode_asi_v9 (int value)
-{
- return lookup_value (asi_table_v9, value);
-}
-
-static const char *
-sparc_decode_asi_v8 (int value)
-{
- return lookup_value (asi_table_v8, value);
-}
-
-/* Handle membar masks. */
-
-static arg membar_table[] =
-{
- { 0x40, "#Sync" },
- { 0x20, "#MemIssue" },
- { 0x10, "#Lookaside" },
- { 0x08, "#StoreStore" },
- { 0x04, "#LoadStore" },
- { 0x02, "#StoreLoad" },
- { 0x01, "#LoadLoad" },
- { 0, 0 }
-};
-
-/* Return the value for membar arg NAME, or -1 if not found. */
-
-int
-sparc_encode_membar (name)
- const char *name;
-{
- return lookup_name (membar_table, name);
-}
-
-/* Return the name for membar value VALUE or NULL if not found. */
-
-const char *
-sparc_decode_membar (value)
- int value;
-{
- return lookup_value (membar_table, value);
-}
-
-/* Handle prefetch args. */
-
-static arg prefetch_table[] =
-{
- { 0, "#n_reads" },
- { 1, "#one_read" },
- { 2, "#n_writes" },
- { 3, "#one_write" },
- { 4, "#page" },
- { 16, "#invalidate" },
- { 0, 0 }
-};
-
-/* Return the value for prefetch arg NAME, or -1 if not found. */
-
-int
-sparc_encode_prefetch (name)
- const char *name;
-{
- return lookup_name (prefetch_table, name);
-}
-
-/* Return the name for prefetch value VALUE or NULL if not found. */
-
-const char *
-sparc_decode_prefetch (value)
- int value;
-{
- return lookup_value (prefetch_table, value);
-}
-
-/* Handle sparclet coprocessor registers. */
-
-static arg sparclet_cpreg_table[] =
-{
- { 0, "%ccsr" },
- { 1, "%ccfr" },
- { 2, "%cccrcr" },
- { 3, "%ccpr" },
- { 4, "%ccsr2" },
- { 5, "%cccrr" },
- { 6, "%ccrstr" },
- { 0, 0 }
-};
-
-/* Return the value for sparclet cpreg arg NAME, or -1 if not found. */
-
-int
-sparc_encode_sparclet_cpreg (name)
- const char *name;
-{
- return lookup_name (sparclet_cpreg_table, name);
-}
-
-/* Return the name for sparclet cpreg value VALUE or NULL if not found. */
-
-const char *
-sparc_decode_sparclet_cpreg (value)
- int value;
-{
- return lookup_value (sparclet_cpreg_table, value);
-}
-
-#undef MASK_V9
-
-/* Bitmask of v9 architectures. */
-#define MASK_V9 ((1 << SPARC_OPCODE_ARCH_V9) \
- | (1 << SPARC_OPCODE_ARCH_V9A) \
- | (1 << SPARC_OPCODE_ARCH_V9B))
-/* 1 if INSN is for v9 only. */
-#define V9_ONLY_P(insn) (! ((insn)->architecture & ~MASK_V9))
-/* 1 if INSN is for v9. */
-#define V9_P(insn) (((insn)->architecture & MASK_V9) != 0)
-
-/* The sorted opcode table. */
-static const struct sparc_opcode **sorted_opcodes;
-
-/* For faster lookup, after insns are sorted they are hashed. */
-/* ??? I think there is room for even more improvement. */
-
-#define HASH_SIZE 256
-/* It is important that we only look at insn code bits as that is how the
- opcode table is hashed. OPCODE_BITS is a table of valid bits for each
- of the main types (0,1,2,3). */
-static int opcode_bits[4] = { 0x01c00000, 0x0, 0x01f80000, 0x01f80000 };
-#define HASH_INSN(INSN) \
- ((((INSN) >> 24) & 0xc0) | (((INSN) & opcode_bits[((INSN) >> 30) & 3]) >> 19))
-struct opcode_hash {
- struct opcode_hash *next;
- const struct sparc_opcode *opcode;
-};
-static struct opcode_hash *opcode_hash_table[HASH_SIZE];
-
-static void build_hash_table
- PARAMS ((const struct sparc_opcode **, struct opcode_hash **, int));
-static int is_delayed_branch PARAMS ((unsigned long));
-static int compare_opcodes PARAMS ((const void *, const void *));
-static int compute_arch_mask PARAMS ((unsigned long));
-
-/* Sign-extend a value which is N bits long. */
-#define SEX(value, bits) \
- ((((int)(value)) << ((8 * sizeof (int)) - bits)) \
- >> ((8 * sizeof (int)) - bits) )
-
-static char *reg_names[] =
-{ "g0", "g1", "g2", "g3", "g4", "g5", "g6", "g7",
- "o0", "o1", "o2", "o3", "o4", "o5", "sp", "o7",
- "l0", "l1", "l2", "l3", "l4", "l5", "l6", "l7",
- "i0", "i1", "i2", "i3", "i4", "i5", "fp", "i7",
- "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
- "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
- "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
- "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
- "f32", "f33", "f34", "f35", "f36", "f37", "f38", "f39",
- "f40", "f41", "f42", "f43", "f44", "f45", "f46", "f47",
- "f48", "f49", "f50", "f51", "f52", "f53", "f54", "f55",
- "f56", "f57", "f58", "f59", "f60", "f61", "f62", "f63",
-/* psr, wim, tbr, fpsr, cpsr are v8 only. */
- "y", "psr", "wim", "tbr", "pc", "npc", "fpsr", "cpsr"
-};
-
-#define freg_names (&reg_names[4 * 8])
-
-/* These are ordered according to there register number in
- rdpr and wrpr insns. */
-static char *v9_priv_reg_names[] =
-{
- "tpc", "tnpc", "tstate", "tt", "tick", "tba", "pstate", "tl",
- "pil", "cwp", "cansave", "canrestore", "cleanwin", "otherwin",
- "wstate", "fq"
- /* "ver" - special cased */
-};
-
-/* These are ordered according to there register number in
- rd and wr insns (-16). */
-static char *v9a_asr_reg_names[] =
-{
- "pcr", "pic", "dcr", "gsr", "set_softint", "clear_softint",
- "softint", "tick_cmpr", "sys_tick", "sys_tick_cmpr"
-};
-
-/* Macros used to extract instruction fields. Not all fields have
- macros defined here, only those which are actually used. */
-
-#define X_RD(i) (((i) >> 25) & 0x1f)
-#define X_RS1(i) (((i) >> 14) & 0x1f)
-#define X_LDST_I(i) (((i) >> 13) & 1)
-#define X_ASI(i) (((i) >> 5) & 0xff)
-#define X_RS2(i) (((i) >> 0) & 0x1f)
-#define X_IMM(i,n) (((i) >> 0) & ((1 << (n)) - 1))
-#define X_SIMM(i,n) SEX (X_IMM ((i), (n)), (n))
-#define X_DISP22(i) (((i) >> 0) & 0x3fffff)
-#define X_IMM22(i) X_DISP22 (i)
-#define X_DISP30(i) (((i) >> 0) & 0x3fffffff)
-
-/* These are for v9. */
-#define X_DISP16(i) (((((i) >> 20) & 3) << 14) | (((i) >> 0) & 0x3fff))
-#define X_DISP19(i) (((i) >> 0) & 0x7ffff)
-#define X_MEMBAR(i) ((i) & 0x7f)
-
-/* Here is the union which was used to extract instruction fields
- before the shift and mask macros were written.
-
- union sparc_insn
- {
- unsigned long int code;
- struct
- {
- unsigned int anop:2;
- #define op ldst.anop
- unsigned int anrd:5;
- #define rd ldst.anrd
- unsigned int op3:6;
- unsigned int anrs1:5;
- #define rs1 ldst.anrs1
- unsigned int i:1;
- unsigned int anasi:8;
- #define asi ldst.anasi
- unsigned int anrs2:5;
- #define rs2 ldst.anrs2
- #define shcnt rs2
- } ldst;
- struct
- {
- unsigned int anop:2, anrd:5, op3:6, anrs1:5, i:1;
- unsigned int IMM13:13;
- #define imm13 IMM13.IMM13
- } IMM13;
- struct
- {
- unsigned int anop:2;
- unsigned int a:1;
- unsigned int cond:4;
- unsigned int op2:3;
- unsigned int DISP22:22;
- #define disp22 branch.DISP22
- #define imm22 disp22
- } branch;
- struct
- {
- unsigned int anop:2;
- unsigned int a:1;
- unsigned int z:1;
- unsigned int rcond:3;
- unsigned int op2:3;
- unsigned int DISP16HI:2;
- unsigned int p:1;
- unsigned int _rs1:5;
- unsigned int DISP16LO:14;
- } branch16;
- struct
- {
- unsigned int anop:2;
- unsigned int adisp30:30;
- #define disp30 call.adisp30
- } call;
- };
-
- */
-
-/* Nonzero if INSN is the opcode for a delayed branch. */
-static int
-is_delayed_branch (insn)
- unsigned long insn;
-{
- struct opcode_hash *op;
-
- for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
- {
- const struct sparc_opcode *opcode = op->opcode;
- if ((opcode->match & insn) == opcode->match
- && (opcode->lose & insn) == 0)
- return (opcode->flags & F_DELAYED);
- }
- return 0;
-}
-
-/* extern void qsort (); */
-
-/* Records current mask of SPARC_OPCODE_ARCH_FOO values, used to pass value
- to compare_opcodes. */
-static unsigned int current_arch_mask;
-
-/* Print one instruction from MEMADDR on INFO->STREAM.
-
- We suffix the instruction with a comment that gives the absolute
- address involved, as well as its symbolic form, if the instruction
- is preceded by a findable `sethi' and it either adds an immediate
- displacement to that register, or it is an `add' or `or' instruction
- on that register. */
-
-int
-print_insn_sparc (memaddr, info)
- bfd_vma memaddr;
- disassemble_info *info;
-{
- FILE *stream = info->stream;
- bfd_byte buffer[4];
- unsigned long insn;
- register struct opcode_hash *op;
- /* Nonzero of opcode table has been initialized. */
- static int opcodes_initialized = 0;
- /* bfd mach number of last call. */
- static unsigned long current_mach = 0;
- bfd_vma (*getword) PARAMS ((const unsigned char *));
-
- if (!opcodes_initialized
- || info->mach != current_mach)
- {
- int i;
-
- current_arch_mask = compute_arch_mask (info->mach);
-
- if (!opcodes_initialized)
- sorted_opcodes = (const struct sparc_opcode **)
- malloc (sparc_num_opcodes * sizeof (struct sparc_opcode *));
- /* Reset the sorted table so we can resort it. */
- for (i = 0; i < sparc_num_opcodes; ++i)
- sorted_opcodes[i] = &sparc_opcodes[i];
- qsort ((char *) sorted_opcodes, sparc_num_opcodes,
- sizeof (sorted_opcodes[0]), compare_opcodes);
-
- build_hash_table (sorted_opcodes, opcode_hash_table, sparc_num_opcodes);
- current_mach = info->mach;
- opcodes_initialized = 1;
- }
-
- {
- int status =
- (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info);
- if (status != 0)
- {
- (*info->memory_error_func) (status, memaddr, info);
- return -1;
- }
- }
-
- /* On SPARClite variants such as DANlite (sparc86x), instructions
- are always big-endian even when the machine is in little-endian mode. */
- if (info->endian == BFD_ENDIAN_BIG || info->mach == bfd_mach_sparc_sparclite)
- getword = bfd_getb32;
- else
- getword = bfd_getl32;
-
- insn = getword (buffer);
-
- info->insn_info_valid = 1; /* We do return this info */
- info->insn_type = dis_nonbranch; /* Assume non branch insn */
- info->branch_delay_insns = 0; /* Assume no delay */
- info->target = 0; /* Assume no target known */
-
- for (op = opcode_hash_table[HASH_INSN (insn)]; op; op = op->next)
- {
- const struct sparc_opcode *opcode = op->opcode;
-
- /* If the insn isn't supported by the current architecture, skip it. */
- if (! (opcode->architecture & current_arch_mask))
- continue;
-
- if ((opcode->match & insn) == opcode->match
- && (opcode->lose & insn) == 0)
- {
- /* Nonzero means that we have found an instruction which has
- the effect of adding or or'ing the imm13 field to rs1. */
- int imm_added_to_rs1 = 0;
- int imm_ored_to_rs1 = 0;
-
- /* Nonzero means that we have found a plus sign in the args
- field of the opcode table. */
- int found_plus = 0;
-
- /* Nonzero means we have an annulled branch. */
- int is_annulled = 0;
-
- /* Do we have an `add' or `or' instruction combining an
- immediate with rs1? */
- if (opcode->match == 0x80102000) /* or */
- imm_ored_to_rs1 = 1;
- if (opcode->match == 0x80002000) /* add */
- imm_added_to_rs1 = 1;
-
- if (X_RS1 (insn) != X_RD (insn)
- && strchr (opcode->args, 'r') != 0)
- /* Can't do simple format if source and dest are different. */
- continue;
- if (X_RS2 (insn) != X_RD (insn)
- && strchr (opcode->args, 'O') != 0)
- /* Can't do simple format if source and dest are different. */
- continue;
-
- (*info->fprintf_func) (stream, opcode->name);
-
- {
- register const char *s;
-
- if (opcode->args[0] != ',')
- (*info->fprintf_func) (stream, " ");
- for (s = opcode->args; *s != '\0'; ++s)
- {
- while (*s == ',')
- {
- (*info->fprintf_func) (stream, ",");
- ++s;
- switch (*s) {
- case 'a':
- (*info->fprintf_func) (stream, "a");
- is_annulled = 1;
- ++s;
- continue;
- case 'N':
- (*info->fprintf_func) (stream, "pn");
- ++s;
- continue;
-
- case 'T':
- (*info->fprintf_func) (stream, "pt");
- ++s;
- continue;
-
- default:
- break;
- } /* switch on arg */
- } /* while there are comma started args */
-
- (*info->fprintf_func) (stream, " ");
-
- switch (*s)
- {
- case '+':
- found_plus = 1;
-
- /* note fall-through */
- default:
- (*info->fprintf_func) (stream, "%c", *s);
- break;
-
- case '#':
- (*info->fprintf_func) (stream, "0");
- break;
-
-#define reg(n) (*info->fprintf_func) (stream, "%%%s", reg_names[n])
- case '1':
- case 'r':
- reg (X_RS1 (insn));
- break;
-
- case '2':
- case 'O':
- reg (X_RS2 (insn));
- break;
-
- case 'd':
- reg (X_RD (insn));
- break;
-#undef reg
-
-#define freg(n) (*info->fprintf_func) (stream, "%%%s", freg_names[n])
-#define fregx(n) (*info->fprintf_func) (stream, "%%%s", freg_names[((n) & ~1) | (((n) & 1) << 5)])
- case 'e':
- freg (X_RS1 (insn));
- break;
- case 'v': /* double/even */
- case 'V': /* quad/multiple of 4 */
- fregx (X_RS1 (insn));
- break;
-
- case 'f':
- freg (X_RS2 (insn));
- break;
- case 'B': /* double/even */
- case 'R': /* quad/multiple of 4 */
- fregx (X_RS2 (insn));
- break;
-
- case 'g':
- freg (X_RD (insn));
- break;
- case 'H': /* double/even */
- case 'J': /* quad/multiple of 4 */
- fregx (X_RD (insn));
- break;
-#undef freg
-#undef fregx
-
-#define creg(n) (*info->fprintf_func) (stream, "%%c%u", (unsigned int) (n))
- case 'b':
- creg (X_RS1 (insn));
- break;
-
- case 'c':
- creg (X_RS2 (insn));
- break;
-
- case 'D':
- creg (X_RD (insn));
- break;
-#undef creg
-
- case 'h':
- (*info->fprintf_func) (stream, "%%hi(%#x)",
- ((unsigned) 0xFFFFFFFF
- & ((int) X_IMM22 (insn) << 10)));
- break;
-
- case 'i': /* 13 bit immediate */
- case 'I': /* 11 bit immediate */
- case 'j': /* 10 bit immediate */
- {
- int imm;
-
- if (*s == 'i')
- imm = X_SIMM (insn, 13);
- else if (*s == 'I')
- imm = X_SIMM (insn, 11);
- else
- imm = X_SIMM (insn, 10);
-
- /* Check to see whether we have a 1+i, and take
- note of that fact.
-
- Note: because of the way we sort the table,
- we will be matching 1+i rather than i+1,
- so it is OK to assume that i is after +,
- not before it. */
- if (found_plus)
- imm_added_to_rs1 = 1;
-
- if (imm <= 9)
- (*info->fprintf_func) (stream, "%d", imm);
- else
- (*info->fprintf_func) (stream, "%#x", imm);
- }
- break;
-
- case 'X': /* 5 bit unsigned immediate */
- case 'Y': /* 6 bit unsigned immediate */
- {
- int imm = X_IMM (insn, *s == 'X' ? 5 : 6);
-
- if (imm <= 9)
- (info->fprintf_func) (stream, "%d", imm);
- else
- (info->fprintf_func) (stream, "%#x", (unsigned) imm);
- }
- break;
-
- case '3':
- (info->fprintf_func) (stream, "%d", X_IMM (insn, 3));
- break;
-
- case 'K':
- {
- int mask = X_MEMBAR (insn);
- int bit = 0x40, printed_one = 0;
- const char *name;
-
- if (mask == 0)
- (info->fprintf_func) (stream, "0");
- else
- while (bit)
- {
- if (mask & bit)
- {
- if (printed_one)
- (info->fprintf_func) (stream, "|");
- name = sparc_decode_membar (bit);
- (info->fprintf_func) (stream, "%s", name);
- printed_one = 1;
- }
- bit >>= 1;
- }
- break;
- }
-
- case 'k':
- info->target = memaddr + SEX (X_DISP16 (insn), 16) * 4;
- (*info->print_address_func) (info->target, info);
- break;
-
- case 'G':
- info->target = memaddr + SEX (X_DISP19 (insn), 19) * 4;
- (*info->print_address_func) (info->target, info);
- break;
-
- case '6':
- case '7':
- case '8':
- case '9':
- (*info->fprintf_func) (stream, "%%fcc%c", *s - '6' + '0');
- break;
-
- case 'z':
- (*info->fprintf_func) (stream, "%%icc");
- break;
-
- case 'Z':
- (*info->fprintf_func) (stream, "%%xcc");
- break;
-
- case 'E':
- (*info->fprintf_func) (stream, "%%ccr");
- break;
-
- case 's':
- (*info->fprintf_func) (stream, "%%fprs");
- break;
-
- case 'o':
- (*info->fprintf_func) (stream, "%%asi");
- break;
-
- case 'W':
- (*info->fprintf_func) (stream, "%%tick");
- break;
-
- case 'P':
- (*info->fprintf_func) (stream, "%%pc");
- break;
-
- case '?':
- if (X_RS1 (insn) == 31)
- (*info->fprintf_func) (stream, "%%ver");
- else if ((unsigned) X_RS1 (insn) < 16)
- (*info->fprintf_func) (stream, "%%%s",
- v9_priv_reg_names[X_RS1 (insn)]);
- else
- (*info->fprintf_func) (stream, "%%reserved");
- break;
-
- case '!':
- if ((unsigned) X_RD (insn) < 15)
- (*info->fprintf_func) (stream, "%%%s",
- v9_priv_reg_names[X_RD (insn)]);
- else
- (*info->fprintf_func) (stream, "%%reserved");
- break;
-
- case '/':
- if (X_RS1 (insn) < 16 || X_RS1 (insn) > 25)
- (*info->fprintf_func) (stream, "%%reserved");
- else
- (*info->fprintf_func) (stream, "%%%s",
- v9a_asr_reg_names[X_RS1 (insn)-16]);
- break;
-
- case '_':
- if (X_RD (insn) < 16 || X_RD (insn) > 25)
- (*info->fprintf_func) (stream, "%%reserved");
- else
- (*info->fprintf_func) (stream, "%%%s",
- v9a_asr_reg_names[X_RD (insn)-16]);
- break;
-
- case '*':
- {
- const char *name = sparc_decode_prefetch (X_RD (insn));
-
- if (name)
- (*info->fprintf_func) (stream, "%s", name);
- else
- (*info->fprintf_func) (stream, "%d", X_RD (insn));
- break;
- }
-
- case 'M':
- (*info->fprintf_func) (stream, "%%asr%d", X_RS1 (insn));
- break;
-
- case 'm':
- (*info->fprintf_func) (stream, "%%asr%d", X_RD (insn));
- break;
-
- case 'L':
- info->target = memaddr + SEX (X_DISP30 (insn), 30) * 4;
- (*info->print_address_func) (info->target, info);
- break;
-
- case 'n':
- (*info->fprintf_func)
- (stream, "%#x", SEX (X_DISP22 (insn), 22));
- break;
-
- case 'l':
- info->target = memaddr + SEX (X_DISP22 (insn), 22) * 4;
- (*info->print_address_func) (info->target, info);
- break;
-
- case 'A':
- {
- const char *name;
-
- if ((info->mach == bfd_mach_sparc_v8plusa) ||
- ((info->mach >= bfd_mach_sparc_v9) &&
- (info->mach <= bfd_mach_sparc_v9b)))
- name = sparc_decode_asi_v9 (X_ASI (insn));
- else
- name = sparc_decode_asi_v8 (X_ASI (insn));
-
- if (name)
- (*info->fprintf_func) (stream, "%s", name);
- else
- (*info->fprintf_func) (stream, "(%d)", X_ASI (insn));
- break;
- }
-
- case 'C':
- (*info->fprintf_func) (stream, "%%csr");
- break;
-
- case 'F':
- (*info->fprintf_func) (stream, "%%fsr");
- break;
-
- case 'p':
- (*info->fprintf_func) (stream, "%%psr");
- break;
-
- case 'q':
- (*info->fprintf_func) (stream, "%%fq");
- break;
-
- case 'Q':
- (*info->fprintf_func) (stream, "%%cq");
- break;
-
- case 't':
- (*info->fprintf_func) (stream, "%%tbr");
- break;
-
- case 'w':
- (*info->fprintf_func) (stream, "%%wim");
- break;
-
- case 'x':
- (*info->fprintf_func) (stream, "%d",
- ((X_LDST_I (insn) << 8)
- + X_ASI (insn)));
- break;
-
- case 'y':
- (*info->fprintf_func) (stream, "%%y");
- break;
-
- case 'u':
- case 'U':
- {
- int val = *s == 'U' ? X_RS1 (insn) : X_RD (insn);
- const char *name = sparc_decode_sparclet_cpreg (val);
-
- if (name)
- (*info->fprintf_func) (stream, "%s", name);
- else
- (*info->fprintf_func) (stream, "%%cpreg(%d)", val);
- break;
- }
- }
- }
- }
-
- /* If we are adding or or'ing something to rs1, then
- check to see whether the previous instruction was
- a sethi to the same register as in the sethi.
- If so, attempt to print the result of the add or
- or (in this context add and or do the same thing)
- and its symbolic value. */
- if (imm_ored_to_rs1 || imm_added_to_rs1)
- {
- unsigned long prev_insn;
- int errcode;
-
- errcode =
- (*info->read_memory_func)
- (memaddr - 4, buffer, sizeof (buffer), info);
- prev_insn = getword (buffer);
-
- if (errcode == 0)
- {
- /* If it is a delayed branch, we need to look at the
- instruction before the delayed branch. This handles
- sequences such as
-
- sethi %o1, %hi(_foo), %o1
- call _printf
- or %o1, %lo(_foo), %o1
- */
-
- if (is_delayed_branch (prev_insn))
- {
- errcode = (*info->read_memory_func)
- (memaddr - 8, buffer, sizeof (buffer), info);
- prev_insn = getword (buffer);
- }
- }
-
- /* If there was a problem reading memory, then assume
- the previous instruction was not sethi. */
- if (errcode == 0)
- {
- /* Is it sethi to the same register? */
- if ((prev_insn & 0xc1c00000) == 0x01000000
- && X_RD (prev_insn) == X_RS1 (insn))
- {
- (*info->fprintf_func) (stream, "\t! ");
- info->target =
- ((unsigned) 0xFFFFFFFF
- & ((int) X_IMM22 (prev_insn) << 10));
- if (imm_added_to_rs1)
- info->target += X_SIMM (insn, 13);
- else
- info->target |= X_SIMM (insn, 13);
- (*info->print_address_func) (info->target, info);
- info->insn_type = dis_dref;
- info->data_size = 4; /* FIXME!!! */
- }
- }
- }
-
- if (opcode->flags & (F_UNBR|F_CONDBR|F_JSR))
- {
- /* FIXME -- check is_annulled flag */
- if (opcode->flags & F_UNBR)
- info->insn_type = dis_branch;
- if (opcode->flags & F_CONDBR)
- info->insn_type = dis_condbranch;
- if (opcode->flags & F_JSR)
- info->insn_type = dis_jsr;
- if (opcode->flags & F_DELAYED)
- info->branch_delay_insns = 1;
- }
-
- return sizeof (buffer);
- }
- }
-
- info->insn_type = dis_noninsn; /* Mark as non-valid instruction */
- (*info->fprintf_func) (stream, _("unknown"));
- return sizeof (buffer);
-}
-
-/* Given BFD mach number, return a mask of SPARC_OPCODE_ARCH_FOO values. */
-
-static int
-compute_arch_mask (mach)
- unsigned long mach;
-{
- switch (mach)
- {
- case 0 :
- case bfd_mach_sparc :
- return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8);
- case bfd_mach_sparc_sparclet :
- return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLET);
- case bfd_mach_sparc_sparclite :
- case bfd_mach_sparc_sparclite_le :
- /* sparclites insns are recognized by default (because that's how
- they've always been treated, for better or worse). Kludge this by
- indicating generic v8 is also selected. */
- return (SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_SPARCLITE)
- | SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V8));
- case bfd_mach_sparc_v8plus :
- case bfd_mach_sparc_v9 :
- return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9);
- case bfd_mach_sparc_v8plusa :
- case bfd_mach_sparc_v9a :
- return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9A);
- case bfd_mach_sparc_v8plusb :
- case bfd_mach_sparc_v9b :
- return SPARC_OPCODE_ARCH_MASK (SPARC_OPCODE_ARCH_V9B);
- }
- abort ();
-}
-
-/* Compare opcodes A and B. */
-
-static int
-compare_opcodes (const void *a, const void *b)
-{
- struct sparc_opcode *op0 = * (struct sparc_opcode **) a;
- struct sparc_opcode *op1 = * (struct sparc_opcode **) b;
- unsigned long int match0 = op0->match, match1 = op1->match;
- unsigned long int lose0 = op0->lose, lose1 = op1->lose;
- register unsigned int i;
-
- /* If one (and only one) insn isn't supported by the current architecture,
- prefer the one that is. If neither are supported, but they're both for
- the same architecture, continue processing. Otherwise (both unsupported
- and for different architectures), prefer lower numbered arch's (fudged
- by comparing the bitmasks). */
- if (op0->architecture & current_arch_mask)
- {
- if (! (op1->architecture & current_arch_mask))
- return -1;
- }
- else
- {
- if (op1->architecture & current_arch_mask)
- return 1;
- else if (op0->architecture != op1->architecture)
- return op0->architecture - op1->architecture;
- }
-
- /* If a bit is set in both match and lose, there is something
- wrong with the opcode table. */
- if (match0 & lose0)
- {
- fprintf
- (stderr,
- /* xgettext:c-format */
- _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"),
- op0->name, match0, lose0);
- op0->lose &= ~op0->match;
- lose0 = op0->lose;
- }
-
- if (match1 & lose1)
- {
- fprintf
- (stderr,
- /* xgettext:c-format */
- _("Internal error: bad sparc-opcode.h: \"%s\", %#.8lx, %#.8lx\n"),
- op1->name, match1, lose1);
- op1->lose &= ~op1->match;
- lose1 = op1->lose;
- }
-
- /* Because the bits that are variable in one opcode are constant in
- another, it is important to order the opcodes in the right order. */
- for (i = 0; i < 32; ++i)
- {
- unsigned long int x = 1 << i;
- int x0 = (match0 & x) != 0;
- int x1 = (match1 & x) != 0;
-
- if (x0 != x1)
- return x1 - x0;
- }
-
- for (i = 0; i < 32; ++i)
- {
- unsigned long int x = 1 << i;
- int x0 = (lose0 & x) != 0;
- int x1 = (lose1 & x) != 0;
-
- if (x0 != x1)
- return x1 - x0;
- }
-
- /* They are functionally equal. So as long as the opcode table is
- valid, we can put whichever one first we want, on aesthetic grounds. */
-
- /* Our first aesthetic ground is that aliases defer to real insns. */
- {
- int alias_diff = (op0->flags & F_ALIAS) - (op1->flags & F_ALIAS);
- if (alias_diff != 0)
- /* Put the one that isn't an alias first. */
- return alias_diff;
- }
-
- /* Except for aliases, two "identical" instructions had
- better have the same opcode. This is a sanity check on the table. */
- i = strcmp (op0->name, op1->name);
- if (i)
- {
- if (op0->flags & F_ALIAS) /* If they're both aliases, be arbitrary. */
- return i;
- else
- fprintf (stderr,
- /* xgettext:c-format */
- _("Internal error: bad sparc-opcode.h: \"%s\" == \"%s\"\n"),
- op0->name, op1->name);
- }
-
- /* Fewer arguments are preferred. */
- {
- int length_diff = strlen (op0->args) - strlen (op1->args);
- if (length_diff != 0)
- /* Put the one with fewer arguments first. */
- return length_diff;
- }
-
- /* Put 1+i before i+1. */
- {
- char *p0 = (char *) strchr (op0->args, '+');
- char *p1 = (char *) strchr (op1->args, '+');
-
- if (p0 && p1)
- {
- /* There is a plus in both operands. Note that a plus
- sign cannot be the first character in args,
- so the following [-1]'s are valid. */
- if (p0[-1] == 'i' && p1[1] == 'i')
- /* op0 is i+1 and op1 is 1+i, so op1 goes first. */
- return 1;
- if (p0[1] == 'i' && p1[-1] == 'i')
- /* op0 is 1+i and op1 is i+1, so op0 goes first. */
- return -1;
- }
- }
-
- /* Put 1,i before i,1. */
- {
- int i0 = strncmp (op0->args, "i,1", 3) == 0;
- int i1 = strncmp (op1->args, "i,1", 3) == 0;
-
- if (i0 ^ i1)
- return i0 - i1;
- }
-
- /* They are, as far as we can tell, identical.
- Since qsort may have rearranged the table partially, there is
- no way to tell which one was first in the opcode table as
- written, so just say there are equal. */
- /* ??? This is no longer true now that we sort a vector of pointers,
- not the table itself. */
- return 0;
-}
-
-/* Build a hash table from the opcode table.
- OPCODE_TABLE is a sorted list of pointers into the opcode table. */
-
-static void
-build_hash_table (opcode_table, hash_table, num_opcodes)
- const struct sparc_opcode **opcode_table;
- struct opcode_hash **hash_table;
- int num_opcodes;
-{
- register int i;
- int hash_count[HASH_SIZE];
- static struct opcode_hash *hash_buf = NULL;
-
- /* Start at the end of the table and work backwards so that each
- chain is sorted. */
-
- memset (hash_table, 0, HASH_SIZE * sizeof (hash_table[0]));
- memset (hash_count, 0, HASH_SIZE * sizeof (hash_count[0]));
- if (hash_buf != NULL)
- free (hash_buf);
- hash_buf = (struct opcode_hash *) malloc (sizeof (struct opcode_hash) * num_opcodes);
- for (i = num_opcodes - 1; i >= 0; --i)
- {
- register int hash = HASH_INSN (opcode_table[i]->match);
- register struct opcode_hash *h = &hash_buf[i];
- h->next = hash_table[hash];
- h->opcode = opcode_table[i];
- hash_table[hash] = h;
- ++hash_count[hash];
- }
-
-#if 0 /* for debugging */
- {
- int min_count = num_opcodes, max_count = 0;
- int total;
-
- for (i = 0; i < HASH_SIZE; ++i)
- {
- if (hash_count[i] < min_count)
- min_count = hash_count[i];
- if (hash_count[i] > max_count)
- max_count = hash_count[i];
- total += hash_count[i];
- }
-
- printf ("Opcode hash table stats: min %d, max %d, ave %f\n",
- min_count, max_count, (double) total / HASH_SIZE);
- }
-#endif
-}
diff --git a/tap-win32.c b/tap-win32.c
index af5e25e..6913c55 100644
--- a/tap-win32.c
+++ b/tap-win32.c
@@ -635,7 +635,7 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle,
static TAPState *tap_win32_state = NULL;
-static void tap_receive(void *opaque, const uint8_t *buf, int size)
+void tap_receive(void *opaque, const uint8_t *buf, int size)
{
TAPState *s = opaque;
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 75a1f13..a613b77 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1,6 +1,6 @@
/*
* ARM virtual CPU header
- *
+ *
* Copyright (c) 2003 Fabrice Bellard
*
* This library is free software; you can redistribute it and/or
@@ -26,6 +26,8 @@
#include "softfloat.h"
+#define ARM_CPU_SAVE_VERSION 1
+
#define TARGET_HAS_ICE 1
#define EXCP_UDEF 1 /* undefined instruction */
@@ -57,11 +59,11 @@ typedef struct CPUARMState {
uint32_t banked_spsr[6];
uint32_t banked_r13[6];
uint32_t banked_r14[6];
-
+
/* These hold r8-r12. */
uint32_t usr_regs[5];
uint32_t fiq_regs[5];
-
+
/* cpsr flag cache for faster execution */
uint32_t CF; /* 0 or 1 */
uint32_t VF; /* V is the bit 31. All other bits are undefined */
@@ -109,7 +111,7 @@ typedef struct CPUARMState {
/* Temporary variables if we don't have spare fp regs. */
float32 tmp0s, tmp1s;
float64 tmp0d, tmp1d;
-
+
float_status fp_status;
} vfp;
@@ -132,7 +134,7 @@ void switch_mode(CPUARMState *, int);
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, struct siginfo *info,
void *puc);
#define CPSR_M (0x1f)
@@ -154,7 +156,7 @@ static inline uint32_t cpsr_read(CPUARMState *env)
{
int ZF;
ZF = (env->NZF == 0);
- return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
+ return env->uncached_cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
(env->CF << 29) | ((env->VF & 0x80000000) >> 3) | (env->QF << 27)
| (env->thumb << 5);
}
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 2ed46a2..b78f7d1 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -4,6 +4,9 @@
#include "cpu.h"
#include "exec-all.h"
+#ifdef CONFIG_TRACE
+#include "trace.h"
+#endif
void cpu_reset(CPUARMState *env)
{
@@ -60,7 +63,7 @@ void cpu_arm_close(CPUARMState *env)
free(env);
}
-#if defined(CONFIG_USER_ONLY)
+#if defined(CONFIG_USER_ONLY)
void do_interrupt (CPUState *env)
{
@@ -163,6 +166,11 @@ void do_interrupt(CPUARMState *env)
int new_mode;
uint32_t offset;
+#ifdef CONFIG_TRACE
+ if (tracing)
+ trace_exception(env->regs[15]);
+#endif
+
/* TODO: Vectored interrupt controller. */
switch (env->exception_index) {
case EXCP_UDEF:
@@ -239,7 +247,7 @@ static inline int check_ap(CPUState *env, int ap, int domain, int access_type,
switch (ap) {
case 0:
- if (access_type != 1)
+ if (access_type == 1)
return 0;
switch ((env->cp15.c1_sys >> 8) & 3) {
case 1:
@@ -420,6 +428,7 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
break;
case 3: /* MMU Domain access control. */
env->cp15.c3 = val;
+ tlb_flush(env, 1);
break;
case 4: /* Reserved. */
goto bad_reg;
@@ -466,7 +475,7 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
tlb_flush_page(env, val + 0x800);
tlb_flush_page(env, val + 0xc00);
#else
- tlb_flush(env, 1);
+ //tlb_flush(env, 1);
#endif
break;
default:
@@ -494,18 +503,10 @@ void helper_set_cp15(CPUState *env, uint32_t insn, uint32_t val)
case 13: /* Process ID. */
switch (op2) {
case 0:
- /* Unlike real hardware the qemu TLB uses virtual addresses,
- not modified virtual addresses, so this causes a TLB flush.
- */
- if (env->cp15.c13_fcse != val)
- tlb_flush(env, 1);
- env->cp15.c13_fcse = val;
+ env->cp15.c9_data = val;
break;
case 1:
- /* This changes the ASID, so do a TLB flush. */
- if (env->cp15.c13_context != val)
- tlb_flush(env, 0);
- env->cp15.c13_context = val;
+ env->cp15.c9_insn = val;
break;
default:
goto bad_reg;
diff --git a/target-arm/op.c b/target-arm/op.c
index f17b812..48a81de 100644
--- a/target-arm/op.c
+++ b/target-arm/op.c
@@ -19,6 +19,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "exec.h"
+#ifdef GEN_TRACE
+#include "trace.h"
+#endif
#define REGNAME r0
#define REG (env->regs[0])
@@ -85,6 +88,30 @@
#define SET_REG(x) REG = x & ~(uint32_t)1
#include "op_template.h"
+#ifdef GEN_TRACE
+void OPPROTO op_shutdown(void)
+{
+ extern void qemu_system_shutdown_request(void);
+ qemu_system_shutdown_request();
+ EXIT_TB();
+}
+
+void OPPROTO op_trace_bb(void)
+{
+ trace_bb_helper(PARAM1, (TranslationBlock *)PARAM2);
+}
+
+void OPPROTO op_trace_insn(void)
+{
+ trace_insn_helper();
+}
+
+void OPPROTO op_add_to_sim_time(void)
+{
+ sim_time += PARAM1;
+}
+#endif
+
void OPPROTO op_bx_T0(void)
{
env->regs[15] = T0 & ~(uint32_t)1;
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index af5c61d..acc83ba 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -177,8 +177,11 @@ void do_vfp_get_fpscr(void)
#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 GETPC() (__builtin_return_address(0))
+#define ALIGNED_ONLY 1
#define SHIFT 0
#include "softmmu_template.h"
@@ -192,6 +195,19 @@ void do_vfp_get_fpscr(void)
#define SHIFT 3
#include "softmmu_template.h"
+static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
+{
+ //printf("::UNALIGNED:: addr=%lx is_write=%d is_user=%d retaddr=%p\n", addr, is_write, is_user, retaddr);
+ if (is_user)
+ {
+ env = cpu_single_env;
+ env->cp15.c5_data = 0x00000001; /* corresponds to an alignment fault */
+ env->cp15.c6_data = addr;
+ env->exception_index = EXCP_DATA_ABORT;
+ cpu_loop_exit();
+ }
+}
+
/* 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) */
@@ -224,4 +240,114 @@ void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
env = saved_env;
}
+#if 1
+#include <string.h>
+/*
+ * The following functions are address translation helper functions
+ * for fast memory access in QEMU.
+ */
+static unsigned long v2p_mmu(target_ulong addr, int is_user)
+{
+ int index;
+ target_ulong tlb_addr;
+ target_phys_addr_t physaddr;
+ void *retaddr;
+
+ index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+redo:
+ tlb_addr = env->tlb_table[is_user][index].addr_read;
+ if ((addr & TARGET_PAGE_MASK) == (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+ physaddr = addr + env->tlb_table[is_user][index].addend;
+ } else {
+ /* the page is not in the TLB : fill it */
+ retaddr = GETPC();
+ tlb_fill(addr, 0, is_user, retaddr);
+ goto redo;
+ }
+ return physaddr;
+}
+
+/*
+ * translation from virtual address of simulated OS
+ * to the address of simulation host (not the physical
+ * address of simulated OS.
+ */
+unsigned long v2p(target_ulong ptr, int is_user)
+{
+ CPUState *saved_env;
+ int index;
+ target_ulong addr;
+ unsigned long physaddr;
+
+ saved_env = env;
+ env = cpu_single_env;
+ addr = ptr;
+ index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ if (__builtin_expect(env->tlb_table[is_user][index].addr_read !=
+ (addr & TARGET_PAGE_MASK), 0)) {
+ return v2p_mmu(addr, is_user);
+ } else {
+ physaddr = addr + env->tlb_table[is_user][index].addend;
+ }
+ env = saved_env;
+ return physaddr;
+}
+
+#define MINSIZE(x,y) ((x) < (y) ? (x) : (y))
+/* copy memory from the simulated virtual space to a buffer in QEMU */
+void vmemcpy(target_ulong ptr, char *buf, int size)
+{
+ if (buf == NULL) return;
+ while (size) {
+ int page_remain = TARGET_PAGE_SIZE - (ptr & ~TARGET_PAGE_MASK);
+ int to_copy = MINSIZE(size, page_remain);
+ char *phys = (char *)v2p(ptr, 0);
+ if (phys == NULL) return;
+ memcpy(buf, phys, to_copy);
+ ptr += to_copy;
+ buf += to_copy;
+ size -= to_copy;
+ }
+}
+
+/* copy memory from the QEMU buffer to simulated virtual space */
+void pmemcpy(target_ulong ptr, char *buf, int size)
+{
+ if (buf == NULL) return;
+ while (size) {
+ int page_remain = TARGET_PAGE_SIZE - (ptr & ~TARGET_PAGE_MASK);
+ int to_copy = MINSIZE(size, page_remain);
+ char *phys = (char *)v2p(ptr, 0);
+ if (phys == NULL) return;
+ memcpy(phys, buf, to_copy);
+ ptr += to_copy;
+ buf += to_copy;
+ size -= to_copy;
+ }
+}
+
+/* copy a string from the simulated virtual space to a buffer in QEMU */
+void vstrcpy(target_ulong ptr, char *buf, int max)
+{
+ char *phys = 0;
+ unsigned long page = 0;
+
+ if (buf == NULL) return;
+
+ while (max) {
+ if ((ptr & TARGET_PAGE_MASK) != page) {
+ phys = (char *)v2p(ptr, 0);
+ page = ptr & TARGET_PAGE_MASK;
+ }
+ *buf = *phys;
+ if (*phys == '\0')
+ return;
+ ptr ++;
+ buf ++;
+ phys ++;
+ max --;
+ }
+}
+#endif
+
#endif
diff --git a/target-arm/op_mem.h b/target-arm/op_mem.h
index 29fd85b..9d4d5c0 100644
--- a/target-arm/op_mem.h
+++ b/target-arm/op_mem.h
@@ -1,12 +1,26 @@
/* ARM memory operations. */
+#ifdef GEN_TRACE
/* Load from address T1 into T0. */
#define MEM_LD_OP(name) \
void OPPROTO glue(op_ld##name,MEMSUFFIX)(void) \
{ \
+ extern int tracing; \
+ extern void dcache_load(uint32_t addr); \
+ if (tracing) \
+ dcache_load(T1); \
T0 = glue(ld##name,MEMSUFFIX)(T1); \
FORCE_RET(); \
}
+#else
+/* Load from address T1 into T0. */
+#define MEM_LD_OP(name) \
+void OPPROTO glue(op_ld##name,MEMSUFFIX)(void) \
+{ \
+ T0 = glue(ld##name,MEMSUFFIX)(T1); \
+ FORCE_RET(); \
+}
+#endif
MEM_LD_OP(ub)
MEM_LD_OP(sb)
@@ -16,6 +30,19 @@ MEM_LD_OP(l)
#undef MEM_LD_OP
+#ifdef GEN_TRACE
+/* Store T0 to address T1. */
+#define MEM_ST_OP(name) \
+void OPPROTO glue(op_st##name,MEMSUFFIX)(void) \
+{ \
+ extern int tracing; \
+ extern void dcache_store(uint32_t addr, uint32_t val); \
+ if (tracing) \
+ dcache_store(T1, T0); \
+ glue(st##name,MEMSUFFIX)(T1, T0); \
+ FORCE_RET(); \
+}
+#else
/* Store T0 to address T1. */
#define MEM_ST_OP(name) \
void OPPROTO glue(op_st##name,MEMSUFFIX)(void) \
@@ -23,6 +50,7 @@ void OPPROTO glue(op_st##name,MEMSUFFIX)(void) \
glue(st##name,MEMSUFFIX)(T1, T0); \
FORCE_RET(); \
}
+#endif
MEM_ST_OP(b)
MEM_ST_OP(w)
@@ -30,6 +58,25 @@ MEM_ST_OP(l)
#undef MEM_ST_OP
+#ifdef GEN_TRACE
+/* Swap T0 with memory at address T1. */
+/* ??? Is this exception safe? */
+#define MEM_SWP_OP(name, lname) \
+void OPPROTO glue(op_swp##name,MEMSUFFIX)(void) \
+{ \
+ extern int tracing; \
+ extern void dcache_swp(uint32_t addr); \
+ uint32_t tmp; \
+ cpu_lock(); \
+ if (tracing) \
+ dcache_swp(T1); \
+ tmp = glue(ld##lname,MEMSUFFIX)(T1); \
+ glue(st##name,MEMSUFFIX)(T1, T0); \
+ T0 = tmp; \
+ cpu_unlock(); \
+ FORCE_RET(); \
+}
+#else
/* Swap T0 with memory at address T1. */
/* ??? Is this exception safe? */
#define MEM_SWP_OP(name, lname) \
@@ -43,6 +90,7 @@ void OPPROTO glue(op_swp##name,MEMSUFFIX)(void) \
cpu_unlock(); \
FORCE_RET(); \
}
+#endif
MEM_SWP_OP(b, ub)
MEM_SWP_OP(l, l)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index fa7ad60..663a730 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -1,6 +1,6 @@
/*
* ARM translation
- *
+ *
* Copyright (c) 2003 Fabrice Bellard
* Copyright (c) 2005 CodeSourcery, LLC
*
@@ -27,6 +27,14 @@
#include "cpu.h"
#include "exec-all.h"
#include "disas.h"
+#ifdef GEN_TRACE
+#include "trace.h"
+#endif
+
+typedef int (*gen_intermediate_code_func)(CPUState *env, struct TranslationBlock *tb);
+
+extern gen_intermediate_code_func _gen_intermediate_code;
+extern gen_intermediate_code_func _gen_intermediate_code_pc;
#define ENABLE_ARCH_5J 0
#define ENABLE_ARCH_6 1
@@ -72,12 +80,20 @@ extern int loglevel;
enum {
#define DEF(s, n, copy_size) INDEX_op_ ## s,
+#ifdef GEN_TRACE
+#include "opc-trace.h"
+#else
#include "opc.h"
+#endif
#undef DEF
NB_OPS,
};
+#ifdef GEN_TRACE
+#include "gen-op-trace.h"
+#else
#include "gen-op.h"
+#endif
static GenOpFunc1 *gen_test_cc[14] = {
gen_op_test_eq,
@@ -96,7 +112,7 @@ static GenOpFunc1 *gen_test_cc[14] = {
gen_op_test_le,
};
-const uint8_t table_logic_cc[16] = {
+static const uint8_t table_logic_cc[16] = {
1, /* and */
1, /* xor */
0, /* sub */
@@ -114,7 +130,7 @@ const uint8_t table_logic_cc[16] = {
1, /* bic */
1, /* mvn */
};
-
+
static GenOpFunc1 *gen_shift_T1_im[4] = {
gen_op_shll_T1_im,
gen_op_shrl_T1_im,
@@ -387,13 +403,13 @@ static inline void gen_add_datah_offset(DisasContext *s, unsigned int insn,
int extra)
{
int val, rm;
-
+
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 {
@@ -687,7 +703,7 @@ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
delta_m = 0;
delta_d = 0;
bank_mask = 0;
-
+
if (veclen > 0) {
if (dp)
bank_mask = 0xc;
@@ -1108,12 +1124,26 @@ static void gen_exception_return(DisasContext *s)
static void disas_arm_insn(CPUState * env, DisasContext *s)
{
unsigned int cond, insn, val, op1, i, shift, rm, rs, rn, rd, sh;
-
+#ifdef GEN_TRACE
+ int insn_ticks = 0;
+#endif
+
insn = ldl_code(s->pc);
+#ifdef GEN_TRACE
+ if (tracing) {
+ trace_add_insn(insn, 0 /* not thumb */);
+ insn_ticks = get_insn_ticks(insn);
+ gen_op_trace_insn();
+ }
+#endif
s->pc += 4;
-
+
cond = insn >> 28;
if (cond == 0xf){
+#ifdef GEN_TRACE
+ if (tracing)
+ gen_op_add_to_sim_time(insn_ticks);
+#endif
/* Unconditional instructions. */
if ((insn & 0x0d70f000) == 0x0550f000)
return; /* PLD */
@@ -1150,6 +1180,13 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
goto illegal_op;
}
if (cond != 0xe) {
+#ifdef GEN_TRACE
+ if (tracing) {
+ /* a non-executed conditional instruction takes only 1 cycle */
+ gen_op_add_to_sim_time(1);
+ insn_ticks -= 1;
+ }
+#endif
/* if not always execute, we generate a conditional jump to
next instruction */
s->condlabel = gen_new_label();
@@ -1158,6 +1195,10 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
//gen_test_cc[cond ^ 1]((long)s->tb, (long)s->pc);
//s->is_jmp = DISAS_JUMP_NEXT;
}
+#ifdef GEN_TRACE
+ if (tracing)
+ gen_op_add_to_sim_time(insn_ticks);
+#endif
if ((insn & 0x0f900000) == 0x03000000) {
if ((insn & 0x0fb0f000) != 0x0320f000)
goto illegal_op;
@@ -1299,7 +1340,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
(insn & 0x00000090) != 0x90) ||
((insn & 0x0e000000) == (1 << 25))) {
int set_cc, logic_cc, shiftop;
-
+
op1 = (insn >> 21) & 0xf;
set_cc = (insn >> 20) & 1;
logic_cc = table_logic_cc[op1] & set_cc;
@@ -1490,14 +1531,14 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
gen_movl_T1_reg(s, rn);
gen_op_addl_T0_T1();
}
- if (insn & (1 << 20))
+ if (insn & (1 << 20))
gen_op_logic_T0_cc();
gen_movl_reg_T0(s, rd);
} else {
/* 64 bit mul */
gen_movl_T0_reg(s, rs);
gen_movl_T1_reg(s, rm);
- if (insn & (1 << 22))
+ if (insn & (1 << 22))
gen_op_imull_T0_T1();
else
gen_op_mull_T0_T1();
@@ -1508,7 +1549,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
gen_op_addq_lo_T0_T1(rn);
gen_op_addq_lo_T0_T1(rd);
}
- if (insn & (1 << 20))
+ if (insn & (1 << 20))
gen_op_logicq_cc();
gen_movl_reg_T0(s, rn);
gen_movl_reg_T1(s, rd);
@@ -1522,7 +1563,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
} else {
/* SWP instruction */
rm = (insn) & 0xf;
-
+
gen_movl_T0_reg(s, rm);
gen_movl_T1_reg(s, rn);
if (insn & (1 << 22)) {
@@ -1594,6 +1635,18 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
case 0x5:
case 0x6:
case 0x7:
+#ifdef GEN_TRACE
+ /* Added a special undefined instruction to cause the
+ * simulator to exit. This allows us to write short assembly
+ * language tests that can exit the simulator.
+ */
+#define EXIT_SIMULATION 0xe6c00110
+ if (insn == EXIT_SIMULATION) {
+ gen_op_shutdown();
+ break;
+ }
+#endif
+
/* Check for undefined extension instructions
* per the ARM Bible IE:
* xxxx 0111 1111 xxxx xxxx xxxx 1111 xxxx
@@ -1679,7 +1732,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
}
rn = (insn >> 16) & 0xf;
gen_movl_T1_reg(s, rn);
-
+
/* compute total size */
loaded_base = 0;
n = 0;
@@ -1724,8 +1777,8 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
} else {
/* store */
if (i == 15) {
- /* special case: r15 = PC + 12 */
- val = (long)s->pc + 8;
+ /* special case: r15 = PC + 8 (was 12) */
+ val = (long)s->pc + 4;
gen_op_movl_TN_im[0](val);
} else if (user) {
gen_op_movl_T0_user(i);
@@ -1777,7 +1830,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
case 0xb:
{
int32_t offset;
-
+
/* branch (and link) */
val = (int32_t)s->pc;
if (insn & (1 << 24)) {
@@ -1834,6 +1887,16 @@ static void disas_thumb_insn(DisasContext *s)
int i;
insn = lduw_code(s->pc);
+#ifdef GEN_TRACE
+ if (tracing) {
+ int insn_ticks;
+
+ trace_add_insn( insn_wrap_thumb(insn), 1 /* thumb insn */ );
+ insn_ticks = get_insn_ticks_thumb(insn);
+ gen_op_trace_insn();
+ gen_op_add_to_sim_time(insn_ticks);
+ }
+#endif
s->pc += 2;
switch (insn >> 12) {
@@ -2357,12 +2420,22 @@ static void disas_thumb_insn(DisasContext *s)
}
offset = ((int32_t)insn << 21) >> 10;
insn = lduw_code(s->pc);
+#ifdef GEN_TRACE
+ if (tracing) {
+ int insn_ticks;
+
+ trace_add_insn( insn_wrap_thumb(insn), 1 /* thumb insn */ );
+ insn_ticks = get_insn_ticks_thumb(insn);
+ gen_op_trace_insn();
+ gen_op_add_to_sim_time(insn_ticks);
+ }
+#endif
offset |= insn & 0x7ff;
val = (uint32_t)s->pc + 2;
gen_op_movl_T1_im(val | 1);
gen_movl_reg_T1(s, 14);
-
+
val += offset << 1;
if (insn & (1 << 12)) {
/* bl */
@@ -2385,8 +2458,8 @@ undef:
/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
basic block 'tb'. If search_pc is TRUE, also generate PC
information for each intermediate instruction. */
-static inline int gen_intermediate_code_internal(CPUState *env,
- TranslationBlock *tb,
+static inline int gen_intermediate_code_internal(CPUState *env,
+ TranslationBlock *tb,
int search_pc)
{
DisasContext dc1, *dc = &dc1;
@@ -2394,10 +2467,10 @@ static inline int gen_intermediate_code_internal(CPUState *env,
int j, lj;
target_ulong pc_start;
uint32_t next_page_start;
-
+
/* generate intermediate code */
pc_start = tb->pc;
-
+
dc->tb = tb;
gen_opc_ptr = gen_opc_buf;
@@ -2415,6 +2488,12 @@ static inline int gen_intermediate_code_internal(CPUState *env,
next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
nb_gen_labels = 0;
lj = -1;
+#ifdef GEN_TRACE
+ if (tracing) {
+ gen_op_trace_bb(trace_static.bb_num, (long) tb);
+ trace_bb_start(dc->pc);
+ }
+#endif
do {
if (env->nb_breakpoints > 0) {
for(j = 0; j < env->nb_breakpoints; j++) {
@@ -2454,6 +2533,12 @@ static inline int gen_intermediate_code_internal(CPUState *env,
} while (!dc->is_jmp && gen_opc_ptr < gen_opc_end &&
!env->singlestep_enabled &&
dc->pc < next_page_start);
+#ifdef GEN_TRACE
+ if (tracing) {
+ trace_bb_end();
+ }
+#endif
+
/* At this stage dc->condjmp will only be set when the skipped
* instruction was a conditional branch, and the PC has already been
* written. */
@@ -2518,21 +2603,58 @@ static inline int gen_intermediate_code_internal(CPUState *env,
return 0;
}
-int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+#if defined(GEN_TRACE)
+static int trace_gen_intermediate_code(CPUState *env, TranslationBlock *tb)
{
return gen_intermediate_code_internal(env, tb, 0);
}
-int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+static int trace_gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+ return gen_intermediate_code_internal(env, tb, 1);
+}
+
+void qemu_trace_enable(void)
+{
+ _gen_intermediate_code = trace_gen_intermediate_code;
+ _gen_intermediate_code_pc = trace_gen_intermediate_code_pc;
+}
+#else
+
+static int default_gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+ return gen_intermediate_code_internal(env, tb, 0);
+}
+
+static int default_gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
{
return gen_intermediate_code_internal(env, tb, 1);
}
-static const char *cpu_mode_names[16] = {
+gen_intermediate_code_func _gen_intermediate_code = default_gen_intermediate_code;
+gen_intermediate_code_func _gen_intermediate_code_pc = default_gen_intermediate_code_pc;
+
+int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
+{
+ return (*_gen_intermediate_code)(env, tb);
+}
+
+int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
+{
+ return (*_gen_intermediate_code_pc)(env, tb);
+}
+
+void qemu_trace_disable( void )
+{
+ _gen_intermediate_code = default_gen_intermediate_code;
+ _gen_intermediate_code_pc = default_gen_intermediate_code_pc;
+}
+
+static const char * const cpu_mode_names[16] = {
"usr", "fiq", "irq", "svc", "???", "???", "???", "abt",
"???", "???", "???", "und", "???", "???", "???", "sys"
};
-void cpu_dump_state(CPUState *env, FILE *f,
+void cpu_dump_state(CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags)
{
@@ -2552,13 +2674,13 @@ void cpu_dump_state(CPUState *env, FILE *f,
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 %x\n",
+ psr,
psr & (1 << 31) ? 'N' : '-',
psr & (1 << 30) ? 'Z' : '-',
psr & (1 << 29) ? 'C' : '-',
psr & (1 << 28) ? 'V' : '-',
- psr & CPSR_T ? 'T' : 'A',
+ psr & CPSR_T ? 'T' : 'A',
cpu_mode_names[psr & 0xf], (psr & 0x10) ? 32 : 26);
for (i = 0; i < 16; i++) {
@@ -2574,3 +2696,4 @@ void cpu_dump_state(CPUState *env, FILE *f,
cpu_fprintf(f, "FPSCR: %08x\n", (int)env->vfp.xregs[ARM_VFP_FPSCR]);
}
+#endif
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
deleted file mode 100644
index 2f23617..0000000
--- a/target-i386/cpu.h
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * i386 virtual CPU header
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifndef CPU_I386_H
-#define CPU_I386_H
-
-#include "config.h"
-
-#ifdef TARGET_X86_64
-#define TARGET_LONG_BITS 64
-#else
-#define TARGET_LONG_BITS 32
-#endif
-
-/* target supports implicit self modifying code */
-#define TARGET_HAS_SMC
-/* support for self modifying code even if the modified instruction is
- close to the modifying instruction */
-#define TARGET_HAS_PRECISE_SMC
-
-#define TARGET_HAS_ICE 1
-
-#include "cpu-defs.h"
-
-#include "softfloat.h"
-
-#if defined(__i386__) && !defined(CONFIG_SOFTMMU)
-#define USE_CODE_COPY
-#endif
-
-#define R_EAX 0
-#define R_ECX 1
-#define R_EDX 2
-#define R_EBX 3
-#define R_ESP 4
-#define R_EBP 5
-#define R_ESI 6
-#define R_EDI 7
-
-#define R_AL 0
-#define R_CL 1
-#define R_DL 2
-#define R_BL 3
-#define R_AH 4
-#define R_CH 5
-#define R_DH 6
-#define R_BH 7
-
-#define R_ES 0
-#define R_CS 1
-#define R_SS 2
-#define R_DS 3
-#define R_FS 4
-#define R_GS 5
-
-/* segment descriptor fields */
-#define DESC_G_MASK (1 << 23)
-#define DESC_B_SHIFT 22
-#define DESC_B_MASK (1 << DESC_B_SHIFT)
-#define DESC_L_SHIFT 21 /* x86_64 only : 64 bit code segment */
-#define DESC_L_MASK (1 << DESC_L_SHIFT)
-#define DESC_AVL_MASK (1 << 20)
-#define DESC_P_MASK (1 << 15)
-#define DESC_DPL_SHIFT 13
-#define DESC_S_MASK (1 << 12)
-#define DESC_TYPE_SHIFT 8
-#define DESC_A_MASK (1 << 8)
-
-#define DESC_CS_MASK (1 << 11) /* 1=code segment 0=data segment */
-#define DESC_C_MASK (1 << 10) /* code: conforming */
-#define DESC_R_MASK (1 << 9) /* code: readable */
-
-#define DESC_E_MASK (1 << 10) /* data: expansion direction */
-#define DESC_W_MASK (1 << 9) /* data: writable */
-
-#define DESC_TSS_BUSY_MASK (1 << 9)
-
-/* eflags masks */
-#define CC_C 0x0001
-#define CC_P 0x0004
-#define CC_A 0x0010
-#define CC_Z 0x0040
-#define CC_S 0x0080
-#define CC_O 0x0800
-
-#define TF_SHIFT 8
-#define IOPL_SHIFT 12
-#define VM_SHIFT 17
-
-#define TF_MASK 0x00000100
-#define IF_MASK 0x00000200
-#define DF_MASK 0x00000400
-#define IOPL_MASK 0x00003000
-#define NT_MASK 0x00004000
-#define RF_MASK 0x00010000
-#define VM_MASK 0x00020000
-#define AC_MASK 0x00040000
-#define VIF_MASK 0x00080000
-#define VIP_MASK 0x00100000
-#define ID_MASK 0x00200000
-
-/* hidden flags - used internally by qemu to represent additionnal cpu
- states. Only the CPL, INHIBIT_IRQ and HALTED are not redundant. We avoid
- using the IOPL_MASK, TF_MASK and VM_MASK bit position to ease oring
- with eflags. */
-/* current cpl */
-#define HF_CPL_SHIFT 0
-/* true if soft mmu is being used */
-#define HF_SOFTMMU_SHIFT 2
-/* true if hardware interrupts must be disabled for next instruction */
-#define HF_INHIBIT_IRQ_SHIFT 3
-/* 16 or 32 segments */
-#define HF_CS32_SHIFT 4
-#define HF_SS32_SHIFT 5
-/* zero base for DS, ES and SS : can be '0' only in 32 bit CS segment */
-#define HF_ADDSEG_SHIFT 6
-/* copy of CR0.PE (protected mode) */
-#define HF_PE_SHIFT 7
-#define HF_TF_SHIFT 8 /* must be same as eflags */
-#define HF_MP_SHIFT 9 /* the order must be MP, EM, TS */
-#define HF_EM_SHIFT 10
-#define HF_TS_SHIFT 11
-#define HF_IOPL_SHIFT 12 /* must be same as eflags */
-#define HF_LMA_SHIFT 14 /* only used on x86_64: long mode active */
-#define HF_CS64_SHIFT 15 /* only used on x86_64: 64 bit code segment */
-#define HF_OSFXSR_SHIFT 16 /* CR4.OSFXSR */
-#define HF_VM_SHIFT 17 /* must be same as eflags */
-#define HF_HALTED_SHIFT 18 /* CPU halted */
-
-#define HF_CPL_MASK (3 << HF_CPL_SHIFT)
-#define HF_SOFTMMU_MASK (1 << HF_SOFTMMU_SHIFT)
-#define HF_INHIBIT_IRQ_MASK (1 << HF_INHIBIT_IRQ_SHIFT)
-#define HF_CS32_MASK (1 << HF_CS32_SHIFT)
-#define HF_SS32_MASK (1 << HF_SS32_SHIFT)
-#define HF_ADDSEG_MASK (1 << HF_ADDSEG_SHIFT)
-#define HF_PE_MASK (1 << HF_PE_SHIFT)
-#define HF_TF_MASK (1 << HF_TF_SHIFT)
-#define HF_MP_MASK (1 << HF_MP_SHIFT)
-#define HF_EM_MASK (1 << HF_EM_SHIFT)
-#define HF_TS_MASK (1 << HF_TS_SHIFT)
-#define HF_LMA_MASK (1 << HF_LMA_SHIFT)
-#define HF_CS64_MASK (1 << HF_CS64_SHIFT)
-#define HF_OSFXSR_MASK (1 << HF_OSFXSR_SHIFT)
-#define HF_HALTED_MASK (1 << HF_HALTED_SHIFT)
-
-#define CR0_PE_MASK (1 << 0)
-#define CR0_MP_MASK (1 << 1)
-#define CR0_EM_MASK (1 << 2)
-#define CR0_TS_MASK (1 << 3)
-#define CR0_ET_MASK (1 << 4)
-#define CR0_NE_MASK (1 << 5)
-#define CR0_WP_MASK (1 << 16)
-#define CR0_AM_MASK (1 << 18)
-#define CR0_PG_MASK (1 << 31)
-
-#define CR4_VME_MASK (1 << 0)
-#define CR4_PVI_MASK (1 << 1)
-#define CR4_TSD_MASK (1 << 2)
-#define CR4_DE_MASK (1 << 3)
-#define CR4_PSE_MASK (1 << 4)
-#define CR4_PAE_MASK (1 << 5)
-#define CR4_PGE_MASK (1 << 7)
-#define CR4_PCE_MASK (1 << 8)
-#define CR4_OSFXSR_MASK (1 << 9)
-#define CR4_OSXMMEXCPT_MASK (1 << 10)
-
-#define PG_PRESENT_BIT 0
-#define PG_RW_BIT 1
-#define PG_USER_BIT 2
-#define PG_PWT_BIT 3
-#define PG_PCD_BIT 4
-#define PG_ACCESSED_BIT 5
-#define PG_DIRTY_BIT 6
-#define PG_PSE_BIT 7
-#define PG_GLOBAL_BIT 8
-#define PG_NX_BIT 63
-
-#define PG_PRESENT_MASK (1 << PG_PRESENT_BIT)
-#define PG_RW_MASK (1 << PG_RW_BIT)
-#define PG_USER_MASK (1 << PG_USER_BIT)
-#define PG_PWT_MASK (1 << PG_PWT_BIT)
-#define PG_PCD_MASK (1 << PG_PCD_BIT)
-#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
-#define PG_DIRTY_MASK (1 << PG_DIRTY_BIT)
-#define PG_PSE_MASK (1 << PG_PSE_BIT)
-#define PG_GLOBAL_MASK (1 << PG_GLOBAL_BIT)
-#define PG_NX_MASK (1LL << PG_NX_BIT)
-
-#define PG_ERROR_W_BIT 1
-
-#define PG_ERROR_P_MASK 0x01
-#define PG_ERROR_W_MASK (1 << PG_ERROR_W_BIT)
-#define PG_ERROR_U_MASK 0x04
-#define PG_ERROR_RSVD_MASK 0x08
-#define PG_ERROR_I_D_MASK 0x10
-
-#define MSR_IA32_APICBASE 0x1b
-#define MSR_IA32_APICBASE_BSP (1<<8)
-#define MSR_IA32_APICBASE_ENABLE (1<<11)
-#define MSR_IA32_APICBASE_BASE (0xfffff<<12)
-
-#define MSR_IA32_SYSENTER_CS 0x174
-#define MSR_IA32_SYSENTER_ESP 0x175
-#define MSR_IA32_SYSENTER_EIP 0x176
-
-#define MSR_MCG_CAP 0x179
-#define MSR_MCG_STATUS 0x17a
-#define MSR_MCG_CTL 0x17b
-
-#define MSR_PAT 0x277
-
-#define MSR_EFER 0xc0000080
-
-#define MSR_EFER_SCE (1 << 0)
-#define MSR_EFER_LME (1 << 8)
-#define MSR_EFER_LMA (1 << 10)
-#define MSR_EFER_NXE (1 << 11)
-#define MSR_EFER_FFXSR (1 << 14)
-
-#define MSR_STAR 0xc0000081
-#define MSR_LSTAR 0xc0000082
-#define MSR_CSTAR 0xc0000083
-#define MSR_FMASK 0xc0000084
-#define MSR_FSBASE 0xc0000100
-#define MSR_GSBASE 0xc0000101
-#define MSR_KERNELGSBASE 0xc0000102
-
-/* cpuid_features bits */
-#define CPUID_FP87 (1 << 0)
-#define CPUID_VME (1 << 1)
-#define CPUID_DE (1 << 2)
-#define CPUID_PSE (1 << 3)
-#define CPUID_TSC (1 << 4)
-#define CPUID_MSR (1 << 5)
-#define CPUID_PAE (1 << 6)
-#define CPUID_MCE (1 << 7)
-#define CPUID_CX8 (1 << 8)
-#define CPUID_APIC (1 << 9)
-#define CPUID_SEP (1 << 11) /* sysenter/sysexit */
-#define CPUID_MTRR (1 << 12)
-#define CPUID_PGE (1 << 13)
-#define CPUID_MCA (1 << 14)
-#define CPUID_CMOV (1 << 15)
-#define CPUID_PAT (1 << 16)
-#define CPUID_CLFLUSH (1 << 19)
-/* ... */
-#define CPUID_MMX (1 << 23)
-#define CPUID_FXSR (1 << 24)
-#define CPUID_SSE (1 << 25)
-#define CPUID_SSE2 (1 << 26)
-
-#define CPUID_EXT_SSE3 (1 << 0)
-#define CPUID_EXT_MONITOR (1 << 3)
-#define CPUID_EXT_CX16 (1 << 13)
-
-#define CPUID_EXT2_SYSCALL (1 << 11)
-#define CPUID_EXT2_NX (1 << 20)
-#define CPUID_EXT2_FFXSR (1 << 25)
-#define CPUID_EXT2_LM (1 << 29)
-
-#define EXCP00_DIVZ 0
-#define EXCP01_SSTP 1
-#define EXCP02_NMI 2
-#define EXCP03_INT3 3
-#define EXCP04_INTO 4
-#define EXCP05_BOUND 5
-#define EXCP06_ILLOP 6
-#define EXCP07_PREX 7
-#define EXCP08_DBLE 8
-#define EXCP09_XERR 9
-#define EXCP0A_TSS 10
-#define EXCP0B_NOSEG 11
-#define EXCP0C_STACK 12
-#define EXCP0D_GPF 13
-#define EXCP0E_PAGE 14
-#define EXCP10_COPR 16
-#define EXCP11_ALGN 17
-#define EXCP12_MCHK 18
-
-enum {
- CC_OP_DYNAMIC, /* must use dynamic code to get cc_op */
- CC_OP_EFLAGS, /* all cc are explicitely computed, CC_SRC = flags */
-
- CC_OP_MULB, /* modify all flags, C, O = (CC_SRC != 0) */
- CC_OP_MULW,
- CC_OP_MULL,
- CC_OP_MULQ,
-
- CC_OP_ADDB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
- CC_OP_ADDW,
- CC_OP_ADDL,
- CC_OP_ADDQ,
-
- CC_OP_ADCB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
- CC_OP_ADCW,
- CC_OP_ADCL,
- CC_OP_ADCQ,
-
- CC_OP_SUBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
- CC_OP_SUBW,
- CC_OP_SUBL,
- CC_OP_SUBQ,
-
- CC_OP_SBBB, /* modify all flags, CC_DST = res, CC_SRC = src1 */
- CC_OP_SBBW,
- CC_OP_SBBL,
- CC_OP_SBBQ,
-
- CC_OP_LOGICB, /* modify all flags, CC_DST = res */
- CC_OP_LOGICW,
- CC_OP_LOGICL,
- CC_OP_LOGICQ,
-
- CC_OP_INCB, /* modify all flags except, CC_DST = res, CC_SRC = C */
- CC_OP_INCW,
- CC_OP_INCL,
- CC_OP_INCQ,
-
- CC_OP_DECB, /* modify all flags except, CC_DST = res, CC_SRC = C */
- CC_OP_DECW,
- CC_OP_DECL,
- CC_OP_DECQ,
-
- CC_OP_SHLB, /* modify all flags, CC_DST = res, CC_SRC.msb = C */
- CC_OP_SHLW,
- CC_OP_SHLL,
- CC_OP_SHLQ,
-
- CC_OP_SARB, /* modify all flags, CC_DST = res, CC_SRC.lsb = C */
- CC_OP_SARW,
- CC_OP_SARL,
- CC_OP_SARQ,
-
- CC_OP_NB,
-};
-
-#ifdef FLOATX80
-#define USE_X86LDOUBLE
-#endif
-
-#ifdef USE_X86LDOUBLE
-typedef floatx80 CPU86_LDouble;
-#else
-typedef float64 CPU86_LDouble;
-#endif
-
-typedef struct SegmentCache {
- uint32_t selector;
- target_ulong base;
- uint32_t limit;
- uint32_t flags;
-} SegmentCache;
-
-typedef union {
- uint8_t _b[16];
- uint16_t _w[8];
- uint32_t _l[4];
- uint64_t _q[2];
- float32 _s[4];
- float64 _d[2];
-} XMMReg;
-
-typedef union {
- uint8_t _b[8];
- uint16_t _w[2];
- uint32_t _l[1];
- uint64_t q;
-} MMXReg;
-
-#ifdef WORDS_BIGENDIAN
-#define XMM_B(n) _b[15 - (n)]
-#define XMM_W(n) _w[7 - (n)]
-#define XMM_L(n) _l[3 - (n)]
-#define XMM_S(n) _s[3 - (n)]
-#define XMM_Q(n) _q[1 - (n)]
-#define XMM_D(n) _d[1 - (n)]
-
-#define MMX_B(n) _b[7 - (n)]
-#define MMX_W(n) _w[3 - (n)]
-#define MMX_L(n) _l[1 - (n)]
-#else
-#define XMM_B(n) _b[n]
-#define XMM_W(n) _w[n]
-#define XMM_L(n) _l[n]
-#define XMM_S(n) _s[n]
-#define XMM_Q(n) _q[n]
-#define XMM_D(n) _d[n]
-
-#define MMX_B(n) _b[n]
-#define MMX_W(n) _w[n]
-#define MMX_L(n) _l[n]
-#endif
-#define MMX_Q(n) q
-
-#ifdef TARGET_X86_64
-#define CPU_NB_REGS 16
-#else
-#define CPU_NB_REGS 8
-#endif
-
-typedef struct CPUX86State {
-#if TARGET_LONG_BITS > HOST_LONG_BITS
- /* temporaries if we cannot store them in host registers */
- target_ulong t0, t1, t2;
-#endif
-
- /* standard registers */
- target_ulong regs[CPU_NB_REGS];
- target_ulong eip;
- target_ulong eflags; /* eflags register. During CPU emulation, CC
- flags and DF are set to zero because they are
- stored elsewhere */
-
- /* emulator internal eflags handling */
- target_ulong cc_src;
- target_ulong cc_dst;
- uint32_t cc_op;
- int32_t df; /* D flag : 1 if D = 0, -1 if D = 1 */
- uint32_t hflags; /* hidden flags, see HF_xxx constants */
-
- /* segments */
- SegmentCache segs[6]; /* selector values */
- SegmentCache ldt;
- SegmentCache tr;
- SegmentCache gdt; /* only base and limit are used */
- SegmentCache idt; /* only base and limit are used */
-
- target_ulong cr[5]; /* NOTE: cr1 is unused */
- uint32_t a20_mask;
-
- /* FPU state */
- unsigned int fpstt; /* top of stack index */
- unsigned int fpus;
- unsigned int fpuc;
- uint8_t fptags[8]; /* 0 = valid, 1 = empty */
- union {
-#ifdef USE_X86LDOUBLE
- CPU86_LDouble d __attribute__((aligned(16)));
-#else
- CPU86_LDouble d;
-#endif
- MMXReg mmx;
- } fpregs[8];
-
- /* emulator internal variables */
- float_status fp_status;
- CPU86_LDouble ft0;
- union {
- float f;
- double d;
- int i32;
- int64_t i64;
- } fp_convert;
-
- float_status sse_status;
- uint32_t mxcsr;
- XMMReg xmm_regs[CPU_NB_REGS];
- XMMReg xmm_t0;
- MMXReg mmx_t0;
-
- /* sysenter registers */
- uint32_t sysenter_cs;
- uint32_t sysenter_esp;
- uint32_t sysenter_eip;
- uint64_t efer;
- uint64_t star;
-#ifdef TARGET_X86_64
- target_ulong lstar;
- target_ulong cstar;
- target_ulong fmask;
- target_ulong kernelgsbase;
-#endif
-
- uint64_t pat;
-
- /* temporary data for USE_CODE_COPY mode */
-#ifdef USE_CODE_COPY
- uint32_t tmp0;
- uint32_t saved_esp;
- int native_fp_regs; /* if true, the FPU state is in the native CPU regs */
-#endif
-
- /* exception/interrupt handling */
- jmp_buf jmp_env;
- int exception_index;
- int error_code;
- int exception_is_int;
- target_ulong exception_next_eip;
- target_ulong dr[8]; /* debug registers */
- int interrupt_request;
- int user_mode_only; /* user mode only simulation */
-
- CPU_COMMON
-
- /* processor features (e.g. for CPUID insn) */
- uint32_t cpuid_level;
- uint32_t cpuid_vendor1;
- uint32_t cpuid_vendor2;
- uint32_t cpuid_vendor3;
- uint32_t cpuid_version;
- uint32_t cpuid_features;
- uint32_t cpuid_ext_features;
- uint32_t cpuid_xlevel;
- uint32_t cpuid_model[12];
- uint32_t cpuid_ext2_features;
-
-#ifdef USE_KQEMU
- int kqemu_enabled;
- int last_io_time;
-#endif
- /* in order to simplify APIC support, we leave this pointer to the
- user */
- struct APICState *apic_state;
-} CPUX86State;
-
-CPUX86State *cpu_x86_init(void);
-int cpu_x86_exec(CPUX86State *s);
-void cpu_x86_close(CPUX86State *s);
-int cpu_get_pic_interrupt(CPUX86State *s);
-/* MSDOS compatibility mode FPU exception support */
-void cpu_set_ferr(CPUX86State *s);
-
-/* this function must always be used to load data in the segment
- cache: it synchronizes the hflags with the segment cache values */
-static inline void cpu_x86_load_seg_cache(CPUX86State *env,
- int seg_reg, unsigned int selector,
- uint32_t base, unsigned int limit,
- unsigned int flags)
-{
- SegmentCache *sc;
- unsigned int new_hflags;
-
- sc = &env->segs[seg_reg];
- sc->selector = selector;
- sc->base = base;
- sc->limit = limit;
- sc->flags = flags;
-
- /* update the hidden flags */
- {
- if (seg_reg == R_CS) {
-#ifdef TARGET_X86_64
- if ((env->hflags & HF_LMA_MASK) && (flags & DESC_L_MASK)) {
- /* long mode */
- env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK;
- env->hflags &= ~(HF_ADDSEG_MASK);
- } else
-#endif
- {
- /* legacy / compatibility case */
- new_hflags = (env->segs[R_CS].flags & DESC_B_MASK)
- >> (DESC_B_SHIFT - HF_CS32_SHIFT);
- env->hflags = (env->hflags & ~(HF_CS32_MASK | HF_CS64_MASK)) |
- new_hflags;
- }
- }
- new_hflags = (env->segs[R_SS].flags & DESC_B_MASK)
- >> (DESC_B_SHIFT - HF_SS32_SHIFT);
- if (env->hflags & HF_CS64_MASK) {
- /* zero base assumed for DS, ES and SS in long mode */
- } else if (!(env->cr[0] & CR0_PE_MASK) ||
- (env->eflags & VM_MASK) ||
- !(env->hflags & HF_CS32_MASK)) {
- /* XXX: try to avoid this test. The problem comes from the
- fact that is real mode or vm86 mode we only modify the
- 'base' and 'selector' fields of the segment cache to go
- faster. A solution may be to force addseg to one in
- translate-i386.c. */
- new_hflags |= HF_ADDSEG_MASK;
- } else {
- new_hflags |= ((env->segs[R_DS].base |
- env->segs[R_ES].base |
- env->segs[R_SS].base) != 0) <<
- HF_ADDSEG_SHIFT;
- }
- env->hflags = (env->hflags &
- ~(HF_SS32_MASK | HF_ADDSEG_MASK)) | new_hflags;
- }
-}
-
-/* wrapper, just in case memory mappings must be changed */
-static inline void cpu_x86_set_cpl(CPUX86State *s, int cpl)
-{
-#if HF_CPL_MASK == 3
- s->hflags = (s->hflags & ~HF_CPL_MASK) | cpl;
-#else
-#error HF_CPL_MASK is hardcoded
-#endif
-}
-
-/* used for debug or cpu save/restore */
-void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f);
-CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper);
-
-/* the following helpers are only usable in user mode simulation as
- they can trigger unexpected exceptions */
-void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector);
-void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32);
-void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32);
-
-/* 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,
- void *puc);
-void cpu_x86_set_a20(CPUX86State *env, int a20_state);
-
-uint64_t cpu_get_tsc(CPUX86State *env);
-
-void cpu_set_apic_base(CPUX86State *env, uint64_t val);
-uint64_t cpu_get_apic_base(CPUX86State *env);
-void cpu_set_apic_tpr(CPUX86State *env, uint8_t val);
-#ifndef NO_CPU_IO_DEFS
-uint8_t cpu_get_apic_tpr(CPUX86State *env);
-#endif
-
-/* will be suppressed */
-void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0);
-
-/* used to debug */
-#define X86_DUMP_FPU 0x0001 /* dump FPU state too */
-#define X86_DUMP_CCOP 0x0002 /* dump qemu flag cache */
-
-#ifdef USE_KQEMU
-static inline int cpu_get_time_fast(void)
-{
- int low, high;
- asm volatile("rdtsc" : "=a" (low), "=d" (high));
- return low;
-}
-#endif
-
-#define TARGET_PAGE_BITS 12
-#include "cpu-all.h"
-
-#endif /* CPU_I386_H */
diff --git a/target-i386/exec.h b/target-i386/exec.h
deleted file mode 100644
index 609a586..0000000
--- a/target-i386/exec.h
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
- * i386 execution defines
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include "config.h"
-#include "dyngen-exec.h"
-
-/* XXX: factorize this mess */
-#ifdef TARGET_X86_64
-#define TARGET_LONG_BITS 64
-#else
-#define TARGET_LONG_BITS 32
-#endif
-
-#include "cpu-defs.h"
-
-/* at least 4 register variables are defined */
-register struct CPUX86State *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
-
-/* XXX: use unsigned long instead of target_ulong - better code will
- be generated for 64 bit CPUs */
-register target_ulong T0 asm(AREG1);
-register target_ulong T1 asm(AREG2);
-register target_ulong T2 asm(AREG3);
-
-/* if more registers are available, we define some registers too */
-#ifdef AREG4
-register target_ulong EAX asm(AREG4);
-#define reg_EAX
-#endif
-
-#ifdef AREG5
-register target_ulong ESP asm(AREG5);
-#define reg_ESP
-#endif
-
-#ifdef AREG6
-register target_ulong EBP asm(AREG6);
-#define reg_EBP
-#endif
-
-#ifdef AREG7
-register target_ulong ECX asm(AREG7);
-#define reg_ECX
-#endif
-
-#ifdef AREG8
-register target_ulong EDX asm(AREG8);
-#define reg_EDX
-#endif
-
-#ifdef AREG9
-register target_ulong EBX asm(AREG9);
-#define reg_EBX
-#endif
-
-#ifdef AREG10
-register target_ulong ESI asm(AREG10);
-#define reg_ESI
-#endif
-
-#ifdef AREG11
-register target_ulong EDI asm(AREG11);
-#define reg_EDI
-#endif
-
-#endif /* ! (TARGET_LONG_BITS > HOST_LONG_BITS) */
-
-#define A0 T2
-
-extern FILE *logfile;
-extern int loglevel;
-
-#ifndef reg_EAX
-#define EAX (env->regs[R_EAX])
-#endif
-#ifndef reg_ECX
-#define ECX (env->regs[R_ECX])
-#endif
-#ifndef reg_EDX
-#define EDX (env->regs[R_EDX])
-#endif
-#ifndef reg_EBX
-#define EBX (env->regs[R_EBX])
-#endif
-#ifndef reg_ESP
-#define ESP (env->regs[R_ESP])
-#endif
-#ifndef reg_EBP
-#define EBP (env->regs[R_EBP])
-#endif
-#ifndef reg_ESI
-#define ESI (env->regs[R_ESI])
-#endif
-#ifndef reg_EDI
-#define EDI (env->regs[R_EDI])
-#endif
-#define EIP (env->eip)
-#define DF (env->df)
-
-#define CC_SRC (env->cc_src)
-#define CC_DST (env->cc_dst)
-#define CC_OP (env->cc_op)
-
-/* float macros */
-#define FT0 (env->ft0)
-#define ST0 (env->fpregs[env->fpstt].d)
-#define ST(n) (env->fpregs[(env->fpstt + (n)) & 7].d)
-#define ST1 ST(1)
-
-#ifdef USE_FP_CONVERT
-#define FP_CONVERT (env->fp_convert)
-#endif
-
-#include "cpu.h"
-#include "exec-all.h"
-
-typedef struct CCTable {
- int (*compute_all)(void); /* return all the flags */
- int (*compute_c)(void); /* return the C flag */
-} CCTable;
-
-extern CCTable cc_table[];
-
-void load_seg(int seg_reg, int selector);
-void helper_ljmp_protected_T0_T1(int next_eip);
-void helper_lcall_real_T0_T1(int shift, int next_eip);
-void helper_lcall_protected_T0_T1(int shift, int next_eip);
-void helper_iret_real(int shift);
-void helper_iret_protected(int shift, int next_eip);
-void helper_lret_protected(int shift, int addend);
-void helper_lldt_T0(void);
-void helper_ltr_T0(void);
-void helper_movl_crN_T0(int reg);
-void helper_movl_drN_T0(int reg);
-void helper_invlpg(target_ulong addr);
-void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0);
-void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3);
-void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4);
-void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr);
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
- int is_write, int is_user, int is_softmmu);
-void tlb_fill(target_ulong addr, int is_write, int is_user,
- void *retaddr);
-void __hidden cpu_lock(void);
-void __hidden cpu_unlock(void);
-void do_interrupt(int intno, int is_int, int error_code,
- target_ulong next_eip, int is_hw);
-void do_interrupt_user(int intno, int is_int, int error_code,
- target_ulong next_eip);
-void raise_interrupt(int intno, int is_int, int error_code,
- int next_eip_addend);
-void raise_exception_err(int exception_index, int error_code);
-void raise_exception(int exception_index);
-void __hidden cpu_loop_exit(void);
-
-void OPPROTO op_movl_eflags_T0(void);
-void OPPROTO op_movl_T0_eflags(void);
-void helper_divl_EAX_T0(void);
-void helper_idivl_EAX_T0(void);
-void helper_mulq_EAX_T0(void);
-void helper_imulq_EAX_T0(void);
-void helper_imulq_T0_T1(void);
-void helper_divq_EAX_T0(void);
-void helper_idivq_EAX_T0(void);
-void helper_bswapq_T0(void);
-void helper_cmpxchg8b(void);
-void helper_cpuid(void);
-void helper_enter_level(int level, int data32);
-void helper_enter64_level(int level, int data64);
-void helper_sysenter(void);
-void helper_sysexit(void);
-void helper_syscall(int next_eip_addend);
-void helper_sysret(int dflag);
-void helper_rdtsc(void);
-void helper_rdmsr(void);
-void helper_wrmsr(void);
-void helper_lsl(void);
-void helper_lar(void);
-void helper_verr(void);
-void helper_verw(void);
-
-void check_iob_T0(void);
-void check_iow_T0(void);
-void check_iol_T0(void);
-void check_iob_DX(void);
-void check_iow_DX(void);
-void check_iol_DX(void);
-
-#if !defined(CONFIG_USER_ONLY)
-
-#include "softmmu_exec.h"
-
-static inline double ldfq(target_ulong ptr)
-{
- union {
- double d;
- uint64_t i;
- } u;
- u.i = ldq(ptr);
- return u.d;
-}
-
-static inline void stfq(target_ulong ptr, double v)
-{
- union {
- double d;
- uint64_t i;
- } u;
- u.d = v;
- stq(ptr, u.i);
-}
-
-static inline float ldfl(target_ulong ptr)
-{
- union {
- float f;
- uint32_t i;
- } u;
- u.i = ldl(ptr);
- return u.f;
-}
-
-static inline void stfl(target_ulong ptr, float v)
-{
- union {
- float f;
- uint32_t i;
- } u;
- u.f = v;
- stl(ptr, u.i);
-}
-
-#endif /* !defined(CONFIG_USER_ONLY) */
-
-#ifdef USE_X86LDOUBLE
-/* use long double functions */
-#define floatx_to_int32 floatx80_to_int32
-#define floatx_to_int64 floatx80_to_int64
-#define floatx_to_int32_round_to_zero floatx80_to_int32_round_to_zero
-#define floatx_to_int64_round_to_zero floatx80_to_int64_round_to_zero
-#define floatx_abs floatx80_abs
-#define floatx_chs floatx80_chs
-#define floatx_round_to_int floatx80_round_to_int
-#define floatx_compare floatx80_compare
-#define floatx_compare_quiet floatx80_compare_quiet
-#define sin sinl
-#define cos cosl
-#define sqrt sqrtl
-#define pow powl
-#define log logl
-#define tan tanl
-#define atan2 atan2l
-#define floor floorl
-#define ceil ceill
-#define ldexp ldexpl
-#else
-#define floatx_to_int32 float64_to_int32
-#define floatx_to_int64 float64_to_int64
-#define floatx_to_int32_round_to_zero float64_to_int32_round_to_zero
-#define floatx_to_int64_round_to_zero float64_to_int64_round_to_zero
-#define floatx_abs float64_abs
-#define floatx_chs float64_chs
-#define floatx_round_to_int float64_round_to_int
-#define floatx_compare float64_compare
-#define floatx_compare_quiet float64_compare_quiet
-#endif
-
-extern CPU86_LDouble sin(CPU86_LDouble x);
-extern CPU86_LDouble cos(CPU86_LDouble x);
-extern CPU86_LDouble sqrt(CPU86_LDouble x);
-extern CPU86_LDouble pow(CPU86_LDouble, CPU86_LDouble);
-extern CPU86_LDouble log(CPU86_LDouble x);
-extern CPU86_LDouble tan(CPU86_LDouble x);
-extern CPU86_LDouble atan2(CPU86_LDouble, CPU86_LDouble);
-extern CPU86_LDouble floor(CPU86_LDouble x);
-extern CPU86_LDouble ceil(CPU86_LDouble x);
-
-#define RC_MASK 0xc00
-#define RC_NEAR 0x000
-#define RC_DOWN 0x400
-#define RC_UP 0x800
-#define RC_CHOP 0xc00
-
-#define MAXTAN 9223372036854775808.0
-
-#ifdef USE_X86LDOUBLE
-
-/* only for x86 */
-typedef union {
- long double d;
- struct {
- unsigned long long lower;
- unsigned short upper;
- } l;
-} CPU86_LDoubleU;
-
-/* the following deal with x86 long double-precision numbers */
-#define MAXEXPD 0x7fff
-#define EXPBIAS 16383
-#define EXPD(fp) (fp.l.upper & 0x7fff)
-#define SIGND(fp) ((fp.l.upper) & 0x8000)
-#define MANTD(fp) (fp.l.lower)
-#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7fff)) | EXPBIAS
-
-#else
-
-/* NOTE: arm is horrible as double 32 bit words are stored in big endian ! */
-typedef union {
- double d;
-#if !defined(WORDS_BIGENDIAN) && !defined(__arm__)
- struct {
- uint32_t lower;
- int32_t upper;
- } l;
-#else
- struct {
- int32_t upper;
- uint32_t lower;
- } l;
-#endif
-#ifndef __arm__
- int64_t ll;
-#endif
-} CPU86_LDoubleU;
-
-/* the following deal with IEEE double-precision numbers */
-#define MAXEXPD 0x7ff
-#define EXPBIAS 1023
-#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF)
-#define SIGND(fp) ((fp.l.upper) & 0x80000000)
-#ifdef __arm__
-#define MANTD(fp) (fp.l.lower | ((uint64_t)(fp.l.upper & ((1 << 20) - 1)) << 32))
-#else
-#define MANTD(fp) (fp.ll & ((1LL << 52) - 1))
-#endif
-#define BIASEXPONENT(fp) fp.l.upper = (fp.l.upper & ~(0x7ff << 20)) | (EXPBIAS << 20)
-#endif
-
-static inline void fpush(void)
-{
- env->fpstt = (env->fpstt - 1) & 7;
- env->fptags[env->fpstt] = 0; /* validate stack entry */
-}
-
-static inline void fpop(void)
-{
- env->fptags[env->fpstt] = 1; /* invvalidate stack entry */
- env->fpstt = (env->fpstt + 1) & 7;
-}
-
-#ifndef USE_X86LDOUBLE
-static inline CPU86_LDouble helper_fldt(target_ulong ptr)
-{
- CPU86_LDoubleU temp;
- int upper, e;
- uint64_t ll;
-
- /* mantissa */
- upper = lduw(ptr + 8);
- /* XXX: handle overflow ? */
- e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
- e |= (upper >> 4) & 0x800; /* sign */
- ll = (ldq(ptr) >> 11) & ((1LL << 52) - 1);
-#ifdef __arm__
- temp.l.upper = (e << 20) | (ll >> 32);
- temp.l.lower = ll;
-#else
- temp.ll = ll | ((uint64_t)e << 52);
-#endif
- return temp.d;
-}
-
-static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr)
-{
- CPU86_LDoubleU temp;
- int e;
-
- temp.d = f;
- /* mantissa */
- stq(ptr, (MANTD(temp) << 11) | (1LL << 63));
- /* exponent + sign */
- e = EXPD(temp) - EXPBIAS + 16383;
- e |= SIGND(temp) >> 16;
- stw(ptr + 8, e);
-}
-#else
-
-/* XXX: same endianness assumed */
-
-#ifdef CONFIG_USER_ONLY
-
-static inline CPU86_LDouble helper_fldt(target_ulong ptr)
-{
- return *(CPU86_LDouble *)ptr;
-}
-
-static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr)
-{
- *(CPU86_LDouble *)ptr = f;
-}
-
-#else
-
-/* we use memory access macros */
-
-static inline CPU86_LDouble helper_fldt(target_ulong ptr)
-{
- CPU86_LDoubleU temp;
-
- temp.l.lower = ldq(ptr);
- temp.l.upper = lduw(ptr + 8);
- return temp.d;
-}
-
-static inline void helper_fstt(CPU86_LDouble f, target_ulong ptr)
-{
- CPU86_LDoubleU temp;
-
- temp.d = f;
- stq(ptr, temp.l.lower);
- stw(ptr + 8, temp.l.upper);
-}
-
-#endif /* !CONFIG_USER_ONLY */
-
-#endif /* USE_X86LDOUBLE */
-
-#define FPUS_IE (1 << 0)
-#define FPUS_DE (1 << 1)
-#define FPUS_ZE (1 << 2)
-#define FPUS_OE (1 << 3)
-#define FPUS_UE (1 << 4)
-#define FPUS_PE (1 << 5)
-#define FPUS_SF (1 << 6)
-#define FPUS_SE (1 << 7)
-#define FPUS_B (1 << 15)
-
-#define FPUC_EM 0x3f
-
-extern const CPU86_LDouble f15rk[7];
-
-void helper_fldt_ST0_A0(void);
-void helper_fstt_ST0_A0(void);
-void fpu_raise_exception(void);
-CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b);
-void helper_fbld_ST0_A0(void);
-void helper_fbst_ST0_A0(void);
-void helper_f2xm1(void);
-void helper_fyl2x(void);
-void helper_fptan(void);
-void helper_fpatan(void);
-void helper_fxtract(void);
-void helper_fprem1(void);
-void helper_fprem(void);
-void helper_fyl2xp1(void);
-void helper_fsqrt(void);
-void helper_fsincos(void);
-void helper_frndint(void);
-void helper_fscale(void);
-void helper_fsin(void);
-void helper_fcos(void);
-void helper_fxam_ST0(void);
-void helper_fstenv(target_ulong ptr, int data32);
-void helper_fldenv(target_ulong ptr, int data32);
-void helper_fsave(target_ulong ptr, int data32);
-void helper_frstor(target_ulong ptr, int data32);
-void helper_fxsave(target_ulong ptr, int data64);
-void helper_fxrstor(target_ulong ptr, int data64);
-void restore_native_fp_state(CPUState *env);
-void save_native_fp_state(CPUState *env);
-float approx_rsqrt(float a);
-float approx_rcp(float a);
-void update_fp_status(void);
-void helper_hlt(void);
-void helper_monitor(void);
-void helper_mwait(void);
-
-extern const uint8_t parity_table[256];
-extern const uint8_t rclw_table[32];
-extern const uint8_t rclb_table[32];
-
-static inline uint32_t compute_eflags(void)
-{
- return env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
-}
-
-/* NOTE: CC_OP must be modified manually to CC_OP_EFLAGS */
-static inline void load_eflags(int eflags, int update_mask)
-{
- CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
- DF = 1 - (2 * ((eflags >> 10) & 1));
- env->eflags = (env->eflags & ~update_mask) |
- (eflags & update_mask);
-}
-
-static inline void env_to_regs(void)
-{
-#ifdef reg_EAX
- EAX = env->regs[R_EAX];
-#endif
-#ifdef reg_ECX
- ECX = env->regs[R_ECX];
-#endif
-#ifdef reg_EDX
- EDX = env->regs[R_EDX];
-#endif
-#ifdef reg_EBX
- EBX = env->regs[R_EBX];
-#endif
-#ifdef reg_ESP
- ESP = env->regs[R_ESP];
-#endif
-#ifdef reg_EBP
- EBP = env->regs[R_EBP];
-#endif
-#ifdef reg_ESI
- ESI = env->regs[R_ESI];
-#endif
-#ifdef reg_EDI
- EDI = env->regs[R_EDI];
-#endif
-}
-
-static inline void regs_to_env(void)
-{
-#ifdef reg_EAX
- env->regs[R_EAX] = EAX;
-#endif
-#ifdef reg_ECX
- env->regs[R_ECX] = ECX;
-#endif
-#ifdef reg_EDX
- env->regs[R_EDX] = EDX;
-#endif
-#ifdef reg_EBX
- env->regs[R_EBX] = EBX;
-#endif
-#ifdef reg_ESP
- env->regs[R_ESP] = ESP;
-#endif
-#ifdef reg_EBP
- env->regs[R_EBP] = EBP;
-#endif
-#ifdef reg_ESI
- env->regs[R_ESI] = ESI;
-#endif
-#ifdef reg_EDI
- env->regs[R_EDI] = EDI;
-#endif
-}
diff --git a/target-i386/helper.c b/target-i386/helper.c
deleted file mode 100644
index 70e9fae..0000000
--- a/target-i386/helper.c
+++ /dev/null
@@ -1,3540 +0,0 @@
-/*
- * i386 helpers
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include "exec.h"
-
-//#define DEBUG_PCALL
-
-#if 0
-#define raise_exception_err(a, b)\
-do {\
- if (logfile)\
- fprintf(logfile, "raise_exception line=%d\n", __LINE__);\
- (raise_exception_err)(a, b);\
-} while (0)
-#endif
-
-const uint8_t parity_table[256] = {
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- CC_P, 0, 0, CC_P, 0, CC_P, CC_P, 0,
- 0, CC_P, CC_P, 0, CC_P, 0, 0, CC_P,
-};
-
-/* modulo 17 table */
-const uint8_t rclw_table[32] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9,10,11,12,13,14,15,
- 16, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 9,10,11,12,13,14,
-};
-
-/* modulo 9 table */
-const uint8_t rclb_table[32] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- 8, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 0, 1, 2, 3, 4, 5,
- 6, 7, 8, 0, 1, 2, 3, 4,
-};
-
-const CPU86_LDouble f15rk[7] =
-{
- 0.00000000000000000000L,
- 1.00000000000000000000L,
- 3.14159265358979323851L, /*pi*/
- 0.30102999566398119523L, /*lg2*/
- 0.69314718055994530943L, /*ln2*/
- 1.44269504088896340739L, /*l2e*/
- 3.32192809488736234781L, /*l2t*/
-};
-
-/* thread support */
-
-spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
-
-void cpu_lock(void)
-{
- spin_lock(&global_cpu_lock);
-}
-
-void cpu_unlock(void)
-{
- spin_unlock(&global_cpu_lock);
-}
-
-void cpu_loop_exit(void)
-{
- /* NOTE: the register at this point must be saved by hand because
- longjmp restore them */
- regs_to_env();
- longjmp(env->jmp_env, 1);
-}
-
-/* return non zero if error */
-static inline int load_segment(uint32_t *e1_ptr, uint32_t *e2_ptr,
- int selector)
-{
- SegmentCache *dt;
- int index;
- target_ulong ptr;
-
- if (selector & 0x4)
- dt = &env->ldt;
- else
- dt = &env->gdt;
- index = selector & ~7;
- if ((index + 7) > dt->limit)
- return -1;
- ptr = dt->base + index;
- *e1_ptr = ldl_kernel(ptr);
- *e2_ptr = ldl_kernel(ptr + 4);
- return 0;
-}
-
-static inline unsigned int get_seg_limit(uint32_t e1, uint32_t e2)
-{
- unsigned int limit;
- limit = (e1 & 0xffff) | (e2 & 0x000f0000);
- if (e2 & DESC_G_MASK)
- limit = (limit << 12) | 0xfff;
- return limit;
-}
-
-static inline uint32_t get_seg_base(uint32_t e1, uint32_t e2)
-{
- return ((e1 >> 16) | ((e2 & 0xff) << 16) | (e2 & 0xff000000));
-}
-
-static inline void load_seg_cache_raw_dt(SegmentCache *sc, uint32_t e1, uint32_t e2)
-{
- sc->base = get_seg_base(e1, e2);
- sc->limit = get_seg_limit(e1, e2);
- sc->flags = e2;
-}
-
-/* init the segment cache in vm86 mode. */
-static inline void load_seg_vm(int seg, int selector)
-{
- selector &= 0xffff;
- cpu_x86_load_seg_cache(env, seg, selector,
- (selector << 4), 0xffff, 0);
-}
-
-static inline void get_ss_esp_from_tss(uint32_t *ss_ptr,
- uint32_t *esp_ptr, int dpl)
-{
- int type, index, shift;
-
-#if 0
- {
- int i;
- printf("TR: base=%p limit=%x\n", env->tr.base, env->tr.limit);
- for(i=0;i<env->tr.limit;i++) {
- printf("%02x ", env->tr.base[i]);
- if ((i & 7) == 7) printf("\n");
- }
- printf("\n");
- }
-#endif
-
- if (!(env->tr.flags & DESC_P_MASK))
- cpu_abort(env, "invalid tss");
- type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
- if ((type & 7) != 1)
- cpu_abort(env, "invalid tss type");
- shift = type >> 3;
- index = (dpl * 4 + 2) << shift;
- if (index + (4 << shift) - 1 > env->tr.limit)
- raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
- if (shift == 0) {
- *esp_ptr = lduw_kernel(env->tr.base + index);
- *ss_ptr = lduw_kernel(env->tr.base + index + 2);
- } else {
- *esp_ptr = ldl_kernel(env->tr.base + index);
- *ss_ptr = lduw_kernel(env->tr.base + index + 4);
- }
-}
-
-/* XXX: merge with load_seg() */
-static void tss_load_seg(int seg_reg, int selector)
-{
- uint32_t e1, e2;
- int rpl, dpl, cpl;
-
- if ((selector & 0xfffc) != 0) {
- if (load_segment(&e1, &e2, selector) != 0)
- raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
- if (!(e2 & DESC_S_MASK))
- raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
- rpl = selector & 3;
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->hflags & HF_CPL_MASK;
- if (seg_reg == R_CS) {
- if (!(e2 & DESC_CS_MASK))
- raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
- /* XXX: is it correct ? */
- if (dpl != rpl)
- raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
- if ((e2 & DESC_C_MASK) && dpl > rpl)
- raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
- } else if (seg_reg == R_SS) {
- /* SS must be writable data */
- if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
- raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
- if (dpl != cpl || dpl != rpl)
- raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
- } else {
- /* not readable code */
- if ((e2 & DESC_CS_MASK) && !(e2 & DESC_R_MASK))
- raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
- /* if data or non conforming code, checks the rights */
- if (((e2 >> DESC_TYPE_SHIFT) & 0xf) < 12) {
- if (dpl < cpl || dpl < rpl)
- raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
- }
- }
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
- cpu_x86_load_seg_cache(env, seg_reg, selector,
- get_seg_base(e1, e2),
- get_seg_limit(e1, e2),
- e2);
- } else {
- if (seg_reg == R_SS || seg_reg == R_CS)
- raise_exception_err(EXCP0A_TSS, selector & 0xfffc);
- }
-}
-
-#define SWITCH_TSS_JMP 0
-#define SWITCH_TSS_IRET 1
-#define SWITCH_TSS_CALL 2
-
-/* XXX: restore CPU state in registers (PowerPC case) */
-static void switch_tss(int tss_selector,
- uint32_t e1, uint32_t e2, int source,
- uint32_t next_eip)
-{
- int tss_limit, tss_limit_max, type, old_tss_limit_max, old_type, v1, v2, i;
- target_ulong tss_base;
- uint32_t new_regs[8], new_segs[6];
- uint32_t new_eflags, new_eip, new_cr3, new_ldt, new_trap;
- uint32_t old_eflags, eflags_mask;
- SegmentCache *dt;
- int index;
- target_ulong ptr;
-
- type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
-#ifdef DEBUG_PCALL
- if (loglevel & CPU_LOG_PCALL)
- fprintf(logfile, "switch_tss: sel=0x%04x type=%d src=%d\n", tss_selector, type, source);
-#endif
-
- /* if task gate, we read the TSS segment and we load it */
- if (type == 5) {
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
- tss_selector = e1 >> 16;
- if (tss_selector & 4)
- raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
- if (load_segment(&e1, &e2, tss_selector) != 0)
- raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
- if (e2 & DESC_S_MASK)
- raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
- type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
- if ((type & 7) != 1)
- raise_exception_err(EXCP0D_GPF, tss_selector & 0xfffc);
- }
-
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, tss_selector & 0xfffc);
-
- if (type & 8)
- tss_limit_max = 103;
- else
- tss_limit_max = 43;
- tss_limit = get_seg_limit(e1, e2);
- tss_base = get_seg_base(e1, e2);
- if ((tss_selector & 4) != 0 ||
- tss_limit < tss_limit_max)
- raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
- old_type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
- if (old_type & 8)
- old_tss_limit_max = 103;
- else
- old_tss_limit_max = 43;
-
- /* read all the registers from the new TSS */
- if (type & 8) {
- /* 32 bit */
- new_cr3 = ldl_kernel(tss_base + 0x1c);
- new_eip = ldl_kernel(tss_base + 0x20);
- new_eflags = ldl_kernel(tss_base + 0x24);
- for(i = 0; i < 8; i++)
- new_regs[i] = ldl_kernel(tss_base + (0x28 + i * 4));
- for(i = 0; i < 6; i++)
- new_segs[i] = lduw_kernel(tss_base + (0x48 + i * 4));
- new_ldt = lduw_kernel(tss_base + 0x60);
- new_trap = ldl_kernel(tss_base + 0x64);
- } else {
- /* 16 bit */
- new_cr3 = 0;
- new_eip = lduw_kernel(tss_base + 0x0e);
- new_eflags = lduw_kernel(tss_base + 0x10);
- for(i = 0; i < 8; i++)
- new_regs[i] = lduw_kernel(tss_base + (0x12 + i * 2)) | 0xffff0000;
- for(i = 0; i < 4; i++)
- new_segs[i] = lduw_kernel(tss_base + (0x22 + i * 4));
- new_ldt = lduw_kernel(tss_base + 0x2a);
- new_segs[R_FS] = 0;
- new_segs[R_GS] = 0;
- new_trap = 0;
- }
-
- /* NOTE: we must avoid memory exceptions during the task switch,
- so we make dummy accesses before */
- /* XXX: it can still fail in some cases, so a bigger hack is
- necessary to valid the TLB after having done the accesses */
-
- v1 = ldub_kernel(env->tr.base);
- v2 = ldub_kernel(env->tr.base + old_tss_limit_max);
- stb_kernel(env->tr.base, v1);
- stb_kernel(env->tr.base + old_tss_limit_max, v2);
-
- /* clear busy bit (it is restartable) */
- if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) {
- target_ulong ptr;
- uint32_t e2;
- ptr = env->gdt.base + (env->tr.selector & ~7);
- e2 = ldl_kernel(ptr + 4);
- e2 &= ~DESC_TSS_BUSY_MASK;
- stl_kernel(ptr + 4, e2);
- }
- old_eflags = compute_eflags();
- if (source == SWITCH_TSS_IRET)
- old_eflags &= ~NT_MASK;
-
- /* save the current state in the old TSS */
- if (type & 8) {
- /* 32 bit */
- stl_kernel(env->tr.base + 0x20, next_eip);
- stl_kernel(env->tr.base + 0x24, old_eflags);
- stl_kernel(env->tr.base + (0x28 + 0 * 4), EAX);
- stl_kernel(env->tr.base + (0x28 + 1 * 4), ECX);
- stl_kernel(env->tr.base + (0x28 + 2 * 4), EDX);
- stl_kernel(env->tr.base + (0x28 + 3 * 4), EBX);
- stl_kernel(env->tr.base + (0x28 + 4 * 4), ESP);
- stl_kernel(env->tr.base + (0x28 + 5 * 4), EBP);
- stl_kernel(env->tr.base + (0x28 + 6 * 4), ESI);
- stl_kernel(env->tr.base + (0x28 + 7 * 4), EDI);
- for(i = 0; i < 6; i++)
- stw_kernel(env->tr.base + (0x48 + i * 4), env->segs[i].selector);
- } else {
- /* 16 bit */
- stw_kernel(env->tr.base + 0x0e, next_eip);
- stw_kernel(env->tr.base + 0x10, old_eflags);
- stw_kernel(env->tr.base + (0x12 + 0 * 2), EAX);
- stw_kernel(env->tr.base + (0x12 + 1 * 2), ECX);
- stw_kernel(env->tr.base + (0x12 + 2 * 2), EDX);
- stw_kernel(env->tr.base + (0x12 + 3 * 2), EBX);
- stw_kernel(env->tr.base + (0x12 + 4 * 2), ESP);
- stw_kernel(env->tr.base + (0x12 + 5 * 2), EBP);
- stw_kernel(env->tr.base + (0x12 + 6 * 2), ESI);
- stw_kernel(env->tr.base + (0x12 + 7 * 2), EDI);
- for(i = 0; i < 4; i++)
- stw_kernel(env->tr.base + (0x22 + i * 4), env->segs[i].selector);
- }
-
- /* now if an exception occurs, it will occurs in the next task
- context */
-
- if (source == SWITCH_TSS_CALL) {
- stw_kernel(tss_base, env->tr.selector);
- new_eflags |= NT_MASK;
- }
-
- /* set busy bit */
- if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_CALL) {
- target_ulong ptr;
- uint32_t e2;
- ptr = env->gdt.base + (tss_selector & ~7);
- e2 = ldl_kernel(ptr + 4);
- e2 |= DESC_TSS_BUSY_MASK;
- stl_kernel(ptr + 4, e2);
- }
-
- /* set the new CPU state */
- /* from this point, any exception which occurs can give problems */
- env->cr[0] |= CR0_TS_MASK;
- env->hflags |= HF_TS_MASK;
- env->tr.selector = tss_selector;
- env->tr.base = tss_base;
- env->tr.limit = tss_limit;
- env->tr.flags = e2 & ~DESC_TSS_BUSY_MASK;
-
- if ((type & 8) && (env->cr[0] & CR0_PG_MASK)) {
- cpu_x86_update_cr3(env, new_cr3);
- }
-
- /* load all registers without an exception, then reload them with
- possible exception */
- env->eip = new_eip;
- eflags_mask = TF_MASK | AC_MASK | ID_MASK |
- IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK;
- if (!(type & 8))
- eflags_mask &= 0xffff;
- load_eflags(new_eflags, eflags_mask);
- /* XXX: what to do in 16 bit case ? */
- EAX = new_regs[0];
- ECX = new_regs[1];
- EDX = new_regs[2];
- EBX = new_regs[3];
- ESP = new_regs[4];
- EBP = new_regs[5];
- ESI = new_regs[6];
- EDI = new_regs[7];
- if (new_eflags & VM_MASK) {
- for(i = 0; i < 6; i++)
- load_seg_vm(i, new_segs[i]);
- /* in vm86, CPL is always 3 */
- cpu_x86_set_cpl(env, 3);
- } else {
- /* CPL is set the RPL of CS */
- cpu_x86_set_cpl(env, new_segs[R_CS] & 3);
- /* first just selectors as the rest may trigger exceptions */
- for(i = 0; i < 6; i++)
- cpu_x86_load_seg_cache(env, i, new_segs[i], 0, 0, 0);
- }
-
- env->ldt.selector = new_ldt & ~4;
- env->ldt.base = 0;
- env->ldt.limit = 0;
- env->ldt.flags = 0;
-
- /* load the LDT */
- if (new_ldt & 4)
- raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
-
- if ((new_ldt & 0xfffc) != 0) {
- dt = &env->gdt;
- index = new_ldt & ~7;
- if ((index + 7) > dt->limit)
- raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
- ptr = dt->base + index;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
- if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
- raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0A_TSS, new_ldt & 0xfffc);
- load_seg_cache_raw_dt(&env->ldt, e1, e2);
- }
-
- /* load the segments */
- if (!(new_eflags & VM_MASK)) {
- tss_load_seg(R_CS, new_segs[R_CS]);
- tss_load_seg(R_SS, new_segs[R_SS]);
- tss_load_seg(R_ES, new_segs[R_ES]);
- tss_load_seg(R_DS, new_segs[R_DS]);
- tss_load_seg(R_FS, new_segs[R_FS]);
- tss_load_seg(R_GS, new_segs[R_GS]);
- }
-
- /* check that EIP is in the CS segment limits */
- if (new_eip > env->segs[R_CS].limit) {
- /* XXX: different exception if CALL ? */
- raise_exception_err(EXCP0D_GPF, 0);
- }
-}
-
-/* check if Port I/O is allowed in TSS */
-static inline void check_io(int addr, int size)
-{
- int io_offset, val, mask;
-
- /* TSS must be a valid 32 bit one */
- if (!(env->tr.flags & DESC_P_MASK) ||
- ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
- env->tr.limit < 103)
- goto fail;
- io_offset = lduw_kernel(env->tr.base + 0x66);
- io_offset += (addr >> 3);
- /* Note: the check needs two bytes */
- if ((io_offset + 1) > env->tr.limit)
- goto fail;
- val = lduw_kernel(env->tr.base + io_offset);
- val >>= (addr & 7);
- mask = (1 << size) - 1;
- /* all bits must be zero to allow the I/O */
- if ((val & mask) != 0) {
- fail:
- raise_exception_err(EXCP0D_GPF, 0);
- }
-}
-
-void check_iob_T0(void)
-{
- check_io(T0, 1);
-}
-
-void check_iow_T0(void)
-{
- check_io(T0, 2);
-}
-
-void check_iol_T0(void)
-{
- check_io(T0, 4);
-}
-
-void check_iob_DX(void)
-{
- check_io(EDX & 0xffff, 1);
-}
-
-void check_iow_DX(void)
-{
- check_io(EDX & 0xffff, 2);
-}
-
-void check_iol_DX(void)
-{
- check_io(EDX & 0xffff, 4);
-}
-
-static inline unsigned int get_sp_mask(unsigned int e2)
-{
- if (e2 & DESC_B_MASK)
- return 0xffffffff;
- else
- return 0xffff;
-}
-
-/* XXX: add a is_user flag to have proper security support */
-#define PUSHW(ssp, sp, sp_mask, val)\
-{\
- sp -= 2;\
- stw_kernel((ssp) + (sp & (sp_mask)), (val));\
-}
-
-#define PUSHL(ssp, sp, sp_mask, val)\
-{\
- sp -= 4;\
- stl_kernel((ssp) + (sp & (sp_mask)), (val));\
-}
-
-#define POPW(ssp, sp, sp_mask, val)\
-{\
- val = lduw_kernel((ssp) + (sp & (sp_mask)));\
- sp += 2;\
-}
-
-#define POPL(ssp, sp, sp_mask, val)\
-{\
- val = (uint32_t)ldl_kernel((ssp) + (sp & (sp_mask)));\
- sp += 4;\
-}
-
-/* protected mode interrupt */
-static void do_interrupt_protected(int intno, int is_int, int error_code,
- unsigned int next_eip, int is_hw)
-{
- SegmentCache *dt;
- target_ulong ptr, ssp;
- int type, dpl, selector, ss_dpl, cpl, sp_mask;
- int has_error_code, new_stack, shift;
- uint32_t e1, e2, offset, ss, esp, ss_e1, ss_e2;
- uint32_t old_eip;
-
- has_error_code = 0;
- if (!is_int && !is_hw) {
- switch(intno) {
- case 8:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 17:
- has_error_code = 1;
- break;
- }
- }
- if (is_int)
- old_eip = next_eip;
- else
- old_eip = env->eip;
-
- dt = &env->idt;
- if (intno * 8 + 7 > dt->limit)
- raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
- ptr = dt->base + intno * 8;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
- /* check gate type */
- type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
- switch(type) {
- case 5: /* task gate */
- /* must do that check here to return the correct error code */
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
- switch_tss(intno * 8, e1, e2, SWITCH_TSS_CALL, old_eip);
- if (has_error_code) {
- int mask, type;
- /* push the error code */
- type = (env->tr.flags >> DESC_TYPE_SHIFT) & 0xf;
- shift = type >> 3;
- if (env->segs[R_SS].flags & DESC_B_MASK)
- mask = 0xffffffff;
- else
- mask = 0xffff;
- esp = (ESP - (2 << shift)) & mask;
- ssp = env->segs[R_SS].base + esp;
- if (shift)
- stl_kernel(ssp, error_code);
- else
- stw_kernel(ssp, error_code);
- ESP = (esp & mask) | (ESP & ~mask);
- }
- return;
- case 6: /* 286 interrupt gate */
- case 7: /* 286 trap gate */
- case 14: /* 386 interrupt gate */
- case 15: /* 386 trap gate */
- break;
- default:
- raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
- break;
- }
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->hflags & HF_CPL_MASK;
- /* check privledge if software int */
- if (is_int && dpl < cpl)
- raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
- /* check valid bit */
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, intno * 8 + 2);
- selector = e1 >> 16;
- offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
- if ((selector & 0xfffc) == 0)
- raise_exception_err(EXCP0D_GPF, 0);
-
- if (load_segment(&e1, &e2, selector) != 0)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- if (dpl > cpl)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
- if (!(e2 & DESC_C_MASK) && dpl < cpl) {
- /* to inner priviledge */
- get_ss_esp_from_tss(&ss, &esp, dpl);
- if ((ss & 0xfffc) == 0)
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- if ((ss & 3) != dpl)
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- if (load_segment(&ss_e1, &ss_e2, ss) != 0)
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
- if (ss_dpl != dpl)
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- if (!(ss_e2 & DESC_S_MASK) ||
- (ss_e2 & DESC_CS_MASK) ||
- !(ss_e2 & DESC_W_MASK))
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- if (!(ss_e2 & DESC_P_MASK))
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- new_stack = 1;
- sp_mask = get_sp_mask(ss_e2);
- ssp = get_seg_base(ss_e1, ss_e2);
- } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
- /* to same priviledge */
- if (env->eflags & VM_MASK)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- new_stack = 0;
- sp_mask = get_sp_mask(env->segs[R_SS].flags);
- ssp = env->segs[R_SS].base;
- esp = ESP;
- dpl = cpl;
- } else {
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- new_stack = 0; /* avoid warning */
- sp_mask = 0; /* avoid warning */
- ssp = 0; /* avoid warning */
- esp = 0; /* avoid warning */
- }
-
- shift = type >> 3;
-
-#if 0
- /* XXX: check that enough room is available */
- push_size = 6 + (new_stack << 2) + (has_error_code << 1);
- if (env->eflags & VM_MASK)
- push_size += 8;
- push_size <<= shift;
-#endif
- if (shift == 1) {
- if (new_stack) {
- if (env->eflags & VM_MASK) {
- PUSHL(ssp, esp, sp_mask, env->segs[R_GS].selector);
- PUSHL(ssp, esp, sp_mask, env->segs[R_FS].selector);
- PUSHL(ssp, esp, sp_mask, env->segs[R_DS].selector);
- PUSHL(ssp, esp, sp_mask, env->segs[R_ES].selector);
- }
- PUSHL(ssp, esp, sp_mask, env->segs[R_SS].selector);
- PUSHL(ssp, esp, sp_mask, ESP);
- }
- PUSHL(ssp, esp, sp_mask, compute_eflags());
- PUSHL(ssp, esp, sp_mask, env->segs[R_CS].selector);
- PUSHL(ssp, esp, sp_mask, old_eip);
- if (has_error_code) {
- PUSHL(ssp, esp, sp_mask, error_code);
- }
- } else {
- if (new_stack) {
- if (env->eflags & VM_MASK) {
- PUSHW(ssp, esp, sp_mask, env->segs[R_GS].selector);
- PUSHW(ssp, esp, sp_mask, env->segs[R_FS].selector);
- PUSHW(ssp, esp, sp_mask, env->segs[R_DS].selector);
- PUSHW(ssp, esp, sp_mask, env->segs[R_ES].selector);
- }
- PUSHW(ssp, esp, sp_mask, env->segs[R_SS].selector);
- PUSHW(ssp, esp, sp_mask, ESP);
- }
- PUSHW(ssp, esp, sp_mask, compute_eflags());
- PUSHW(ssp, esp, sp_mask, env->segs[R_CS].selector);
- PUSHW(ssp, esp, sp_mask, old_eip);
- if (has_error_code) {
- PUSHW(ssp, esp, sp_mask, error_code);
- }
- }
-
- if (new_stack) {
- if (env->eflags & VM_MASK) {
- cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0, 0);
- cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0, 0);
- cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0, 0);
- cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0, 0);
- }
- ss = (ss & ~3) | dpl;
- cpu_x86_load_seg_cache(env, R_SS, ss,
- ssp, get_seg_limit(ss_e1, ss_e2), ss_e2);
- }
- ESP = (ESP & ~sp_mask) | (esp & sp_mask);
-
- selector = (selector & ~3) | dpl;
- cpu_x86_load_seg_cache(env, R_CS, selector,
- get_seg_base(e1, e2),
- get_seg_limit(e1, e2),
- e2);
- cpu_x86_set_cpl(env, dpl);
- env->eip = offset;
-
- /* interrupt gate clear IF mask */
- if ((type & 1) == 0) {
- env->eflags &= ~IF_MASK;
- }
- env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
-}
-
-#ifdef TARGET_X86_64
-
-#define PUSHQ(sp, val)\
-{\
- sp -= 8;\
- stq_kernel(sp, (val));\
-}
-
-#define POPQ(sp, val)\
-{\
- val = ldq_kernel(sp);\
- sp += 8;\
-}
-
-static inline target_ulong get_rsp_from_tss(int level)
-{
- int index;
-
-#if 0
- printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
- env->tr.base, env->tr.limit);
-#endif
-
- if (!(env->tr.flags & DESC_P_MASK))
- cpu_abort(env, "invalid tss");
- index = 8 * level + 4;
- if ((index + 7) > env->tr.limit)
- raise_exception_err(EXCP0A_TSS, env->tr.selector & 0xfffc);
- return ldq_kernel(env->tr.base + index);
-}
-
-/* 64 bit interrupt */
-static void do_interrupt64(int intno, int is_int, int error_code,
- target_ulong next_eip, int is_hw)
-{
- SegmentCache *dt;
- target_ulong ptr;
- int type, dpl, selector, cpl, ist;
- int has_error_code, new_stack;
- uint32_t e1, e2, e3, ss;
- target_ulong old_eip, esp, offset;
-
- has_error_code = 0;
- if (!is_int && !is_hw) {
- switch(intno) {
- case 8:
- case 10:
- case 11:
- case 12:
- case 13:
- case 14:
- case 17:
- has_error_code = 1;
- break;
- }
- }
- if (is_int)
- old_eip = next_eip;
- else
- old_eip = env->eip;
-
- dt = &env->idt;
- if (intno * 16 + 15 > dt->limit)
- raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
- ptr = dt->base + intno * 16;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
- e3 = ldl_kernel(ptr + 8);
- /* check gate type */
- type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
- switch(type) {
- case 14: /* 386 interrupt gate */
- case 15: /* 386 trap gate */
- break;
- default:
- raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
- break;
- }
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->hflags & HF_CPL_MASK;
- /* check privledge if software int */
- if (is_int && dpl < cpl)
- raise_exception_err(EXCP0D_GPF, intno * 16 + 2);
- /* check valid bit */
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, intno * 16 + 2);
- selector = e1 >> 16;
- offset = ((target_ulong)e3 << 32) | (e2 & 0xffff0000) | (e1 & 0x0000ffff);
- ist = e2 & 7;
- if ((selector & 0xfffc) == 0)
- raise_exception_err(EXCP0D_GPF, 0);
-
- if (load_segment(&e1, &e2, selector) != 0)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- if (dpl > cpl)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
- if (!(e2 & DESC_L_MASK) || (e2 & DESC_B_MASK))
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- if ((!(e2 & DESC_C_MASK) && dpl < cpl) || ist != 0) {
- /* to inner priviledge */
- if (ist != 0)
- esp = get_rsp_from_tss(ist + 3);
- else
- esp = get_rsp_from_tss(dpl);
- esp &= ~0xfLL; /* align stack */
- ss = 0;
- new_stack = 1;
- } else if ((e2 & DESC_C_MASK) || dpl == cpl) {
- /* to same priviledge */
- if (env->eflags & VM_MASK)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- new_stack = 0;
- if (ist != 0)
- esp = get_rsp_from_tss(ist + 3);
- else
- esp = ESP;
- esp &= ~0xfLL; /* align stack */
- dpl = cpl;
- } else {
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- new_stack = 0; /* avoid warning */
- esp = 0; /* avoid warning */
- }
-
- PUSHQ(esp, env->segs[R_SS].selector);
- PUSHQ(esp, ESP);
- PUSHQ(esp, compute_eflags());
- PUSHQ(esp, env->segs[R_CS].selector);
- PUSHQ(esp, old_eip);
- if (has_error_code) {
- PUSHQ(esp, error_code);
- }
-
- if (new_stack) {
- ss = 0 | dpl;
- cpu_x86_load_seg_cache(env, R_SS, ss, 0, 0, 0);
- }
- ESP = esp;
-
- selector = (selector & ~3) | dpl;
- cpu_x86_load_seg_cache(env, R_CS, selector,
- get_seg_base(e1, e2),
- get_seg_limit(e1, e2),
- e2);
- cpu_x86_set_cpl(env, dpl);
- env->eip = offset;
-
- /* interrupt gate clear IF mask */
- if ((type & 1) == 0) {
- env->eflags &= ~IF_MASK;
- }
- env->eflags &= ~(TF_MASK | VM_MASK | RF_MASK | NT_MASK);
-}
-#endif
-
-void helper_syscall(int next_eip_addend)
-{
- int selector;
-
- if (!(env->efer & MSR_EFER_SCE)) {
- raise_exception_err(EXCP06_ILLOP, 0);
- }
- selector = (env->star >> 32) & 0xffff;
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK) {
- int code64;
-
- ECX = env->eip + next_eip_addend;
- env->regs[11] = compute_eflags();
-
- code64 = env->hflags & HF_CS64_MASK;
-
- 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_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,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_W_MASK | DESC_A_MASK);
- env->eflags &= ~env->fmask;
- if (code64)
- env->eip = env->lstar;
- else
- env->eip = env->cstar;
- } else
-#endif
- {
- ECX = (uint32_t)(env->eip + next_eip_addend);
-
- 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_S_MASK |
- DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
- cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_W_MASK | DESC_A_MASK);
- env->eflags &= ~(IF_MASK | RF_MASK | VM_MASK);
- env->eip = (uint32_t)env->star;
- }
-}
-
-void helper_sysret(int dflag)
-{
- int cpl, selector;
-
- if (!(env->efer & MSR_EFER_SCE)) {
- raise_exception_err(EXCP06_ILLOP, 0);
- }
- cpl = env->hflags & HF_CPL_MASK;
- if (!(env->cr[0] & CR0_PE_MASK) || cpl != 0) {
- raise_exception_err(EXCP0D_GPF, 0);
- }
- selector = (env->star >> 48) & 0xffff;
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK) {
- 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_S_MASK | (3 << DESC_DPL_SHIFT) |
- DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
- DESC_L_MASK);
- env->eip = ECX;
- } else {
- cpu_x86_load_seg_cache(env, R_CS, selector | 3,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
- DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
- env->eip = (uint32_t)ECX;
- }
- cpu_x86_load_seg_cache(env, R_SS, selector + 8,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
- DESC_W_MASK | DESC_A_MASK);
- load_eflags((uint32_t)(env->regs[11]), TF_MASK | AC_MASK | ID_MASK |
- IF_MASK | IOPL_MASK | VM_MASK | RF_MASK | NT_MASK);
- cpu_x86_set_cpl(env, 3);
- } else
-#endif
- {
- cpu_x86_load_seg_cache(env, R_CS, selector | 3,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
- DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
- env->eip = (uint32_t)ECX;
- cpu_x86_load_seg_cache(env, R_SS, selector + 8,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
- DESC_W_MASK | DESC_A_MASK);
- env->eflags |= IF_MASK;
- cpu_x86_set_cpl(env, 3);
- }
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env)) {
- if (env->hflags & HF_LMA_MASK)
- CC_OP = CC_OP_EFLAGS;
- env->exception_index = -1;
- cpu_loop_exit();
- }
-#endif
-}
-
-/* real mode interrupt */
-static void do_interrupt_real(int intno, int is_int, int error_code,
- unsigned int next_eip)
-{
- SegmentCache *dt;
- target_ulong ptr, ssp;
- int selector;
- uint32_t offset, esp;
- uint32_t old_cs, old_eip;
-
- /* real mode (simpler !) */
- dt = &env->idt;
- if (intno * 4 + 3 > dt->limit)
- raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
- ptr = dt->base + intno * 4;
- offset = lduw_kernel(ptr);
- selector = lduw_kernel(ptr + 2);
- esp = ESP;
- ssp = env->segs[R_SS].base;
- if (is_int)
- old_eip = next_eip;
- else
- old_eip = env->eip;
- old_cs = env->segs[R_CS].selector;
- /* XXX: use SS segment size ? */
- PUSHW(ssp, esp, 0xffff, compute_eflags());
- PUSHW(ssp, esp, 0xffff, old_cs);
- PUSHW(ssp, esp, 0xffff, old_eip);
-
- /* update processor state */
- ESP = (ESP & ~0xffff) | (esp & 0xffff);
- env->eip = offset;
- env->segs[R_CS].selector = selector;
- env->segs[R_CS].base = (selector << 4);
- env->eflags &= ~(IF_MASK | TF_MASK | AC_MASK | RF_MASK);
-}
-
-/* fake user mode interrupt */
-void do_interrupt_user(int intno, int is_int, int error_code,
- target_ulong next_eip)
-{
- SegmentCache *dt;
- target_ulong ptr;
- int dpl, cpl;
- uint32_t e2;
-
- dt = &env->idt;
- ptr = dt->base + (intno * 8);
- e2 = ldl_kernel(ptr + 4);
-
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->hflags & HF_CPL_MASK;
- /* check privledge if software int */
- if (is_int && dpl < cpl)
- raise_exception_err(EXCP0D_GPF, intno * 8 + 2);
-
- /* Since we emulate only user space, we cannot do more than
- exiting the emulation with the suitable exception and error
- code */
- if (is_int)
- EIP = next_eip;
-}
-
-/*
- * Begin execution of an interruption. 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 is_int is TRUE.
- */
-void do_interrupt(int intno, int is_int, int error_code,
- target_ulong next_eip, int is_hw)
-{
- if (loglevel & CPU_LOG_INT) {
- if ((env->cr[0] & CR0_PE_MASK)) {
- static int count;
- fprintf(logfile, "%6d: v=%02x e=%04x i=%d cpl=%d IP=%04x:" TARGET_FMT_lx " pc=" TARGET_FMT_lx " SP=%04x:" TARGET_FMT_lx,
- count, intno, error_code, is_int,
- env->hflags & HF_CPL_MASK,
- env->segs[R_CS].selector, EIP,
- (int)env->segs[R_CS].base + EIP,
- env->segs[R_SS].selector, ESP);
- if (intno == 0x0e) {
- fprintf(logfile, " CR2=" TARGET_FMT_lx, env->cr[2]);
- } else {
- fprintf(logfile, " EAX=" TARGET_FMT_lx, EAX);
- }
- fprintf(logfile, "\n");
- cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
-#if 0
- {
- int i;
- uint8_t *ptr;
- fprintf(logfile, " code=");
- ptr = env->segs[R_CS].base + env->eip;
- for(i = 0; i < 16; i++) {
- fprintf(logfile, " %02x", ldub(ptr + i));
- }
- fprintf(logfile, "\n");
- }
-#endif
- count++;
- }
- }
- if (env->cr[0] & CR0_PE_MASK) {
-#if TARGET_X86_64
- if (env->hflags & HF_LMA_MASK) {
- do_interrupt64(intno, is_int, error_code, next_eip, is_hw);
- } else
-#endif
- {
- do_interrupt_protected(intno, is_int, error_code, next_eip, is_hw);
- }
- } else {
- do_interrupt_real(intno, is_int, error_code, next_eip);
- }
-}
-
-/*
- * 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
- * is_int is TRUE.
- */
-void raise_interrupt(int intno, int is_int, int error_code,
- int next_eip_addend)
-{
- env->exception_index = intno;
- env->error_code = error_code;
- env->exception_is_int = is_int;
- env->exception_next_eip = env->eip + next_eip_addend;
- cpu_loop_exit();
-}
-
-/* same as raise_exception_err, but do not restore global registers */
-static void raise_exception_err_norestore(int exception_index, int error_code)
-{
- env->exception_index = exception_index;
- env->error_code = error_code;
- env->exception_is_int = 0;
- env->exception_next_eip = 0;
- longjmp(env->jmp_env, 1);
-}
-
-/* shortcuts to generate exceptions */
-
-void (raise_exception_err)(int exception_index, int error_code)
-{
- raise_interrupt(exception_index, 0, error_code, 0);
-}
-
-void raise_exception(int exception_index)
-{
- raise_interrupt(exception_index, 0, 0, 0);
-}
-
-#ifdef BUGGY_GCC_DIV64
-/* gcc 2.95.4 on PowerPC does not seem to like using __udivdi3, so we
- call it from another function */
-uint32_t div32(uint64_t *q_ptr, uint64_t num, uint32_t den)
-{
- *q_ptr = num / den;
- return num % den;
-}
-
-int32_t idiv32(int64_t *q_ptr, int64_t num, int32_t den)
-{
- *q_ptr = num / den;
- return num % den;
-}
-#endif
-
-void helper_divl_EAX_T0(void)
-{
- unsigned int den, r;
- uint64_t num, q;
-
- num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
- den = T0;
- if (den == 0) {
- raise_exception(EXCP00_DIVZ);
- }
-#ifdef BUGGY_GCC_DIV64
- r = div32(&q, num, den);
-#else
- q = (num / den);
- r = (num % den);
-#endif
- if (q > 0xffffffff)
- raise_exception(EXCP00_DIVZ);
- EAX = (uint32_t)q;
- EDX = (uint32_t)r;
-}
-
-void helper_idivl_EAX_T0(void)
-{
- int den, r;
- int64_t num, q;
-
- num = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
- den = T0;
- if (den == 0) {
- raise_exception(EXCP00_DIVZ);
- }
-#ifdef BUGGY_GCC_DIV64
- r = idiv32(&q, num, den);
-#else
- q = (num / den);
- r = (num % den);
-#endif
- if (q != (int32_t)q)
- raise_exception(EXCP00_DIVZ);
- EAX = (uint32_t)q;
- EDX = (uint32_t)r;
-}
-
-void helper_cmpxchg8b(void)
-{
- uint64_t d;
- int eflags;
-
- eflags = cc_table[CC_OP].compute_all();
- d = ldq(A0);
- if (d == (((uint64_t)EDX << 32) | EAX)) {
- stq(A0, ((uint64_t)ECX << 32) | EBX);
- eflags |= CC_Z;
- } else {
- EDX = d >> 32;
- EAX = d;
- eflags &= ~CC_Z;
- }
- CC_SRC = eflags;
-}
-
-void helper_cpuid(void)
-{
- uint32_t index;
- index = (uint32_t)EAX;
-
- /* test if maximum index reached */
- if (index & 0x80000000) {
- if (index > env->cpuid_xlevel)
- index = env->cpuid_level;
- } else {
- if (index > env->cpuid_level)
- index = env->cpuid_level;
- }
-
- switch(index) {
- case 0:
- EAX = env->cpuid_level;
- EBX = env->cpuid_vendor1;
- EDX = env->cpuid_vendor2;
- ECX = env->cpuid_vendor3;
- break;
- case 1:
- EAX = env->cpuid_version;
- EBX = 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
- ECX = env->cpuid_ext_features;
- EDX = env->cpuid_features;
- break;
- case 2:
- /* cache info: needed for Pentium Pro compatibility */
- EAX = 0x410601;
- EBX = 0;
- ECX = 0;
- EDX = 0;
- break;
- case 0x80000000:
- EAX = env->cpuid_xlevel;
- EBX = env->cpuid_vendor1;
- EDX = env->cpuid_vendor2;
- ECX = env->cpuid_vendor3;
- break;
- case 0x80000001:
- EAX = env->cpuid_features;
- EBX = 0;
- ECX = 0;
- EDX = env->cpuid_ext2_features;
- break;
- case 0x80000002:
- case 0x80000003:
- case 0x80000004:
- EAX = env->cpuid_model[(index - 0x80000002) * 4 + 0];
- EBX = env->cpuid_model[(index - 0x80000002) * 4 + 1];
- ECX = env->cpuid_model[(index - 0x80000002) * 4 + 2];
- EDX = env->cpuid_model[(index - 0x80000002) * 4 + 3];
- break;
- case 0x80000005:
- /* cache info (L1 cache) */
- EAX = 0x01ff01ff;
- EBX = 0x01ff01ff;
- ECX = 0x40020140;
- EDX = 0x40020140;
- break;
- case 0x80000006:
- /* cache info (L2 cache) */
- EAX = 0;
- EBX = 0x42004200;
- ECX = 0x02008140;
- EDX = 0;
- break;
- case 0x80000008:
- /* virtual & phys address size in low 2 bytes. */
- EAX = 0x00003028;
- EBX = 0;
- ECX = 0;
- EDX = 0;
- break;
- default:
- /* reserved values: zero */
- EAX = 0;
- EBX = 0;
- ECX = 0;
- EDX = 0;
- break;
- }
-}
-
-void helper_enter_level(int level, int data32)
-{
- target_ulong ssp;
- uint32_t esp_mask, esp, ebp;
-
- esp_mask = get_sp_mask(env->segs[R_SS].flags);
- ssp = env->segs[R_SS].base;
- ebp = EBP;
- esp = ESP;
- if (data32) {
- /* 32 bit */
- esp -= 4;
- while (--level) {
- esp -= 4;
- ebp -= 4;
- stl(ssp + (esp & esp_mask), ldl(ssp + (ebp & esp_mask)));
- }
- esp -= 4;
- stl(ssp + (esp & esp_mask), T1);
- } else {
- /* 16 bit */
- esp -= 2;
- while (--level) {
- esp -= 2;
- ebp -= 2;
- stw(ssp + (esp & esp_mask), lduw(ssp + (ebp & esp_mask)));
- }
- esp -= 2;
- stw(ssp + (esp & esp_mask), T1);
- }
-}
-
-#ifdef TARGET_X86_64
-void helper_enter64_level(int level, int data64)
-{
- target_ulong esp, ebp;
- ebp = EBP;
- esp = ESP;
-
- if (data64) {
- /* 64 bit */
- esp -= 8;
- while (--level) {
- esp -= 8;
- ebp -= 8;
- stq(esp, ldq(ebp));
- }
- esp -= 8;
- stq(esp, T1);
- } else {
- /* 16 bit */
- esp -= 2;
- while (--level) {
- esp -= 2;
- ebp -= 2;
- stw(esp, lduw(ebp));
- }
- esp -= 2;
- stw(esp, T1);
- }
-}
-#endif
-
-void helper_lldt_T0(void)
-{
- int selector;
- SegmentCache *dt;
- uint32_t e1, e2;
- int index, entry_limit;
- target_ulong ptr;
-
- selector = T0 & 0xffff;
- if ((selector & 0xfffc) == 0) {
- /* XXX: NULL selector case: invalid LDT */
- env->ldt.base = 0;
- env->ldt.limit = 0;
- } else {
- if (selector & 0x4)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- dt = &env->gdt;
- index = selector & ~7;
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK)
- entry_limit = 15;
- else
-#endif
- entry_limit = 7;
- if ((index + entry_limit) > dt->limit)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- ptr = dt->base + index;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
- if ((e2 & DESC_S_MASK) || ((e2 >> DESC_TYPE_SHIFT) & 0xf) != 2)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK) {
- uint32_t e3;
- e3 = ldl_kernel(ptr + 8);
- load_seg_cache_raw_dt(&env->ldt, e1, e2);
- env->ldt.base |= (target_ulong)e3 << 32;
- } else
-#endif
- {
- load_seg_cache_raw_dt(&env->ldt, e1, e2);
- }
- }
- env->ldt.selector = selector;
-}
-
-void helper_ltr_T0(void)
-{
- int selector;
- SegmentCache *dt;
- uint32_t e1, e2;
- int index, type, entry_limit;
- target_ulong ptr;
-
- selector = T0 & 0xffff;
- if ((selector & 0xfffc) == 0) {
- /* NULL selector case: invalid TR */
- env->tr.base = 0;
- env->tr.limit = 0;
- env->tr.flags = 0;
- } else {
- if (selector & 0x4)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- dt = &env->gdt;
- index = selector & ~7;
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK)
- entry_limit = 15;
- else
-#endif
- entry_limit = 7;
- if ((index + entry_limit) > dt->limit)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- ptr = dt->base + index;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
- type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
- if ((e2 & DESC_S_MASK) ||
- (type != 1 && type != 9))
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK) {
- uint32_t e3;
- e3 = ldl_kernel(ptr + 8);
- load_seg_cache_raw_dt(&env->tr, e1, e2);
- env->tr.base |= (target_ulong)e3 << 32;
- } else
-#endif
- {
- load_seg_cache_raw_dt(&env->tr, e1, e2);
- }
- e2 |= DESC_TSS_BUSY_MASK;
- stl_kernel(ptr + 4, e2);
- }
- env->tr.selector = selector;
-}
-
-/* only works if protected mode and not VM86. seg_reg must be != R_CS */
-void load_seg(int seg_reg, int selector)
-{
- uint32_t e1, e2;
- int cpl, dpl, rpl;
- SegmentCache *dt;
- int index;
- target_ulong ptr;
-
- selector &= 0xffff;
- cpl = env->hflags & HF_CPL_MASK;
- if ((selector & 0xfffc) == 0) {
- /* null selector case */
- if (seg_reg == R_SS
-#ifdef TARGET_X86_64
- && (!(env->hflags & HF_CS64_MASK) || cpl == 3)
-#endif
- )
- raise_exception_err(EXCP0D_GPF, 0);
- cpu_x86_load_seg_cache(env, seg_reg, selector, 0, 0, 0);
- } else {
-
- if (selector & 0x4)
- dt = &env->ldt;
- else
- dt = &env->gdt;
- index = selector & ~7;
- if ((index + 7) > dt->limit)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- ptr = dt->base + index;
- e1 = ldl_kernel(ptr);
- e2 = ldl_kernel(ptr + 4);
-
- if (!(e2 & DESC_S_MASK))
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- rpl = selector & 3;
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- if (seg_reg == R_SS) {
- /* must be writable segment */
- if ((e2 & DESC_CS_MASK) || !(e2 & DESC_W_MASK))
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- if (rpl != cpl || dpl != cpl)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- } else {
- /* must be readable segment */
- if ((e2 & (DESC_CS_MASK | DESC_R_MASK)) == DESC_CS_MASK)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
-
- if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
- /* if not conforming code, test rights */
- if (dpl < cpl || dpl < rpl)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- }
- }
-
- if (!(e2 & DESC_P_MASK)) {
- if (seg_reg == R_SS)
- raise_exception_err(EXCP0C_STACK, selector & 0xfffc);
- else
- raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
- }
-
- /* set the access bit if not already set */
- if (!(e2 & DESC_A_MASK)) {
- e2 |= DESC_A_MASK;
- stl_kernel(ptr + 4, e2);
- }
-
- cpu_x86_load_seg_cache(env, seg_reg, selector,
- get_seg_base(e1, e2),
- get_seg_limit(e1, e2),
- e2);
-#if 0
- fprintf(logfile, "load_seg: sel=0x%04x base=0x%08lx limit=0x%08lx flags=%08x\n",
- selector, (unsigned long)sc->base, sc->limit, sc->flags);
-#endif
- }
-}
-
-/* protected mode jump */
-void helper_ljmp_protected_T0_T1(int next_eip_addend)
-{
- int new_cs, gate_cs, type;
- uint32_t e1, e2, cpl, dpl, rpl, limit;
- target_ulong new_eip, next_eip;
-
- new_cs = T0;
- new_eip = T1;
- if ((new_cs & 0xfffc) == 0)
- raise_exception_err(EXCP0D_GPF, 0);
- if (load_segment(&e1, &e2, new_cs) != 0)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- cpl = env->hflags & HF_CPL_MASK;
- if (e2 & DESC_S_MASK) {
- if (!(e2 & DESC_CS_MASK))
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- if (e2 & DESC_C_MASK) {
- /* conforming code segment */
- if (dpl > cpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- } else {
- /* non conforming code segment */
- rpl = new_cs & 3;
- if (rpl > cpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- if (dpl != cpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- }
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
- limit = get_seg_limit(e1, e2);
- if (new_eip > limit &&
- !(env->hflags & HF_LMA_MASK) && !(e2 & DESC_L_MASK))
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
- get_seg_base(e1, e2), limit, e2);
- EIP = new_eip;
- } else {
- /* jump to call or task gate */
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- rpl = new_cs & 3;
- cpl = env->hflags & HF_CPL_MASK;
- type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
- switch(type) {
- case 1: /* 286 TSS */
- case 9: /* 386 TSS */
- case 5: /* task gate */
- if (dpl < cpl || dpl < rpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- next_eip = env->eip + next_eip_addend;
- switch_tss(new_cs, e1, e2, SWITCH_TSS_JMP, next_eip);
- CC_OP = CC_OP_EFLAGS;
- break;
- case 4: /* 286 call gate */
- case 12: /* 386 call gate */
- if ((dpl < cpl) || (dpl < rpl))
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
- gate_cs = e1 >> 16;
- new_eip = (e1 & 0xffff);
- if (type == 12)
- new_eip |= (e2 & 0xffff0000);
- if (load_segment(&e1, &e2, gate_cs) != 0)
- raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- /* must be code segment */
- if (((e2 & (DESC_S_MASK | DESC_CS_MASK)) !=
- (DESC_S_MASK | DESC_CS_MASK)))
- raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
- if (((e2 & DESC_C_MASK) && (dpl > cpl)) ||
- (!(e2 & DESC_C_MASK) && (dpl != cpl)))
- raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0D_GPF, gate_cs & 0xfffc);
- limit = get_seg_limit(e1, e2);
- if (new_eip > limit)
- raise_exception_err(EXCP0D_GPF, 0);
- cpu_x86_load_seg_cache(env, R_CS, (gate_cs & 0xfffc) | cpl,
- get_seg_base(e1, e2), limit, e2);
- EIP = new_eip;
- break;
- default:
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- break;
- }
- }
-}
-
-/* real mode call */
-void helper_lcall_real_T0_T1(int shift, int next_eip)
-{
- int new_cs, new_eip;
- uint32_t esp, esp_mask;
- target_ulong ssp;
-
- new_cs = T0;
- new_eip = T1;
- esp = ESP;
- esp_mask = get_sp_mask(env->segs[R_SS].flags);
- ssp = env->segs[R_SS].base;
- if (shift) {
- PUSHL(ssp, esp, esp_mask, env->segs[R_CS].selector);
- PUSHL(ssp, esp, esp_mask, next_eip);
- } else {
- PUSHW(ssp, esp, esp_mask, env->segs[R_CS].selector);
- PUSHW(ssp, esp, esp_mask, next_eip);
- }
-
- ESP = (ESP & ~esp_mask) | (esp & esp_mask);
- env->eip = new_eip;
- env->segs[R_CS].selector = new_cs;
- env->segs[R_CS].base = (new_cs << 4);
-}
-
-/* protected mode call */
-void helper_lcall_protected_T0_T1(int shift, int next_eip_addend)
-{
- int new_cs, new_stack, i;
- uint32_t e1, e2, cpl, dpl, rpl, selector, offset, param_count;
- uint32_t ss, ss_e1, ss_e2, sp, type, ss_dpl, sp_mask;
- uint32_t val, limit, old_sp_mask;
- target_ulong ssp, old_ssp, next_eip, new_eip;
-
- new_cs = T0;
- new_eip = T1;
- next_eip = env->eip + next_eip_addend;
-#ifdef DEBUG_PCALL
- if (loglevel & CPU_LOG_PCALL) {
- fprintf(logfile, "lcall %04x:%08x s=%d\n",
- new_cs, (uint32_t)new_eip, shift);
- cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
- }
-#endif
- if ((new_cs & 0xfffc) == 0)
- raise_exception_err(EXCP0D_GPF, 0);
- if (load_segment(&e1, &e2, new_cs) != 0)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- cpl = env->hflags & HF_CPL_MASK;
-#ifdef DEBUG_PCALL
- if (loglevel & CPU_LOG_PCALL) {
- fprintf(logfile, "desc=%08x:%08x\n", e1, e2);
- }
-#endif
- if (e2 & DESC_S_MASK) {
- if (!(e2 & DESC_CS_MASK))
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- if (e2 & DESC_C_MASK) {
- /* conforming code segment */
- if (dpl > cpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- } else {
- /* non conforming code segment */
- rpl = new_cs & 3;
- if (rpl > cpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- if (dpl != cpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- }
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
-
-#ifdef TARGET_X86_64
- /* XXX: check 16/32 bit cases in long mode */
- if (shift == 2) {
- target_ulong rsp;
- /* 64 bit case */
- rsp = ESP;
- PUSHQ(rsp, env->segs[R_CS].selector);
- PUSHQ(rsp, next_eip);
- /* from this point, not restartable */
- ESP = rsp;
- cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
- get_seg_base(e1, e2),
- get_seg_limit(e1, e2), e2);
- EIP = new_eip;
- } else
-#endif
- {
- sp = ESP;
- sp_mask = get_sp_mask(env->segs[R_SS].flags);
- ssp = env->segs[R_SS].base;
- if (shift) {
- PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
- PUSHL(ssp, sp, sp_mask, next_eip);
- } else {
- PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
- PUSHW(ssp, sp, sp_mask, next_eip);
- }
-
- limit = get_seg_limit(e1, e2);
- if (new_eip > limit)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- /* from this point, not restartable */
- ESP = (ESP & ~sp_mask) | (sp & sp_mask);
- cpu_x86_load_seg_cache(env, R_CS, (new_cs & 0xfffc) | cpl,
- get_seg_base(e1, e2), limit, e2);
- EIP = new_eip;
- }
- } else {
- /* check gate type */
- type = (e2 >> DESC_TYPE_SHIFT) & 0x1f;
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- rpl = new_cs & 3;
- switch(type) {
- case 1: /* available 286 TSS */
- case 9: /* available 386 TSS */
- case 5: /* task gate */
- if (dpl < cpl || dpl < rpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- switch_tss(new_cs, e1, e2, SWITCH_TSS_CALL, next_eip);
- CC_OP = CC_OP_EFLAGS;
- return;
- case 4: /* 286 call gate */
- case 12: /* 386 call gate */
- break;
- default:
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- break;
- }
- shift = type >> 3;
-
- if (dpl < cpl || dpl < rpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- /* check valid bit */
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
- selector = e1 >> 16;
- offset = (e2 & 0xffff0000) | (e1 & 0x0000ffff);
- param_count = e2 & 0x1f;
- if ((selector & 0xfffc) == 0)
- raise_exception_err(EXCP0D_GPF, 0);
-
- if (load_segment(&e1, &e2, selector) != 0)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- if (!(e2 & DESC_S_MASK) || !(e2 & (DESC_CS_MASK)))
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- if (dpl > cpl)
- raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
-
- if (!(e2 & DESC_C_MASK) && dpl < cpl) {
- /* to inner priviledge */
- get_ss_esp_from_tss(&ss, &sp, dpl);
-#ifdef DEBUG_PCALL
- if (loglevel & CPU_LOG_PCALL)
- fprintf(logfile, "new ss:esp=%04x:%08x param_count=%d ESP=" TARGET_FMT_lx "\n",
- ss, sp, param_count, ESP);
-#endif
- if ((ss & 0xfffc) == 0)
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- if ((ss & 3) != dpl)
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- if (load_segment(&ss_e1, &ss_e2, ss) != 0)
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- ss_dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
- if (ss_dpl != dpl)
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- if (!(ss_e2 & DESC_S_MASK) ||
- (ss_e2 & DESC_CS_MASK) ||
- !(ss_e2 & DESC_W_MASK))
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
- if (!(ss_e2 & DESC_P_MASK))
- raise_exception_err(EXCP0A_TSS, ss & 0xfffc);
-
- // push_size = ((param_count * 2) + 8) << shift;
-
- old_sp_mask = get_sp_mask(env->segs[R_SS].flags);
- old_ssp = env->segs[R_SS].base;
-
- sp_mask = get_sp_mask(ss_e2);
- ssp = get_seg_base(ss_e1, ss_e2);
- if (shift) {
- PUSHL(ssp, sp, sp_mask, env->segs[R_SS].selector);
- PUSHL(ssp, sp, sp_mask, ESP);
- for(i = param_count - 1; i >= 0; i--) {
- val = ldl_kernel(old_ssp + ((ESP + i * 4) & old_sp_mask));
- PUSHL(ssp, sp, sp_mask, val);
- }
- } else {
- PUSHW(ssp, sp, sp_mask, env->segs[R_SS].selector);
- PUSHW(ssp, sp, sp_mask, ESP);
- for(i = param_count - 1; i >= 0; i--) {
- val = lduw_kernel(old_ssp + ((ESP + i * 2) & old_sp_mask));
- PUSHW(ssp, sp, sp_mask, val);
- }
- }
- new_stack = 1;
- } else {
- /* to same priviledge */
- sp = ESP;
- sp_mask = get_sp_mask(env->segs[R_SS].flags);
- ssp = env->segs[R_SS].base;
- // push_size = (4 << shift);
- new_stack = 0;
- }
-
- if (shift) {
- PUSHL(ssp, sp, sp_mask, env->segs[R_CS].selector);
- PUSHL(ssp, sp, sp_mask, next_eip);
- } else {
- PUSHW(ssp, sp, sp_mask, env->segs[R_CS].selector);
- PUSHW(ssp, sp, sp_mask, next_eip);
- }
-
- /* from this point, not restartable */
-
- if (new_stack) {
- ss = (ss & ~3) | dpl;
- cpu_x86_load_seg_cache(env, R_SS, ss,
- ssp,
- get_seg_limit(ss_e1, ss_e2),
- ss_e2);
- }
-
- selector = (selector & ~3) | dpl;
- cpu_x86_load_seg_cache(env, R_CS, selector,
- get_seg_base(e1, e2),
- get_seg_limit(e1, e2),
- e2);
- cpu_x86_set_cpl(env, dpl);
- ESP = (ESP & ~sp_mask) | (sp & sp_mask);
- EIP = offset;
- }
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env)) {
- env->exception_index = -1;
- cpu_loop_exit();
- }
-#endif
-}
-
-/* real and vm86 mode iret */
-void helper_iret_real(int shift)
-{
- uint32_t sp, new_cs, new_eip, new_eflags, sp_mask;
- target_ulong ssp;
- int eflags_mask;
-
- sp_mask = 0xffff; /* XXXX: use SS segment size ? */
- sp = ESP;
- ssp = env->segs[R_SS].base;
- if (shift == 1) {
- /* 32 bits */
- POPL(ssp, sp, sp_mask, new_eip);
- POPL(ssp, sp, sp_mask, new_cs);
- new_cs &= 0xffff;
- POPL(ssp, sp, sp_mask, new_eflags);
- } else {
- /* 16 bits */
- POPW(ssp, sp, sp_mask, new_eip);
- POPW(ssp, sp, sp_mask, new_cs);
- POPW(ssp, sp, sp_mask, new_eflags);
- }
- ESP = (ESP & ~sp_mask) | (sp & sp_mask);
- load_seg_vm(R_CS, new_cs);
- env->eip = new_eip;
- if (env->eflags & VM_MASK)
- eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | RF_MASK | NT_MASK;
- else
- eflags_mask = TF_MASK | AC_MASK | ID_MASK | IF_MASK | IOPL_MASK | RF_MASK | NT_MASK;
- if (shift == 0)
- eflags_mask &= 0xffff;
- load_eflags(new_eflags, eflags_mask);
-}
-
-static inline void validate_seg(int seg_reg, int cpl)
-{
- int dpl;
- uint32_t e2;
-
- /* XXX: on x86_64, we do not want to nullify FS and GS because
- they may still contain a valid base. I would be interested to
- know how a real x86_64 CPU behaves */
- if ((seg_reg == R_FS || seg_reg == R_GS) &&
- (env->segs[seg_reg].selector & 0xfffc) == 0)
- return;
-
- e2 = env->segs[seg_reg].flags;
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- if (!(e2 & DESC_CS_MASK) || !(e2 & DESC_C_MASK)) {
- /* data or non conforming code segment */
- if (dpl < cpl) {
- cpu_x86_load_seg_cache(env, seg_reg, 0, 0, 0, 0);
- }
- }
-}
-
-/* protected mode iret */
-static inline void helper_ret_protected(int shift, int is_iret, int addend)
-{
- uint32_t new_cs, new_eflags, new_ss;
- uint32_t new_es, new_ds, new_fs, new_gs;
- uint32_t e1, e2, ss_e1, ss_e2;
- int cpl, dpl, rpl, eflags_mask, iopl;
- target_ulong ssp, sp, new_eip, new_esp, sp_mask;
-
-#ifdef TARGET_X86_64
- if (shift == 2)
- sp_mask = -1;
- else
-#endif
- sp_mask = get_sp_mask(env->segs[R_SS].flags);
- sp = ESP;
- ssp = env->segs[R_SS].base;
- new_eflags = 0; /* avoid warning */
-#ifdef TARGET_X86_64
- if (shift == 2) {
- POPQ(sp, new_eip);
- POPQ(sp, new_cs);
- new_cs &= 0xffff;
- if (is_iret) {
- POPQ(sp, new_eflags);
- }
- } else
-#endif
- if (shift == 1) {
- /* 32 bits */
- POPL(ssp, sp, sp_mask, new_eip);
- POPL(ssp, sp, sp_mask, new_cs);
- new_cs &= 0xffff;
- if (is_iret) {
- POPL(ssp, sp, sp_mask, new_eflags);
- if (new_eflags & VM_MASK)
- goto return_to_vm86;
- }
- } else {
- /* 16 bits */
- POPW(ssp, sp, sp_mask, new_eip);
- POPW(ssp, sp, sp_mask, new_cs);
- if (is_iret)
- POPW(ssp, sp, sp_mask, new_eflags);
- }
-#ifdef DEBUG_PCALL
- if (loglevel & CPU_LOG_PCALL) {
- fprintf(logfile, "lret new %04x:" TARGET_FMT_lx " s=%d addend=0x%x\n",
- new_cs, new_eip, shift, addend);
- cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
- }
-#endif
- if ((new_cs & 0xfffc) == 0)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- if (load_segment(&e1, &e2, new_cs) != 0)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- if (!(e2 & DESC_S_MASK) ||
- !(e2 & DESC_CS_MASK))
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- cpl = env->hflags & HF_CPL_MASK;
- rpl = new_cs & 3;
- if (rpl < cpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- if (e2 & DESC_C_MASK) {
- if (dpl > rpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- } else {
- if (dpl != rpl)
- raise_exception_err(EXCP0D_GPF, new_cs & 0xfffc);
- }
- if (!(e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, new_cs & 0xfffc);
-
- sp += addend;
- if (rpl == cpl && (!(env->hflags & HF_CS64_MASK) ||
- ((env->hflags & HF_CS64_MASK) && !is_iret))) {
- /* return to same priledge level */
- cpu_x86_load_seg_cache(env, R_CS, new_cs,
- get_seg_base(e1, e2),
- get_seg_limit(e1, e2),
- e2);
- } else {
- /* return to different priviledge level */
-#ifdef TARGET_X86_64
- if (shift == 2) {
- POPQ(sp, new_esp);
- POPQ(sp, new_ss);
- new_ss &= 0xffff;
- } else
-#endif
- if (shift == 1) {
- /* 32 bits */
- POPL(ssp, sp, sp_mask, new_esp);
- POPL(ssp, sp, sp_mask, new_ss);
- new_ss &= 0xffff;
- } else {
- /* 16 bits */
- POPW(ssp, sp, sp_mask, new_esp);
- POPW(ssp, sp, sp_mask, new_ss);
- }
-#ifdef DEBUG_PCALL
- if (loglevel & CPU_LOG_PCALL) {
- fprintf(logfile, "new ss:esp=%04x:" TARGET_FMT_lx "\n",
- new_ss, new_esp);
- }
-#endif
- if ((new_ss & 0xfffc) == 0) {
-#ifdef TARGET_X86_64
- /* NULL ss is allowed in long mode if cpl != 3*/
- 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);
- } else
-#endif
- {
- raise_exception_err(EXCP0D_GPF, 0);
- }
- } else {
- if ((new_ss & 3) != rpl)
- raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
- if (load_segment(&ss_e1, &ss_e2, new_ss) != 0)
- raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
- if (!(ss_e2 & DESC_S_MASK) ||
- (ss_e2 & DESC_CS_MASK) ||
- !(ss_e2 & DESC_W_MASK))
- raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
- dpl = (ss_e2 >> DESC_DPL_SHIFT) & 3;
- if (dpl != rpl)
- raise_exception_err(EXCP0D_GPF, new_ss & 0xfffc);
- if (!(ss_e2 & DESC_P_MASK))
- raise_exception_err(EXCP0B_NOSEG, new_ss & 0xfffc);
- cpu_x86_load_seg_cache(env, R_SS, new_ss,
- get_seg_base(ss_e1, ss_e2),
- get_seg_limit(ss_e1, ss_e2),
- ss_e2);
- }
-
- cpu_x86_load_seg_cache(env, R_CS, new_cs,
- get_seg_base(e1, e2),
- get_seg_limit(e1, e2),
- e2);
- cpu_x86_set_cpl(env, rpl);
- sp = new_esp;
-#ifdef TARGET_X86_64
- if (env->hflags & HF_CS64_MASK)
- sp_mask = -1;
- else
-#endif
- sp_mask = get_sp_mask(ss_e2);
-
- /* validate data segments */
- validate_seg(R_ES, rpl);
- validate_seg(R_DS, rpl);
- validate_seg(R_FS, rpl);
- validate_seg(R_GS, rpl);
-
- sp += addend;
- }
- ESP = (ESP & ~sp_mask) | (sp & sp_mask);
- env->eip = new_eip;
- if (is_iret) {
- /* NOTE: 'cpl' is the _old_ CPL */
- eflags_mask = TF_MASK | AC_MASK | ID_MASK | RF_MASK | NT_MASK;
- if (cpl == 0)
- eflags_mask |= IOPL_MASK;
- iopl = (env->eflags >> IOPL_SHIFT) & 3;
- if (cpl <= iopl)
- eflags_mask |= IF_MASK;
- if (shift == 0)
- eflags_mask &= 0xffff;
- load_eflags(new_eflags, eflags_mask);
- }
- return;
-
- return_to_vm86:
- POPL(ssp, sp, sp_mask, new_esp);
- POPL(ssp, sp, sp_mask, new_ss);
- POPL(ssp, sp, sp_mask, new_es);
- POPL(ssp, sp, sp_mask, new_ds);
- POPL(ssp, sp, sp_mask, new_fs);
- POPL(ssp, sp, sp_mask, new_gs);
-
- /* modify processor state */
- load_eflags(new_eflags, TF_MASK | AC_MASK | ID_MASK |
- IF_MASK | IOPL_MASK | VM_MASK | NT_MASK | VIF_MASK | VIP_MASK);
- load_seg_vm(R_CS, new_cs & 0xffff);
- cpu_x86_set_cpl(env, 3);
- load_seg_vm(R_SS, new_ss & 0xffff);
- load_seg_vm(R_ES, new_es & 0xffff);
- load_seg_vm(R_DS, new_ds & 0xffff);
- load_seg_vm(R_FS, new_fs & 0xffff);
- load_seg_vm(R_GS, new_gs & 0xffff);
-
- env->eip = new_eip & 0xffff;
- ESP = new_esp;
-}
-
-void helper_iret_protected(int shift, int next_eip)
-{
- int tss_selector, type;
- uint32_t e1, e2;
-
- /* specific case for TSS */
- if (env->eflags & NT_MASK) {
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK)
- raise_exception_err(EXCP0D_GPF, 0);
-#endif
- tss_selector = lduw_kernel(env->tr.base + 0);
- if (tss_selector & 4)
- raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
- if (load_segment(&e1, &e2, tss_selector) != 0)
- raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
- type = (e2 >> DESC_TYPE_SHIFT) & 0x17;
- /* NOTE: we check both segment and busy TSS */
- if (type != 3)
- raise_exception_err(EXCP0A_TSS, tss_selector & 0xfffc);
- switch_tss(tss_selector, e1, e2, SWITCH_TSS_IRET, next_eip);
- } else {
- helper_ret_protected(shift, 1, 0);
- }
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env)) {
- CC_OP = CC_OP_EFLAGS;
- env->exception_index = -1;
- cpu_loop_exit();
- }
-#endif
-}
-
-void helper_lret_protected(int shift, int addend)
-{
- helper_ret_protected(shift, 0, addend);
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env)) {
- env->exception_index = -1;
- cpu_loop_exit();
- }
-#endif
-}
-
-void helper_sysenter(void)
-{
- if (env->sysenter_cs == 0) {
- raise_exception_err(EXCP0D_GPF, 0);
- }
- env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK);
- cpu_x86_set_cpl(env, 0);
- cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
- cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK |
- DESC_W_MASK | DESC_A_MASK);
- ESP = env->sysenter_esp;
- EIP = env->sysenter_eip;
-}
-
-void helper_sysexit(void)
-{
- int cpl;
-
- cpl = env->hflags & HF_CPL_MASK;
- if (env->sysenter_cs == 0 || cpl != 0) {
- raise_exception_err(EXCP0D_GPF, 0);
- }
- cpu_x86_set_cpl(env, 3);
- cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
- DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
- cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3,
- 0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
- DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
- DESC_W_MASK | DESC_A_MASK);
- ESP = ECX;
- EIP = EDX;
-#ifdef USE_KQEMU
- if (kqemu_is_ok(env)) {
- env->exception_index = -1;
- cpu_loop_exit();
- }
-#endif
-}
-
-void helper_movl_crN_T0(int reg)
-{
-#if !defined(CONFIG_USER_ONLY)
- switch(reg) {
- case 0:
- cpu_x86_update_cr0(env, T0);
- break;
- case 3:
- cpu_x86_update_cr3(env, T0);
- break;
- case 4:
- cpu_x86_update_cr4(env, T0);
- break;
- case 8:
- cpu_set_apic_tpr(env, T0);
- break;
- default:
- env->cr[reg] = T0;
- break;
- }
-#endif
-}
-
-/* XXX: do more */
-void helper_movl_drN_T0(int reg)
-{
- env->dr[reg] = T0;
-}
-
-void helper_invlpg(target_ulong addr)
-{
- cpu_x86_flush_tlb(env, addr);
-}
-
-void helper_rdtsc(void)
-{
- uint64_t val;
-
- if ((env->cr[4] & CR4_TSD_MASK) && ((env->hflags & HF_CPL_MASK) != 0)) {
- raise_exception(EXCP0D_GPF);
- }
- val = cpu_get_tsc(env);
- EAX = (uint32_t)(val);
- EDX = (uint32_t)(val >> 32);
-}
-
-#if defined(CONFIG_USER_ONLY)
-void helper_wrmsr(void)
-{
-}
-
-void helper_rdmsr(void)
-{
-}
-#else
-void helper_wrmsr(void)
-{
- uint64_t val;
-
- val = ((uint32_t)EAX) | ((uint64_t)((uint32_t)EDX) << 32);
-
- switch((uint32_t)ECX) {
- case MSR_IA32_SYSENTER_CS:
- env->sysenter_cs = val & 0xffff;
- break;
- case MSR_IA32_SYSENTER_ESP:
- env->sysenter_esp = val;
- break;
- case MSR_IA32_SYSENTER_EIP:
- env->sysenter_eip = val;
- break;
- case MSR_IA32_APICBASE:
- cpu_set_apic_base(env, val);
- break;
- case MSR_EFER:
- {
- uint64_t update_mask;
- update_mask = 0;
- if (env->cpuid_ext2_features & CPUID_EXT2_SYSCALL)
- update_mask |= MSR_EFER_SCE;
- if (env->cpuid_ext2_features & CPUID_EXT2_LM)
- update_mask |= MSR_EFER_LME;
- if (env->cpuid_ext2_features & CPUID_EXT2_FFXSR)
- update_mask |= MSR_EFER_FFXSR;
- if (env->cpuid_ext2_features & CPUID_EXT2_NX)
- update_mask |= MSR_EFER_NXE;
- env->efer = (env->efer & ~update_mask) |
- (val & update_mask);
- }
- break;
- case MSR_STAR:
- env->star = val;
- break;
- case MSR_PAT:
- env->pat = val;
- break;
-#ifdef TARGET_X86_64
- case MSR_LSTAR:
- env->lstar = val;
- break;
- case MSR_CSTAR:
- env->cstar = val;
- break;
- case MSR_FMASK:
- env->fmask = val;
- break;
- case MSR_FSBASE:
- env->segs[R_FS].base = val;
- break;
- case MSR_GSBASE:
- env->segs[R_GS].base = val;
- break;
- case MSR_KERNELGSBASE:
- env->kernelgsbase = val;
- break;
-#endif
- default:
- /* XXX: exception ? */
- break;
- }
-}
-
-void helper_rdmsr(void)
-{
- uint64_t val;
- switch((uint32_t)ECX) {
- case MSR_IA32_SYSENTER_CS:
- val = env->sysenter_cs;
- break;
- case MSR_IA32_SYSENTER_ESP:
- val = env->sysenter_esp;
- break;
- case MSR_IA32_SYSENTER_EIP:
- val = env->sysenter_eip;
- break;
- case MSR_IA32_APICBASE:
- val = cpu_get_apic_base(env);
- break;
- case MSR_EFER:
- val = env->efer;
- break;
- case MSR_STAR:
- val = env->star;
- break;
- case MSR_PAT:
- val = env->pat;
- break;
-#ifdef TARGET_X86_64
- case MSR_LSTAR:
- val = env->lstar;
- break;
- case MSR_CSTAR:
- val = env->cstar;
- break;
- case MSR_FMASK:
- val = env->fmask;
- break;
- case MSR_FSBASE:
- val = env->segs[R_FS].base;
- break;
- case MSR_GSBASE:
- val = env->segs[R_GS].base;
- break;
- case MSR_KERNELGSBASE:
- val = env->kernelgsbase;
- break;
-#endif
- default:
- /* XXX: exception ? */
- val = 0;
- break;
- }
- EAX = (uint32_t)(val);
- EDX = (uint32_t)(val >> 32);
-}
-#endif
-
-void helper_lsl(void)
-{
- unsigned int selector, limit;
- uint32_t e1, e2, eflags;
- int rpl, dpl, cpl, type;
-
- eflags = cc_table[CC_OP].compute_all();
- selector = T0 & 0xffff;
- if (load_segment(&e1, &e2, selector) != 0)
- goto fail;
- rpl = selector & 3;
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->hflags & HF_CPL_MASK;
- if (e2 & DESC_S_MASK) {
- if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
- /* conforming */
- } else {
- if (dpl < cpl || dpl < rpl)
- goto fail;
- }
- } else {
- type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
- switch(type) {
- case 1:
- case 2:
- case 3:
- case 9:
- case 11:
- break;
- default:
- goto fail;
- }
- if (dpl < cpl || dpl < rpl) {
- fail:
- CC_SRC = eflags & ~CC_Z;
- return;
- }
- }
- limit = get_seg_limit(e1, e2);
- T1 = limit;
- CC_SRC = eflags | CC_Z;
-}
-
-void helper_lar(void)
-{
- unsigned int selector;
- uint32_t e1, e2, eflags;
- int rpl, dpl, cpl, type;
-
- eflags = cc_table[CC_OP].compute_all();
- selector = T0 & 0xffff;
- if ((selector & 0xfffc) == 0)
- goto fail;
- if (load_segment(&e1, &e2, selector) != 0)
- goto fail;
- rpl = selector & 3;
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->hflags & HF_CPL_MASK;
- if (e2 & DESC_S_MASK) {
- if ((e2 & DESC_CS_MASK) && (e2 & DESC_C_MASK)) {
- /* conforming */
- } else {
- if (dpl < cpl || dpl < rpl)
- goto fail;
- }
- } else {
- type = (e2 >> DESC_TYPE_SHIFT) & 0xf;
- switch(type) {
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 9:
- case 11:
- case 12:
- break;
- default:
- goto fail;
- }
- if (dpl < cpl || dpl < rpl) {
- fail:
- CC_SRC = eflags & ~CC_Z;
- return;
- }
- }
- T1 = e2 & 0x00f0ff00;
- CC_SRC = eflags | CC_Z;
-}
-
-void helper_verr(void)
-{
- unsigned int selector;
- uint32_t e1, e2, eflags;
- int rpl, dpl, cpl;
-
- eflags = cc_table[CC_OP].compute_all();
- selector = T0 & 0xffff;
- if ((selector & 0xfffc) == 0)
- goto fail;
- if (load_segment(&e1, &e2, selector) != 0)
- goto fail;
- if (!(e2 & DESC_S_MASK))
- goto fail;
- rpl = selector & 3;
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->hflags & HF_CPL_MASK;
- if (e2 & DESC_CS_MASK) {
- if (!(e2 & DESC_R_MASK))
- goto fail;
- if (!(e2 & DESC_C_MASK)) {
- if (dpl < cpl || dpl < rpl)
- goto fail;
- }
- } else {
- if (dpl < cpl || dpl < rpl) {
- fail:
- CC_SRC = eflags & ~CC_Z;
- return;
- }
- }
- CC_SRC = eflags | CC_Z;
-}
-
-void helper_verw(void)
-{
- unsigned int selector;
- uint32_t e1, e2, eflags;
- int rpl, dpl, cpl;
-
- eflags = cc_table[CC_OP].compute_all();
- selector = T0 & 0xffff;
- if ((selector & 0xfffc) == 0)
- goto fail;
- if (load_segment(&e1, &e2, selector) != 0)
- goto fail;
- if (!(e2 & DESC_S_MASK))
- goto fail;
- rpl = selector & 3;
- dpl = (e2 >> DESC_DPL_SHIFT) & 3;
- cpl = env->hflags & HF_CPL_MASK;
- if (e2 & DESC_CS_MASK) {
- goto fail;
- } else {
- if (dpl < cpl || dpl < rpl)
- goto fail;
- if (!(e2 & DESC_W_MASK)) {
- fail:
- CC_SRC = eflags & ~CC_Z;
- return;
- }
- }
- CC_SRC = eflags | CC_Z;
-}
-
-/* FPU helpers */
-
-void helper_fldt_ST0_A0(void)
-{
- int new_fpstt;
- new_fpstt = (env->fpstt - 1) & 7;
- env->fpregs[new_fpstt].d = helper_fldt(A0);
- env->fpstt = new_fpstt;
- env->fptags[new_fpstt] = 0; /* validate stack entry */
-}
-
-void helper_fstt_ST0_A0(void)
-{
- helper_fstt(ST0, A0);
-}
-
-void fpu_set_exception(int mask)
-{
- env->fpus |= mask;
- if (env->fpus & (~env->fpuc & FPUC_EM))
- env->fpus |= FPUS_SE | FPUS_B;
-}
-
-CPU86_LDouble helper_fdiv(CPU86_LDouble a, CPU86_LDouble b)
-{
- if (b == 0.0)
- fpu_set_exception(FPUS_ZE);
- return a / b;
-}
-
-void fpu_raise_exception(void)
-{
- if (env->cr[0] & CR0_NE_MASK) {
- raise_exception(EXCP10_COPR);
- }
-#if !defined(CONFIG_USER_ONLY)
- else {
- cpu_set_ferr(env);
- }
-#endif
-}
-
-/* BCD ops */
-
-void helper_fbld_ST0_A0(void)
-{
- CPU86_LDouble tmp;
- uint64_t val;
- unsigned int v;
- int i;
-
- val = 0;
- for(i = 8; i >= 0; i--) {
- v = ldub(A0 + i);
- val = (val * 100) + ((v >> 4) * 10) + (v & 0xf);
- }
- tmp = val;
- if (ldub(A0 + 9) & 0x80)
- tmp = -tmp;
- fpush();
- ST0 = tmp;
-}
-
-void helper_fbst_ST0_A0(void)
-{
- int v;
- target_ulong mem_ref, mem_end;
- int64_t val;
-
- val = floatx_to_int64(ST0, &env->fp_status);
- mem_ref = A0;
- mem_end = mem_ref + 9;
- if (val < 0) {
- stb(mem_end, 0x80);
- val = -val;
- } else {
- stb(mem_end, 0x00);
- }
- while (mem_ref < mem_end) {
- if (val == 0)
- break;
- v = val % 100;
- val = val / 100;
- v = ((v / 10) << 4) | (v % 10);
- stb(mem_ref++, v);
- }
- while (mem_ref < mem_end) {
- stb(mem_ref++, 0);
- }
-}
-
-void helper_f2xm1(void)
-{
- ST0 = pow(2.0,ST0) - 1.0;
-}
-
-void helper_fyl2x(void)
-{
- CPU86_LDouble fptemp;
-
- fptemp = ST0;
- if (fptemp>0.0){
- fptemp = log(fptemp)/log(2.0); /* log2(ST) */
- ST1 *= fptemp;
- fpop();
- } else {
- env->fpus &= (~0x4700);
- env->fpus |= 0x400;
- }
-}
-
-void helper_fptan(void)
-{
- CPU86_LDouble fptemp;
-
- fptemp = ST0;
- if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
- env->fpus |= 0x400;
- } else {
- ST0 = tan(fptemp);
- fpush();
- ST0 = 1.0;
- env->fpus &= (~0x400); /* C2 <-- 0 */
- /* the above code is for |arg| < 2**52 only */
- }
-}
-
-void helper_fpatan(void)
-{
- CPU86_LDouble fptemp, fpsrcop;
-
- fpsrcop = ST1;
- fptemp = ST0;
- ST1 = atan2(fpsrcop,fptemp);
- fpop();
-}
-
-void helper_fxtract(void)
-{
- CPU86_LDoubleU temp;
- unsigned int expdif;
-
- temp.d = ST0;
- expdif = EXPD(temp) - EXPBIAS;
- /*DP exponent bias*/
- ST0 = expdif;
- fpush();
- BIASEXPONENT(temp);
- ST0 = temp.d;
-}
-
-void helper_fprem1(void)
-{
- CPU86_LDouble dblq, fpsrcop, fptemp;
- CPU86_LDoubleU fpsrcop1, fptemp1;
- int expdif;
- int q;
-
- fpsrcop = ST0;
- fptemp = ST1;
- fpsrcop1.d = fpsrcop;
- fptemp1.d = fptemp;
- expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
- 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 */
- 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 */
- } else {
- env->fpus |= 0x400; /* C2 <-- 1 */
- 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);
- ST0 -= (ST1 * fpsrcop * fptemp);
- }
-}
-
-void helper_fprem(void)
-{
- CPU86_LDouble dblq, fpsrcop, fptemp;
- CPU86_LDoubleU fpsrcop1, fptemp1;
- int expdif;
- int q;
-
- fpsrcop = ST0;
- fptemp = ST1;
- fpsrcop1.d = fpsrcop;
- fptemp1.d = fptemp;
- expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
- 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 */
- 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 */
- } else {
- env->fpus |= 0x400; /* C2 <-- 1 */
- fptemp = pow(2.0, expdif-50);
- fpsrcop = (ST0 / ST1) / fptemp;
- /* fpsrcop = integer obtained by chopping */
- fpsrcop = (fpsrcop < 0.0)?
- -(floor(fabs(fpsrcop))): floor(fpsrcop);
- ST0 -= (ST1 * fpsrcop * fptemp);
- }
-}
-
-void helper_fyl2xp1(void)
-{
- CPU86_LDouble fptemp;
-
- fptemp = ST0;
- if ((fptemp+1.0)>0.0) {
- fptemp = log(fptemp+1.0) / log(2.0); /* log2(ST+1.0) */
- ST1 *= fptemp;
- fpop();
- } else {
- env->fpus &= (~0x4700);
- env->fpus |= 0x400;
- }
-}
-
-void helper_fsqrt(void)
-{
- CPU86_LDouble fptemp;
-
- fptemp = ST0;
- if (fptemp<0.0) {
- env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
- env->fpus |= 0x400;
- }
- ST0 = sqrt(fptemp);
-}
-
-void helper_fsincos(void)
-{
- CPU86_LDouble fptemp;
-
- fptemp = ST0;
- if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
- env->fpus |= 0x400;
- } else {
- ST0 = sin(fptemp);
- fpush();
- ST0 = cos(fptemp);
- env->fpus &= (~0x400); /* C2 <-- 0 */
- /* the above code is for |arg| < 2**63 only */
- }
-}
-
-void helper_frndint(void)
-{
- ST0 = floatx_round_to_int(ST0, &env->fp_status);
-}
-
-void helper_fscale(void)
-{
- ST0 = ldexp (ST0, (int)(ST1));
-}
-
-void helper_fsin(void)
-{
- CPU86_LDouble fptemp;
-
- fptemp = ST0;
- if ((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
- env->fpus |= 0x400;
- } else {
- ST0 = sin(fptemp);
- env->fpus &= (~0x400); /* C2 <-- 0 */
- /* the above code is for |arg| < 2**53 only */
- }
-}
-
-void helper_fcos(void)
-{
- CPU86_LDouble fptemp;
-
- fptemp = ST0;
- if((fptemp > MAXTAN)||(fptemp < -MAXTAN)) {
- env->fpus |= 0x400;
- } else {
- ST0 = cos(fptemp);
- env->fpus &= (~0x400); /* C2 <-- 0 */
- /* the above code is for |arg5 < 2**63 only */
- }
-}
-
-void helper_fxam_ST0(void)
-{
- CPU86_LDoubleU temp;
- int expdif;
-
- temp.d = ST0;
-
- env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
- if (SIGND(temp))
- env->fpus |= 0x200; /* C1 <-- 1 */
-
- /* XXX: test fptags too */
- expdif = EXPD(temp);
- if (expdif == MAXEXPD) {
-#ifdef USE_X86LDOUBLE
- if (MANTD(temp) == 0x8000000000000000ULL)
-#else
- if (MANTD(temp) == 0)
-#endif
- env->fpus |= 0x500 /*Infinity*/;
- else
- env->fpus |= 0x100 /*NaN*/;
- } else if (expdif == 0) {
- if (MANTD(temp) == 0)
- env->fpus |= 0x4000 /*Zero*/;
- else
- env->fpus |= 0x4400 /*Denormal*/;
- } else {
- env->fpus |= 0x400;
- }
-}
-
-void helper_fstenv(target_ulong ptr, int data32)
-{
- int fpus, fptag, exp, i;
- uint64_t mant;
- CPU86_LDoubleU tmp;
-
- fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
- fptag = 0;
- for (i=7; i>=0; i--) {
- fptag <<= 2;
- if (env->fptags[i]) {
- fptag |= 3;
- } else {
- tmp.d = env->fpregs[i].d;
- exp = EXPD(tmp);
- mant = MANTD(tmp);
- if (exp == 0 && mant == 0) {
- /* zero */
- fptag |= 1;
- } else if (exp == 0 || exp == MAXEXPD
-#ifdef USE_X86LDOUBLE
- || (mant & (1LL << 63)) == 0
-#endif
- ) {
- /* NaNs, infinity, denormal */
- fptag |= 2;
- }
- }
- }
- if (data32) {
- /* 32 bit */
- stl(ptr, env->fpuc);
- stl(ptr + 4, fpus);
- stl(ptr + 8, fptag);
- stl(ptr + 12, 0); /* fpip */
- stl(ptr + 16, 0); /* fpcs */
- stl(ptr + 20, 0); /* fpoo */
- stl(ptr + 24, 0); /* fpos */
- } else {
- /* 16 bit */
- stw(ptr, env->fpuc);
- stw(ptr + 2, fpus);
- stw(ptr + 4, fptag);
- stw(ptr + 6, 0);
- stw(ptr + 8, 0);
- stw(ptr + 10, 0);
- stw(ptr + 12, 0);
- }
-}
-
-void helper_fldenv(target_ulong ptr, int data32)
-{
- int i, fpus, fptag;
-
- if (data32) {
- env->fpuc = lduw(ptr);
- fpus = lduw(ptr + 4);
- fptag = lduw(ptr + 8);
- }
- else {
- env->fpuc = lduw(ptr);
- fpus = lduw(ptr + 2);
- fptag = lduw(ptr + 4);
- }
- env->fpstt = (fpus >> 11) & 7;
- env->fpus = fpus & ~0x3800;
- for(i = 0;i < 8; i++) {
- env->fptags[i] = ((fptag & 3) == 3);
- fptag >>= 2;
- }
-}
-
-void helper_fsave(target_ulong ptr, int data32)
-{
- CPU86_LDouble tmp;
- int i;
-
- helper_fstenv(ptr, data32);
-
- ptr += (14 << data32);
- for(i = 0;i < 8; i++) {
- tmp = ST(i);
- helper_fstt(tmp, ptr);
- ptr += 10;
- }
-
- /* fninit */
- env->fpus = 0;
- env->fpstt = 0;
- env->fpuc = 0x37f;
- env->fptags[0] = 1;
- env->fptags[1] = 1;
- env->fptags[2] = 1;
- env->fptags[3] = 1;
- env->fptags[4] = 1;
- env->fptags[5] = 1;
- env->fptags[6] = 1;
- env->fptags[7] = 1;
-}
-
-void helper_frstor(target_ulong ptr, int data32)
-{
- CPU86_LDouble tmp;
- int i;
-
- helper_fldenv(ptr, data32);
- ptr += (14 << data32);
-
- for(i = 0;i < 8; i++) {
- tmp = helper_fldt(ptr);
- ST(i) = tmp;
- ptr += 10;
- }
-}
-
-void helper_fxsave(target_ulong ptr, int data64)
-{
- int fpus, fptag, i, nb_xmm_regs;
- CPU86_LDouble tmp;
- target_ulong addr;
-
- fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
- fptag = 0;
- for(i = 0; i < 8; i++) {
- fptag |= (env->fptags[i] << i);
- }
- stw(ptr, env->fpuc);
- stw(ptr + 2, fpus);
- stw(ptr + 4, fptag ^ 0xff);
-
- addr = ptr + 0x20;
- for(i = 0;i < 8; i++) {
- tmp = ST(i);
- helper_fstt(tmp, addr);
- addr += 16;
- }
-
- if (env->cr[4] & CR4_OSFXSR_MASK) {
- /* XXX: finish it */
- stl(ptr + 0x18, env->mxcsr); /* mxcsr */
- stl(ptr + 0x1c, 0x0000ffff); /* mxcsr_mask */
- nb_xmm_regs = 8 << data64;
- addr = ptr + 0xa0;
- for(i = 0; i < nb_xmm_regs; i++) {
- stq(addr, env->xmm_regs[i].XMM_Q(0));
- stq(addr + 8, env->xmm_regs[i].XMM_Q(1));
- addr += 16;
- }
- }
-}
-
-void helper_fxrstor(target_ulong ptr, int data64)
-{
- int i, fpus, fptag, nb_xmm_regs;
- CPU86_LDouble tmp;
- target_ulong addr;
-
- env->fpuc = lduw(ptr);
- fpus = lduw(ptr + 2);
- fptag = lduw(ptr + 4);
- env->fpstt = (fpus >> 11) & 7;
- env->fpus = fpus & ~0x3800;
- fptag ^= 0xff;
- for(i = 0;i < 8; i++) {
- env->fptags[i] = ((fptag >> i) & 1);
- }
-
- addr = ptr + 0x20;
- for(i = 0;i < 8; i++) {
- tmp = helper_fldt(addr);
- ST(i) = tmp;
- addr += 16;
- }
-
- if (env->cr[4] & CR4_OSFXSR_MASK) {
- /* XXX: finish it */
- env->mxcsr = ldl(ptr + 0x18);
- //ldl(ptr + 0x1c);
- nb_xmm_regs = 8 << data64;
- addr = ptr + 0xa0;
- for(i = 0; i < nb_xmm_regs; i++) {
- env->xmm_regs[i].XMM_Q(0) = ldq(addr);
- env->xmm_regs[i].XMM_Q(1) = ldq(addr + 8);
- addr += 16;
- }
- }
-}
-
-#ifndef USE_X86LDOUBLE
-
-void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
-{
- CPU86_LDoubleU temp;
- int e;
-
- temp.d = f;
- /* mantissa */
- *pmant = (MANTD(temp) << 11) | (1LL << 63);
- /* exponent + sign */
- e = EXPD(temp) - EXPBIAS + 16383;
- e |= SIGND(temp) >> 16;
- *pexp = e;
-}
-
-CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
-{
- CPU86_LDoubleU temp;
- int e;
- uint64_t ll;
-
- /* XXX: handle overflow ? */
- e = (upper & 0x7fff) - 16383 + EXPBIAS; /* exponent */
- e |= (upper >> 4) & 0x800; /* sign */
- ll = (mant >> 11) & ((1LL << 52) - 1);
-#ifdef __arm__
- temp.l.upper = (e << 20) | (ll >> 32);
- temp.l.lower = ll;
-#else
- temp.ll = ll | ((uint64_t)e << 52);
-#endif
- return temp.d;
-}
-
-#else
-
-void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, CPU86_LDouble f)
-{
- CPU86_LDoubleU temp;
-
- temp.d = f;
- *pmant = temp.l.lower;
- *pexp = temp.l.upper;
-}
-
-CPU86_LDouble cpu_set_fp80(uint64_t mant, uint16_t upper)
-{
- CPU86_LDoubleU temp;
-
- temp.l.upper = upper;
- temp.l.lower = mant;
- return temp.d;
-}
-#endif
-
-#ifdef TARGET_X86_64
-
-//#define DEBUG_MULDIV
-
-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;
-#ifdef DEBUG_MULDIV
- printf("mul: 0x%016" PRIx64 " * 0x%016" PRIx64 " = 0x%016" PRIx64 "%016" PRIx64 "\n",
- a, b, *phigh, *plow);
-#endif
-}
-
-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);
- }
-}
-
-/* return TRUE if overflow */
-static int div64(uint64_t *plow, uint64_t *phigh, uint64_t b)
-{
- uint64_t q, r, a1, a0;
- int i, qb, ab;
-
- a0 = *plow;
- a1 = *phigh;
- if (a1 == 0) {
- q = a0 / b;
- r = a0 % b;
- *plow = q;
- *phigh = r;
- } else {
- if (a1 >= b)
- return 1;
- /* XXX: use a better algorithm */
- for(i = 0; i < 64; i++) {
- ab = a1 >> 63;
- a1 = (a1 << 1) | (a0 >> 63);
- if (ab || a1 >= b) {
- a1 -= b;
- qb = 1;
- } else {
- qb = 0;
- }
- a0 = (a0 << 1) | qb;
- }
-#if defined(DEBUG_MULDIV)
- printf("div: 0x%016" PRIx64 "%016" PRIx64 " / 0x%016" PRIx64 ": q=0x%016" PRIx64 " r=0x%016" PRIx64 "\n",
- *phigh, *plow, b, a0, a1);
-#endif
- *plow = a0;
- *phigh = a1;
- }
- return 0;
-}
-
-/* return TRUE if overflow */
-static int idiv64(uint64_t *plow, uint64_t *phigh, int64_t b)
-{
- int sa, sb;
- sa = ((int64_t)*phigh < 0);
- if (sa)
- neg128(plow, phigh);
- sb = (b < 0);
- if (sb)
- b = -b;
- if (div64(plow, phigh, b) != 0)
- return 1;
- if (sa ^ sb) {
- if (*plow > (1ULL << 63))
- return 1;
- *plow = - *plow;
- } else {
- if (*plow >= (1ULL << 63))
- return 1;
- }
- if (sa)
- *phigh = - *phigh;
- return 0;
-}
-
-void helper_mulq_EAX_T0(void)
-{
- uint64_t r0, r1;
-
- mul64(&r0, &r1, EAX, T0);
- EAX = r0;
- EDX = r1;
- CC_DST = r0;
- CC_SRC = r1;
-}
-
-void helper_imulq_EAX_T0(void)
-{
- uint64_t r0, r1;
-
- imul64(&r0, &r1, EAX, T0);
- EAX = r0;
- EDX = r1;
- CC_DST = r0;
- CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
-}
-
-void helper_imulq_T0_T1(void)
-{
- uint64_t r0, r1;
-
- imul64(&r0, &r1, T0, T1);
- T0 = r0;
- CC_DST = r0;
- CC_SRC = ((int64_t)r1 != ((int64_t)r0 >> 63));
-}
-
-void helper_divq_EAX_T0(void)
-{
- uint64_t r0, r1;
- if (T0 == 0) {
- raise_exception(EXCP00_DIVZ);
- }
- r0 = EAX;
- r1 = EDX;
- if (div64(&r0, &r1, T0))
- raise_exception(EXCP00_DIVZ);
- EAX = r0;
- EDX = r1;
-}
-
-void helper_idivq_EAX_T0(void)
-{
- uint64_t r0, r1;
- if (T0 == 0) {
- raise_exception(EXCP00_DIVZ);
- }
- r0 = EAX;
- r1 = EDX;
- if (idiv64(&r0, &r1, T0))
- raise_exception(EXCP00_DIVZ);
- EAX = r0;
- EDX = r1;
-}
-
-void helper_bswapq_T0(void)
-{
- T0 = bswap64(T0);
-}
-#endif
-
-void helper_hlt(void)
-{
- env->hflags &= ~HF_INHIBIT_IRQ_MASK; /* needed if sti is just before */
- env->hflags |= HF_HALTED_MASK;
- env->exception_index = EXCP_HLT;
- cpu_loop_exit();
-}
-
-void helper_monitor(void)
-{
- if (ECX != 0)
- raise_exception(EXCP0D_GPF);
- /* XXX: store address ? */
-}
-
-void helper_mwait(void)
-{
- if (ECX != 0)
- raise_exception(EXCP0D_GPF);
- /* XXX: not complete but not completely erroneous */
- if (env->cpu_index != 0 || env->next_cpu != NULL) {
- /* more than one CPU: do not sleep because another CPU may
- wake this one */
- } else {
- helper_hlt();
- }
-}
-
-float approx_rsqrt(float a)
-{
- return 1.0 / sqrt(a);
-}
-
-float approx_rcp(float a)
-{
- return 1.0 / a;
-}
-
-void update_fp_status(void)
-{
- int rnd_type;
-
- /* set rounding mode */
- switch(env->fpuc & RC_MASK) {
- default:
- case RC_NEAR:
- rnd_type = float_round_nearest_even;
- break;
- case RC_DOWN:
- rnd_type = float_round_down;
- break;
- case RC_UP:
- rnd_type = float_round_up;
- break;
- case RC_CHOP:
- rnd_type = float_round_to_zero;
- break;
- }
- set_float_rounding_mode(rnd_type, &env->fp_status);
-#ifdef FLOATX80
- switch((env->fpuc >> 8) & 3) {
- case 0:
- rnd_type = 32;
- break;
- case 2:
- rnd_type = 64;
- break;
- case 3:
- default:
- rnd_type = 80;
- break;
- }
- set_floatx80_rounding_precision(rnd_type, &env->fp_status);
-#endif
-}
-
-#if !defined(CONFIG_USER_ONLY)
-
-#define MMUSUFFIX _mmu
-#define GETPC() (__builtin_return_address(0))
-
-#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"
-
-#endif
-
-/* 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;
- int ret;
- unsigned long pc;
- CPUX86State *saved_env;
-
- /* XXX: hack to restore env in all cases, even if not called from
- generated code */
- saved_env = env;
- env = cpu_single_env;
-
- ret = cpu_x86_handle_mmu_fault(env, addr, is_write, is_user, 1);
- if (ret) {
- if (retaddr) {
- /* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
- if (tb) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, pc, NULL);
- }
- }
- if (retaddr)
- raise_exception_err(env->exception_index, env->error_code);
- else
- raise_exception_err_norestore(env->exception_index, env->error_code);
- }
- env = saved_env;
-}
diff --git a/target-i386/helper2.c b/target-i386/helper2.c
deleted file mode 100644
index 19af159..0000000
--- a/target-i386/helper2.c
+++ /dev/null
@@ -1,1031 +0,0 @@
-/*
- * i386 helpers (without register variable usage)
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <assert.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-
-//#define DEBUG_MMU
-
-#ifdef USE_CODE_COPY
-#include <asm/ldt.h>
-#include <linux/unistd.h>
-#include <linux/version.h>
-
-int modify_ldt(int func, void *ptr, unsigned long bytecount)
-{
- return syscall(__NR_modify_ldt, func, ptr, bytecount);
-}
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66)
-#define modify_ldt_ldt_s user_desc
-#endif
-#endif /* USE_CODE_COPY */
-
-CPUX86State *cpu_x86_init(void)
-{
- CPUX86State *env;
- static int inited;
-
- env = qemu_mallocz(sizeof(CPUX86State));
- if (!env)
- return NULL;
- cpu_exec_init(env);
-
- /* init various static tables */
- if (!inited) {
- inited = 1;
- optimize_flags_init();
- }
-#ifdef USE_CODE_COPY
- /* testing code for code copy case */
- {
- struct modify_ldt_ldt_s ldt;
-
- ldt.entry_number = 1;
- ldt.base_addr = (unsigned long)env;
- ldt.limit = (sizeof(CPUState) + 0xfff) >> 12;
- ldt.seg_32bit = 1;
- ldt.contents = MODIFY_LDT_CONTENTS_DATA;
- ldt.read_exec_only = 0;
- ldt.limit_in_pages = 1;
- ldt.seg_not_present = 0;
- ldt.useable = 1;
- modify_ldt(1, &ldt, sizeof(ldt)); /* write ldt entry */
-
- asm volatile ("movl %0, %%fs" : : "r" ((1 << 3) | 7));
- }
-#endif
- {
- int family, model, stepping;
-#ifdef TARGET_X86_64
- env->cpuid_vendor1 = 0x68747541; /* "Auth" */
- env->cpuid_vendor2 = 0x69746e65; /* "enti" */
- env->cpuid_vendor3 = 0x444d4163; /* "cAMD" */
- family = 6;
- model = 2;
- stepping = 3;
-#else
- env->cpuid_vendor1 = 0x756e6547; /* "Genu" */
- env->cpuid_vendor2 = 0x49656e69; /* "ineI" */
- env->cpuid_vendor3 = 0x6c65746e; /* "ntel" */
-#if 0
- /* pentium 75-200 */
- family = 5;
- model = 2;
- stepping = 11;
-#else
- /* pentium pro */
- family = 6;
- model = 3;
- stepping = 3;
-#endif
-#endif
- env->cpuid_level = 2;
- env->cpuid_version = (family << 8) | (model << 4) | stepping;
- env->cpuid_features = (CPUID_FP87 | CPUID_DE | CPUID_PSE |
- CPUID_TSC | CPUID_MSR | CPUID_MCE |
- CPUID_CX8 | CPUID_PGE | CPUID_CMOV |
- CPUID_PAT);
- env->pat = 0x0007040600070406ULL;
- env->cpuid_ext_features = CPUID_EXT_SSE3;
- env->cpuid_features |= CPUID_FXSR | CPUID_MMX | CPUID_SSE | CPUID_SSE2 | CPUID_PAE | CPUID_SEP;
- env->cpuid_features |= CPUID_APIC;
- env->cpuid_xlevel = 0;
- {
- const char *model_id = "QEMU Virtual CPU version " QEMU_VERSION;
- int c, len, i;
- len = strlen(model_id);
- for(i = 0; i < 48; i++) {
- if (i >= len)
- c = '\0';
- else
- c = model_id[i];
- env->cpuid_model[i >> 2] |= c << (8 * (i & 3));
- }
- }
-#ifdef TARGET_X86_64
- /* currently not enabled for std i386 because not fully tested */
- env->cpuid_ext2_features = (env->cpuid_features & 0x0183F3FF);
- env->cpuid_ext2_features |= CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX;
- env->cpuid_xlevel = 0x80000008;
-
- /* these features are needed for Win64 and aren't fully implemented */
- env->cpuid_features |= CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA;
-#endif
- }
- cpu_reset(env);
-#ifdef USE_KQEMU
- kqemu_init(env);
-#endif
- return env;
-}
-
-/* NOTE: must be called outside the CPU execute loop */
-void cpu_reset(CPUX86State *env)
-{
- int i;
-
- memset(env, 0, offsetof(CPUX86State, breakpoints));
-
- tlb_flush(env, 1);
-
- /* init to reset state */
-
-#ifdef CONFIG_SOFTMMU
- env->hflags |= HF_SOFTMMU_MASK;
-#endif
-
- cpu_x86_update_cr0(env, 0x60000010);
- env->a20_mask = 0xffffffff;
-
- env->idt.limit = 0xffff;
- env->gdt.limit = 0xffff;
- env->ldt.limit = 0xffff;
- env->ldt.flags = DESC_P_MASK;
- env->tr.limit = 0xffff;
- env->tr.flags = DESC_P_MASK;
-
- cpu_x86_load_seg_cache(env, R_CS, 0xf000, 0xffff0000, 0xffff, 0);
- cpu_x86_load_seg_cache(env, R_DS, 0, 0, 0xffff, 0);
- cpu_x86_load_seg_cache(env, R_ES, 0, 0, 0xffff, 0);
- cpu_x86_load_seg_cache(env, R_SS, 0, 0, 0xffff, 0);
- cpu_x86_load_seg_cache(env, R_FS, 0, 0, 0xffff, 0);
- cpu_x86_load_seg_cache(env, R_GS, 0, 0, 0xffff, 0);
-
- env->eip = 0xfff0;
- env->regs[R_EDX] = 0x600; /* indicate P6 processor */
-
- env->eflags = 0x2;
-
- /* FPU init */
- for(i = 0;i < 8; i++)
- env->fptags[i] = 1;
- env->fpuc = 0x37f;
-
- env->mxcsr = 0x1f80;
-}
-
-void cpu_x86_close(CPUX86State *env)
-{
- free(env);
-}
-
-/***********************************************************/
-/* x86 debug */
-
-static const char *cc_op_str[] = {
- "DYNAMIC",
- "EFLAGS",
-
- "MULB",
- "MULW",
- "MULL",
- "MULQ",
-
- "ADDB",
- "ADDW",
- "ADDL",
- "ADDQ",
-
- "ADCB",
- "ADCW",
- "ADCL",
- "ADCQ",
-
- "SUBB",
- "SUBW",
- "SUBL",
- "SUBQ",
-
- "SBBB",
- "SBBW",
- "SBBL",
- "SBBQ",
-
- "LOGICB",
- "LOGICW",
- "LOGICL",
- "LOGICQ",
-
- "INCB",
- "INCW",
- "INCL",
- "INCQ",
-
- "DECB",
- "DECW",
- "DECL",
- "DECQ",
-
- "SHLB",
- "SHLW",
- "SHLL",
- "SHLQ",
-
- "SARB",
- "SARW",
- "SARL",
- "SARQ",
-};
-
-void cpu_dump_state(CPUState *env, FILE *f,
- int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
- int flags)
-{
- int eflags, i, nb;
- char cc_op_name[32];
- static const char *seg_name[6] = { "ES", "CS", "SS", "DS", "FS", "GS" };
-
- eflags = env->eflags;
-#ifdef TARGET_X86_64
- if (env->hflags & HF_CS64_MASK) {
- cpu_fprintf(f,
- "RAX=%016" PRIx64 " RBX=%016" PRIx64 " RCX=%016" PRIx64 " RDX=%016" PRIx64 "\n"
- "RSI=%016" PRIx64 " RDI=%016" PRIx64 " RBP=%016" PRIx64 " RSP=%016" PRIx64 "\n"
- "R8 =%016" PRIx64 " R9 =%016" PRIx64 " R10=%016" PRIx64 " R11=%016" PRIx64 "\n"
- "R12=%016" PRIx64 " R13=%016" PRIx64 " R14=%016" PRIx64 " R15=%016" PRIx64 "\n"
- "RIP=%016" PRIx64 " RFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n",
- env->regs[R_EAX],
- env->regs[R_EBX],
- env->regs[R_ECX],
- env->regs[R_EDX],
- env->regs[R_ESI],
- env->regs[R_EDI],
- env->regs[R_EBP],
- env->regs[R_ESP],
- env->regs[8],
- env->regs[9],
- env->regs[10],
- env->regs[11],
- env->regs[12],
- env->regs[13],
- env->regs[14],
- env->regs[15],
- env->eip, eflags,
- eflags & DF_MASK ? 'D' : '-',
- eflags & CC_O ? 'O' : '-',
- eflags & CC_S ? 'S' : '-',
- eflags & CC_Z ? 'Z' : '-',
- eflags & CC_A ? 'A' : '-',
- eflags & CC_P ? 'P' : '-',
- eflags & CC_C ? 'C' : '-',
- env->hflags & HF_CPL_MASK,
- (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
- (env->a20_mask >> 20) & 1,
- (env->hflags >> HF_HALTED_SHIFT) & 1);
- } else
-#endif
- {
- cpu_fprintf(f, "EAX=%08x EBX=%08x ECX=%08x EDX=%08x\n"
- "ESI=%08x EDI=%08x EBP=%08x ESP=%08x\n"
- "EIP=%08x EFL=%08x [%c%c%c%c%c%c%c] CPL=%d II=%d A20=%d HLT=%d\n",
- (uint32_t)env->regs[R_EAX],
- (uint32_t)env->regs[R_EBX],
- (uint32_t)env->regs[R_ECX],
- (uint32_t)env->regs[R_EDX],
- (uint32_t)env->regs[R_ESI],
- (uint32_t)env->regs[R_EDI],
- (uint32_t)env->regs[R_EBP],
- (uint32_t)env->regs[R_ESP],
- (uint32_t)env->eip, eflags,
- eflags & DF_MASK ? 'D' : '-',
- eflags & CC_O ? 'O' : '-',
- eflags & CC_S ? 'S' : '-',
- eflags & CC_Z ? 'Z' : '-',
- eflags & CC_A ? 'A' : '-',
- eflags & CC_P ? 'P' : '-',
- eflags & CC_C ? 'C' : '-',
- env->hflags & HF_CPL_MASK,
- (env->hflags >> HF_INHIBIT_IRQ_SHIFT) & 1,
- (env->a20_mask >> 20) & 1,
- (env->hflags >> HF_HALTED_SHIFT) & 1);
- }
-
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK) {
- for(i = 0; i < 6; i++) {
- SegmentCache *sc = &env->segs[i];
- cpu_fprintf(f, "%s =%04x %016" PRIx64 " %08x %08x\n",
- seg_name[i],
- sc->selector,
- sc->base,
- sc->limit,
- sc->flags);
- }
- cpu_fprintf(f, "LDT=%04x %016" PRIx64 " %08x %08x\n",
- env->ldt.selector,
- env->ldt.base,
- env->ldt.limit,
- env->ldt.flags);
- cpu_fprintf(f, "TR =%04x %016" PRIx64 " %08x %08x\n",
- env->tr.selector,
- env->tr.base,
- env->tr.limit,
- env->tr.flags);
- cpu_fprintf(f, "GDT= %016" PRIx64 " %08x\n",
- env->gdt.base, env->gdt.limit);
- cpu_fprintf(f, "IDT= %016" PRIx64 " %08x\n",
- env->idt.base, env->idt.limit);
- cpu_fprintf(f, "CR0=%08x CR2=%016" PRIx64 " CR3=%016" PRIx64 " CR4=%08x\n",
- (uint32_t)env->cr[0],
- env->cr[2],
- env->cr[3],
- (uint32_t)env->cr[4]);
- } else
-#endif
- {
- for(i = 0; i < 6; i++) {
- SegmentCache *sc = &env->segs[i];
- cpu_fprintf(f, "%s =%04x %08x %08x %08x\n",
- seg_name[i],
- sc->selector,
- (uint32_t)sc->base,
- sc->limit,
- sc->flags);
- }
- cpu_fprintf(f, "LDT=%04x %08x %08x %08x\n",
- env->ldt.selector,
- (uint32_t)env->ldt.base,
- env->ldt.limit,
- env->ldt.flags);
- cpu_fprintf(f, "TR =%04x %08x %08x %08x\n",
- env->tr.selector,
- (uint32_t)env->tr.base,
- env->tr.limit,
- env->tr.flags);
- cpu_fprintf(f, "GDT= %08x %08x\n",
- (uint32_t)env->gdt.base, env->gdt.limit);
- cpu_fprintf(f, "IDT= %08x %08x\n",
- (uint32_t)env->idt.base, env->idt.limit);
- cpu_fprintf(f, "CR0=%08x CR2=%08x CR3=%08x CR4=%08x\n",
- (uint32_t)env->cr[0],
- (uint32_t)env->cr[2],
- (uint32_t)env->cr[3],
- (uint32_t)env->cr[4]);
- }
- if (flags & X86_DUMP_CCOP) {
- if ((unsigned)env->cc_op < CC_OP_NB)
- snprintf(cc_op_name, sizeof(cc_op_name), "%s", cc_op_str[env->cc_op]);
- else
- snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op);
-#ifdef TARGET_X86_64
- if (env->hflags & HF_CS64_MASK) {
- cpu_fprintf(f, "CCS=%016" PRIx64 " CCD=%016" PRIx64 " CCO=%-8s\n",
- env->cc_src, env->cc_dst,
- cc_op_name);
- } else
-#endif
- {
- cpu_fprintf(f, "CCS=%08x CCD=%08x CCO=%-8s\n",
- (uint32_t)env->cc_src, (uint32_t)env->cc_dst,
- cc_op_name);
- }
- }
- if (flags & X86_DUMP_FPU) {
- int fptag;
- fptag = 0;
- for(i = 0; i < 8; i++) {
- fptag |= ((!env->fptags[i]) << i);
- }
- cpu_fprintf(f, "FCW=%04x FSW=%04x [ST=%d] FTW=%02x MXCSR=%08x\n",
- env->fpuc,
- (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11,
- env->fpstt,
- fptag,
- env->mxcsr);
- for(i=0;i<8;i++) {
-#if defined(USE_X86LDOUBLE)
- union {
- long double d;
- struct {
- uint64_t lower;
- uint16_t upper;
- } l;
- } tmp;
- tmp.d = env->fpregs[i].d;
- cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
- i, tmp.l.lower, tmp.l.upper);
-#else
- cpu_fprintf(f, "FPR%d=%016" PRIx64,
- i, env->fpregs[i].mmx.q);
-#endif
- if ((i & 1) == 1)
- cpu_fprintf(f, "\n");
- else
- cpu_fprintf(f, " ");
- }
- if (env->hflags & HF_CS64_MASK)
- nb = 16;
- else
- nb = 8;
- for(i=0;i<nb;i++) {
- cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
- i,
- env->xmm_regs[i].XMM_L(3),
- env->xmm_regs[i].XMM_L(2),
- env->xmm_regs[i].XMM_L(1),
- env->xmm_regs[i].XMM_L(0));
- if ((i & 1) == 1)
- cpu_fprintf(f, "\n");
- else
- cpu_fprintf(f, " ");
- }
- }
-}
-
-/***********************************************************/
-/* x86 mmu */
-/* XXX: add PGE support */
-
-void cpu_x86_set_a20(CPUX86State *env, int a20_state)
-{
- a20_state = (a20_state != 0);
- if (a20_state != ((env->a20_mask >> 20) & 1)) {
-#if defined(DEBUG_MMU)
- printf("A20 update: a20=%d\n", a20_state);
-#endif
- /* if the cpu is currently executing code, we must unlink it and
- all the potentially executing TB */
- cpu_interrupt(env, CPU_INTERRUPT_EXITTB);
-
- /* when a20 is changed, all the MMU mappings are invalid, so
- we must flush everything */
- tlb_flush(env, 1);
- env->a20_mask = 0xffefffff | (a20_state << 20);
- }
-}
-
-void cpu_x86_update_cr0(CPUX86State *env, uint32_t new_cr0)
-{
- int pe_state;
-
-#if defined(DEBUG_MMU)
- printf("CR0 update: CR0=0x%08x\n", new_cr0);
-#endif
- if ((new_cr0 & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK)) !=
- (env->cr[0] & (CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK))) {
- tlb_flush(env, 1);
- }
-
-#ifdef TARGET_X86_64
- if (!(env->cr[0] & CR0_PG_MASK) && (new_cr0 & CR0_PG_MASK) &&
- (env->efer & MSR_EFER_LME)) {
- /* enter in long mode */
- /* XXX: generate an exception */
- if (!(env->cr[4] & CR4_PAE_MASK))
- return;
- env->efer |= MSR_EFER_LMA;
- env->hflags |= HF_LMA_MASK;
- } else if ((env->cr[0] & CR0_PG_MASK) && !(new_cr0 & CR0_PG_MASK) &&
- (env->efer & MSR_EFER_LMA)) {
- /* exit long mode */
- env->efer &= ~MSR_EFER_LMA;
- env->hflags &= ~(HF_LMA_MASK | HF_CS64_MASK);
- env->eip &= 0xffffffff;
- }
-#endif
- env->cr[0] = new_cr0 | CR0_ET_MASK;
-
- /* update PE flag in hidden flags */
- pe_state = (env->cr[0] & CR0_PE_MASK);
- env->hflags = (env->hflags & ~HF_PE_MASK) | (pe_state << HF_PE_SHIFT);
- /* ensure that ADDSEG is always set in real mode */
- env->hflags |= ((pe_state ^ 1) << HF_ADDSEG_SHIFT);
- /* update FPU flags */
- env->hflags = (env->hflags & ~(HF_MP_MASK | HF_EM_MASK | HF_TS_MASK)) |
- ((new_cr0 << (HF_MP_SHIFT - 1)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK));
-}
-
-/* XXX: in legacy PAE mode, generate a GPF if reserved bits are set in
- the PDPT */
-void cpu_x86_update_cr3(CPUX86State *env, target_ulong new_cr3)
-{
- env->cr[3] = new_cr3;
- if (env->cr[0] & CR0_PG_MASK) {
-#if defined(DEBUG_MMU)
- printf("CR3 update: CR3=" TARGET_FMT_lx "\n", new_cr3);
-#endif
- tlb_flush(env, 0);
- }
-}
-
-void cpu_x86_update_cr4(CPUX86State *env, uint32_t new_cr4)
-{
-#if defined(DEBUG_MMU)
- printf("CR4 update: CR4=%08x\n", (uint32_t)env->cr[4]);
-#endif
- if ((new_cr4 & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK)) !=
- (env->cr[4] & (CR4_PGE_MASK | CR4_PAE_MASK | CR4_PSE_MASK))) {
- tlb_flush(env, 1);
- }
- /* SSE handling */
- if (!(env->cpuid_features & CPUID_SSE))
- new_cr4 &= ~CR4_OSFXSR_MASK;
- if (new_cr4 & CR4_OSFXSR_MASK)
- env->hflags |= HF_OSFXSR_MASK;
- else
- env->hflags &= ~HF_OSFXSR_MASK;
-
- env->cr[4] = new_cr4;
-}
-
-/* XXX: also flush 4MB pages */
-void cpu_x86_flush_tlb(CPUX86State *env, target_ulong addr)
-{
- tlb_flush_page(env, addr);
-}
-
-#if defined(CONFIG_USER_ONLY)
-
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
- int is_write, int is_user, int is_softmmu)
-{
- /* user mode only emulation */
- is_write &= 1;
- env->cr[2] = addr;
- env->error_code = (is_write << PG_ERROR_W_BIT);
- env->error_code |= PG_ERROR_U_MASK;
- env->exception_index = EXCP0E_PAGE;
- return 1;
-}
-
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
- return addr;
-}
-
-#else
-
-#define PHYS_ADDR_MASK 0xfffff000
-
-/* return value:
- -1 = cannot handle fault
- 0 = nothing more to do
- 1 = generate PF fault
- 2 = soft MMU activation required for this block
-*/
-int cpu_x86_handle_mmu_fault(CPUX86State *env, target_ulong addr,
- int is_write1, int is_user, int is_softmmu)
-{
- uint64_t ptep, pte;
- uint32_t pdpe_addr, pde_addr, pte_addr;
- int error_code, is_dirty, prot, page_size, ret, is_write;
- unsigned long paddr, page_offset;
- target_ulong vaddr, virt_addr;
-
-#if defined(DEBUG_MMU)
- printf("MMU fault: addr=" TARGET_FMT_lx " w=%d u=%d eip=" TARGET_FMT_lx "\n",
- addr, is_write1, is_user, env->eip);
-#endif
- is_write = is_write1 & 1;
-
- if (!(env->cr[0] & CR0_PG_MASK)) {
- pte = addr;
- virt_addr = addr & TARGET_PAGE_MASK;
- prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- page_size = 4096;
- goto do_mapping;
- }
-
- if (env->cr[4] & CR4_PAE_MASK) {
- uint64_t pde, pdpe;
-
- /* XXX: we only use 32 bit physical addresses */
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK) {
- uint32_t pml4e_addr;
- uint64_t pml4e;
- int32_t sext;
-
- /* test virtual address sign extension */
- sext = (int64_t)addr >> 47;
- if (sext != 0 && sext != -1) {
- env->error_code = 0;
- env->exception_index = EXCP0D_GPF;
- return 1;
- }
-
- pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
- env->a20_mask;
- pml4e = ldq_phys(pml4e_addr);
- if (!(pml4e & PG_PRESENT_MASK)) {
- error_code = 0;
- goto do_fault;
- }
- if (!(env->efer & MSR_EFER_NXE) && (pml4e & PG_NX_MASK)) {
- error_code = PG_ERROR_RSVD_MASK;
- goto do_fault;
- }
- if (!(pml4e & PG_ACCESSED_MASK)) {
- pml4e |= PG_ACCESSED_MASK;
- stl_phys_notdirty(pml4e_addr, pml4e);
- }
- ptep = pml4e ^ PG_NX_MASK;
- pdpe_addr = ((pml4e & PHYS_ADDR_MASK) + (((addr >> 30) & 0x1ff) << 3)) &
- env->a20_mask;
- pdpe = ldq_phys(pdpe_addr);
- if (!(pdpe & PG_PRESENT_MASK)) {
- error_code = 0;
- goto do_fault;
- }
- if (!(env->efer & MSR_EFER_NXE) && (pdpe & PG_NX_MASK)) {
- error_code = PG_ERROR_RSVD_MASK;
- goto do_fault;
- }
- ptep &= pdpe ^ PG_NX_MASK;
- if (!(pdpe & PG_ACCESSED_MASK)) {
- pdpe |= PG_ACCESSED_MASK;
- stl_phys_notdirty(pdpe_addr, pdpe);
- }
- } else
-#endif
- {
- /* XXX: load them when cr3 is loaded ? */
- pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) &
- env->a20_mask;
- pdpe = ldq_phys(pdpe_addr);
- if (!(pdpe & PG_PRESENT_MASK)) {
- error_code = 0;
- goto do_fault;
- }
- ptep = PG_NX_MASK | PG_USER_MASK | PG_RW_MASK;
- }
-
- pde_addr = ((pdpe & PHYS_ADDR_MASK) + (((addr >> 21) & 0x1ff) << 3)) &
- env->a20_mask;
- pde = ldq_phys(pde_addr);
- if (!(pde & PG_PRESENT_MASK)) {
- error_code = 0;
- goto do_fault;
- }
- if (!(env->efer & MSR_EFER_NXE) && (pde & PG_NX_MASK)) {
- error_code = PG_ERROR_RSVD_MASK;
- goto do_fault;
- }
- ptep &= pde ^ PG_NX_MASK;
- if (pde & PG_PSE_MASK) {
- /* 2 MB page */
- page_size = 2048 * 1024;
- ptep ^= PG_NX_MASK;
- if ((ptep & PG_NX_MASK) && is_write1 == 2)
- goto do_fault_protect;
- if (is_user) {
- if (!(ptep & PG_USER_MASK))
- goto do_fault_protect;
- if (is_write && !(ptep & PG_RW_MASK))
- goto do_fault_protect;
- } else {
- if ((env->cr[0] & CR0_WP_MASK) &&
- is_write && !(ptep & PG_RW_MASK))
- goto do_fault_protect;
- }
- is_dirty = is_write && !(pde & PG_DIRTY_MASK);
- if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
- pde |= PG_ACCESSED_MASK;
- if (is_dirty)
- pde |= PG_DIRTY_MASK;
- stl_phys_notdirty(pde_addr, pde);
- }
- /* align to page_size */
- pte = pde & ((PHYS_ADDR_MASK & ~(page_size - 1)) | 0xfff);
- virt_addr = addr & ~(page_size - 1);
- } else {
- /* 4 KB page */
- if (!(pde & PG_ACCESSED_MASK)) {
- pde |= PG_ACCESSED_MASK;
- stl_phys_notdirty(pde_addr, pde);
- }
- pte_addr = ((pde & PHYS_ADDR_MASK) + (((addr >> 12) & 0x1ff) << 3)) &
- env->a20_mask;
- pte = ldq_phys(pte_addr);
- if (!(pte & PG_PRESENT_MASK)) {
- error_code = 0;
- goto do_fault;
- }
- if (!(env->efer & MSR_EFER_NXE) && (pte & PG_NX_MASK)) {
- error_code = PG_ERROR_RSVD_MASK;
- goto do_fault;
- }
- /* combine pde and pte nx, user and rw protections */
- ptep &= pte ^ PG_NX_MASK;
- ptep ^= PG_NX_MASK;
- if ((ptep & PG_NX_MASK) && is_write1 == 2)
- goto do_fault_protect;
- if (is_user) {
- if (!(ptep & PG_USER_MASK))
- goto do_fault_protect;
- if (is_write && !(ptep & PG_RW_MASK))
- goto do_fault_protect;
- } else {
- if ((env->cr[0] & CR0_WP_MASK) &&
- is_write && !(ptep & PG_RW_MASK))
- goto do_fault_protect;
- }
- is_dirty = is_write && !(pte & PG_DIRTY_MASK);
- if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
- pte |= PG_ACCESSED_MASK;
- if (is_dirty)
- pte |= PG_DIRTY_MASK;
- stl_phys_notdirty(pte_addr, pte);
- }
- page_size = 4096;
- virt_addr = addr & ~0xfff;
- pte = pte & (PHYS_ADDR_MASK | 0xfff);
- }
- } else {
- uint32_t pde;
-
- /* page directory entry */
- pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) &
- env->a20_mask;
- pde = ldl_phys(pde_addr);
- if (!(pde & PG_PRESENT_MASK)) {
- error_code = 0;
- goto do_fault;
- }
- /* if PSE bit is set, then we use a 4MB page */
- if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
- page_size = 4096 * 1024;
- if (is_user) {
- if (!(pde & PG_USER_MASK))
- goto do_fault_protect;
- if (is_write && !(pde & PG_RW_MASK))
- goto do_fault_protect;
- } else {
- if ((env->cr[0] & CR0_WP_MASK) &&
- is_write && !(pde & PG_RW_MASK))
- goto do_fault_protect;
- }
- is_dirty = is_write && !(pde & PG_DIRTY_MASK);
- if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
- pde |= PG_ACCESSED_MASK;
- if (is_dirty)
- pde |= PG_DIRTY_MASK;
- stl_phys_notdirty(pde_addr, pde);
- }
-
- pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
- ptep = pte;
- virt_addr = addr & ~(page_size - 1);
- } else {
- if (!(pde & PG_ACCESSED_MASK)) {
- pde |= PG_ACCESSED_MASK;
- stl_phys_notdirty(pde_addr, pde);
- }
-
- /* page directory entry */
- pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) &
- env->a20_mask;
- pte = ldl_phys(pte_addr);
- if (!(pte & PG_PRESENT_MASK)) {
- error_code = 0;
- goto do_fault;
- }
- /* combine pde and pte user and rw protections */
- ptep = pte & pde;
- if (is_user) {
- if (!(ptep & PG_USER_MASK))
- goto do_fault_protect;
- if (is_write && !(ptep & PG_RW_MASK))
- goto do_fault_protect;
- } else {
- if ((env->cr[0] & CR0_WP_MASK) &&
- is_write && !(ptep & PG_RW_MASK))
- goto do_fault_protect;
- }
- is_dirty = is_write && !(pte & PG_DIRTY_MASK);
- if (!(pte & PG_ACCESSED_MASK) || is_dirty) {
- pte |= PG_ACCESSED_MASK;
- if (is_dirty)
- pte |= PG_DIRTY_MASK;
- stl_phys_notdirty(pte_addr, pte);
- }
- page_size = 4096;
- virt_addr = addr & ~0xfff;
- }
- }
- /* the page can be put in the TLB */
- prot = PAGE_READ;
- if (!(ptep & PG_NX_MASK))
- prot |= PAGE_EXEC;
- if (pte & PG_DIRTY_MASK) {
- /* only set write access if already dirty... otherwise wait
- for dirty access */
- if (is_user) {
- if (ptep & PG_RW_MASK)
- prot |= PAGE_WRITE;
- } else {
- if (!(env->cr[0] & CR0_WP_MASK) ||
- (ptep & PG_RW_MASK))
- prot |= PAGE_WRITE;
- }
- }
- do_mapping:
- pte = pte & env->a20_mask;
-
- /* Even if 4MB pages, we map only one 4KB page in the cache to
- avoid filling it too fast */
- page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
- paddr = (pte & TARGET_PAGE_MASK) + page_offset;
- vaddr = virt_addr + page_offset;
-
- ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
- return ret;
- do_fault_protect:
- error_code = PG_ERROR_P_MASK;
- do_fault:
- env->cr[2] = addr;
- error_code |= (is_write << PG_ERROR_W_BIT);
- if (is_user)
- error_code |= PG_ERROR_U_MASK;
- if (is_write1 == 2 &&
- (env->efer & MSR_EFER_NXE) &&
- (env->cr[4] & CR4_PAE_MASK))
- error_code |= PG_ERROR_I_D_MASK;
- env->error_code = error_code;
- env->exception_index = EXCP0E_PAGE;
- return 1;
-}
-
-target_ulong 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;
-
- if (env->cr[4] & CR4_PAE_MASK) {
- uint32_t pdpe_addr, pde_addr, pte_addr;
- uint32_t pdpe;
-
- /* XXX: we only use 32 bit physical addresses */
-#ifdef TARGET_X86_64
- if (env->hflags & HF_LMA_MASK) {
- uint32_t pml4e_addr, pml4e;
- int32_t sext;
-
- /* test virtual address sign extension */
- sext = (int64_t)addr >> 47;
- if (sext != 0 && sext != -1)
- return -1;
-
- pml4e_addr = ((env->cr[3] & ~0xfff) + (((addr >> 39) & 0x1ff) << 3)) &
- env->a20_mask;
- pml4e = ldl_phys(pml4e_addr);
- if (!(pml4e & PG_PRESENT_MASK))
- return -1;
-
- pdpe_addr = ((pml4e & ~0xfff) + (((addr >> 30) & 0x1ff) << 3)) &
- env->a20_mask;
- pdpe = ldl_phys(pdpe_addr);
- if (!(pdpe & PG_PRESENT_MASK))
- return -1;
- } else
-#endif
- {
- pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) &
- env->a20_mask;
- pdpe = ldl_phys(pdpe_addr);
- if (!(pdpe & PG_PRESENT_MASK))
- return -1;
- }
-
- pde_addr = ((pdpe & ~0xfff) + (((addr >> 21) & 0x1ff) << 3)) &
- env->a20_mask;
- pde = ldl_phys(pde_addr);
- if (!(pde & PG_PRESENT_MASK)) {
- return -1;
- }
- if (pde & PG_PSE_MASK) {
- /* 2 MB page */
- page_size = 2048 * 1024;
- pte = pde & ~( (page_size - 1) & ~0xfff); /* align to page_size */
- } else {
- /* 4 KB page */
- pte_addr = ((pde & ~0xfff) + (((addr >> 12) & 0x1ff) << 3)) &
- env->a20_mask;
- page_size = 4096;
- pte = ldl_phys(pte_addr);
- }
- } else {
- if (!(env->cr[0] & CR0_PG_MASK)) {
- pte = addr;
- page_size = 4096;
- } else {
- /* page directory entry */
- pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask;
- pde = ldl_phys(pde_addr);
- if (!(pde & PG_PRESENT_MASK))
- return -1;
- if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
- pte = pde & ~0x003ff000; /* align to 4MB */
- page_size = 4096 * 1024;
- } else {
- /* page directory entry */
- pte_addr = ((pde & ~0xfff) + ((addr >> 10) & 0xffc)) & env->a20_mask;
- pte = ldl_phys(pte_addr);
- if (!(pte & PG_PRESENT_MASK))
- return -1;
- page_size = 4096;
- }
- }
- pte = pte & env->a20_mask;
- }
-
- page_offset = (addr & TARGET_PAGE_MASK) & (page_size - 1);
- paddr = (pte & TARGET_PAGE_MASK) + page_offset;
- return paddr;
-}
-#endif /* !CONFIG_USER_ONLY */
-
-#if defined(USE_CODE_COPY)
-struct fpstate {
- uint16_t fpuc;
- uint16_t dummy1;
- uint16_t fpus;
- uint16_t dummy2;
- uint16_t fptag;
- uint16_t dummy3;
-
- uint32_t fpip;
- uint32_t fpcs;
- uint32_t fpoo;
- uint32_t fpos;
- uint8_t fpregs1[8 * 10];
-};
-
-void restore_native_fp_state(CPUState *env)
-{
- int fptag, i, j;
- struct fpstate fp1, *fp = &fp1;
-
- fp->fpuc = env->fpuc;
- fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
- fptag = 0;
- for (i=7; i>=0; i--) {
- fptag <<= 2;
- if (env->fptags[i]) {
- fptag |= 3;
- } else {
- /* the FPU automatically computes it */
- }
- }
- fp->fptag = fptag;
- j = env->fpstt;
- for(i = 0;i < 8; i++) {
- memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10);
- j = (j + 1) & 7;
- }
- asm volatile ("frstor %0" : "=m" (*fp));
- env->native_fp_regs = 1;
-}
-
-void save_native_fp_state(CPUState *env)
-{
- int fptag, i, j;
- uint16_t fpuc;
- struct fpstate fp1, *fp = &fp1;
-
- asm volatile ("fsave %0" : : "m" (*fp));
- env->fpuc = fp->fpuc;
- env->fpstt = (fp->fpus >> 11) & 7;
- env->fpus = fp->fpus & ~0x3800;
- fptag = fp->fptag;
- for(i = 0;i < 8; i++) {
- env->fptags[i] = ((fptag & 3) == 3);
- fptag >>= 2;
- }
- j = env->fpstt;
- for(i = 0;i < 8; i++) {
- memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);
- j = (j + 1) & 7;
- }
- /* we must restore the default rounding state */
- /* XXX: we do not restore the exception state */
- fpuc = 0x037f | (env->fpuc & (3 << 10));
- asm volatile("fldcw %0" : : "m" (fpuc));
- env->native_fp_regs = 0;
-}
-#endif
diff --git a/target-i386/op.c b/target-i386/op.c
deleted file mode 100644
index 7a3aa77..0000000
--- a/target-i386/op.c
+++ /dev/null
@@ -1,2444 +0,0 @@
-/*
- * i386 micro operations
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#define ASM_SOFTMMU
-#include "exec.h"
-
-/* n must be a constant to be efficient */
-static inline target_long lshift(target_long x, int n)
-{
- if (n >= 0)
- return x << n;
- else
- return x >> (-n);
-}
-
-/* we define the various pieces of code used by the JIT */
-
-#define REG EAX
-#define REGNAME _EAX
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG ECX
-#define REGNAME _ECX
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG EDX
-#define REGNAME _EDX
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG EBX
-#define REGNAME _EBX
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG ESP
-#define REGNAME _ESP
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG EBP
-#define REGNAME _EBP
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG ESI
-#define REGNAME _ESI
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG EDI
-#define REGNAME _EDI
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#ifdef TARGET_X86_64
-
-#define REG (env->regs[8])
-#define REGNAME _R8
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG (env->regs[9])
-#define REGNAME _R9
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG (env->regs[10])
-#define REGNAME _R10
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG (env->regs[11])
-#define REGNAME _R11
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG (env->regs[12])
-#define REGNAME _R12
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG (env->regs[13])
-#define REGNAME _R13
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG (env->regs[14])
-#define REGNAME _R14
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#define REG (env->regs[15])
-#define REGNAME _R15
-#include "opreg_template.h"
-#undef REG
-#undef REGNAME
-
-#endif
-
-/* operations with flags */
-
-/* update flags with T0 and T1 (add/sub case) */
-void OPPROTO op_update2_cc(void)
-{
- CC_SRC = T1;
- CC_DST = T0;
-}
-
-/* update flags with T0 (logic operation case) */
-void OPPROTO op_update1_cc(void)
-{
- CC_DST = T0;
-}
-
-void OPPROTO op_update_neg_cc(void)
-{
- CC_SRC = -T0;
- CC_DST = T0;
-}
-
-void OPPROTO op_cmpl_T0_T1_cc(void)
-{
- CC_SRC = T1;
- CC_DST = T0 - T1;
-}
-
-void OPPROTO op_update_inc_cc(void)
-{
- CC_SRC = cc_table[CC_OP].compute_c();
- CC_DST = T0;
-}
-
-void OPPROTO op_testl_T0_T1_cc(void)
-{
- CC_DST = T0 & T1;
-}
-
-/* operations without flags */
-
-void OPPROTO op_addl_T0_T1(void)
-{
- T0 += T1;
-}
-
-void OPPROTO op_orl_T0_T1(void)
-{
- T0 |= T1;
-}
-
-void OPPROTO op_andl_T0_T1(void)
-{
- T0 &= T1;
-}
-
-void OPPROTO op_subl_T0_T1(void)
-{
- T0 -= T1;
-}
-
-void OPPROTO op_xorl_T0_T1(void)
-{
- T0 ^= T1;
-}
-
-void OPPROTO op_negl_T0(void)
-{
- T0 = -T0;
-}
-
-void OPPROTO op_incl_T0(void)
-{
- T0++;
-}
-
-void OPPROTO op_decl_T0(void)
-{
- T0--;
-}
-
-void OPPROTO op_notl_T0(void)
-{
- T0 = ~T0;
-}
-
-void OPPROTO op_bswapl_T0(void)
-{
- T0 = bswap32(T0);
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_bswapq_T0(void)
-{
- helper_bswapq_T0();
-}
-#endif
-
-/* multiply/divide */
-
-/* XXX: add eflags optimizations */
-/* XXX: add non P4 style flags */
-
-void OPPROTO op_mulb_AL_T0(void)
-{
- unsigned int res;
- res = (uint8_t)EAX * (uint8_t)T0;
- EAX = (EAX & ~0xffff) | res;
- CC_DST = res;
- CC_SRC = (res & 0xff00);
-}
-
-void OPPROTO op_imulb_AL_T0(void)
-{
- int res;
- res = (int8_t)EAX * (int8_t)T0;
- EAX = (EAX & ~0xffff) | (res & 0xffff);
- CC_DST = res;
- CC_SRC = (res != (int8_t)res);
-}
-
-void OPPROTO op_mulw_AX_T0(void)
-{
- unsigned int res;
- res = (uint16_t)EAX * (uint16_t)T0;
- EAX = (EAX & ~0xffff) | (res & 0xffff);
- EDX = (EDX & ~0xffff) | ((res >> 16) & 0xffff);
- CC_DST = res;
- CC_SRC = res >> 16;
-}
-
-void OPPROTO op_imulw_AX_T0(void)
-{
- int res;
- res = (int16_t)EAX * (int16_t)T0;
- EAX = (EAX & ~0xffff) | (res & 0xffff);
- EDX = (EDX & ~0xffff) | ((res >> 16) & 0xffff);
- CC_DST = res;
- CC_SRC = (res != (int16_t)res);
-}
-
-void OPPROTO op_mull_EAX_T0(void)
-{
- uint64_t res;
- res = (uint64_t)((uint32_t)EAX) * (uint64_t)((uint32_t)T0);
- EAX = (uint32_t)res;
- EDX = (uint32_t)(res >> 32);
- CC_DST = (uint32_t)res;
- CC_SRC = (uint32_t)(res >> 32);
-}
-
-void OPPROTO op_imull_EAX_T0(void)
-{
- int64_t res;
- res = (int64_t)((int32_t)EAX) * (int64_t)((int32_t)T0);
- EAX = (uint32_t)(res);
- EDX = (uint32_t)(res >> 32);
- CC_DST = res;
- CC_SRC = (res != (int32_t)res);
-}
-
-void OPPROTO op_imulw_T0_T1(void)
-{
- int res;
- res = (int16_t)T0 * (int16_t)T1;
- T0 = res;
- CC_DST = res;
- CC_SRC = (res != (int16_t)res);
-}
-
-void OPPROTO op_imull_T0_T1(void)
-{
- int64_t res;
- res = (int64_t)((int32_t)T0) * (int64_t)((int32_t)T1);
- T0 = res;
- CC_DST = res;
- CC_SRC = (res != (int32_t)res);
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_mulq_EAX_T0(void)
-{
- helper_mulq_EAX_T0();
-}
-
-void OPPROTO op_imulq_EAX_T0(void)
-{
- helper_imulq_EAX_T0();
-}
-
-void OPPROTO op_imulq_T0_T1(void)
-{
- helper_imulq_T0_T1();
-}
-#endif
-
-/* division, flags are undefined */
-
-void OPPROTO op_divb_AL_T0(void)
-{
- unsigned int num, den, q, r;
-
- num = (EAX & 0xffff);
- den = (T0 & 0xff);
- if (den == 0) {
- raise_exception(EXCP00_DIVZ);
- }
- q = (num / den);
- if (q > 0xff)
- raise_exception(EXCP00_DIVZ);
- q &= 0xff;
- r = (num % den) & 0xff;
- EAX = (EAX & ~0xffff) | (r << 8) | q;
-}
-
-void OPPROTO op_idivb_AL_T0(void)
-{
- int num, den, q, r;
-
- num = (int16_t)EAX;
- den = (int8_t)T0;
- if (den == 0) {
- raise_exception(EXCP00_DIVZ);
- }
- q = (num / den);
- if (q != (int8_t)q)
- raise_exception(EXCP00_DIVZ);
- q &= 0xff;
- r = (num % den) & 0xff;
- EAX = (EAX & ~0xffff) | (r << 8) | q;
-}
-
-void OPPROTO op_divw_AX_T0(void)
-{
- unsigned int num, den, q, r;
-
- num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
- den = (T0 & 0xffff);
- if (den == 0) {
- raise_exception(EXCP00_DIVZ);
- }
- q = (num / den);
- if (q > 0xffff)
- raise_exception(EXCP00_DIVZ);
- q &= 0xffff;
- r = (num % den) & 0xffff;
- EAX = (EAX & ~0xffff) | q;
- EDX = (EDX & ~0xffff) | r;
-}
-
-void OPPROTO op_idivw_AX_T0(void)
-{
- int num, den, q, r;
-
- num = (EAX & 0xffff) | ((EDX & 0xffff) << 16);
- den = (int16_t)T0;
- if (den == 0) {
- raise_exception(EXCP00_DIVZ);
- }
- q = (num / den);
- if (q != (int16_t)q)
- raise_exception(EXCP00_DIVZ);
- q &= 0xffff;
- r = (num % den) & 0xffff;
- EAX = (EAX & ~0xffff) | q;
- EDX = (EDX & ~0xffff) | r;
-}
-
-void OPPROTO op_divl_EAX_T0(void)
-{
- helper_divl_EAX_T0();
-}
-
-void OPPROTO op_idivl_EAX_T0(void)
-{
- helper_idivl_EAX_T0();
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_divq_EAX_T0(void)
-{
- helper_divq_EAX_T0();
-}
-
-void OPPROTO op_idivq_EAX_T0(void)
-{
- helper_idivq_EAX_T0();
-}
-#endif
-
-/* constant load & misc op */
-
-/* XXX: consistent names */
-void OPPROTO op_movl_T0_imu(void)
-{
- T0 = (uint32_t)PARAM1;
-}
-
-void OPPROTO op_movl_T0_im(void)
-{
- T0 = (int32_t)PARAM1;
-}
-
-void OPPROTO op_addl_T0_im(void)
-{
- T0 += PARAM1;
-}
-
-void OPPROTO op_andl_T0_ffff(void)
-{
- T0 = T0 & 0xffff;
-}
-
-void OPPROTO op_andl_T0_im(void)
-{
- T0 = T0 & PARAM1;
-}
-
-void OPPROTO op_movl_T0_T1(void)
-{
- T0 = T1;
-}
-
-void OPPROTO op_movl_T1_imu(void)
-{
- T1 = (uint32_t)PARAM1;
-}
-
-void OPPROTO op_movl_T1_im(void)
-{
- T1 = (int32_t)PARAM1;
-}
-
-void OPPROTO op_addl_T1_im(void)
-{
- T1 += PARAM1;
-}
-
-void OPPROTO op_movl_T1_A0(void)
-{
- T1 = A0;
-}
-
-void OPPROTO op_movl_A0_im(void)
-{
- A0 = (uint32_t)PARAM1;
-}
-
-void OPPROTO op_addl_A0_im(void)
-{
- A0 = (uint32_t)(A0 + PARAM1);
-}
-
-void OPPROTO op_movl_A0_seg(void)
-{
- A0 = (uint32_t)*(target_ulong *)((char *)env + PARAM1);
-}
-
-void OPPROTO op_addl_A0_seg(void)
-{
- A0 = (uint32_t)(A0 + *(target_ulong *)((char *)env + PARAM1));
-}
-
-void OPPROTO op_addl_A0_AL(void)
-{
- A0 = (uint32_t)(A0 + (EAX & 0xff));
-}
-
-#ifdef WORDS_BIGENDIAN
-typedef union UREG64 {
- struct { uint16_t v3, v2, v1, v0; } w;
- struct { uint32_t v1, v0; } l;
- uint64_t q;
-} UREG64;
-#else
-typedef union UREG64 {
- struct { uint16_t v0, v1, v2, v3; } w;
- struct { uint32_t v0, v1; } l;
- uint64_t q;
-} UREG64;
-#endif
-
-#ifdef TARGET_X86_64
-
-#define PARAMQ1 \
-({\
- UREG64 __p;\
- __p.l.v1 = PARAM1;\
- __p.l.v0 = PARAM2;\
- __p.q;\
-})
-
-void OPPROTO op_movq_T0_im64(void)
-{
- T0 = PARAMQ1;
-}
-
-void OPPROTO op_movq_T1_im64(void)
-{
- T1 = PARAMQ1;
-}
-
-void OPPROTO op_movq_A0_im(void)
-{
- A0 = (int32_t)PARAM1;
-}
-
-void OPPROTO op_movq_A0_im64(void)
-{
- A0 = PARAMQ1;
-}
-
-void OPPROTO op_addq_A0_im(void)
-{
- A0 = (A0 + (int32_t)PARAM1);
-}
-
-void OPPROTO op_addq_A0_im64(void)
-{
- A0 = (A0 + PARAMQ1);
-}
-
-void OPPROTO op_movq_A0_seg(void)
-{
- A0 = *(target_ulong *)((char *)env + PARAM1);
-}
-
-void OPPROTO op_addq_A0_seg(void)
-{
- A0 += *(target_ulong *)((char *)env + PARAM1);
-}
-
-void OPPROTO op_addq_A0_AL(void)
-{
- A0 = (A0 + (EAX & 0xff));
-}
-
-#endif
-
-void OPPROTO op_andl_A0_ffff(void)
-{
- A0 = A0 & 0xffff;
-}
-
-/* memory access */
-
-#define MEMSUFFIX _raw
-#include "ops_mem.h"
-
-#if !defined(CONFIG_USER_ONLY)
-#define MEMSUFFIX _kernel
-#include "ops_mem.h"
-
-#define MEMSUFFIX _user
-#include "ops_mem.h"
-#endif
-
-/* indirect jump */
-
-void OPPROTO op_jmp_T0(void)
-{
- EIP = T0;
-}
-
-void OPPROTO op_movl_eip_im(void)
-{
- EIP = (uint32_t)PARAM1;
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_movq_eip_im(void)
-{
- EIP = (int32_t)PARAM1;
-}
-
-void OPPROTO op_movq_eip_im64(void)
-{
- EIP = PARAMQ1;
-}
-#endif
-
-void OPPROTO op_hlt(void)
-{
- helper_hlt();
-}
-
-void OPPROTO op_monitor(void)
-{
- helper_monitor();
-}
-
-void OPPROTO op_mwait(void)
-{
- helper_mwait();
-}
-
-void OPPROTO op_debug(void)
-{
- env->exception_index = EXCP_DEBUG;
- cpu_loop_exit();
-}
-
-void OPPROTO op_raise_interrupt(void)
-{
- int intno, next_eip_addend;
- intno = PARAM1;
- next_eip_addend = PARAM2;
- raise_interrupt(intno, 1, 0, next_eip_addend);
-}
-
-void OPPROTO op_raise_exception(void)
-{
- int exception_index;
- exception_index = PARAM1;
- raise_exception(exception_index);
-}
-
-void OPPROTO op_into(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- if (eflags & CC_O) {
- raise_interrupt(EXCP04_INTO, 1, 0, PARAM1);
- }
- FORCE_RET();
-}
-
-void OPPROTO op_cli(void)
-{
- env->eflags &= ~IF_MASK;
-}
-
-void OPPROTO op_sti(void)
-{
- env->eflags |= IF_MASK;
-}
-
-void OPPROTO op_set_inhibit_irq(void)
-{
- env->hflags |= HF_INHIBIT_IRQ_MASK;
-}
-
-void OPPROTO op_reset_inhibit_irq(void)
-{
- env->hflags &= ~HF_INHIBIT_IRQ_MASK;
-}
-
-#if 0
-/* vm86plus instructions */
-void OPPROTO op_cli_vm(void)
-{
- env->eflags &= ~VIF_MASK;
-}
-
-void OPPROTO op_sti_vm(void)
-{
- env->eflags |= VIF_MASK;
- if (env->eflags & VIP_MASK) {
- EIP = PARAM1;
- raise_exception(EXCP0D_GPF);
- }
- FORCE_RET();
-}
-#endif
-
-void OPPROTO op_boundw(void)
-{
- int low, high, v;
- low = ldsw(A0);
- high = ldsw(A0 + 2);
- v = (int16_t)T0;
- if (v < low || v > high) {
- raise_exception(EXCP05_BOUND);
- }
- FORCE_RET();
-}
-
-void OPPROTO op_boundl(void)
-{
- int low, high, v;
- low = ldl(A0);
- high = ldl(A0 + 4);
- v = T0;
- if (v < low || v > high) {
- raise_exception(EXCP05_BOUND);
- }
- FORCE_RET();
-}
-
-void OPPROTO op_cmpxchg8b(void)
-{
- helper_cmpxchg8b();
-}
-
-void OPPROTO op_movl_T0_0(void)
-{
- T0 = 0;
-}
-
-void OPPROTO op_exit_tb(void)
-{
- EXIT_TB();
-}
-
-/* multiple size ops */
-
-#define ldul ldl
-
-#define SHIFT 0
-#include "ops_template.h"
-#undef SHIFT
-
-#define SHIFT 1
-#include "ops_template.h"
-#undef SHIFT
-
-#define SHIFT 2
-#include "ops_template.h"
-#undef SHIFT
-
-#ifdef TARGET_X86_64
-
-#define SHIFT 3
-#include "ops_template.h"
-#undef SHIFT
-
-#endif
-
-/* sign extend */
-
-void OPPROTO op_movsbl_T0_T0(void)
-{
- T0 = (int8_t)T0;
-}
-
-void OPPROTO op_movzbl_T0_T0(void)
-{
- T0 = (uint8_t)T0;
-}
-
-void OPPROTO op_movswl_T0_T0(void)
-{
- T0 = (int16_t)T0;
-}
-
-void OPPROTO op_movzwl_T0_T0(void)
-{
- T0 = (uint16_t)T0;
-}
-
-void OPPROTO op_movswl_EAX_AX(void)
-{
- EAX = (int16_t)EAX;
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_movslq_T0_T0(void)
-{
- T0 = (int32_t)T0;
-}
-
-void OPPROTO op_movslq_RAX_EAX(void)
-{
- EAX = (int32_t)EAX;
-}
-#endif
-
-void OPPROTO op_movsbw_AX_AL(void)
-{
- EAX = (EAX & ~0xffff) | ((int8_t)EAX & 0xffff);
-}
-
-void OPPROTO op_movslq_EDX_EAX(void)
-{
- EDX = (int32_t)EAX >> 31;
-}
-
-void OPPROTO op_movswl_DX_AX(void)
-{
- EDX = (EDX & ~0xffff) | (((int16_t)EAX >> 15) & 0xffff);
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_movsqo_RDX_RAX(void)
-{
- EDX = (int64_t)EAX >> 63;
-}
-#endif
-
-/* string ops helpers */
-
-void OPPROTO op_addl_ESI_T0(void)
-{
- ESI = (uint32_t)(ESI + T0);
-}
-
-void OPPROTO op_addw_ESI_T0(void)
-{
- ESI = (ESI & ~0xffff) | ((ESI + T0) & 0xffff);
-}
-
-void OPPROTO op_addl_EDI_T0(void)
-{
- EDI = (uint32_t)(EDI + T0);
-}
-
-void OPPROTO op_addw_EDI_T0(void)
-{
- EDI = (EDI & ~0xffff) | ((EDI + T0) & 0xffff);
-}
-
-void OPPROTO op_decl_ECX(void)
-{
- ECX = (uint32_t)(ECX - 1);
-}
-
-void OPPROTO op_decw_ECX(void)
-{
- ECX = (ECX & ~0xffff) | ((ECX - 1) & 0xffff);
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_addq_ESI_T0(void)
-{
- ESI = (ESI + T0);
-}
-
-void OPPROTO op_addq_EDI_T0(void)
-{
- EDI = (EDI + T0);
-}
-
-void OPPROTO op_decq_ECX(void)
-{
- ECX--;
-}
-#endif
-
-/* push/pop utils */
-
-void op_addl_A0_SS(void)
-{
- A0 = (uint32_t)(A0 + env->segs[R_SS].base);
-}
-
-void op_subl_A0_2(void)
-{
- A0 = (uint32_t)(A0 - 2);
-}
-
-void op_subl_A0_4(void)
-{
- A0 = (uint32_t)(A0 - 4);
-}
-
-void op_addl_ESP_4(void)
-{
- ESP = (uint32_t)(ESP + 4);
-}
-
-void op_addl_ESP_2(void)
-{
- ESP = (uint32_t)(ESP + 2);
-}
-
-void op_addw_ESP_4(void)
-{
- ESP = (ESP & ~0xffff) | ((ESP + 4) & 0xffff);
-}
-
-void op_addw_ESP_2(void)
-{
- ESP = (ESP & ~0xffff) | ((ESP + 2) & 0xffff);
-}
-
-void op_addl_ESP_im(void)
-{
- ESP = (uint32_t)(ESP + PARAM1);
-}
-
-void op_addw_ESP_im(void)
-{
- ESP = (ESP & ~0xffff) | ((ESP + PARAM1) & 0xffff);
-}
-
-#ifdef TARGET_X86_64
-void op_subq_A0_2(void)
-{
- A0 -= 2;
-}
-
-void op_subq_A0_8(void)
-{
- A0 -= 8;
-}
-
-void op_addq_ESP_8(void)
-{
- ESP += 8;
-}
-
-void op_addq_ESP_im(void)
-{
- ESP += PARAM1;
-}
-#endif
-
-void OPPROTO op_rdtsc(void)
-{
- helper_rdtsc();
-}
-
-void OPPROTO op_cpuid(void)
-{
- helper_cpuid();
-}
-
-void OPPROTO op_enter_level(void)
-{
- helper_enter_level(PARAM1, PARAM2);
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_enter64_level(void)
-{
- helper_enter64_level(PARAM1, PARAM2);
-}
-#endif
-
-void OPPROTO op_sysenter(void)
-{
- helper_sysenter();
-}
-
-void OPPROTO op_sysexit(void)
-{
- helper_sysexit();
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_syscall(void)
-{
- helper_syscall(PARAM1);
-}
-
-void OPPROTO op_sysret(void)
-{
- helper_sysret(PARAM1);
-}
-#endif
-
-void OPPROTO op_rdmsr(void)
-{
- helper_rdmsr();
-}
-
-void OPPROTO op_wrmsr(void)
-{
- helper_wrmsr();
-}
-
-/* bcd */
-
-/* XXX: exception */
-void OPPROTO op_aam(void)
-{
- int base = PARAM1;
- int al, ah;
- al = EAX & 0xff;
- ah = al / base;
- al = al % base;
- EAX = (EAX & ~0xffff) | al | (ah << 8);
- CC_DST = al;
-}
-
-void OPPROTO op_aad(void)
-{
- int base = PARAM1;
- int al, ah;
- al = EAX & 0xff;
- ah = (EAX >> 8) & 0xff;
- al = ((ah * base) + al) & 0xff;
- EAX = (EAX & ~0xffff) | al;
- CC_DST = al;
-}
-
-void OPPROTO op_aaa(void)
-{
- int icarry;
- int al, ah, af;
- int eflags;
-
- eflags = cc_table[CC_OP].compute_all();
- af = eflags & CC_A;
- al = EAX & 0xff;
- ah = (EAX >> 8) & 0xff;
-
- icarry = (al > 0xf9);
- if (((al & 0x0f) > 9 ) || af) {
- al = (al + 6) & 0x0f;
- ah = (ah + 1 + icarry) & 0xff;
- eflags |= CC_C | CC_A;
- } else {
- eflags &= ~(CC_C | CC_A);
- al &= 0x0f;
- }
- EAX = (EAX & ~0xffff) | al | (ah << 8);
- CC_SRC = eflags;
- FORCE_RET();
-}
-
-void OPPROTO op_aas(void)
-{
- int icarry;
- int al, ah, af;
- int eflags;
-
- eflags = cc_table[CC_OP].compute_all();
- af = eflags & CC_A;
- al = EAX & 0xff;
- ah = (EAX >> 8) & 0xff;
-
- icarry = (al < 6);
- if (((al & 0x0f) > 9 ) || af) {
- al = (al - 6) & 0x0f;
- ah = (ah - 1 - icarry) & 0xff;
- eflags |= CC_C | CC_A;
- } else {
- eflags &= ~(CC_C | CC_A);
- al &= 0x0f;
- }
- EAX = (EAX & ~0xffff) | al | (ah << 8);
- CC_SRC = eflags;
- FORCE_RET();
-}
-
-void OPPROTO op_daa(void)
-{
- int al, af, cf;
- int eflags;
-
- eflags = cc_table[CC_OP].compute_all();
- cf = eflags & CC_C;
- af = eflags & CC_A;
- al = EAX & 0xff;
-
- eflags = 0;
- if (((al & 0x0f) > 9 ) || af) {
- al = (al + 6) & 0xff;
- eflags |= CC_A;
- }
- if ((al > 0x9f) || cf) {
- al = (al + 0x60) & 0xff;
- eflags |= CC_C;
- }
- EAX = (EAX & ~0xff) | al;
- /* well, speed is not an issue here, so we compute the flags by hand */
- eflags |= (al == 0) << 6; /* zf */
- eflags |= parity_table[al]; /* pf */
- eflags |= (al & 0x80); /* sf */
- CC_SRC = eflags;
- FORCE_RET();
-}
-
-void OPPROTO op_das(void)
-{
- int al, al1, af, cf;
- int eflags;
-
- eflags = cc_table[CC_OP].compute_all();
- cf = eflags & CC_C;
- af = eflags & CC_A;
- al = EAX & 0xff;
-
- eflags = 0;
- al1 = al;
- if (((al & 0x0f) > 9 ) || af) {
- eflags |= CC_A;
- if (al < 6 || cf)
- eflags |= CC_C;
- al = (al - 6) & 0xff;
- }
- if ((al1 > 0x99) || cf) {
- al = (al - 0x60) & 0xff;
- eflags |= CC_C;
- }
- EAX = (EAX & ~0xff) | al;
- /* well, speed is not an issue here, so we compute the flags by hand */
- eflags |= (al == 0) << 6; /* zf */
- eflags |= parity_table[al]; /* pf */
- eflags |= (al & 0x80); /* sf */
- CC_SRC = eflags;
- FORCE_RET();
-}
-
-/* segment handling */
-
-/* never use it with R_CS */
-void OPPROTO op_movl_seg_T0(void)
-{
- load_seg(PARAM1, T0);
-}
-
-/* faster VM86 version */
-void OPPROTO op_movl_seg_T0_vm(void)
-{
- int selector;
- SegmentCache *sc;
-
- selector = T0 & 0xffff;
- /* env->segs[] access */
- sc = (SegmentCache *)((char *)env + PARAM1);
- sc->selector = selector;
- sc->base = (selector << 4);
-}
-
-void OPPROTO op_movl_T0_seg(void)
-{
- T0 = env->segs[PARAM1].selector;
-}
-
-void OPPROTO op_lsl(void)
-{
- helper_lsl();
-}
-
-void OPPROTO op_lar(void)
-{
- helper_lar();
-}
-
-void OPPROTO op_verr(void)
-{
- helper_verr();
-}
-
-void OPPROTO op_verw(void)
-{
- helper_verw();
-}
-
-void OPPROTO op_arpl(void)
-{
- if ((T0 & 3) < (T1 & 3)) {
- /* XXX: emulate bug or 0xff3f0000 oring as in bochs ? */
- T0 = (T0 & ~3) | (T1 & 3);
- T1 = CC_Z;
- } else {
- T1 = 0;
- }
- FORCE_RET();
-}
-
-void OPPROTO op_arpl_update(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- CC_SRC = (eflags & ~CC_Z) | T1;
-}
-
-/* T0: segment, T1:eip */
-void OPPROTO op_ljmp_protected_T0_T1(void)
-{
- helper_ljmp_protected_T0_T1(PARAM1);
-}
-
-void OPPROTO op_lcall_real_T0_T1(void)
-{
- helper_lcall_real_T0_T1(PARAM1, PARAM2);
-}
-
-void OPPROTO op_lcall_protected_T0_T1(void)
-{
- helper_lcall_protected_T0_T1(PARAM1, PARAM2);
-}
-
-void OPPROTO op_iret_real(void)
-{
- helper_iret_real(PARAM1);
-}
-
-void OPPROTO op_iret_protected(void)
-{
- helper_iret_protected(PARAM1, PARAM2);
-}
-
-void OPPROTO op_lret_protected(void)
-{
- helper_lret_protected(PARAM1, PARAM2);
-}
-
-void OPPROTO op_lldt_T0(void)
-{
- helper_lldt_T0();
-}
-
-void OPPROTO op_ltr_T0(void)
-{
- helper_ltr_T0();
-}
-
-/* CR registers access */
-void OPPROTO op_movl_crN_T0(void)
-{
- helper_movl_crN_T0(PARAM1);
-}
-
-#if !defined(CONFIG_USER_ONLY)
-void OPPROTO op_movtl_T0_cr8(void)
-{
- T0 = cpu_get_apic_tpr(env);
-}
-#endif
-
-/* DR registers access */
-void OPPROTO op_movl_drN_T0(void)
-{
- helper_movl_drN_T0(PARAM1);
-}
-
-void OPPROTO op_lmsw_T0(void)
-{
- /* only 4 lower bits of CR0 are modified. PE cannot be set to zero
- if already set to one. */
- T0 = (env->cr[0] & ~0xe) | (T0 & 0xf);
- helper_movl_crN_T0(0);
-}
-
-void OPPROTO op_invlpg_A0(void)
-{
- helper_invlpg(A0);
-}
-
-void OPPROTO op_movl_T0_env(void)
-{
- T0 = *(uint32_t *)((char *)env + PARAM1);
-}
-
-void OPPROTO op_movl_env_T0(void)
-{
- *(uint32_t *)((char *)env + PARAM1) = T0;
-}
-
-void OPPROTO op_movl_env_T1(void)
-{
- *(uint32_t *)((char *)env + PARAM1) = T1;
-}
-
-void OPPROTO op_movtl_T0_env(void)
-{
- T0 = *(target_ulong *)((char *)env + PARAM1);
-}
-
-void OPPROTO op_movtl_env_T0(void)
-{
- *(target_ulong *)((char *)env + PARAM1) = T0;
-}
-
-void OPPROTO op_movtl_T1_env(void)
-{
- T1 = *(target_ulong *)((char *)env + PARAM1);
-}
-
-void OPPROTO op_movtl_env_T1(void)
-{
- *(target_ulong *)((char *)env + PARAM1) = T1;
-}
-
-void OPPROTO op_clts(void)
-{
- env->cr[0] &= ~CR0_TS_MASK;
- env->hflags &= ~HF_TS_MASK;
-}
-
-/* flags handling */
-
-void OPPROTO op_goto_tb0(void)
-{
- GOTO_TB(op_goto_tb0, PARAM1, 0);
-}
-
-void OPPROTO op_goto_tb1(void)
-{
- GOTO_TB(op_goto_tb1, PARAM1, 1);
-}
-
-void OPPROTO op_jmp_label(void)
-{
- GOTO_LABEL_PARAM(1);
-}
-
-void OPPROTO op_jnz_T0_label(void)
-{
- if (T0)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO op_jz_T0_label(void)
-{
- if (!T0)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-/* slow set cases (compute x86 flags) */
-void OPPROTO op_seto_T0_cc(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- T0 = (eflags >> 11) & 1;
-}
-
-void OPPROTO op_setb_T0_cc(void)
-{
- T0 = cc_table[CC_OP].compute_c();
-}
-
-void OPPROTO op_setz_T0_cc(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- T0 = (eflags >> 6) & 1;
-}
-
-void OPPROTO op_setbe_T0_cc(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- T0 = (eflags & (CC_Z | CC_C)) != 0;
-}
-
-void OPPROTO op_sets_T0_cc(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- T0 = (eflags >> 7) & 1;
-}
-
-void OPPROTO op_setp_T0_cc(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- T0 = (eflags >> 2) & 1;
-}
-
-void OPPROTO op_setl_T0_cc(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- T0 = ((eflags ^ (eflags >> 4)) >> 7) & 1;
-}
-
-void OPPROTO op_setle_T0_cc(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- T0 = (((eflags ^ (eflags >> 4)) & 0x80) || (eflags & CC_Z)) != 0;
-}
-
-void OPPROTO op_xor_T0_1(void)
-{
- T0 ^= 1;
-}
-
-void OPPROTO op_set_cc_op(void)
-{
- CC_OP = PARAM1;
-}
-
-void OPPROTO op_mov_T0_cc(void)
-{
- T0 = cc_table[CC_OP].compute_all();
-}
-
-/* XXX: clear VIF/VIP in all ops ? */
-
-void OPPROTO op_movl_eflags_T0(void)
-{
- load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK));
-}
-
-void OPPROTO op_movw_eflags_T0(void)
-{
- load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff);
-}
-
-void OPPROTO op_movl_eflags_T0_io(void)
-{
- load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK));
-}
-
-void OPPROTO op_movw_eflags_T0_io(void)
-{
- load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK) & 0xffff);
-}
-
-void OPPROTO op_movl_eflags_T0_cpl0(void)
-{
- load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK));
-}
-
-void OPPROTO op_movw_eflags_T0_cpl0(void)
-{
- load_eflags(T0, (TF_MASK | AC_MASK | ID_MASK | NT_MASK | IF_MASK | IOPL_MASK) & 0xffff);
-}
-
-#if 0
-/* vm86plus version */
-void OPPROTO op_movw_eflags_T0_vm(void)
-{
- int eflags;
- eflags = T0;
- CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
- DF = 1 - (2 * ((eflags >> 10) & 1));
- /* we also update some system flags as in user mode */
- env->eflags = (env->eflags & ~(FL_UPDATE_MASK16 | VIF_MASK)) |
- (eflags & FL_UPDATE_MASK16);
- if (eflags & IF_MASK) {
- env->eflags |= VIF_MASK;
- if (env->eflags & VIP_MASK) {
- EIP = PARAM1;
- raise_exception(EXCP0D_GPF);
- }
- }
- FORCE_RET();
-}
-
-void OPPROTO op_movl_eflags_T0_vm(void)
-{
- int eflags;
- eflags = T0;
- CC_SRC = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
- DF = 1 - (2 * ((eflags >> 10) & 1));
- /* we also update some system flags as in user mode */
- env->eflags = (env->eflags & ~(FL_UPDATE_MASK32 | VIF_MASK)) |
- (eflags & FL_UPDATE_MASK32);
- if (eflags & IF_MASK) {
- env->eflags |= VIF_MASK;
- if (env->eflags & VIP_MASK) {
- EIP = PARAM1;
- raise_exception(EXCP0D_GPF);
- }
- }
- FORCE_RET();
-}
-#endif
-
-/* XXX: compute only O flag */
-void OPPROTO op_movb_eflags_T0(void)
-{
- int of;
- of = cc_table[CC_OP].compute_all() & CC_O;
- CC_SRC = (T0 & (CC_S | CC_Z | CC_A | CC_P | CC_C)) | of;
-}
-
-void OPPROTO op_movl_T0_eflags(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- eflags |= (DF & DF_MASK);
- eflags |= env->eflags & ~(VM_MASK | RF_MASK);
- T0 = eflags;
-}
-
-/* vm86plus version */
-#if 0
-void OPPROTO op_movl_T0_eflags_vm(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- eflags |= (DF & DF_MASK);
- eflags |= env->eflags & ~(VM_MASK | RF_MASK | IF_MASK);
- if (env->eflags & VIF_MASK)
- eflags |= IF_MASK;
- T0 = eflags;
-}
-#endif
-
-void OPPROTO op_cld(void)
-{
- DF = 1;
-}
-
-void OPPROTO op_std(void)
-{
- DF = -1;
-}
-
-void OPPROTO op_clc(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- eflags &= ~CC_C;
- CC_SRC = eflags;
-}
-
-void OPPROTO op_stc(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- eflags |= CC_C;
- CC_SRC = eflags;
-}
-
-void OPPROTO op_cmc(void)
-{
- int eflags;
- eflags = cc_table[CC_OP].compute_all();
- eflags ^= CC_C;
- CC_SRC = eflags;
-}
-
-void OPPROTO op_salc(void)
-{
- int cf;
- cf = cc_table[CC_OP].compute_c();
- EAX = (EAX & ~0xff) | ((-cf) & 0xff);
-}
-
-static int compute_all_eflags(void)
-{
- return CC_SRC;
-}
-
-static int compute_c_eflags(void)
-{
- return CC_SRC & CC_C;
-}
-
-CCTable cc_table[CC_OP_NB] = {
- [CC_OP_DYNAMIC] = { /* should never happen */ },
-
- [CC_OP_EFLAGS] = { compute_all_eflags, compute_c_eflags },
-
- [CC_OP_MULB] = { compute_all_mulb, compute_c_mull },
- [CC_OP_MULW] = { compute_all_mulw, compute_c_mull },
- [CC_OP_MULL] = { compute_all_mull, compute_c_mull },
-
- [CC_OP_ADDB] = { compute_all_addb, compute_c_addb },
- [CC_OP_ADDW] = { compute_all_addw, compute_c_addw },
- [CC_OP_ADDL] = { compute_all_addl, compute_c_addl },
-
- [CC_OP_ADCB] = { compute_all_adcb, compute_c_adcb },
- [CC_OP_ADCW] = { compute_all_adcw, compute_c_adcw },
- [CC_OP_ADCL] = { compute_all_adcl, compute_c_adcl },
-
- [CC_OP_SUBB] = { compute_all_subb, compute_c_subb },
- [CC_OP_SUBW] = { compute_all_subw, compute_c_subw },
- [CC_OP_SUBL] = { compute_all_subl, compute_c_subl },
-
- [CC_OP_SBBB] = { compute_all_sbbb, compute_c_sbbb },
- [CC_OP_SBBW] = { compute_all_sbbw, compute_c_sbbw },
- [CC_OP_SBBL] = { compute_all_sbbl, compute_c_sbbl },
-
- [CC_OP_LOGICB] = { compute_all_logicb, compute_c_logicb },
- [CC_OP_LOGICW] = { compute_all_logicw, compute_c_logicw },
- [CC_OP_LOGICL] = { compute_all_logicl, compute_c_logicl },
-
- [CC_OP_INCB] = { compute_all_incb, compute_c_incl },
- [CC_OP_INCW] = { compute_all_incw, compute_c_incl },
- [CC_OP_INCL] = { compute_all_incl, compute_c_incl },
-
- [CC_OP_DECB] = { compute_all_decb, compute_c_incl },
- [CC_OP_DECW] = { compute_all_decw, compute_c_incl },
- [CC_OP_DECL] = { compute_all_decl, compute_c_incl },
-
- [CC_OP_SHLB] = { compute_all_shlb, compute_c_shlb },
- [CC_OP_SHLW] = { compute_all_shlw, compute_c_shlw },
- [CC_OP_SHLL] = { compute_all_shll, compute_c_shll },
-
- [CC_OP_SARB] = { compute_all_sarb, compute_c_sarl },
- [CC_OP_SARW] = { compute_all_sarw, compute_c_sarl },
- [CC_OP_SARL] = { compute_all_sarl, compute_c_sarl },
-
-#ifdef TARGET_X86_64
- [CC_OP_MULQ] = { compute_all_mulq, compute_c_mull },
-
- [CC_OP_ADDQ] = { compute_all_addq, compute_c_addq },
-
- [CC_OP_ADCQ] = { compute_all_adcq, compute_c_adcq },
-
- [CC_OP_SUBQ] = { compute_all_subq, compute_c_subq },
-
- [CC_OP_SBBQ] = { compute_all_sbbq, compute_c_sbbq },
-
- [CC_OP_LOGICQ] = { compute_all_logicq, compute_c_logicq },
-
- [CC_OP_INCQ] = { compute_all_incq, compute_c_incl },
-
- [CC_OP_DECQ] = { compute_all_decq, compute_c_incl },
-
- [CC_OP_SHLQ] = { compute_all_shlq, compute_c_shlq },
-
- [CC_OP_SARQ] = { compute_all_sarq, compute_c_sarl },
-#endif
-};
-
-/* floating point support. Some of the code for complicated x87
- functions comes from the LGPL'ed x86 emulator found in the Willows
- TWIN windows emulator. */
-
-/* fp load FT0 */
-
-void OPPROTO op_flds_FT0_A0(void)
-{
-#ifdef USE_FP_CONVERT
- FP_CONVERT.i32 = ldl(A0);
- FT0 = FP_CONVERT.f;
-#else
- FT0 = ldfl(A0);
-#endif
-}
-
-void OPPROTO op_fldl_FT0_A0(void)
-{
-#ifdef USE_FP_CONVERT
- FP_CONVERT.i64 = ldq(A0);
- FT0 = FP_CONVERT.d;
-#else
- FT0 = ldfq(A0);
-#endif
-}
-
-/* helpers are needed to avoid static constant reference. XXX: find a better way */
-#ifdef USE_INT_TO_FLOAT_HELPERS
-
-void helper_fild_FT0_A0(void)
-{
- FT0 = (CPU86_LDouble)ldsw(A0);
-}
-
-void helper_fildl_FT0_A0(void)
-{
- FT0 = (CPU86_LDouble)((int32_t)ldl(A0));
-}
-
-void helper_fildll_FT0_A0(void)
-{
- FT0 = (CPU86_LDouble)((int64_t)ldq(A0));
-}
-
-void OPPROTO op_fild_FT0_A0(void)
-{
- helper_fild_FT0_A0();
-}
-
-void OPPROTO op_fildl_FT0_A0(void)
-{
- helper_fildl_FT0_A0();
-}
-
-void OPPROTO op_fildll_FT0_A0(void)
-{
- helper_fildll_FT0_A0();
-}
-
-#else
-
-void OPPROTO op_fild_FT0_A0(void)
-{
-#ifdef USE_FP_CONVERT
- FP_CONVERT.i32 = ldsw(A0);
- FT0 = (CPU86_LDouble)FP_CONVERT.i32;
-#else
- FT0 = (CPU86_LDouble)ldsw(A0);
-#endif
-}
-
-void OPPROTO op_fildl_FT0_A0(void)
-{
-#ifdef USE_FP_CONVERT
- FP_CONVERT.i32 = (int32_t) ldl(A0);
- FT0 = (CPU86_LDouble)FP_CONVERT.i32;
-#else
- FT0 = (CPU86_LDouble)((int32_t)ldl(A0));
-#endif
-}
-
-void OPPROTO op_fildll_FT0_A0(void)
-{
-#ifdef USE_FP_CONVERT
- FP_CONVERT.i64 = (int64_t) ldq(A0);
- FT0 = (CPU86_LDouble)FP_CONVERT.i64;
-#else
- FT0 = (CPU86_LDouble)((int64_t)ldq(A0));
-#endif
-}
-#endif
-
-/* fp load ST0 */
-
-void OPPROTO op_flds_ST0_A0(void)
-{
- int new_fpstt;
- new_fpstt = (env->fpstt - 1) & 7;
-#ifdef USE_FP_CONVERT
- FP_CONVERT.i32 = ldl(A0);
- env->fpregs[new_fpstt].d = FP_CONVERT.f;
-#else
- env->fpregs[new_fpstt].d = ldfl(A0);
-#endif
- env->fpstt = new_fpstt;
- env->fptags[new_fpstt] = 0; /* validate stack entry */
-}
-
-void OPPROTO op_fldl_ST0_A0(void)
-{
- int new_fpstt;
- new_fpstt = (env->fpstt - 1) & 7;
-#ifdef USE_FP_CONVERT
- FP_CONVERT.i64 = ldq(A0);
- env->fpregs[new_fpstt].d = FP_CONVERT.d;
-#else
- env->fpregs[new_fpstt].d = ldfq(A0);
-#endif
- env->fpstt = new_fpstt;
- env->fptags[new_fpstt] = 0; /* validate stack entry */
-}
-
-void OPPROTO op_fldt_ST0_A0(void)
-{
- helper_fldt_ST0_A0();
-}
-
-/* helpers are needed to avoid static constant reference. XXX: find a better way */
-#ifdef USE_INT_TO_FLOAT_HELPERS
-
-void helper_fild_ST0_A0(void)
-{
- int new_fpstt;
- new_fpstt = (env->fpstt - 1) & 7;
- env->fpregs[new_fpstt].d = (CPU86_LDouble)ldsw(A0);
- env->fpstt = new_fpstt;
- env->fptags[new_fpstt] = 0; /* validate stack entry */
-}
-
-void helper_fildl_ST0_A0(void)
-{
- int new_fpstt;
- new_fpstt = (env->fpstt - 1) & 7;
- env->fpregs[new_fpstt].d = (CPU86_LDouble)((int32_t)ldl(A0));
- env->fpstt = new_fpstt;
- env->fptags[new_fpstt] = 0; /* validate stack entry */
-}
-
-void helper_fildll_ST0_A0(void)
-{
- int new_fpstt;
- new_fpstt = (env->fpstt - 1) & 7;
- env->fpregs[new_fpstt].d = (CPU86_LDouble)((int64_t)ldq(A0));
- env->fpstt = new_fpstt;
- env->fptags[new_fpstt] = 0; /* validate stack entry */
-}
-
-void OPPROTO op_fild_ST0_A0(void)
-{
- helper_fild_ST0_A0();
-}
-
-void OPPROTO op_fildl_ST0_A0(void)
-{
- helper_fildl_ST0_A0();
-}
-
-void OPPROTO op_fildll_ST0_A0(void)
-{
- helper_fildll_ST0_A0();
-}
-
-#else
-
-void OPPROTO op_fild_ST0_A0(void)
-{
- int new_fpstt;
- new_fpstt = (env->fpstt - 1) & 7;
-#ifdef USE_FP_CONVERT
- FP_CONVERT.i32 = ldsw(A0);
- env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i32;
-#else
- env->fpregs[new_fpstt].d = (CPU86_LDouble)ldsw(A0);
-#endif
- env->fpstt = new_fpstt;
- env->fptags[new_fpstt] = 0; /* validate stack entry */
-}
-
-void OPPROTO op_fildl_ST0_A0(void)
-{
- int new_fpstt;
- new_fpstt = (env->fpstt - 1) & 7;
-#ifdef USE_FP_CONVERT
- FP_CONVERT.i32 = (int32_t) ldl(A0);
- env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i32;
-#else
- env->fpregs[new_fpstt].d = (CPU86_LDouble)((int32_t)ldl(A0));
-#endif
- env->fpstt = new_fpstt;
- env->fptags[new_fpstt] = 0; /* validate stack entry */
-}
-
-void OPPROTO op_fildll_ST0_A0(void)
-{
- int new_fpstt;
- new_fpstt = (env->fpstt - 1) & 7;
-#ifdef USE_FP_CONVERT
- FP_CONVERT.i64 = (int64_t) ldq(A0);
- env->fpregs[new_fpstt].d = (CPU86_LDouble)FP_CONVERT.i64;
-#else
- env->fpregs[new_fpstt].d = (CPU86_LDouble)((int64_t)ldq(A0));
-#endif
- env->fpstt = new_fpstt;
- env->fptags[new_fpstt] = 0; /* validate stack entry */
-}
-
-#endif
-
-/* fp store */
-
-void OPPROTO op_fsts_ST0_A0(void)
-{
-#ifdef USE_FP_CONVERT
- FP_CONVERT.f = (float)ST0;
- stfl(A0, FP_CONVERT.f);
-#else
- stfl(A0, (float)ST0);
-#endif
- FORCE_RET();
-}
-
-void OPPROTO op_fstl_ST0_A0(void)
-{
- stfq(A0, (double)ST0);
- FORCE_RET();
-}
-
-void OPPROTO op_fstt_ST0_A0(void)
-{
- helper_fstt_ST0_A0();
-}
-
-void OPPROTO op_fist_ST0_A0(void)
-{
-#if defined(__sparc__) && !defined(__sparc_v9__)
- register CPU86_LDouble d asm("o0");
-#else
- CPU86_LDouble d;
-#endif
- int val;
-
- d = ST0;
- val = floatx_to_int32(d, &env->fp_status);
- if (val != (int16_t)val)
- val = -32768;
- stw(A0, val);
- FORCE_RET();
-}
-
-void OPPROTO op_fistl_ST0_A0(void)
-{
-#if defined(__sparc__) && !defined(__sparc_v9__)
- register CPU86_LDouble d asm("o0");
-#else
- CPU86_LDouble d;
-#endif
- int val;
-
- d = ST0;
- val = floatx_to_int32(d, &env->fp_status);
- stl(A0, val);
- FORCE_RET();
-}
-
-void OPPROTO op_fistll_ST0_A0(void)
-{
-#if defined(__sparc__) && !defined(__sparc_v9__)
- register CPU86_LDouble d asm("o0");
-#else
- CPU86_LDouble d;
-#endif
- int64_t val;
-
- d = ST0;
- val = floatx_to_int64(d, &env->fp_status);
- stq(A0, val);
- FORCE_RET();
-}
-
-void OPPROTO op_fistt_ST0_A0(void)
-{
-#if defined(__sparc__) && !defined(__sparc_v9__)
- register CPU86_LDouble d asm("o0");
-#else
- CPU86_LDouble d;
-#endif
- int val;
-
- d = ST0;
- val = floatx_to_int32_round_to_zero(d, &env->fp_status);
- if (val != (int16_t)val)
- val = -32768;
- stw(A0, val);
- FORCE_RET();
-}
-
-void OPPROTO op_fisttl_ST0_A0(void)
-{
-#if defined(__sparc__) && !defined(__sparc_v9__)
- register CPU86_LDouble d asm("o0");
-#else
- CPU86_LDouble d;
-#endif
- int val;
-
- d = ST0;
- val = floatx_to_int32_round_to_zero(d, &env->fp_status);
- stl(A0, val);
- FORCE_RET();
-}
-
-void OPPROTO op_fisttll_ST0_A0(void)
-{
-#if defined(__sparc__) && !defined(__sparc_v9__)
- register CPU86_LDouble d asm("o0");
-#else
- CPU86_LDouble d;
-#endif
- int64_t val;
-
- d = ST0;
- val = floatx_to_int64_round_to_zero(d, &env->fp_status);
- stq(A0, val);
- FORCE_RET();
-}
-
-void OPPROTO op_fbld_ST0_A0(void)
-{
- helper_fbld_ST0_A0();
-}
-
-void OPPROTO op_fbst_ST0_A0(void)
-{
- helper_fbst_ST0_A0();
-}
-
-/* FPU move */
-
-void OPPROTO op_fpush(void)
-{
- fpush();
-}
-
-void OPPROTO op_fpop(void)
-{
- fpop();
-}
-
-void OPPROTO op_fdecstp(void)
-{
- env->fpstt = (env->fpstt - 1) & 7;
- env->fpus &= (~0x4700);
-}
-
-void OPPROTO op_fincstp(void)
-{
- env->fpstt = (env->fpstt + 1) & 7;
- env->fpus &= (~0x4700);
-}
-
-void OPPROTO op_ffree_STN(void)
-{
- env->fptags[(env->fpstt + PARAM1) & 7] = 1;
-}
-
-void OPPROTO op_fmov_ST0_FT0(void)
-{
- ST0 = FT0;
-}
-
-void OPPROTO op_fmov_FT0_STN(void)
-{
- FT0 = ST(PARAM1);
-}
-
-void OPPROTO op_fmov_ST0_STN(void)
-{
- ST0 = ST(PARAM1);
-}
-
-void OPPROTO op_fmov_STN_ST0(void)
-{
- ST(PARAM1) = ST0;
-}
-
-void OPPROTO op_fxchg_ST0_STN(void)
-{
- CPU86_LDouble tmp;
- tmp = ST(PARAM1);
- ST(PARAM1) = ST0;
- ST0 = tmp;
-}
-
-/* FPU operations */
-
-const int fcom_ccval[4] = {0x0100, 0x4000, 0x0000, 0x4500};
-
-void OPPROTO op_fcom_ST0_FT0(void)
-{
- int ret;
-
- ret = floatx_compare(ST0, FT0, &env->fp_status);
- env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret + 1];
- FORCE_RET();
-}
-
-void OPPROTO op_fucom_ST0_FT0(void)
-{
- int ret;
-
- ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
- env->fpus = (env->fpus & ~0x4500) | fcom_ccval[ret+ 1];
- FORCE_RET();
-}
-
-const int fcomi_ccval[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
-
-void OPPROTO op_fcomi_ST0_FT0(void)
-{
- int eflags;
- int ret;
-
- ret = floatx_compare(ST0, FT0, &env->fp_status);
- eflags = cc_table[CC_OP].compute_all();
- eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
- CC_SRC = eflags;
- FORCE_RET();
-}
-
-void OPPROTO op_fucomi_ST0_FT0(void)
-{
- int eflags;
- int ret;
-
- ret = floatx_compare_quiet(ST0, FT0, &env->fp_status);
- eflags = cc_table[CC_OP].compute_all();
- eflags = (eflags & ~(CC_Z | CC_P | CC_C)) | fcomi_ccval[ret + 1];
- CC_SRC = eflags;
- FORCE_RET();
-}
-
-void OPPROTO op_fcmov_ST0_STN_T0(void)
-{
- if (T0) {
- ST0 = ST(PARAM1);
- }
- FORCE_RET();
-}
-
-void OPPROTO op_fadd_ST0_FT0(void)
-{
- ST0 += FT0;
-}
-
-void OPPROTO op_fmul_ST0_FT0(void)
-{
- ST0 *= FT0;
-}
-
-void OPPROTO op_fsub_ST0_FT0(void)
-{
- ST0 -= FT0;
-}
-
-void OPPROTO op_fsubr_ST0_FT0(void)
-{
- ST0 = FT0 - ST0;
-}
-
-void OPPROTO op_fdiv_ST0_FT0(void)
-{
- ST0 = helper_fdiv(ST0, FT0);
-}
-
-void OPPROTO op_fdivr_ST0_FT0(void)
-{
- ST0 = helper_fdiv(FT0, ST0);
-}
-
-/* fp operations between STN and ST0 */
-
-void OPPROTO op_fadd_STN_ST0(void)
-{
- ST(PARAM1) += ST0;
-}
-
-void OPPROTO op_fmul_STN_ST0(void)
-{
- ST(PARAM1) *= ST0;
-}
-
-void OPPROTO op_fsub_STN_ST0(void)
-{
- ST(PARAM1) -= ST0;
-}
-
-void OPPROTO op_fsubr_STN_ST0(void)
-{
- CPU86_LDouble *p;
- p = &ST(PARAM1);
- *p = ST0 - *p;
-}
-
-void OPPROTO op_fdiv_STN_ST0(void)
-{
- CPU86_LDouble *p;
- p = &ST(PARAM1);
- *p = helper_fdiv(*p, ST0);
-}
-
-void OPPROTO op_fdivr_STN_ST0(void)
-{
- CPU86_LDouble *p;
- p = &ST(PARAM1);
- *p = helper_fdiv(ST0, *p);
-}
-
-/* misc FPU operations */
-void OPPROTO op_fchs_ST0(void)
-{
- ST0 = floatx_chs(ST0);
-}
-
-void OPPROTO op_fabs_ST0(void)
-{
- ST0 = floatx_abs(ST0);
-}
-
-void OPPROTO op_fxam_ST0(void)
-{
- helper_fxam_ST0();
-}
-
-void OPPROTO op_fld1_ST0(void)
-{
- ST0 = f15rk[1];
-}
-
-void OPPROTO op_fldl2t_ST0(void)
-{
- ST0 = f15rk[6];
-}
-
-void OPPROTO op_fldl2e_ST0(void)
-{
- ST0 = f15rk[5];
-}
-
-void OPPROTO op_fldpi_ST0(void)
-{
- ST0 = f15rk[2];
-}
-
-void OPPROTO op_fldlg2_ST0(void)
-{
- ST0 = f15rk[3];
-}
-
-void OPPROTO op_fldln2_ST0(void)
-{
- ST0 = f15rk[4];
-}
-
-void OPPROTO op_fldz_ST0(void)
-{
- ST0 = f15rk[0];
-}
-
-void OPPROTO op_fldz_FT0(void)
-{
- FT0 = f15rk[0];
-}
-
-/* associated heplers to reduce generated code length and to simplify
- relocation (FP constants are usually stored in .rodata section) */
-
-void OPPROTO op_f2xm1(void)
-{
- helper_f2xm1();
-}
-
-void OPPROTO op_fyl2x(void)
-{
- helper_fyl2x();
-}
-
-void OPPROTO op_fptan(void)
-{
- helper_fptan();
-}
-
-void OPPROTO op_fpatan(void)
-{
- helper_fpatan();
-}
-
-void OPPROTO op_fxtract(void)
-{
- helper_fxtract();
-}
-
-void OPPROTO op_fprem1(void)
-{
- helper_fprem1();
-}
-
-
-void OPPROTO op_fprem(void)
-{
- helper_fprem();
-}
-
-void OPPROTO op_fyl2xp1(void)
-{
- helper_fyl2xp1();
-}
-
-void OPPROTO op_fsqrt(void)
-{
- helper_fsqrt();
-}
-
-void OPPROTO op_fsincos(void)
-{
- helper_fsincos();
-}
-
-void OPPROTO op_frndint(void)
-{
- helper_frndint();
-}
-
-void OPPROTO op_fscale(void)
-{
- helper_fscale();
-}
-
-void OPPROTO op_fsin(void)
-{
- helper_fsin();
-}
-
-void OPPROTO op_fcos(void)
-{
- helper_fcos();
-}
-
-void OPPROTO op_fnstsw_A0(void)
-{
- int fpus;
- fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
- stw(A0, fpus);
- FORCE_RET();
-}
-
-void OPPROTO op_fnstsw_EAX(void)
-{
- int fpus;
- fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
- EAX = (EAX & ~0xffff) | fpus;
-}
-
-void OPPROTO op_fnstcw_A0(void)
-{
- stw(A0, env->fpuc);
- FORCE_RET();
-}
-
-void OPPROTO op_fldcw_A0(void)
-{
- env->fpuc = lduw(A0);
- update_fp_status();
-}
-
-void OPPROTO op_fclex(void)
-{
- env->fpus &= 0x7f00;
-}
-
-void OPPROTO op_fwait(void)
-{
- if (env->fpus & FPUS_SE)
- fpu_raise_exception();
- FORCE_RET();
-}
-
-void OPPROTO op_fninit(void)
-{
- env->fpus = 0;
- env->fpstt = 0;
- env->fpuc = 0x37f;
- env->fptags[0] = 1;
- env->fptags[1] = 1;
- env->fptags[2] = 1;
- env->fptags[3] = 1;
- env->fptags[4] = 1;
- env->fptags[5] = 1;
- env->fptags[6] = 1;
- env->fptags[7] = 1;
-}
-
-void OPPROTO op_fnstenv_A0(void)
-{
- helper_fstenv(A0, PARAM1);
-}
-
-void OPPROTO op_fldenv_A0(void)
-{
- helper_fldenv(A0, PARAM1);
-}
-
-void OPPROTO op_fnsave_A0(void)
-{
- helper_fsave(A0, PARAM1);
-}
-
-void OPPROTO op_frstor_A0(void)
-{
- helper_frstor(A0, PARAM1);
-}
-
-/* threading support */
-void OPPROTO op_lock(void)
-{
- cpu_lock();
-}
-
-void OPPROTO op_unlock(void)
-{
- cpu_unlock();
-}
-
-/* SSE support */
-static inline void memcpy16(void *d, void *s)
-{
- ((uint32_t *)d)[0] = ((uint32_t *)s)[0];
- ((uint32_t *)d)[1] = ((uint32_t *)s)[1];
- ((uint32_t *)d)[2] = ((uint32_t *)s)[2];
- ((uint32_t *)d)[3] = ((uint32_t *)s)[3];
-}
-
-void OPPROTO op_movo(void)
-{
- /* XXX: badly generated code */
- XMMReg *d, *s;
- d = (XMMReg *)((char *)env + PARAM1);
- s = (XMMReg *)((char *)env + PARAM2);
- memcpy16(d, s);
-}
-
-void OPPROTO op_movq(void)
-{
- uint64_t *d, *s;
- d = (uint64_t *)((char *)env + PARAM1);
- s = (uint64_t *)((char *)env + PARAM2);
- *d = *s;
-}
-
-void OPPROTO op_movl(void)
-{
- uint32_t *d, *s;
- d = (uint32_t *)((char *)env + PARAM1);
- s = (uint32_t *)((char *)env + PARAM2);
- *d = *s;
-}
-
-void OPPROTO op_movq_env_0(void)
-{
- uint64_t *d;
- d = (uint64_t *)((char *)env + PARAM1);
- *d = 0;
-}
-
-void OPPROTO op_fxsave_A0(void)
-{
- helper_fxsave(A0, PARAM1);
-}
-
-void OPPROTO op_fxrstor_A0(void)
-{
- helper_fxrstor(A0, PARAM1);
-}
-
-/* XXX: optimize by storing fptt and fptags in the static cpu state */
-void OPPROTO op_enter_mmx(void)
-{
- env->fpstt = 0;
- *(uint32_t *)(env->fptags) = 0;
- *(uint32_t *)(env->fptags + 4) = 0;
-}
-
-void OPPROTO op_emms(void)
-{
- /* set to empty state */
- *(uint32_t *)(env->fptags) = 0x01010101;
- *(uint32_t *)(env->fptags + 4) = 0x01010101;
-}
-
-#define SHIFT 0
-#include "ops_sse.h"
-
-#define SHIFT 1
-#include "ops_sse.h"
diff --git a/target-i386/opreg_template.h b/target-i386/opreg_template.h
deleted file mode 100644
index 6480636..0000000
--- a/target-i386/opreg_template.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * i386 micro operations (templates for various register related
- * operations)
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-void OPPROTO glue(op_movl_A0,REGNAME)(void)
-{
- A0 = (uint32_t)REG;
-}
-
-void OPPROTO glue(op_addl_A0,REGNAME)(void)
-{
- A0 = (uint32_t)(A0 + REG);
-}
-
-void OPPROTO glue(glue(op_addl_A0,REGNAME),_s1)(void)
-{
- A0 = (uint32_t)(A0 + (REG << 1));
-}
-
-void OPPROTO glue(glue(op_addl_A0,REGNAME),_s2)(void)
-{
- A0 = (uint32_t)(A0 + (REG << 2));
-}
-
-void OPPROTO glue(glue(op_addl_A0,REGNAME),_s3)(void)
-{
- A0 = (uint32_t)(A0 + (REG << 3));
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO glue(op_movq_A0,REGNAME)(void)
-{
- A0 = REG;
-}
-
-void OPPROTO glue(op_addq_A0,REGNAME)(void)
-{
- A0 = (A0 + REG);
-}
-
-void OPPROTO glue(glue(op_addq_A0,REGNAME),_s1)(void)
-{
- A0 = (A0 + (REG << 1));
-}
-
-void OPPROTO glue(glue(op_addq_A0,REGNAME),_s2)(void)
-{
- A0 = (A0 + (REG << 2));
-}
-
-void OPPROTO glue(glue(op_addq_A0,REGNAME),_s3)(void)
-{
- A0 = (A0 + (REG << 3));
-}
-#endif
-
-void OPPROTO glue(op_movl_T0,REGNAME)(void)
-{
- T0 = REG;
-}
-
-void OPPROTO glue(op_movl_T1,REGNAME)(void)
-{
- T1 = REG;
-}
-
-void OPPROTO glue(op_movh_T0,REGNAME)(void)
-{
- T0 = REG >> 8;
-}
-
-void OPPROTO glue(op_movh_T1,REGNAME)(void)
-{
- T1 = REG >> 8;
-}
-
-void OPPROTO glue(glue(op_movl,REGNAME),_T0)(void)
-{
- REG = (uint32_t)T0;
-}
-
-void OPPROTO glue(glue(op_movl,REGNAME),_T1)(void)
-{
- REG = (uint32_t)T1;
-}
-
-void OPPROTO glue(glue(op_movl,REGNAME),_A0)(void)
-{
- REG = (uint32_t)A0;
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO glue(glue(op_movq,REGNAME),_T0)(void)
-{
- REG = T0;
-}
-
-void OPPROTO glue(glue(op_movq,REGNAME),_T1)(void)
-{
- REG = T1;
-}
-
-void OPPROTO glue(glue(op_movq,REGNAME),_A0)(void)
-{
- REG = A0;
-}
-#endif
-
-/* mov T1 to REG if T0 is true */
-void OPPROTO glue(glue(op_cmovw,REGNAME),_T1_T0)(void)
-{
- if (T0)
- REG = (REG & ~0xffff) | (T1 & 0xffff);
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_cmovl,REGNAME),_T1_T0)(void)
-{
- if (T0)
- REG = (uint32_t)T1;
- FORCE_RET();
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO glue(glue(op_cmovq,REGNAME),_T1_T0)(void)
-{
- if (T0)
- REG = T1;
- FORCE_RET();
-}
-#endif
-
-/* NOTE: T0 high order bits are ignored */
-void OPPROTO glue(glue(op_movw,REGNAME),_T0)(void)
-{
- REG = (REG & ~0xffff) | (T0 & 0xffff);
-}
-
-/* NOTE: T0 high order bits are ignored */
-void OPPROTO glue(glue(op_movw,REGNAME),_T1)(void)
-{
- REG = (REG & ~0xffff) | (T1 & 0xffff);
-}
-
-/* NOTE: A0 high order bits are ignored */
-void OPPROTO glue(glue(op_movw,REGNAME),_A0)(void)
-{
- REG = (REG & ~0xffff) | (A0 & 0xffff);
-}
-
-/* NOTE: T0 high order bits are ignored */
-void OPPROTO glue(glue(op_movb,REGNAME),_T0)(void)
-{
- REG = (REG & ~0xff) | (T0 & 0xff);
-}
-
-/* NOTE: T0 high order bits are ignored */
-void OPPROTO glue(glue(op_movh,REGNAME),_T0)(void)
-{
- REG = (REG & ~0xff00) | ((T0 & 0xff) << 8);
-}
-
-/* NOTE: T1 high order bits are ignored */
-void OPPROTO glue(glue(op_movb,REGNAME),_T1)(void)
-{
- REG = (REG & ~0xff) | (T1 & 0xff);
-}
-
-/* NOTE: T1 high order bits are ignored */
-void OPPROTO glue(glue(op_movh,REGNAME),_T1)(void)
-{
- REG = (REG & ~0xff00) | ((T1 & 0xff) << 8);
-}
-
diff --git a/target-i386/ops_mem.h b/target-i386/ops_mem.h
deleted file mode 100644
index 7ec84dd..0000000
--- a/target-i386/ops_mem.h
+++ /dev/null
@@ -1,156 +0,0 @@
-void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T0_A0)(void)
-{
- T0 = glue(ldub, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T0_A0)(void)
-{
- T0 = glue(ldsb, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T0_A0)(void)
-{
- T0 = glue(lduw, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T0_A0)(void)
-{
- T0 = glue(ldsw, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T0_A0)(void)
-{
- T0 = (uint32_t)glue(ldl, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_ldub, MEMSUFFIX), _T1_A0)(void)
-{
- T1 = glue(ldub, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_ldsb, MEMSUFFIX), _T1_A0)(void)
-{
- T1 = glue(ldsb, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_lduw, MEMSUFFIX), _T1_A0)(void)
-{
- T1 = glue(lduw, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_ldsw, MEMSUFFIX), _T1_A0)(void)
-{
- T1 = glue(ldsw, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_ldl, MEMSUFFIX), _T1_A0)(void)
-{
- T1 = (uint32_t)glue(ldl, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T0_A0)(void)
-{
- glue(stb, MEMSUFFIX)(A0, T0);
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T0_A0)(void)
-{
- glue(stw, MEMSUFFIX)(A0, T0);
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T0_A0)(void)
-{
- glue(stl, MEMSUFFIX)(A0, T0);
- FORCE_RET();
-}
-
-#if 0
-void OPPROTO glue(glue(op_stb, MEMSUFFIX), _T1_A0)(void)
-{
- glue(stb, MEMSUFFIX)(A0, T1);
- FORCE_RET();
-}
-#endif
-
-void OPPROTO glue(glue(op_stw, MEMSUFFIX), _T1_A0)(void)
-{
- glue(stw, MEMSUFFIX)(A0, T1);
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_stl, MEMSUFFIX), _T1_A0)(void)
-{
- glue(stl, MEMSUFFIX)(A0, T1);
- FORCE_RET();
-}
-
-/* SSE/MMX support */
-void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _env_A0)(void)
-{
- uint64_t *p;
- p = (uint64_t *)((char *)env + PARAM1);
- *p = glue(ldq, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_stq, MEMSUFFIX), _env_A0)(void)
-{
- uint64_t *p;
- p = (uint64_t *)((char *)env + PARAM1);
- glue(stq, MEMSUFFIX)(A0, *p);
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_ldo, MEMSUFFIX), _env_A0)(void)
-{
- XMMReg *p;
- p = (XMMReg *)((char *)env + PARAM1);
- p->XMM_Q(0) = glue(ldq, MEMSUFFIX)(A0);
- p->XMM_Q(1) = glue(ldq, MEMSUFFIX)(A0 + 8);
-}
-
-void OPPROTO glue(glue(op_sto, MEMSUFFIX), _env_A0)(void)
-{
- XMMReg *p;
- p = (XMMReg *)((char *)env + PARAM1);
- glue(stq, MEMSUFFIX)(A0, p->XMM_Q(0));
- glue(stq, MEMSUFFIX)(A0 + 8, p->XMM_Q(1));
- FORCE_RET();
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO glue(glue(op_ldsl, MEMSUFFIX), _T0_A0)(void)
-{
- T0 = (int32_t)glue(ldl, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_ldsl, MEMSUFFIX), _T1_A0)(void)
-{
- T1 = (int32_t)glue(ldl, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _T0_A0)(void)
-{
- T0 = glue(ldq, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_ldq, MEMSUFFIX), _T1_A0)(void)
-{
- T1 = glue(ldq, MEMSUFFIX)(A0);
-}
-
-void OPPROTO glue(glue(op_stq, MEMSUFFIX), _T0_A0)(void)
-{
- glue(stq, MEMSUFFIX)(A0, T0);
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_stq, MEMSUFFIX), _T1_A0)(void)
-{
- glue(stq, MEMSUFFIX)(A0, T1);
- FORCE_RET();
-}
-#endif
-
-#undef MEMSUFFIX
diff --git a/target-i386/ops_sse.h b/target-i386/ops_sse.h
deleted file mode 100644
index cdc3801..0000000
--- a/target-i386/ops_sse.h
+++ /dev/null
@@ -1,1374 +0,0 @@
-/*
- * MMX/SSE/SSE2/PNI support
- *
- * Copyright (c) 2005 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#if SHIFT == 0
-#define Reg MMXReg
-#define XMM_ONLY(x...)
-#define B(n) MMX_B(n)
-#define W(n) MMX_W(n)
-#define L(n) MMX_L(n)
-#define Q(n) q
-#define SUFFIX _mmx
-#else
-#define Reg XMMReg
-#define XMM_ONLY(x...) x
-#define B(n) XMM_B(n)
-#define W(n) XMM_W(n)
-#define L(n) XMM_L(n)
-#define Q(n) XMM_Q(n)
-#define SUFFIX _xmm
-#endif
-
-void OPPROTO glue(op_psrlw, SUFFIX)(void)
-{
- Reg *d, *s;
- int shift;
-
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- if (s->Q(0) > 15) {
- d->Q(0) = 0;
-#if SHIFT == 1
- d->Q(1) = 0;
-#endif
- } else {
- shift = s->B(0);
- d->W(0) >>= shift;
- d->W(1) >>= shift;
- d->W(2) >>= shift;
- d->W(3) >>= shift;
-#if SHIFT == 1
- d->W(4) >>= shift;
- d->W(5) >>= shift;
- d->W(6) >>= shift;
- d->W(7) >>= shift;
-#endif
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(op_psraw, SUFFIX)(void)
-{
- Reg *d, *s;
- int shift;
-
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- if (s->Q(0) > 15) {
- shift = 15;
- } else {
- shift = s->B(0);
- }
- d->W(0) = (int16_t)d->W(0) >> shift;
- d->W(1) = (int16_t)d->W(1) >> shift;
- d->W(2) = (int16_t)d->W(2) >> shift;
- d->W(3) = (int16_t)d->W(3) >> shift;
-#if SHIFT == 1
- d->W(4) = (int16_t)d->W(4) >> shift;
- d->W(5) = (int16_t)d->W(5) >> shift;
- d->W(6) = (int16_t)d->W(6) >> shift;
- d->W(7) = (int16_t)d->W(7) >> shift;
-#endif
-}
-
-void OPPROTO glue(op_psllw, SUFFIX)(void)
-{
- Reg *d, *s;
- int shift;
-
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- if (s->Q(0) > 15) {
- d->Q(0) = 0;
-#if SHIFT == 1
- d->Q(1) = 0;
-#endif
- } else {
- shift = s->B(0);
- d->W(0) <<= shift;
- d->W(1) <<= shift;
- d->W(2) <<= shift;
- d->W(3) <<= shift;
-#if SHIFT == 1
- d->W(4) <<= shift;
- d->W(5) <<= shift;
- d->W(6) <<= shift;
- d->W(7) <<= shift;
-#endif
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(op_psrld, SUFFIX)(void)
-{
- Reg *d, *s;
- int shift;
-
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- if (s->Q(0) > 31) {
- d->Q(0) = 0;
-#if SHIFT == 1
- d->Q(1) = 0;
-#endif
- } else {
- shift = s->B(0);
- d->L(0) >>= shift;
- d->L(1) >>= shift;
-#if SHIFT == 1
- d->L(2) >>= shift;
- d->L(3) >>= shift;
-#endif
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(op_psrad, SUFFIX)(void)
-{
- Reg *d, *s;
- int shift;
-
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- if (s->Q(0) > 31) {
- shift = 31;
- } else {
- shift = s->B(0);
- }
- d->L(0) = (int32_t)d->L(0) >> shift;
- d->L(1) = (int32_t)d->L(1) >> shift;
-#if SHIFT == 1
- d->L(2) = (int32_t)d->L(2) >> shift;
- d->L(3) = (int32_t)d->L(3) >> shift;
-#endif
-}
-
-void OPPROTO glue(op_pslld, SUFFIX)(void)
-{
- Reg *d, *s;
- int shift;
-
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- if (s->Q(0) > 31) {
- d->Q(0) = 0;
-#if SHIFT == 1
- d->Q(1) = 0;
-#endif
- } else {
- shift = s->B(0);
- d->L(0) <<= shift;
- d->L(1) <<= shift;
-#if SHIFT == 1
- d->L(2) <<= shift;
- d->L(3) <<= shift;
-#endif
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(op_psrlq, SUFFIX)(void)
-{
- Reg *d, *s;
- int shift;
-
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- if (s->Q(0) > 63) {
- d->Q(0) = 0;
-#if SHIFT == 1
- d->Q(1) = 0;
-#endif
- } else {
- shift = s->B(0);
- d->Q(0) >>= shift;
-#if SHIFT == 1
- d->Q(1) >>= shift;
-#endif
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(op_psllq, SUFFIX)(void)
-{
- Reg *d, *s;
- int shift;
-
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- if (s->Q(0) > 63) {
- d->Q(0) = 0;
-#if SHIFT == 1
- d->Q(1) = 0;
-#endif
- } else {
- shift = s->B(0);
- d->Q(0) <<= shift;
-#if SHIFT == 1
- d->Q(1) <<= shift;
-#endif
- }
- FORCE_RET();
-}
-
-#if SHIFT == 1
-void OPPROTO glue(op_psrldq, SUFFIX)(void)
-{
- Reg *d, *s;
- int shift, i;
-
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- shift = s->L(0);
- if (shift > 16)
- shift = 16;
- for(i = 0; i < 16 - shift; i++)
- d->B(i) = d->B(i + shift);
- for(i = 16 - shift; i < 16; i++)
- d->B(i) = 0;
- FORCE_RET();
-}
-
-void OPPROTO glue(op_pslldq, SUFFIX)(void)
-{
- Reg *d, *s;
- int shift, i;
-
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- shift = s->L(0);
- if (shift > 16)
- shift = 16;
- for(i = 15; i >= shift; i--)
- d->B(i) = d->B(i - shift);
- for(i = 0; i < shift; i++)
- d->B(i) = 0;
- FORCE_RET();
-}
-#endif
-
-#define SSE_OP_B(name, F)\
-void OPPROTO glue(name, SUFFIX) (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->B(0) = F(d->B(0), s->B(0));\
- d->B(1) = F(d->B(1), s->B(1));\
- d->B(2) = F(d->B(2), s->B(2));\
- d->B(3) = F(d->B(3), s->B(3));\
- d->B(4) = F(d->B(4), s->B(4));\
- d->B(5) = F(d->B(5), s->B(5));\
- d->B(6) = F(d->B(6), s->B(6));\
- d->B(7) = F(d->B(7), s->B(7));\
- XMM_ONLY(\
- d->B(8) = F(d->B(8), s->B(8));\
- d->B(9) = F(d->B(9), s->B(9));\
- d->B(10) = F(d->B(10), s->B(10));\
- d->B(11) = F(d->B(11), s->B(11));\
- d->B(12) = F(d->B(12), s->B(12));\
- d->B(13) = F(d->B(13), s->B(13));\
- d->B(14) = F(d->B(14), s->B(14));\
- d->B(15) = F(d->B(15), s->B(15));\
- )\
-}
-
-#define SSE_OP_W(name, F)\
-void OPPROTO glue(name, SUFFIX) (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->W(0) = F(d->W(0), s->W(0));\
- d->W(1) = F(d->W(1), s->W(1));\
- d->W(2) = F(d->W(2), s->W(2));\
- d->W(3) = F(d->W(3), s->W(3));\
- XMM_ONLY(\
- d->W(4) = F(d->W(4), s->W(4));\
- d->W(5) = F(d->W(5), s->W(5));\
- d->W(6) = F(d->W(6), s->W(6));\
- d->W(7) = F(d->W(7), s->W(7));\
- )\
-}
-
-#define SSE_OP_L(name, F)\
-void OPPROTO glue(name, SUFFIX) (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->L(0) = F(d->L(0), s->L(0));\
- d->L(1) = F(d->L(1), s->L(1));\
- XMM_ONLY(\
- d->L(2) = F(d->L(2), s->L(2));\
- d->L(3) = F(d->L(3), s->L(3));\
- )\
-}
-
-#define SSE_OP_Q(name, F)\
-void OPPROTO glue(name, SUFFIX) (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->Q(0) = F(d->Q(0), s->Q(0));\
- XMM_ONLY(\
- d->Q(1) = F(d->Q(1), s->Q(1));\
- )\
-}
-
-#if SHIFT == 0
-static inline int satub(int x)
-{
- if (x < 0)
- return 0;
- else if (x > 255)
- return 255;
- else
- return x;
-}
-
-static inline int satuw(int x)
-{
- if (x < 0)
- return 0;
- else if (x > 65535)
- return 65535;
- else
- return x;
-}
-
-static inline int satsb(int x)
-{
- if (x < -128)
- return -128;
- else if (x > 127)
- return 127;
- else
- return x;
-}
-
-static inline int satsw(int x)
-{
- if (x < -32768)
- return -32768;
- else if (x > 32767)
- return 32767;
- else
- return x;
-}
-
-#define FADD(a, b) ((a) + (b))
-#define FADDUB(a, b) satub((a) + (b))
-#define FADDUW(a, b) satuw((a) + (b))
-#define FADDSB(a, b) satsb((int8_t)(a) + (int8_t)(b))
-#define FADDSW(a, b) satsw((int16_t)(a) + (int16_t)(b))
-
-#define FSUB(a, b) ((a) - (b))
-#define FSUBUB(a, b) satub((a) - (b))
-#define FSUBUW(a, b) satuw((a) - (b))
-#define FSUBSB(a, b) satsb((int8_t)(a) - (int8_t)(b))
-#define FSUBSW(a, b) satsw((int16_t)(a) - (int16_t)(b))
-#define FMINUB(a, b) ((a) < (b)) ? (a) : (b)
-#define FMINSW(a, b) ((int16_t)(a) < (int16_t)(b)) ? (a) : (b)
-#define FMAXUB(a, b) ((a) > (b)) ? (a) : (b)
-#define FMAXSW(a, b) ((int16_t)(a) > (int16_t)(b)) ? (a) : (b)
-
-#define FAND(a, b) (a) & (b)
-#define FANDN(a, b) ((~(a)) & (b))
-#define FOR(a, b) (a) | (b)
-#define FXOR(a, b) (a) ^ (b)
-
-#define FCMPGTB(a, b) (int8_t)(a) > (int8_t)(b) ? -1 : 0
-#define FCMPGTW(a, b) (int16_t)(a) > (int16_t)(b) ? -1 : 0
-#define FCMPGTL(a, b) (int32_t)(a) > (int32_t)(b) ? -1 : 0
-#define FCMPEQ(a, b) (a) == (b) ? -1 : 0
-
-#define FMULLW(a, b) (a) * (b)
-#define FMULHUW(a, b) (a) * (b) >> 16
-#define FMULHW(a, b) (int16_t)(a) * (int16_t)(b) >> 16
-
-#define FAVG(a, b) ((a) + (b) + 1) >> 1
-#endif
-
-SSE_OP_B(op_paddb, FADD)
-SSE_OP_W(op_paddw, FADD)
-SSE_OP_L(op_paddl, FADD)
-SSE_OP_Q(op_paddq, FADD)
-
-SSE_OP_B(op_psubb, FSUB)
-SSE_OP_W(op_psubw, FSUB)
-SSE_OP_L(op_psubl, FSUB)
-SSE_OP_Q(op_psubq, FSUB)
-
-SSE_OP_B(op_paddusb, FADDUB)
-SSE_OP_B(op_paddsb, FADDSB)
-SSE_OP_B(op_psubusb, FSUBUB)
-SSE_OP_B(op_psubsb, FSUBSB)
-
-SSE_OP_W(op_paddusw, FADDUW)
-SSE_OP_W(op_paddsw, FADDSW)
-SSE_OP_W(op_psubusw, FSUBUW)
-SSE_OP_W(op_psubsw, FSUBSW)
-
-SSE_OP_B(op_pminub, FMINUB)
-SSE_OP_B(op_pmaxub, FMAXUB)
-
-SSE_OP_W(op_pminsw, FMINSW)
-SSE_OP_W(op_pmaxsw, FMAXSW)
-
-SSE_OP_Q(op_pand, FAND)
-SSE_OP_Q(op_pandn, FANDN)
-SSE_OP_Q(op_por, FOR)
-SSE_OP_Q(op_pxor, FXOR)
-
-SSE_OP_B(op_pcmpgtb, FCMPGTB)
-SSE_OP_W(op_pcmpgtw, FCMPGTW)
-SSE_OP_L(op_pcmpgtl, FCMPGTL)
-
-SSE_OP_B(op_pcmpeqb, FCMPEQ)
-SSE_OP_W(op_pcmpeqw, FCMPEQ)
-SSE_OP_L(op_pcmpeql, FCMPEQ)
-
-SSE_OP_W(op_pmullw, FMULLW)
-SSE_OP_W(op_pmulhuw, FMULHUW)
-SSE_OP_W(op_pmulhw, FMULHW)
-
-SSE_OP_B(op_pavgb, FAVG)
-SSE_OP_W(op_pavgw, FAVG)
-
-void OPPROTO glue(op_pmuludq, SUFFIX) (void)
-{
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- d->Q(0) = (uint64_t)s->L(0) * (uint64_t)d->L(0);
-#if SHIFT == 1
- d->Q(1) = (uint64_t)s->L(2) * (uint64_t)d->L(2);
-#endif
-}
-
-void OPPROTO glue(op_pmaddwd, SUFFIX) (void)
-{
- int i;
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- for(i = 0; i < (2 << SHIFT); i++) {
- d->L(i) = (int16_t)s->W(2*i) * (int16_t)d->W(2*i) +
- (int16_t)s->W(2*i+1) * (int16_t)d->W(2*i+1);
- }
- FORCE_RET();
-}
-
-#if SHIFT == 0
-static inline int abs1(int a)
-{
- if (a < 0)
- return -a;
- else
- return a;
-}
-#endif
-void OPPROTO glue(op_psadbw, SUFFIX) (void)
-{
- unsigned int val;
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- val = 0;
- val += abs1(d->B(0) - s->B(0));
- val += abs1(d->B(1) - s->B(1));
- val += abs1(d->B(2) - s->B(2));
- val += abs1(d->B(3) - s->B(3));
- val += abs1(d->B(4) - s->B(4));
- val += abs1(d->B(5) - s->B(5));
- val += abs1(d->B(6) - s->B(6));
- val += abs1(d->B(7) - s->B(7));
- d->Q(0) = val;
-#if SHIFT == 1
- val = 0;
- val += abs1(d->B(8) - s->B(8));
- val += abs1(d->B(9) - s->B(9));
- val += abs1(d->B(10) - s->B(10));
- val += abs1(d->B(11) - s->B(11));
- val += abs1(d->B(12) - s->B(12));
- val += abs1(d->B(13) - s->B(13));
- val += abs1(d->B(14) - s->B(14));
- val += abs1(d->B(15) - s->B(15));
- d->Q(1) = val;
-#endif
-}
-
-void OPPROTO glue(op_maskmov, SUFFIX) (void)
-{
- int i;
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- for(i = 0; i < (8 << SHIFT); i++) {
- if (s->B(i) & 0x80)
- stb(A0 + i, d->B(i));
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(op_movl_mm_T0, SUFFIX) (void)
-{
- Reg *d;
- d = (Reg *)((char *)env + PARAM1);
- d->L(0) = T0;
- d->L(1) = 0;
-#if SHIFT == 1
- d->Q(1) = 0;
-#endif
-}
-
-void OPPROTO glue(op_movl_T0_mm, SUFFIX) (void)
-{
- Reg *s;
- s = (Reg *)((char *)env + PARAM1);
- T0 = s->L(0);
-}
-
-#if SHIFT == 0
-void OPPROTO glue(op_pshufw, SUFFIX) (void)
-{
- Reg r, *d, *s;
- int order;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- order = PARAM3;
- r.W(0) = s->W(order & 3);
- r.W(1) = s->W((order >> 2) & 3);
- r.W(2) = s->W((order >> 4) & 3);
- r.W(3) = s->W((order >> 6) & 3);
- *d = r;
-}
-#else
-void OPPROTO op_shufps(void)
-{
- Reg r, *d, *s;
- int order;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- order = PARAM3;
- r.L(0) = d->L(order & 3);
- r.L(1) = d->L((order >> 2) & 3);
- r.L(2) = s->L((order >> 4) & 3);
- r.L(3) = s->L((order >> 6) & 3);
- *d = r;
-}
-
-void OPPROTO op_shufpd(void)
-{
- Reg r, *d, *s;
- int order;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- order = PARAM3;
- r.Q(0) = d->Q(order & 1);
- r.Q(1) = s->Q((order >> 1) & 1);
- *d = r;
-}
-
-void OPPROTO glue(op_pshufd, SUFFIX) (void)
-{
- Reg r, *d, *s;
- int order;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- order = PARAM3;
- r.L(0) = s->L(order & 3);
- r.L(1) = s->L((order >> 2) & 3);
- r.L(2) = s->L((order >> 4) & 3);
- r.L(3) = s->L((order >> 6) & 3);
- *d = r;
-}
-
-void OPPROTO glue(op_pshuflw, SUFFIX) (void)
-{
- Reg r, *d, *s;
- int order;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- order = PARAM3;
- r.W(0) = s->W(order & 3);
- r.W(1) = s->W((order >> 2) & 3);
- r.W(2) = s->W((order >> 4) & 3);
- r.W(3) = s->W((order >> 6) & 3);
- r.Q(1) = s->Q(1);
- *d = r;
-}
-
-void OPPROTO glue(op_pshufhw, SUFFIX) (void)
-{
- Reg r, *d, *s;
- int order;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- order = PARAM3;
- r.Q(0) = s->Q(0);
- r.W(4) = s->W(4 + (order & 3));
- r.W(5) = s->W(4 + ((order >> 2) & 3));
- r.W(6) = s->W(4 + ((order >> 4) & 3));
- r.W(7) = s->W(4 + ((order >> 6) & 3));
- *d = r;
-}
-#endif
-
-#if SHIFT == 1
-/* FPU ops */
-/* XXX: not accurate */
-
-#define SSE_OP_S(name, F)\
-void OPPROTO op_ ## name ## ps (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0));\
- d->XMM_S(1) = F(32, d->XMM_S(1), s->XMM_S(1));\
- d->XMM_S(2) = F(32, d->XMM_S(2), s->XMM_S(2));\
- d->XMM_S(3) = F(32, d->XMM_S(3), s->XMM_S(3));\
-}\
-\
-void OPPROTO op_ ## name ## ss (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->XMM_S(0) = F(32, d->XMM_S(0), s->XMM_S(0));\
-}\
-void OPPROTO op_ ## name ## pd (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
- d->XMM_D(1) = F(64, d->XMM_D(1), s->XMM_D(1));\
-}\
-\
-void OPPROTO op_ ## name ## sd (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->XMM_D(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
-}
-
-#define FPU_ADD(size, a, b) float ## size ## _add(a, b, &env->sse_status)
-#define FPU_SUB(size, a, b) float ## size ## _sub(a, b, &env->sse_status)
-#define FPU_MUL(size, a, b) float ## size ## _mul(a, b, &env->sse_status)
-#define FPU_DIV(size, a, b) float ## size ## _div(a, b, &env->sse_status)
-#define FPU_MIN(size, a, b) (a) < (b) ? (a) : (b)
-#define FPU_MAX(size, a, b) (a) > (b) ? (a) : (b)
-#define FPU_SQRT(size, a, b) float ## size ## _sqrt(b, &env->sse_status)
-
-SSE_OP_S(add, FPU_ADD)
-SSE_OP_S(sub, FPU_SUB)
-SSE_OP_S(mul, FPU_MUL)
-SSE_OP_S(div, FPU_DIV)
-SSE_OP_S(min, FPU_MIN)
-SSE_OP_S(max, FPU_MAX)
-SSE_OP_S(sqrt, FPU_SQRT)
-
-
-/* float to float conversions */
-void OPPROTO op_cvtps2pd(void)
-{
- float32 s0, s1;
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- s0 = s->XMM_S(0);
- s1 = s->XMM_S(1);
- d->XMM_D(0) = float32_to_float64(s0, &env->sse_status);
- d->XMM_D(1) = float32_to_float64(s1, &env->sse_status);
-}
-
-void OPPROTO op_cvtpd2ps(void)
-{
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- d->XMM_S(0) = float64_to_float32(s->XMM_D(0), &env->sse_status);
- d->XMM_S(1) = float64_to_float32(s->XMM_D(1), &env->sse_status);
- d->Q(1) = 0;
-}
-
-void OPPROTO op_cvtss2sd(void)
-{
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- d->XMM_D(0) = float32_to_float64(s->XMM_S(0), &env->sse_status);
-}
-
-void OPPROTO op_cvtsd2ss(void)
-{
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
- d->XMM_S(0) = float64_to_float32(s->XMM_D(0), &env->sse_status);
-}
-
-/* integer to float */
-void OPPROTO op_cvtdq2ps(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_S(0) = int32_to_float32(s->XMM_L(0), &env->sse_status);
- d->XMM_S(1) = int32_to_float32(s->XMM_L(1), &env->sse_status);
- d->XMM_S(2) = int32_to_float32(s->XMM_L(2), &env->sse_status);
- d->XMM_S(3) = int32_to_float32(s->XMM_L(3), &env->sse_status);
-}
-
-void OPPROTO op_cvtdq2pd(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- int32_t l0, l1;
- l0 = (int32_t)s->XMM_L(0);
- l1 = (int32_t)s->XMM_L(1);
- d->XMM_D(0) = int32_to_float64(l0, &env->sse_status);
- d->XMM_D(1) = int32_to_float64(l1, &env->sse_status);
-}
-
-void OPPROTO op_cvtpi2ps(void)
-{
- XMMReg *d = (Reg *)((char *)env + PARAM1);
- MMXReg *s = (MMXReg *)((char *)env + PARAM2);
- d->XMM_S(0) = int32_to_float32(s->MMX_L(0), &env->sse_status);
- d->XMM_S(1) = int32_to_float32(s->MMX_L(1), &env->sse_status);
-}
-
-void OPPROTO op_cvtpi2pd(void)
-{
- XMMReg *d = (Reg *)((char *)env + PARAM1);
- MMXReg *s = (MMXReg *)((char *)env + PARAM2);
- d->XMM_D(0) = int32_to_float64(s->MMX_L(0), &env->sse_status);
- d->XMM_D(1) = int32_to_float64(s->MMX_L(1), &env->sse_status);
-}
-
-void OPPROTO op_cvtsi2ss(void)
-{
- XMMReg *d = (Reg *)((char *)env + PARAM1);
- d->XMM_S(0) = int32_to_float32(T0, &env->sse_status);
-}
-
-void OPPROTO op_cvtsi2sd(void)
-{
- XMMReg *d = (Reg *)((char *)env + PARAM1);
- d->XMM_D(0) = int32_to_float64(T0, &env->sse_status);
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_cvtsq2ss(void)
-{
- XMMReg *d = (Reg *)((char *)env + PARAM1);
- d->XMM_S(0) = int64_to_float32(T0, &env->sse_status);
-}
-
-void OPPROTO op_cvtsq2sd(void)
-{
- XMMReg *d = (Reg *)((char *)env + PARAM1);
- d->XMM_D(0) = int64_to_float64(T0, &env->sse_status);
-}
-#endif
-
-/* float to integer */
-void OPPROTO op_cvtps2dq(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_L(0) = float32_to_int32(s->XMM_S(0), &env->sse_status);
- d->XMM_L(1) = float32_to_int32(s->XMM_S(1), &env->sse_status);
- d->XMM_L(2) = float32_to_int32(s->XMM_S(2), &env->sse_status);
- d->XMM_L(3) = float32_to_int32(s->XMM_S(3), &env->sse_status);
-}
-
-void OPPROTO op_cvtpd2dq(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_L(0) = float64_to_int32(s->XMM_D(0), &env->sse_status);
- d->XMM_L(1) = float64_to_int32(s->XMM_D(1), &env->sse_status);
- d->XMM_Q(1) = 0;
-}
-
-void OPPROTO op_cvtps2pi(void)
-{
- MMXReg *d = (MMXReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->MMX_L(0) = float32_to_int32(s->XMM_S(0), &env->sse_status);
- d->MMX_L(1) = float32_to_int32(s->XMM_S(1), &env->sse_status);
-}
-
-void OPPROTO op_cvtpd2pi(void)
-{
- MMXReg *d = (MMXReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->MMX_L(0) = float64_to_int32(s->XMM_D(0), &env->sse_status);
- d->MMX_L(1) = float64_to_int32(s->XMM_D(1), &env->sse_status);
-}
-
-void OPPROTO op_cvtss2si(void)
-{
- XMMReg *s = (XMMReg *)((char *)env + PARAM1);
- T0 = float32_to_int32(s->XMM_S(0), &env->sse_status);
-}
-
-void OPPROTO op_cvtsd2si(void)
-{
- XMMReg *s = (XMMReg *)((char *)env + PARAM1);
- T0 = float64_to_int32(s->XMM_D(0), &env->sse_status);
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_cvtss2sq(void)
-{
- XMMReg *s = (XMMReg *)((char *)env + PARAM1);
- T0 = float32_to_int64(s->XMM_S(0), &env->sse_status);
-}
-
-void OPPROTO op_cvtsd2sq(void)
-{
- XMMReg *s = (XMMReg *)((char *)env + PARAM1);
- T0 = float64_to_int64(s->XMM_D(0), &env->sse_status);
-}
-#endif
-
-/* float to integer truncated */
-void OPPROTO op_cvttps2dq(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_L(0) = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status);
- d->XMM_L(1) = float32_to_int32_round_to_zero(s->XMM_S(1), &env->sse_status);
- d->XMM_L(2) = float32_to_int32_round_to_zero(s->XMM_S(2), &env->sse_status);
- d->XMM_L(3) = float32_to_int32_round_to_zero(s->XMM_S(3), &env->sse_status);
-}
-
-void OPPROTO op_cvttpd2dq(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_L(0) = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status);
- d->XMM_L(1) = float64_to_int32_round_to_zero(s->XMM_D(1), &env->sse_status);
- d->XMM_Q(1) = 0;
-}
-
-void OPPROTO op_cvttps2pi(void)
-{
- MMXReg *d = (MMXReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->MMX_L(0) = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status);
- d->MMX_L(1) = float32_to_int32_round_to_zero(s->XMM_S(1), &env->sse_status);
-}
-
-void OPPROTO op_cvttpd2pi(void)
-{
- MMXReg *d = (MMXReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->MMX_L(0) = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status);
- d->MMX_L(1) = float64_to_int32_round_to_zero(s->XMM_D(1), &env->sse_status);
-}
-
-void OPPROTO op_cvttss2si(void)
-{
- XMMReg *s = (XMMReg *)((char *)env + PARAM1);
- T0 = float32_to_int32_round_to_zero(s->XMM_S(0), &env->sse_status);
-}
-
-void OPPROTO op_cvttsd2si(void)
-{
- XMMReg *s = (XMMReg *)((char *)env + PARAM1);
- T0 = float64_to_int32_round_to_zero(s->XMM_D(0), &env->sse_status);
-}
-
-#ifdef TARGET_X86_64
-void OPPROTO op_cvttss2sq(void)
-{
- XMMReg *s = (XMMReg *)((char *)env + PARAM1);
- T0 = float32_to_int64_round_to_zero(s->XMM_S(0), &env->sse_status);
-}
-
-void OPPROTO op_cvttsd2sq(void)
-{
- XMMReg *s = (XMMReg *)((char *)env + PARAM1);
- T0 = float64_to_int64_round_to_zero(s->XMM_D(0), &env->sse_status);
-}
-#endif
-
-void OPPROTO op_rsqrtps(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_S(0) = approx_rsqrt(s->XMM_S(0));
- d->XMM_S(1) = approx_rsqrt(s->XMM_S(1));
- d->XMM_S(2) = approx_rsqrt(s->XMM_S(2));
- d->XMM_S(3) = approx_rsqrt(s->XMM_S(3));
-}
-
-void OPPROTO op_rsqrtss(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_S(0) = approx_rsqrt(s->XMM_S(0));
-}
-
-void OPPROTO op_rcpps(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_S(0) = approx_rcp(s->XMM_S(0));
- d->XMM_S(1) = approx_rcp(s->XMM_S(1));
- d->XMM_S(2) = approx_rcp(s->XMM_S(2));
- d->XMM_S(3) = approx_rcp(s->XMM_S(3));
-}
-
-void OPPROTO op_rcpss(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_S(0) = approx_rcp(s->XMM_S(0));
-}
-
-void OPPROTO op_haddps(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- XMMReg r;
- r.XMM_S(0) = d->XMM_S(0) + d->XMM_S(1);
- r.XMM_S(1) = d->XMM_S(2) + d->XMM_S(3);
- r.XMM_S(2) = s->XMM_S(0) + s->XMM_S(1);
- r.XMM_S(3) = s->XMM_S(2) + s->XMM_S(3);
- *d = r;
-}
-
-void OPPROTO op_haddpd(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- XMMReg r;
- r.XMM_D(0) = d->XMM_D(0) + d->XMM_D(1);
- r.XMM_D(1) = s->XMM_D(0) + s->XMM_D(1);
- *d = r;
-}
-
-void OPPROTO op_hsubps(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- XMMReg r;
- r.XMM_S(0) = d->XMM_S(0) - d->XMM_S(1);
- r.XMM_S(1) = d->XMM_S(2) - d->XMM_S(3);
- r.XMM_S(2) = s->XMM_S(0) - s->XMM_S(1);
- r.XMM_S(3) = s->XMM_S(2) - s->XMM_S(3);
- *d = r;
-}
-
-void OPPROTO op_hsubpd(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- XMMReg r;
- r.XMM_D(0) = d->XMM_D(0) - d->XMM_D(1);
- r.XMM_D(1) = s->XMM_D(0) - s->XMM_D(1);
- *d = r;
-}
-
-void OPPROTO op_addsubps(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_S(0) = d->XMM_S(0) - s->XMM_S(0);
- d->XMM_S(1) = d->XMM_S(1) + s->XMM_S(1);
- d->XMM_S(2) = d->XMM_S(2) - s->XMM_S(2);
- d->XMM_S(3) = d->XMM_S(3) + s->XMM_S(3);
-}
-
-void OPPROTO op_addsubpd(void)
-{
- XMMReg *d = (XMMReg *)((char *)env + PARAM1);
- XMMReg *s = (XMMReg *)((char *)env + PARAM2);
- d->XMM_D(0) = d->XMM_D(0) - s->XMM_D(0);
- d->XMM_D(1) = d->XMM_D(1) + s->XMM_D(1);
-}
-
-/* XXX: unordered */
-#define SSE_OP_CMP(name, F)\
-void OPPROTO op_ ## name ## ps (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0));\
- d->XMM_L(1) = F(32, d->XMM_S(1), s->XMM_S(1));\
- d->XMM_L(2) = F(32, d->XMM_S(2), s->XMM_S(2));\
- d->XMM_L(3) = F(32, d->XMM_S(3), s->XMM_S(3));\
-}\
-\
-void OPPROTO op_ ## name ## ss (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->XMM_L(0) = F(32, d->XMM_S(0), s->XMM_S(0));\
-}\
-void OPPROTO op_ ## name ## pd (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
- d->XMM_Q(1) = F(64, d->XMM_D(1), s->XMM_D(1));\
-}\
-\
-void OPPROTO op_ ## name ## sd (void)\
-{\
- Reg *d, *s;\
- d = (Reg *)((char *)env + PARAM1);\
- s = (Reg *)((char *)env + PARAM2);\
- d->XMM_Q(0) = F(64, d->XMM_D(0), s->XMM_D(0));\
-}
-
-#define FPU_CMPEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? -1 : 0
-#define FPU_CMPLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? -1 : 0
-#define FPU_CMPLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? -1 : 0
-#define FPU_CMPUNORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? - 1 : 0
-#define FPU_CMPNEQ(size, a, b) float ## size ## _eq(a, b, &env->sse_status) ? 0 : -1
-#define FPU_CMPNLT(size, a, b) float ## size ## _lt(a, b, &env->sse_status) ? 0 : -1
-#define FPU_CMPNLE(size, a, b) float ## size ## _le(a, b, &env->sse_status) ? 0 : -1
-#define FPU_CMPORD(size, a, b) float ## size ## _unordered(a, b, &env->sse_status) ? 0 : -1
-
-SSE_OP_CMP(cmpeq, FPU_CMPEQ)
-SSE_OP_CMP(cmplt, FPU_CMPLT)
-SSE_OP_CMP(cmple, FPU_CMPLE)
-SSE_OP_CMP(cmpunord, FPU_CMPUNORD)
-SSE_OP_CMP(cmpneq, FPU_CMPNEQ)
-SSE_OP_CMP(cmpnlt, FPU_CMPNLT)
-SSE_OP_CMP(cmpnle, FPU_CMPNLE)
-SSE_OP_CMP(cmpord, FPU_CMPORD)
-
-const int comis_eflags[4] = {CC_C, CC_Z, 0, CC_Z | CC_P | CC_C};
-
-void OPPROTO op_ucomiss(void)
-{
- int ret;
- float32 s0, s1;
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- s0 = d->XMM_S(0);
- s1 = s->XMM_S(0);
- ret = float32_compare_quiet(s0, s1, &env->sse_status);
- CC_SRC = comis_eflags[ret + 1];
- FORCE_RET();
-}
-
-void OPPROTO op_comiss(void)
-{
- int ret;
- float32 s0, s1;
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- s0 = d->XMM_S(0);
- s1 = s->XMM_S(0);
- ret = float32_compare(s0, s1, &env->sse_status);
- CC_SRC = comis_eflags[ret + 1];
- FORCE_RET();
-}
-
-void OPPROTO op_ucomisd(void)
-{
- int ret;
- float64 d0, d1;
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- d0 = d->XMM_D(0);
- d1 = s->XMM_D(0);
- ret = float64_compare_quiet(d0, d1, &env->sse_status);
- CC_SRC = comis_eflags[ret + 1];
- FORCE_RET();
-}
-
-void OPPROTO op_comisd(void)
-{
- int ret;
- float64 d0, d1;
- Reg *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- d0 = d->XMM_D(0);
- d1 = s->XMM_D(0);
- ret = float64_compare(d0, d1, &env->sse_status);
- CC_SRC = comis_eflags[ret + 1];
- FORCE_RET();
-}
-
-void OPPROTO op_movmskps(void)
-{
- int b0, b1, b2, b3;
- Reg *s;
- s = (Reg *)((char *)env + PARAM1);
- b0 = s->XMM_L(0) >> 31;
- b1 = s->XMM_L(1) >> 31;
- b2 = s->XMM_L(2) >> 31;
- b3 = s->XMM_L(3) >> 31;
- T0 = b0 | (b1 << 1) | (b2 << 2) | (b3 << 3);
-}
-
-void OPPROTO op_movmskpd(void)
-{
- int b0, b1;
- Reg *s;
- s = (Reg *)((char *)env + PARAM1);
- b0 = s->XMM_L(1) >> 31;
- b1 = s->XMM_L(3) >> 31;
- T0 = b0 | (b1 << 1);
-}
-
-#endif
-
-void OPPROTO glue(op_pmovmskb, SUFFIX)(void)
-{
- Reg *s;
- s = (Reg *)((char *)env + PARAM1);
- T0 = 0;
- T0 |= (s->XMM_B(0) >> 7);
- T0 |= (s->XMM_B(1) >> 6) & 0x02;
- T0 |= (s->XMM_B(2) >> 5) & 0x04;
- T0 |= (s->XMM_B(3) >> 4) & 0x08;
- T0 |= (s->XMM_B(4) >> 3) & 0x10;
- T0 |= (s->XMM_B(5) >> 2) & 0x20;
- T0 |= (s->XMM_B(6) >> 1) & 0x40;
- T0 |= (s->XMM_B(7)) & 0x80;
-#if SHIFT == 1
- T0 |= (s->XMM_B(8) << 1) & 0x0100;
- T0 |= (s->XMM_B(9) << 2) & 0x0200;
- T0 |= (s->XMM_B(10) << 3) & 0x0400;
- T0 |= (s->XMM_B(11) << 4) & 0x0800;
- T0 |= (s->XMM_B(12) << 5) & 0x1000;
- T0 |= (s->XMM_B(13) << 6) & 0x2000;
- T0 |= (s->XMM_B(14) << 7) & 0x4000;
- T0 |= (s->XMM_B(15) << 8) & 0x8000;
-#endif
-}
-
-void OPPROTO glue(op_pinsrw, SUFFIX) (void)
-{
- Reg *d = (Reg *)((char *)env + PARAM1);
- int pos = PARAM2;
-
- d->W(pos) = T0;
-}
-
-void OPPROTO glue(op_pextrw, SUFFIX) (void)
-{
- Reg *s = (Reg *)((char *)env + PARAM1);
- int pos = PARAM2;
-
- T0 = s->W(pos);
-}
-
-void OPPROTO glue(op_packsswb, SUFFIX) (void)
-{
- Reg r, *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- r.B(0) = satsb((int16_t)d->W(0));
- r.B(1) = satsb((int16_t)d->W(1));
- r.B(2) = satsb((int16_t)d->W(2));
- r.B(3) = satsb((int16_t)d->W(3));
-#if SHIFT == 1
- r.B(4) = satsb((int16_t)d->W(4));
- r.B(5) = satsb((int16_t)d->W(5));
- r.B(6) = satsb((int16_t)d->W(6));
- r.B(7) = satsb((int16_t)d->W(7));
-#endif
- r.B((4 << SHIFT) + 0) = satsb((int16_t)s->W(0));
- r.B((4 << SHIFT) + 1) = satsb((int16_t)s->W(1));
- r.B((4 << SHIFT) + 2) = satsb((int16_t)s->W(2));
- r.B((4 << SHIFT) + 3) = satsb((int16_t)s->W(3));
-#if SHIFT == 1
- r.B(12) = satsb((int16_t)s->W(4));
- r.B(13) = satsb((int16_t)s->W(5));
- r.B(14) = satsb((int16_t)s->W(6));
- r.B(15) = satsb((int16_t)s->W(7));
-#endif
- *d = r;
-}
-
-void OPPROTO glue(op_packuswb, SUFFIX) (void)
-{
- Reg r, *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- r.B(0) = satub((int16_t)d->W(0));
- r.B(1) = satub((int16_t)d->W(1));
- r.B(2) = satub((int16_t)d->W(2));
- r.B(3) = satub((int16_t)d->W(3));
-#if SHIFT == 1
- r.B(4) = satub((int16_t)d->W(4));
- r.B(5) = satub((int16_t)d->W(5));
- r.B(6) = satub((int16_t)d->W(6));
- r.B(7) = satub((int16_t)d->W(7));
-#endif
- r.B((4 << SHIFT) + 0) = satub((int16_t)s->W(0));
- r.B((4 << SHIFT) + 1) = satub((int16_t)s->W(1));
- r.B((4 << SHIFT) + 2) = satub((int16_t)s->W(2));
- r.B((4 << SHIFT) + 3) = satub((int16_t)s->W(3));
-#if SHIFT == 1
- r.B(12) = satub((int16_t)s->W(4));
- r.B(13) = satub((int16_t)s->W(5));
- r.B(14) = satub((int16_t)s->W(6));
- r.B(15) = satub((int16_t)s->W(7));
-#endif
- *d = r;
-}
-
-void OPPROTO glue(op_packssdw, SUFFIX) (void)
-{
- Reg r, *d, *s;
- d = (Reg *)((char *)env + PARAM1);
- s = (Reg *)((char *)env + PARAM2);
-
- r.W(0) = satsw(d->L(0));
- r.W(1) = satsw(d->L(1));
-#if SHIFT == 1
- r.W(2) = satsw(d->L(2));
- r.W(3) = satsw(d->L(3));
-#endif
- r.W((2 << SHIFT) + 0) = satsw(s->L(0));
- r.W((2 << SHIFT) + 1) = satsw(s->L(1));
-#if SHIFT == 1
- r.W(6) = satsw(s->L(2));
- r.W(7) = satsw(s->L(3));
-#endif
- *d = r;
-}
-
-#define UNPCK_OP(base_name, base) \
- \
-void OPPROTO glue(op_punpck ## base_name ## bw, SUFFIX) (void) \
-{ \
- Reg r, *d, *s; \
- d = (Reg *)((char *)env + PARAM1); \
- s = (Reg *)((char *)env + PARAM2); \
- \
- r.B(0) = d->B((base << (SHIFT + 2)) + 0); \
- r.B(1) = s->B((base << (SHIFT + 2)) + 0); \
- r.B(2) = d->B((base << (SHIFT + 2)) + 1); \
- r.B(3) = s->B((base << (SHIFT + 2)) + 1); \
- r.B(4) = d->B((base << (SHIFT + 2)) + 2); \
- r.B(5) = s->B((base << (SHIFT + 2)) + 2); \
- r.B(6) = d->B((base << (SHIFT + 2)) + 3); \
- r.B(7) = s->B((base << (SHIFT + 2)) + 3); \
-XMM_ONLY( \
- r.B(8) = d->B((base << (SHIFT + 2)) + 4); \
- r.B(9) = s->B((base << (SHIFT + 2)) + 4); \
- r.B(10) = d->B((base << (SHIFT + 2)) + 5); \
- r.B(11) = s->B((base << (SHIFT + 2)) + 5); \
- r.B(12) = d->B((base << (SHIFT + 2)) + 6); \
- r.B(13) = s->B((base << (SHIFT + 2)) + 6); \
- r.B(14) = d->B((base << (SHIFT + 2)) + 7); \
- r.B(15) = s->B((base << (SHIFT + 2)) + 7); \
-) \
- *d = r; \
-} \
- \
-void OPPROTO glue(op_punpck ## base_name ## wd, SUFFIX) (void) \
-{ \
- Reg r, *d, *s; \
- d = (Reg *)((char *)env + PARAM1); \
- s = (Reg *)((char *)env + PARAM2); \
- \
- r.W(0) = d->W((base << (SHIFT + 1)) + 0); \
- r.W(1) = s->W((base << (SHIFT + 1)) + 0); \
- r.W(2) = d->W((base << (SHIFT + 1)) + 1); \
- r.W(3) = s->W((base << (SHIFT + 1)) + 1); \
-XMM_ONLY( \
- r.W(4) = d->W((base << (SHIFT + 1)) + 2); \
- r.W(5) = s->W((base << (SHIFT + 1)) + 2); \
- r.W(6) = d->W((base << (SHIFT + 1)) + 3); \
- r.W(7) = s->W((base << (SHIFT + 1)) + 3); \
-) \
- *d = r; \
-} \
- \
-void OPPROTO glue(op_punpck ## base_name ## dq, SUFFIX) (void) \
-{ \
- Reg r, *d, *s; \
- d = (Reg *)((char *)env + PARAM1); \
- s = (Reg *)((char *)env + PARAM2); \
- \
- r.L(0) = d->L((base << SHIFT) + 0); \
- r.L(1) = s->L((base << SHIFT) + 0); \
-XMM_ONLY( \
- r.L(2) = d->L((base << SHIFT) + 1); \
- r.L(3) = s->L((base << SHIFT) + 1); \
-) \
- *d = r; \
-} \
- \
-XMM_ONLY( \
-void OPPROTO glue(op_punpck ## base_name ## qdq, SUFFIX) (void) \
-{ \
- Reg r, *d, *s; \
- d = (Reg *)((char *)env + PARAM1); \
- s = (Reg *)((char *)env + PARAM2); \
- \
- r.Q(0) = d->Q(base); \
- r.Q(1) = s->Q(base); \
- *d = r; \
-} \
-)
-
-UNPCK_OP(l, 0)
-UNPCK_OP(h, 1)
-
-#undef SHIFT
-#undef XMM_ONLY
-#undef Reg
-#undef B
-#undef W
-#undef L
-#undef Q
-#undef SUFFIX
diff --git a/target-i386/ops_template.h b/target-i386/ops_template.h
deleted file mode 100644
index 373b77a..0000000
--- a/target-i386/ops_template.h
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * i386 micro operations (included several times to generate
- * different operand sizes)
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#define DATA_BITS (1 << (3 + SHIFT))
-#define SHIFT_MASK (DATA_BITS - 1)
-#define SIGN_MASK (((target_ulong)1) << (DATA_BITS - 1))
-#if DATA_BITS <= 32
-#define SHIFT1_MASK 0x1f
-#else
-#define SHIFT1_MASK 0x3f
-#endif
-
-#if DATA_BITS == 8
-#define SUFFIX b
-#define DATA_TYPE uint8_t
-#define DATA_STYPE int8_t
-#define DATA_MASK 0xff
-#elif DATA_BITS == 16
-#define SUFFIX w
-#define DATA_TYPE uint16_t
-#define DATA_STYPE int16_t
-#define DATA_MASK 0xffff
-#elif DATA_BITS == 32
-#define SUFFIX l
-#define DATA_TYPE uint32_t
-#define DATA_STYPE int32_t
-#define DATA_MASK 0xffffffff
-#elif DATA_BITS == 64
-#define SUFFIX q
-#define DATA_TYPE uint64_t
-#define DATA_STYPE int64_t
-#define DATA_MASK 0xffffffffffffffffULL
-#else
-#error unhandled operand size
-#endif
-
-/* dynamic flags computation */
-
-static int glue(compute_all_add, SUFFIX)(void)
-{
- int cf, pf, af, zf, sf, of;
- target_long src1, src2;
- src1 = CC_SRC;
- src2 = CC_DST - CC_SRC;
- cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
- return cf | pf | af | zf | sf | of;
-}
-
-static int glue(compute_c_add, SUFFIX)(void)
-{
- int cf;
- target_long src1;
- src1 = CC_SRC;
- cf = (DATA_TYPE)CC_DST < (DATA_TYPE)src1;
- return cf;
-}
-
-static int glue(compute_all_adc, SUFFIX)(void)
-{
- int cf, pf, af, zf, sf, of;
- target_long src1, src2;
- src1 = CC_SRC;
- src2 = CC_DST - CC_SRC - 1;
- cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = lshift((src1 ^ src2 ^ -1) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
- return cf | pf | af | zf | sf | of;
-}
-
-static int glue(compute_c_adc, SUFFIX)(void)
-{
- int cf;
- target_long src1;
- src1 = CC_SRC;
- cf = (DATA_TYPE)CC_DST <= (DATA_TYPE)src1;
- return cf;
-}
-
-static int glue(compute_all_sub, SUFFIX)(void)
-{
- int cf, pf, af, zf, sf, of;
- target_long src1, src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
- cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
- return cf | pf | af | zf | sf | of;
-}
-
-static int glue(compute_c_sub, SUFFIX)(void)
-{
- int cf;
- target_long src1, src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
- cf = (DATA_TYPE)src1 < (DATA_TYPE)src2;
- return cf;
-}
-
-static int glue(compute_all_sbb, SUFFIX)(void)
-{
- int cf, pf, af, zf, sf, of;
- target_long src1, src2;
- src1 = CC_DST + CC_SRC + 1;
- src2 = CC_SRC;
- cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = lshift((src1 ^ src2) & (src1 ^ CC_DST), 12 - DATA_BITS) & CC_O;
- return cf | pf | af | zf | sf | of;
-}
-
-static int glue(compute_c_sbb, SUFFIX)(void)
-{
- int cf;
- target_long src1, src2;
- src1 = CC_DST + CC_SRC + 1;
- src2 = CC_SRC;
- cf = (DATA_TYPE)src1 <= (DATA_TYPE)src2;
- return cf;
-}
-
-static int glue(compute_all_logic, SUFFIX)(void)
-{
- int cf, pf, af, zf, sf, of;
- cf = 0;
- pf = parity_table[(uint8_t)CC_DST];
- af = 0;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = 0;
- return cf | pf | af | zf | sf | of;
-}
-
-static int glue(compute_c_logic, SUFFIX)(void)
-{
- return 0;
-}
-
-static int glue(compute_all_inc, SUFFIX)(void)
-{
- int cf, pf, af, zf, sf, of;
- target_long src1, src2;
- src1 = CC_DST - 1;
- src2 = 1;
- cf = CC_SRC;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = ((CC_DST & DATA_MASK) == SIGN_MASK) << 11;
- return cf | pf | af | zf | sf | of;
-}
-
-#if DATA_BITS == 32
-static int glue(compute_c_inc, SUFFIX)(void)
-{
- return CC_SRC;
-}
-#endif
-
-static int glue(compute_all_dec, SUFFIX)(void)
-{
- int cf, pf, af, zf, sf, of;
- target_long src1, src2;
- src1 = CC_DST + 1;
- src2 = 1;
- cf = CC_SRC;
- pf = parity_table[(uint8_t)CC_DST];
- af = (CC_DST ^ src1 ^ src2) & 0x10;
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = ((CC_DST & DATA_MASK) == ((target_ulong)SIGN_MASK - 1)) << 11;
- return cf | pf | af | zf | sf | of;
-}
-
-static int glue(compute_all_shl, SUFFIX)(void)
-{
- int cf, pf, af, zf, sf, of;
- cf = (CC_SRC >> (DATA_BITS - 1)) & CC_C;
- pf = parity_table[(uint8_t)CC_DST];
- af = 0; /* undefined */
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- /* of is defined if shift count == 1 */
- of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
- return cf | pf | af | zf | sf | of;
-}
-
-static int glue(compute_c_shl, SUFFIX)(void)
-{
- return (CC_SRC >> (DATA_BITS - 1)) & CC_C;
-}
-
-#if DATA_BITS == 32
-static int glue(compute_c_sar, SUFFIX)(void)
-{
- return CC_SRC & 1;
-}
-#endif
-
-static int glue(compute_all_sar, SUFFIX)(void)
-{
- int cf, pf, af, zf, sf, of;
- cf = CC_SRC & 1;
- pf = parity_table[(uint8_t)CC_DST];
- af = 0; /* undefined */
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- /* of is defined if shift count == 1 */
- of = lshift(CC_SRC ^ CC_DST, 12 - DATA_BITS) & CC_O;
- return cf | pf | af | zf | sf | of;
-}
-
-#if DATA_BITS == 32
-static int glue(compute_c_mul, SUFFIX)(void)
-{
- int cf;
- cf = (CC_SRC != 0);
- return cf;
-}
-#endif
-
-/* NOTE: we compute the flags like the P4. On olders CPUs, only OF and
- CF are modified and it is slower to do that. */
-static int glue(compute_all_mul, SUFFIX)(void)
-{
- int cf, pf, af, zf, sf, of;
- cf = (CC_SRC != 0);
- pf = parity_table[(uint8_t)CC_DST];
- af = 0; /* undefined */
- zf = ((DATA_TYPE)CC_DST == 0) << 6;
- sf = lshift(CC_DST, 8 - DATA_BITS) & 0x80;
- of = cf << 11;
- return cf | pf | af | zf | sf | of;
-}
-
-/* various optimized jumps cases */
-
-void OPPROTO glue(op_jb_sub, SUFFIX)(void)
-{
- target_long src1, src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
-
- if ((DATA_TYPE)src1 < (DATA_TYPE)src2)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO glue(op_jz_sub, SUFFIX)(void)
-{
- if ((DATA_TYPE)CC_DST == 0)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO glue(op_jnz_sub, SUFFIX)(void)
-{
- if ((DATA_TYPE)CC_DST != 0)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO glue(op_jbe_sub, SUFFIX)(void)
-{
- target_long src1, src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
-
- if ((DATA_TYPE)src1 <= (DATA_TYPE)src2)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO glue(op_js_sub, SUFFIX)(void)
-{
- if (CC_DST & SIGN_MASK)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO glue(op_jl_sub, SUFFIX)(void)
-{
- target_long src1, src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
-
- if ((DATA_STYPE)src1 < (DATA_STYPE)src2)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO glue(op_jle_sub, SUFFIX)(void)
-{
- target_long src1, src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
-
- if ((DATA_STYPE)src1 <= (DATA_STYPE)src2)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-/* oldies */
-
-#if DATA_BITS >= 16
-
-void OPPROTO glue(op_loopnz, SUFFIX)(void)
-{
- if ((DATA_TYPE)ECX != 0 && !(T0 & CC_Z))
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO glue(op_loopz, SUFFIX)(void)
-{
- if ((DATA_TYPE)ECX != 0 && (T0 & CC_Z))
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO glue(op_jz_ecx, SUFFIX)(void)
-{
- if ((DATA_TYPE)ECX == 0)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO glue(op_jnz_ecx, SUFFIX)(void)
-{
- if ((DATA_TYPE)ECX != 0)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-#endif
-
-/* various optimized set cases */
-
-void OPPROTO glue(op_setb_T0_sub, SUFFIX)(void)
-{
- target_long src1, src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
-
- T0 = ((DATA_TYPE)src1 < (DATA_TYPE)src2);
-}
-
-void OPPROTO glue(op_setz_T0_sub, SUFFIX)(void)
-{
- T0 = ((DATA_TYPE)CC_DST == 0);
-}
-
-void OPPROTO glue(op_setbe_T0_sub, SUFFIX)(void)
-{
- target_long src1, src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
-
- T0 = ((DATA_TYPE)src1 <= (DATA_TYPE)src2);
-}
-
-void OPPROTO glue(op_sets_T0_sub, SUFFIX)(void)
-{
- T0 = lshift(CC_DST, -(DATA_BITS - 1)) & 1;
-}
-
-void OPPROTO glue(op_setl_T0_sub, SUFFIX)(void)
-{
- target_long src1, src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
-
- T0 = ((DATA_STYPE)src1 < (DATA_STYPE)src2);
-}
-
-void OPPROTO glue(op_setle_T0_sub, SUFFIX)(void)
-{
- target_long src1, src2;
- src1 = CC_DST + CC_SRC;
- src2 = CC_SRC;
-
- T0 = ((DATA_STYPE)src1 <= (DATA_STYPE)src2);
-}
-
-/* shifts */
-
-void OPPROTO glue(glue(op_shl, SUFFIX), _T0_T1)(void)
-{
- int count;
- count = T1 & SHIFT1_MASK;
- T0 = T0 << count;
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_shr, SUFFIX), _T0_T1)(void)
-{
- int count;
- count = T1 & SHIFT1_MASK;
- T0 &= DATA_MASK;
- T0 = T0 >> count;
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_sar, SUFFIX), _T0_T1)(void)
-{
- int count;
- target_long src;
-
- count = T1 & SHIFT1_MASK;
- src = (DATA_STYPE)T0;
- T0 = src >> count;
- FORCE_RET();
-}
-
-#undef MEM_WRITE
-#include "ops_template_mem.h"
-
-#define MEM_WRITE 0
-#include "ops_template_mem.h"
-
-#if !defined(CONFIG_USER_ONLY)
-#define MEM_WRITE 1
-#include "ops_template_mem.h"
-
-#define MEM_WRITE 2
-#include "ops_template_mem.h"
-#endif
-
-/* bit operations */
-#if DATA_BITS >= 16
-
-void OPPROTO glue(glue(op_bt, SUFFIX), _T0_T1_cc)(void)
-{
- int count;
- count = T1 & SHIFT_MASK;
- CC_SRC = T0 >> count;
-}
-
-void OPPROTO glue(glue(op_bts, SUFFIX), _T0_T1_cc)(void)
-{
- int count;
- count = T1 & SHIFT_MASK;
- T1 = T0 >> count;
- T0 |= (((target_long)1) << count);
-}
-
-void OPPROTO glue(glue(op_btr, SUFFIX), _T0_T1_cc)(void)
-{
- int count;
- count = T1 & SHIFT_MASK;
- T1 = T0 >> count;
- T0 &= ~(((target_long)1) << count);
-}
-
-void OPPROTO glue(glue(op_btc, SUFFIX), _T0_T1_cc)(void)
-{
- int count;
- count = T1 & SHIFT_MASK;
- T1 = T0 >> count;
- T0 ^= (((target_long)1) << count);
-}
-
-void OPPROTO glue(glue(op_add_bit, SUFFIX), _A0_T1)(void)
-{
- A0 += ((DATA_STYPE)T1 >> (3 + SHIFT)) << SHIFT;
-}
-
-void OPPROTO glue(glue(op_bsf, SUFFIX), _T0_cc)(void)
-{
- int count;
- target_long res;
-
- res = T0 & DATA_MASK;
- if (res != 0) {
- count = 0;
- while ((res & 1) == 0) {
- count++;
- res >>= 1;
- }
- T1 = count;
- CC_DST = 1; /* ZF = 0 */
- } else {
- CC_DST = 0; /* ZF = 1 */
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_bsr, SUFFIX), _T0_cc)(void)
-{
- int count;
- target_long res;
-
- res = T0 & DATA_MASK;
- if (res != 0) {
- count = DATA_BITS - 1;
- while ((res & SIGN_MASK) == 0) {
- count--;
- res <<= 1;
- }
- T1 = count;
- CC_DST = 1; /* ZF = 0 */
- } else {
- CC_DST = 0; /* ZF = 1 */
- }
- FORCE_RET();
-}
-
-#endif
-
-#if DATA_BITS == 32
-void OPPROTO op_update_bt_cc(void)
-{
- CC_SRC = T1;
-}
-#endif
-
-/* string operations */
-
-void OPPROTO glue(op_movl_T0_Dshift, SUFFIX)(void)
-{
- T0 = DF << SHIFT;
-}
-
-/* port I/O */
-#if DATA_BITS <= 32
-void OPPROTO glue(glue(op_out, SUFFIX), _T0_T1)(void)
-{
- glue(cpu_out, SUFFIX)(env, T0, T1 & DATA_MASK);
-}
-
-void OPPROTO glue(glue(op_in, SUFFIX), _T0_T1)(void)
-{
- T1 = glue(cpu_in, SUFFIX)(env, T0);
-}
-
-void OPPROTO glue(glue(op_in, SUFFIX), _DX_T0)(void)
-{
- T0 = glue(cpu_in, SUFFIX)(env, EDX & 0xffff);
-}
-
-void OPPROTO glue(glue(op_out, SUFFIX), _DX_T0)(void)
-{
- glue(cpu_out, SUFFIX)(env, EDX & 0xffff, T0);
-}
-
-void OPPROTO glue(glue(op_check_io, SUFFIX), _T0)(void)
-{
- glue(glue(check_io, SUFFIX), _T0)();
-}
-
-void OPPROTO glue(glue(op_check_io, SUFFIX), _DX)(void)
-{
- glue(glue(check_io, SUFFIX), _DX)();
-}
-#endif
-
-#undef DATA_BITS
-#undef SHIFT_MASK
-#undef SHIFT1_MASK
-#undef SIGN_MASK
-#undef DATA_TYPE
-#undef DATA_STYPE
-#undef DATA_MASK
-#undef SUFFIX
diff --git a/target-i386/ops_template_mem.h b/target-i386/ops_template_mem.h
deleted file mode 100644
index 9f72a8c..0000000
--- a/target-i386/ops_template_mem.h
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * i386 micro operations (included several times to generate
- * different operand sizes)
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#ifdef MEM_WRITE
-
-#if MEM_WRITE == 0
-
-#if DATA_BITS == 8
-#define MEM_SUFFIX b_raw
-#elif DATA_BITS == 16
-#define MEM_SUFFIX w_raw
-#elif DATA_BITS == 32
-#define MEM_SUFFIX l_raw
-#elif DATA_BITS == 64
-#define MEM_SUFFIX q_raw
-#endif
-
-#elif MEM_WRITE == 1
-
-#if DATA_BITS == 8
-#define MEM_SUFFIX b_kernel
-#elif DATA_BITS == 16
-#define MEM_SUFFIX w_kernel
-#elif DATA_BITS == 32
-#define MEM_SUFFIX l_kernel
-#elif DATA_BITS == 64
-#define MEM_SUFFIX q_kernel
-#endif
-
-#elif MEM_WRITE == 2
-
-#if DATA_BITS == 8
-#define MEM_SUFFIX b_user
-#elif DATA_BITS == 16
-#define MEM_SUFFIX w_user
-#elif DATA_BITS == 32
-#define MEM_SUFFIX l_user
-#elif DATA_BITS == 64
-#define MEM_SUFFIX q_user
-#endif
-
-#else
-
-#error invalid MEM_WRITE
-
-#endif
-
-#else
-
-#define MEM_SUFFIX SUFFIX
-
-#endif
-
-void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1_cc)(void)
-{
- int count;
- target_long src;
-
- if (T1 & SHIFT1_MASK) {
- count = T1 & SHIFT_MASK;
- src = T0;
- T0 &= DATA_MASK;
- T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#else
- /* gcc 3.2 workaround. This is really a bug in gcc. */
- asm volatile("" : : "r" (T0));
-#endif
- CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
- (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
- (T0 & CC_C);
- CC_OP = CC_OP_EFLAGS;
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1_cc)(void)
-{
- int count;
- target_long src;
-
- if (T1 & SHIFT1_MASK) {
- count = T1 & SHIFT_MASK;
- src = T0;
- T0 &= DATA_MASK;
- T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#else
- /* gcc 3.2 workaround. This is really a bug in gcc. */
- asm volatile("" : : "r" (T0));
-#endif
- CC_SRC = (cc_table[CC_OP].compute_all() & ~(CC_O | CC_C)) |
- (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
- ((T0 >> (DATA_BITS - 1)) & CC_C);
- CC_OP = CC_OP_EFLAGS;
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_rol, MEM_SUFFIX), _T0_T1)(void)
-{
- int count;
- count = T1 & SHIFT_MASK;
- if (count) {
- T0 &= DATA_MASK;
- T0 = (T0 << count) | (T0 >> (DATA_BITS - count));
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_ror, MEM_SUFFIX), _T0_T1)(void)
-{
- int count;
- count = T1 & SHIFT_MASK;
- if (count) {
- T0 &= DATA_MASK;
- T0 = (T0 >> count) | (T0 << (DATA_BITS - count));
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_rcl, MEM_SUFFIX), _T0_T1_cc)(void)
-{
- int count, eflags;
- target_ulong src;
- target_long res;
-
- count = T1 & SHIFT1_MASK;
-#if DATA_BITS == 16
- count = rclw_table[count];
-#elif DATA_BITS == 8
- count = rclb_table[count];
-#endif
- if (count) {
- eflags = cc_table[CC_OP].compute_all();
- T0 &= DATA_MASK;
- src = T0;
- res = (T0 << count) | ((target_ulong)(eflags & CC_C) << (count - 1));
- if (count > 1)
- res |= T0 >> (DATA_BITS + 1 - count);
- T0 = res;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = (eflags & ~(CC_C | CC_O)) |
- (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
- ((src >> (DATA_BITS - count)) & CC_C);
- CC_OP = CC_OP_EFLAGS;
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_rcr, MEM_SUFFIX), _T0_T1_cc)(void)
-{
- int count, eflags;
- target_ulong src;
- target_long res;
-
- count = T1 & SHIFT1_MASK;
-#if DATA_BITS == 16
- count = rclw_table[count];
-#elif DATA_BITS == 8
- count = rclb_table[count];
-#endif
- if (count) {
- eflags = cc_table[CC_OP].compute_all();
- T0 &= DATA_MASK;
- src = T0;
- res = (T0 >> count) | ((target_ulong)(eflags & CC_C) << (DATA_BITS - count));
- if (count > 1)
- res |= T0 << (DATA_BITS + 1 - count);
- T0 = res;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = (eflags & ~(CC_C | CC_O)) |
- (lshift(src ^ T0, 11 - (DATA_BITS - 1)) & CC_O) |
- ((src >> (count - 1)) & CC_C);
- CC_OP = CC_OP_EFLAGS;
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_shl, MEM_SUFFIX), _T0_T1_cc)(void)
-{
- int count;
- target_long src;
-
- count = T1 & SHIFT1_MASK;
- if (count) {
- src = (DATA_TYPE)T0 << (count - 1);
- T0 = T0 << count;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = src;
- CC_DST = T0;
- CC_OP = CC_OP_SHLB + SHIFT;
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_shr, MEM_SUFFIX), _T0_T1_cc)(void)
-{
- int count;
- target_long src;
-
- count = T1 & SHIFT1_MASK;
- if (count) {
- T0 &= DATA_MASK;
- src = T0 >> (count - 1);
- T0 = T0 >> count;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = src;
- CC_DST = T0;
- CC_OP = CC_OP_SARB + SHIFT;
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_sar, MEM_SUFFIX), _T0_T1_cc)(void)
-{
- int count;
- target_long src;
-
- count = T1 & SHIFT1_MASK;
- if (count) {
- src = (DATA_STYPE)T0;
- T0 = src >> count;
- src = src >> (count - 1);
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = src;
- CC_DST = T0;
- CC_OP = CC_OP_SARB + SHIFT;
- }
- FORCE_RET();
-}
-
-#if DATA_BITS == 16
-/* XXX: overflow flag might be incorrect in some cases in shldw */
-void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
-{
- int count;
- unsigned int res, tmp;
- count = PARAM1;
- T1 &= 0xffff;
- res = T1 | (T0 << 16);
- tmp = res >> (32 - count);
- res <<= count;
- if (count > 16)
- res |= T1 << (count - 16);
- T0 = res >> 16;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = tmp;
- CC_DST = T0;
-}
-
-void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
-{
- int count;
- unsigned int res, tmp;
- count = ECX & 0x1f;
- if (count) {
- T1 &= 0xffff;
- res = T1 | (T0 << 16);
- tmp = res >> (32 - count);
- res <<= count;
- if (count > 16)
- res |= T1 << (count - 16);
- T0 = res >> 16;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = tmp;
- CC_DST = T0;
- CC_OP = CC_OP_SARB + SHIFT;
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
-{
- int count;
- unsigned int res, tmp;
-
- count = PARAM1;
- res = (T0 & 0xffff) | (T1 << 16);
- tmp = res >> (count - 1);
- res >>= count;
- if (count > 16)
- res |= T1 << (32 - count);
- T0 = res;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = tmp;
- CC_DST = T0;
-}
-
-
-void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
-{
- int count;
- unsigned int res, tmp;
-
- count = ECX & 0x1f;
- if (count) {
- res = (T0 & 0xffff) | (T1 << 16);
- tmp = res >> (count - 1);
- res >>= count;
- if (count > 16)
- res |= T1 << (32 - count);
- T0 = res;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = tmp;
- CC_DST = T0;
- CC_OP = CC_OP_SARB + SHIFT;
- }
- FORCE_RET();
-}
-#endif
-
-#if DATA_BITS >= 32
-void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_im_cc)(void)
-{
- int count;
- target_long tmp;
-
- count = PARAM1;
- T0 &= DATA_MASK;
- T1 &= DATA_MASK;
- tmp = T0 << (count - 1);
- T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = tmp;
- CC_DST = T0;
-}
-
-void OPPROTO glue(glue(op_shld, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
-{
- int count;
- target_long tmp;
-
- count = ECX & SHIFT1_MASK;
- if (count) {
- T0 &= DATA_MASK;
- T1 &= DATA_MASK;
- tmp = T0 << (count - 1);
- T0 = (T0 << count) | (T1 >> (DATA_BITS - count));
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = tmp;
- CC_DST = T0;
- CC_OP = CC_OP_SHLB + SHIFT;
- }
- FORCE_RET();
-}
-
-void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_im_cc)(void)
-{
- int count;
- target_long tmp;
-
- count = PARAM1;
- T0 &= DATA_MASK;
- T1 &= DATA_MASK;
- tmp = T0 >> (count - 1);
- T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = tmp;
- CC_DST = T0;
-}
-
-
-void OPPROTO glue(glue(op_shrd, MEM_SUFFIX), _T0_T1_ECX_cc)(void)
-{
- int count;
- target_long tmp;
-
- count = ECX & SHIFT1_MASK;
- if (count) {
- T0 &= DATA_MASK;
- T1 &= DATA_MASK;
- tmp = T0 >> (count - 1);
- T0 = (T0 >> count) | (T1 << (DATA_BITS - count));
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = tmp;
- CC_DST = T0;
- CC_OP = CC_OP_SARB + SHIFT;
- }
- FORCE_RET();
-}
-#endif
-
-/* carry add/sub (we only need to set CC_OP differently) */
-
-void OPPROTO glue(glue(op_adc, MEM_SUFFIX), _T0_T1_cc)(void)
-{
- int cf;
- cf = cc_table[CC_OP].compute_c();
- T0 = T0 + T1 + cf;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = T1;
- CC_DST = T0;
- CC_OP = CC_OP_ADDB + SHIFT + cf * 4;
-}
-
-void OPPROTO glue(glue(op_sbb, MEM_SUFFIX), _T0_T1_cc)(void)
-{
- int cf;
- cf = cc_table[CC_OP].compute_c();
- T0 = T0 - T1 - cf;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- CC_SRC = T1;
- CC_DST = T0;
- CC_OP = CC_OP_SUBB + SHIFT + cf * 4;
-}
-
-void OPPROTO glue(glue(op_cmpxchg, MEM_SUFFIX), _T0_T1_EAX_cc)(void)
-{
- target_ulong src, dst;
-
- src = T0;
- dst = EAX - T0;
- if ((DATA_TYPE)dst == 0) {
- T0 = T1;
-#ifdef MEM_WRITE
- glue(st, MEM_SUFFIX)(A0, T0);
-#endif
- } else {
- EAX = (EAX & ~DATA_MASK) | (T0 & DATA_MASK);
- }
- CC_SRC = src;
- CC_DST = dst;
- FORCE_RET();
-}
-
-#undef MEM_SUFFIX
-#undef MEM_WRITE
diff --git a/target-i386/translate-copy.c b/target-i386/translate-copy.c
deleted file mode 100644
index cf8bd5a..0000000
--- a/target-i386/translate-copy.c
+++ /dev/null
@@ -1,1323 +0,0 @@
-/*
- * i386 on i386 translation
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include "config.h"
-
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <assert.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-#include "disas.h"
-
-#ifdef USE_CODE_COPY
-
-#include <signal.h>
-#include <sys/mman.h>
-#include <sys/ucontext.h>
-
-extern char exec_loop;
-
-/* operand size */
-enum {
- OT_BYTE = 0,
- OT_WORD,
- OT_LONG,
- OT_QUAD,
-};
-
-#define PREFIX_REPZ 0x01
-#define PREFIX_REPNZ 0x02
-#define PREFIX_LOCK 0x04
-#define PREFIX_DATA 0x08
-#define PREFIX_ADR 0x10
-
-typedef struct DisasContext {
- /* current insn context */
- int override; /* -1 if no override */
- int prefix;
- int aflag, dflag;
- target_ulong pc; /* pc = eip + cs_base */
- int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
- static state change (stop translation) */
- /* code output */
- uint8_t *gen_code_ptr;
- uint8_t *gen_code_start;
-
- /* current block context */
- target_ulong cs_base; /* base of CS segment */
- int pe; /* protected mode */
- int code32; /* 32 bit code segment */
- int f_st; /* currently unused */
- int vm86; /* vm86 mode */
- int cpl;
- int iopl;
- int flags;
- struct TranslationBlock *tb;
-} DisasContext;
-
-#define CPU_FIELD_OFFSET(field) offsetof(CPUState, field)
-
-#define CPU_SEG 0x64 /* fs override */
-
-static inline void gb(DisasContext *s, uint32_t val)
-{
- *s->gen_code_ptr++ = val;
-}
-
-static inline void gw(DisasContext *s, uint32_t val)
-{
- *s->gen_code_ptr++ = val;
- *s->gen_code_ptr++ = val >> 8;
-}
-
-static inline void gl(DisasContext *s, uint32_t val)
-{
- *s->gen_code_ptr++ = val;
- *s->gen_code_ptr++ = val >> 8;
- *s->gen_code_ptr++ = val >> 16;
- *s->gen_code_ptr++ = val >> 24;
-}
-
-static inline void gjmp(DisasContext *s, long val)
-{
- gb(s, 0xe9); /* jmp */
- gl(s, val - (long)(s->gen_code_ptr + 4));
-}
-
-static inline void gen_movl_addr_im(DisasContext *s,
- uint32_t addr, uint32_t val)
-{
- gb(s, CPU_SEG); /* seg movl im, addr */
- gb(s, 0xc7);
- gb(s, 0x05);
- gl(s, addr);
- gl(s, val);
-}
-
-static inline void gen_movw_addr_im(DisasContext *s,
- uint32_t addr, uint32_t val)
-{
- gb(s, CPU_SEG); /* seg movl im, addr */
- gb(s, 0x66);
- gb(s, 0xc7);
- gb(s, 0x05);
- gl(s, addr);
- gw(s, val);
-}
-
-
-static void gen_jmp(DisasContext *s, uint32_t target_eip)
-{
- TranslationBlock *tb = s->tb;
-
- gb(s, 0xe9); /* jmp */
- tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start;
- gl(s, 0);
-
- tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start;
- gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip);
- gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb);
- gjmp(s, (long)&exec_loop);
-
- s->is_jmp = 1;
-}
-
-static void gen_jcc(DisasContext *s, int op,
- uint32_t target_eip, uint32_t next_eip)
-{
- TranslationBlock *tb = s->tb;
-
- gb(s, 0x0f); /* jcc */
- gb(s, 0x80 + op);
- tb->tb_jmp_offset[0] = s->gen_code_ptr - s->gen_code_start;
- gl(s, 0);
- gb(s, 0xe9); /* jmp */
- tb->tb_jmp_offset[1] = s->gen_code_ptr - s->gen_code_start;
- gl(s, 0);
-
- tb->tb_next_offset[0] = s->gen_code_ptr - s->gen_code_start;
- gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), target_eip);
- gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb);
- gjmp(s, (long)&exec_loop);
-
- tb->tb_next_offset[1] = s->gen_code_ptr - s->gen_code_start;
- gen_movl_addr_im(s, CPU_FIELD_OFFSET(eip), next_eip);
- gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), (uint32_t)tb | 1);
- gjmp(s, (long)&exec_loop);
-
- s->is_jmp = 1;
-}
-
-static void gen_eob(DisasContext *s)
-{
- gen_movl_addr_im(s, CPU_FIELD_OFFSET(tmp0), 0);
- gjmp(s, (long)&exec_loop);
-
- s->is_jmp = 1;
-}
-
-static inline void gen_lea_modrm(DisasContext *s, int modrm)
-{
- int havesib;
- int base, disp;
- int index;
- int scale;
- int mod, rm, code;
-
- mod = (modrm >> 6) & 3;
- rm = modrm & 7;
-
- if (s->aflag) {
-
- havesib = 0;
- base = rm;
- index = 0;
- scale = 0;
-
- if (base == 4) {
- havesib = 1;
- code = ldub_code(s->pc++);
- scale = (code >> 6) & 3;
- index = (code >> 3) & 7;
- base = code & 7;
- }
-
- switch (mod) {
- case 0:
- if (base == 5) {
- base = -1;
- disp = ldl_code(s->pc);
- s->pc += 4;
- } else {
- disp = 0;
- }
- break;
- case 1:
- disp = (int8_t)ldub_code(s->pc++);
- break;
- default:
- case 2:
- disp = ldl_code(s->pc);
- s->pc += 4;
- break;
- }
-
- } else {
- switch (mod) {
- case 0:
- if (rm == 6) {
- disp = lduw_code(s->pc);
- s->pc += 2;
- } else {
- disp = 0;
- }
- break;
- case 1:
- disp = (int8_t)ldub_code(s->pc++);
- break;
- default:
- case 2:
- disp = lduw_code(s->pc);
- s->pc += 2;
- break;
- }
- }
-}
-
-static inline void parse_modrm(DisasContext *s, int modrm)
-{
- if ((modrm & 0xc0) != 0xc0)
- gen_lea_modrm(s, modrm);
-}
-
-static inline uint32_t insn_get(DisasContext *s, int ot)
-{
- uint32_t ret;
-
- switch(ot) {
- case OT_BYTE:
- ret = ldub_code(s->pc);
- s->pc++;
- break;
- case OT_WORD:
- ret = lduw_code(s->pc);
- s->pc += 2;
- break;
- default:
- case OT_LONG:
- ret = ldl_code(s->pc);
- s->pc += 4;
- break;
- }
- return ret;
-}
-
-/* convert one instruction. s->is_jmp is set if the translation must
- be stopped. */
-static int disas_insn(DisasContext *s)
-{
- target_ulong pc_start, pc_tmp, pc_start_insn;
- int b, prefixes, aflag, dflag, next_eip, val;
- int ot;
- int modrm, mod, op, rm;
-
- pc_start = s->pc;
- prefixes = 0;
- aflag = s->code32;
- dflag = s->code32;
- s->override = -1;
- next_byte:
- b = ldub_code(s->pc);
- s->pc++;
- /* check prefixes */
- switch (b) {
- case 0xf3:
- prefixes |= PREFIX_REPZ;
- goto next_byte;
- case 0xf2:
- prefixes |= PREFIX_REPNZ;
- goto next_byte;
- case 0xf0:
- prefixes |= PREFIX_LOCK;
- goto next_byte;
- case 0x2e:
- s->override = R_CS;
- goto next_byte;
- case 0x36:
- s->override = R_SS;
- goto next_byte;
- case 0x3e:
- s->override = R_DS;
- goto next_byte;
- case 0x26:
- s->override = R_ES;
- goto next_byte;
- case 0x64:
- s->override = R_FS;
- goto next_byte;
- case 0x65:
- s->override = R_GS;
- goto next_byte;
- case 0x66:
- prefixes |= PREFIX_DATA;
- goto next_byte;
- case 0x67:
- prefixes |= PREFIX_ADR;
- goto next_byte;
- }
-
- if (prefixes & PREFIX_DATA)
- dflag ^= 1;
- if (prefixes & PREFIX_ADR)
- aflag ^= 1;
-
- s->prefix = prefixes;
- s->aflag = aflag;
- s->dflag = dflag;
-
- /* lock generation */
- if (prefixes & PREFIX_LOCK)
- goto unsupported_op;
- if (s->override == R_FS || s->override == R_GS || s->override == R_CS)
- goto unsupported_op;
-
- pc_start_insn = s->pc - 1;
- /* now check op code */
- reswitch:
- switch(b) {
- case 0x0f:
- /**************************/
- /* extended op code */
- b = ldub_code(s->pc++) | 0x100;
- goto reswitch;
-
- /**************************/
- /* arith & logic */
- case 0x00 ... 0x05:
- case 0x08 ... 0x0d:
- case 0x10 ... 0x15:
- case 0x18 ... 0x1d:
- case 0x20 ... 0x25:
- case 0x28 ... 0x2d:
- case 0x30 ... 0x35:
- case 0x38 ... 0x3d:
- {
- int f;
- f = (b >> 1) & 3;
-
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
-
- switch(f) {
- case 0: /* OP Ev, Gv */
- modrm = ldub_code(s->pc++);
- parse_modrm(s, modrm);
- break;
- case 1: /* OP Gv, Ev */
- modrm = ldub_code(s->pc++);
- parse_modrm(s, modrm);
- break;
- case 2: /* OP A, Iv */
- insn_get(s, ot);
- break;
- }
- }
- break;
-
- case 0x80: /* GRP1 */
- case 0x81:
- case 0x82:
- case 0x83:
- {
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
-
- modrm = ldub_code(s->pc++);
- parse_modrm(s, modrm);
-
- switch(b) {
- default:
- case 0x80:
- case 0x81:
- case 0x82:
- insn_get(s, ot);
- break;
- case 0x83:
- insn_get(s, OT_BYTE);
- break;
- }
- }
- break;
-
- /**************************/
- /* inc, dec, and other misc arith */
- case 0x40 ... 0x47: /* inc Gv */
- break;
- case 0x48 ... 0x4f: /* dec Gv */
- break;
- case 0xf6: /* GRP3 */
- case 0xf7:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
-
- modrm = ldub_code(s->pc++);
- op = (modrm >> 3) & 7;
- parse_modrm(s, modrm);
-
- switch(op) {
- case 0: /* test */
- insn_get(s, ot);
- break;
- case 2: /* not */
- break;
- case 3: /* neg */
- break;
- case 4: /* mul */
- break;
- case 5: /* imul */
- break;
- case 6: /* div */
- break;
- case 7: /* idiv */
- break;
- default:
- goto illegal_op;
- }
- break;
-
- case 0xfe: /* GRP4 */
- case 0xff: /* GRP5 */
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
-
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- op = (modrm >> 3) & 7;
- if (op >= 2 && b == 0xfe) {
- goto illegal_op;
- }
- pc_tmp = s->pc;
- parse_modrm(s, modrm);
-
- switch(op) {
- case 0: /* inc Ev */
- break;
- case 1: /* dec Ev */
- break;
- case 2: /* call Ev */
- /* XXX: optimize and handle MEM exceptions specifically
- fs movl %eax, regs[0]
- movl Ev, %eax
- pushl next_eip
- fs movl %eax, eip
- */
- goto unsupported_op;
- case 3: /* lcall Ev */
- goto unsupported_op;
- case 4: /* jmp Ev */
- /* XXX: optimize and handle MEM exceptions specifically
- fs movl %eax, regs[0]
- movl Ev, %eax
- fs movl %eax, eip
- */
- goto unsupported_op;
- case 5: /* ljmp Ev */
- goto unsupported_op;
- case 6: /* push Ev */
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0xa8: /* test eAX, Iv */
- case 0xa9:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- insn_get(s, ot);
- break;
-
- case 0x98: /* CWDE/CBW */
- break;
- case 0x99: /* CDQ/CWD */
- break;
- case 0x1af: /* imul Gv, Ev */
- case 0x69: /* imul Gv, Ev, I */
- case 0x6b:
- ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
- parse_modrm(s, modrm);
- if (b == 0x69) {
- insn_get(s, ot);
- } else if (b == 0x6b) {
- insn_get(s, OT_BYTE);
- } else {
- }
- break;
-
- case 0x84: /* test Ev, Gv */
- case 0x85:
-
- case 0x1c0:
- case 0x1c1: /* xadd Ev, Gv */
-
- case 0x1b0:
- case 0x1b1: /* cmpxchg Ev, Gv */
-
- case 0x8f: /* pop Ev */
-
- case 0x88:
- case 0x89: /* mov Gv, Ev */
-
- case 0x8a:
- case 0x8b: /* mov Ev, Gv */
-
- case 0x1b6: /* movzbS Gv, Eb */
- case 0x1b7: /* movzwS Gv, Eb */
- case 0x1be: /* movsbS Gv, Eb */
- case 0x1bf: /* movswS Gv, Eb */
-
- case 0x86:
- case 0x87: /* xchg Ev, Gv */
-
- case 0xd0:
- case 0xd1: /* shift Ev,1 */
-
- case 0xd2:
- case 0xd3: /* shift Ev,cl */
-
- case 0x1a5: /* shld cl */
- case 0x1ad: /* shrd cl */
-
- case 0x190 ... 0x19f: /* setcc Gv */
-
- /* XXX: emulate cmov if not available ? */
- case 0x140 ... 0x14f: /* cmov Gv, Ev */
-
- case 0x1a3: /* bt Gv, Ev */
- case 0x1ab: /* bts */
- case 0x1b3: /* btr */
- case 0x1bb: /* btc */
-
- case 0x1bc: /* bsf */
- case 0x1bd: /* bsr */
-
- modrm = ldub_code(s->pc++);
- parse_modrm(s, modrm);
- break;
-
- case 0x1c7: /* cmpxchg8b */
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- if (mod == 3)
- goto illegal_op;
- parse_modrm(s, modrm);
- break;
-
- /**************************/
- /* push/pop */
- case 0x50 ... 0x57: /* push */
- case 0x58 ... 0x5f: /* pop */
- case 0x60: /* pusha */
- case 0x61: /* popa */
- break;
-
- case 0x68: /* push Iv */
- case 0x6a:
- ot = dflag ? OT_LONG : OT_WORD;
- if (b == 0x68)
- insn_get(s, ot);
- else
- insn_get(s, OT_BYTE);
- break;
- case 0xc8: /* enter */
- lduw_code(s->pc);
- s->pc += 2;
- ldub_code(s->pc++);
- break;
- case 0xc9: /* leave */
- break;
-
- case 0x06: /* push es */
- case 0x0e: /* push cs */
- case 0x16: /* push ss */
- case 0x1e: /* push ds */
- /* XXX: optimize:
- push segs[n].selector
- */
- goto unsupported_op;
- case 0x1a0: /* push fs */
- case 0x1a8: /* push gs */
- goto unsupported_op;
- case 0x07: /* pop es */
- case 0x17: /* pop ss */
- case 0x1f: /* pop ds */
- goto unsupported_op;
- case 0x1a1: /* pop fs */
- case 0x1a9: /* pop gs */
- goto unsupported_op;
- case 0x8e: /* mov seg, Gv */
- /* XXX: optimize:
- fs movl r, regs[]
- movl segs[].selector, r
- mov r, Gv
- fs movl regs[], r
- */
- goto unsupported_op;
- case 0x8c: /* mov Gv, seg */
- goto unsupported_op;
- case 0xc4: /* les Gv */
- op = R_ES;
- goto do_lxx;
- case 0xc5: /* lds Gv */
- op = R_DS;
- goto do_lxx;
- case 0x1b2: /* lss Gv */
- op = R_SS;
- goto do_lxx;
- case 0x1b4: /* lfs Gv */
- op = R_FS;
- goto do_lxx;
- case 0x1b5: /* lgs Gv */
- op = R_GS;
- do_lxx:
- goto unsupported_op;
- /************************/
- /* floats */
- case 0xd8 ... 0xdf:
-#if 1
- /* currently not stable enough */
- goto unsupported_op;
-#else
- if (s->flags & (HF_EM_MASK | HF_TS_MASK))
- goto unsupported_op;
-#endif
-#if 0
- /* for testing FPU context switch */
- {
- static int count;
- count = (count + 1) % 3;
- if (count != 0)
- goto unsupported_op;
- }
-#endif
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- rm = modrm & 7;
- op = ((b & 7) << 3) | ((modrm >> 3) & 7);
- if (mod != 3) {
- /* memory op */
- parse_modrm(s, modrm);
- switch(op) {
- case 0x00 ... 0x07: /* fxxxs */
- case 0x10 ... 0x17: /* fixxxl */
- case 0x20 ... 0x27: /* fxxxl */
- case 0x30 ... 0x37: /* fixxx */
- break;
- case 0x08: /* flds */
- case 0x0a: /* fsts */
- case 0x0b: /* fstps */
- case 0x18: /* fildl */
- case 0x1a: /* fistl */
- case 0x1b: /* fistpl */
- case 0x28: /* fldl */
- case 0x2a: /* fstl */
- case 0x2b: /* fstpl */
- case 0x38: /* filds */
- case 0x3a: /* fists */
- case 0x3b: /* fistps */
- case 0x0c: /* fldenv mem */
- case 0x0d: /* fldcw mem */
- case 0x0e: /* fnstenv mem */
- case 0x0f: /* fnstcw mem */
- case 0x1d: /* fldt mem */
- case 0x1f: /* fstpt mem */
- case 0x2c: /* frstor mem */
- case 0x2e: /* fnsave mem */
- case 0x2f: /* fnstsw mem */
- case 0x3c: /* fbld */
- case 0x3e: /* fbstp */
- case 0x3d: /* fildll */
- case 0x3f: /* fistpll */
- break;
- default:
- goto illegal_op;
- }
- } else {
- /* register float ops */
- switch(op) {
- case 0x08: /* fld sti */
- case 0x09: /* fxchg sti */
- break;
- case 0x0a: /* grp d9/2 */
- switch(rm) {
- case 0: /* fnop */
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x0c: /* grp d9/4 */
- switch(rm) {
- case 0: /* fchs */
- case 1: /* fabs */
- case 4: /* ftst */
- case 5: /* fxam */
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x0d: /* grp d9/5 */
- switch(rm) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x0e: /* grp d9/6 */
- break;
- case 0x0f: /* grp d9/7 */
- break;
- case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
- case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
- case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
- break;
- case 0x02: /* fcom */
- break;
- case 0x03: /* fcomp */
- break;
- case 0x15: /* da/5 */
- switch(rm) {
- case 1: /* fucompp */
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x1c:
- switch(rm) {
- case 0: /* feni (287 only, just do nop here) */
- case 1: /* fdisi (287 only, just do nop here) */
- goto unsupported_op;
- case 2: /* fclex */
- case 3: /* fninit */
- case 4: /* fsetpm (287 only, just do nop here) */
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x1d: /* fucomi */
- break;
- case 0x1e: /* fcomi */
- break;
- case 0x28: /* ffree sti */
- break;
- case 0x2a: /* fst sti */
- break;
- case 0x2b: /* fstp sti */
- break;
- case 0x2c: /* fucom st(i) */
- break;
- case 0x2d: /* fucomp st(i) */
- break;
- case 0x33: /* de/3 */
- switch(rm) {
- case 1: /* fcompp */
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x3c: /* df/4 */
- switch(rm) {
- case 0:
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x3d: /* fucomip */
- break;
- case 0x3e: /* fcomip */
- break;
- case 0x10 ... 0x13: /* fcmovxx */
- case 0x18 ... 0x1b:
- break;
- default:
- goto illegal_op;
- }
- }
- s->tb->cflags |= CF_TB_FP_USED;
- break;
-
- /**************************/
- /* mov */
- case 0xc6:
- case 0xc7: /* mov Ev, Iv */
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
- parse_modrm(s, modrm);
- insn_get(s, ot);
- break;
-
- case 0x8d: /* lea */
- ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- if (mod == 3)
- goto illegal_op;
- parse_modrm(s, modrm);
- break;
-
- case 0xa0: /* mov EAX, Ov */
- case 0xa1:
- case 0xa2: /* mov Ov, EAX */
- case 0xa3:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- if (s->aflag)
- insn_get(s, OT_LONG);
- else
- insn_get(s, OT_WORD);
- break;
- case 0xd7: /* xlat */
- break;
- case 0xb0 ... 0xb7: /* mov R, Ib */
- insn_get(s, OT_BYTE);
- break;
- case 0xb8 ... 0xbf: /* mov R, Iv */
- ot = dflag ? OT_LONG : OT_WORD;
- insn_get(s, ot);
- break;
-
- case 0x91 ... 0x97: /* xchg R, EAX */
- break;
-
- /************************/
- /* shifts */
- case 0xc0:
- case 0xc1: /* shift Ev,imm */
-
- case 0x1a4: /* shld imm */
- case 0x1ac: /* shrd imm */
- modrm = ldub_code(s->pc++);
- parse_modrm(s, modrm);
- ldub_code(s->pc++);
- break;
-
- /************************/
- /* string ops */
-
- case 0xa4: /* movsS */
- case 0xa5:
- break;
-
- case 0xaa: /* stosS */
- case 0xab:
- break;
-
- case 0xac: /* lodsS */
- case 0xad:
- break;
-
- case 0xae: /* scasS */
- case 0xaf:
- break;
-
- case 0xa6: /* cmpsS */
- case 0xa7:
- break;
-
- case 0x6c: /* insS */
- case 0x6d:
- goto unsupported_op;
-
- case 0x6e: /* outsS */
- case 0x6f:
- goto unsupported_op;
-
- /************************/
- /* port I/O */
- case 0xe4:
- case 0xe5:
- goto unsupported_op;
-
- case 0xe6:
- case 0xe7:
- goto unsupported_op;
-
- case 0xec:
- case 0xed:
- goto unsupported_op;
-
- case 0xee:
- case 0xef:
- goto unsupported_op;
-
- /************************/
- /* control */
-#if 0
- case 0xc2: /* ret im */
- val = ldsw_code(s->pc);
- s->pc += 2;
- gen_pop_T0(s);
- gen_stack_update(s, val + (2 << s->dflag));
- if (s->dflag == 0)
- gen_op_andl_T0_ffff();
- gen_op_jmp_T0();
- gen_eob(s);
- break;
-#endif
-
- case 0xc3: /* ret */
- gb(s, CPU_SEG);
- if (!s->dflag)
- gb(s, 0x66); /* d16 */
- gb(s, 0x8f); /* pop addr */
- gb(s, 0x05);
- gl(s, CPU_FIELD_OFFSET(eip));
- if (!s->dflag) {
- /* reset high bits of EIP */
- gen_movw_addr_im(s, CPU_FIELD_OFFSET(eip) + 2, 0);
- }
- gen_eob(s);
- goto no_copy;
- case 0xca: /* lret im */
- case 0xcb: /* lret */
- case 0xcf: /* iret */
- case 0x9a: /* lcall im */
- case 0xea: /* ljmp im */
- goto unsupported_op;
-
- case 0xe8: /* call im */
- ot = dflag ? OT_LONG : OT_WORD;
- val = insn_get(s, ot);
- next_eip = s->pc - s->cs_base;
- val += next_eip;
- if (s->dflag) {
- gb(s, 0x68); /* pushl imm */
- gl(s, next_eip);
- } else {
- gb(s, 0x66); /* pushw imm */
- gb(s, 0x68);
- gw(s, next_eip);
- val &= 0xffff;
- }
- gen_jmp(s, val);
- goto no_copy;
- case 0xe9: /* jmp */
- ot = dflag ? OT_LONG : OT_WORD;
- val = insn_get(s, ot);
- val += s->pc - s->cs_base;
- if (s->dflag == 0)
- val = val & 0xffff;
- gen_jmp(s, val);
- goto no_copy;
- case 0xeb: /* jmp Jb */
- val = (int8_t)insn_get(s, OT_BYTE);
- val += s->pc - s->cs_base;
- if (s->dflag == 0)
- val = val & 0xffff;
- gen_jmp(s, val);
- goto no_copy;
- case 0x70 ... 0x7f: /* jcc Jb */
- val = (int8_t)insn_get(s, OT_BYTE);
- goto do_jcc;
- case 0x180 ... 0x18f: /* jcc Jv */
- if (dflag) {
- val = insn_get(s, OT_LONG);
- } else {
- val = (int16_t)insn_get(s, OT_WORD);
- }
- do_jcc:
- next_eip = s->pc - s->cs_base;
- val += next_eip;
- if (s->dflag == 0)
- val &= 0xffff;
- gen_jcc(s, b & 0xf, val, next_eip);
- goto no_copy;
-
- /************************/
- /* flags */
- case 0x9c: /* pushf */
- /* XXX: put specific code ? */
- goto unsupported_op;
- case 0x9d: /* popf */
- goto unsupported_op;
-
- case 0x9e: /* sahf */
- case 0x9f: /* lahf */
- case 0xf5: /* cmc */
- case 0xf8: /* clc */
- case 0xf9: /* stc */
- case 0xfc: /* cld */
- case 0xfd: /* std */
- break;
-
- /************************/
- /* bit operations */
- case 0x1ba: /* bt/bts/btr/btc Gv, im */
- ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
- op = (modrm >> 3) & 7;
- parse_modrm(s, modrm);
- /* load shift */
- ldub_code(s->pc++);
- if (op < 4)
- goto illegal_op;
- break;
- /************************/
- /* bcd */
- case 0x27: /* daa */
- break;
- case 0x2f: /* das */
- break;
- case 0x37: /* aaa */
- break;
- case 0x3f: /* aas */
- break;
- case 0xd4: /* aam */
- ldub_code(s->pc++);
- break;
- case 0xd5: /* aad */
- ldub_code(s->pc++);
- break;
- /************************/
- /* misc */
- case 0x90: /* nop */
- break;
- case 0x9b: /* fwait */
- if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
- (HF_MP_MASK | HF_TS_MASK)) {
- goto unsupported_op;
- }
- break;
- case 0xcc: /* int3 */
- goto unsupported_op;
- case 0xcd: /* int N */
- goto unsupported_op;
- case 0xce: /* into */
- goto unsupported_op;
- case 0xf1: /* icebp (undocumented, exits to external debugger) */
- goto unsupported_op;
- case 0xfa: /* cli */
- goto unsupported_op;
- case 0xfb: /* sti */
- goto unsupported_op;
- case 0x62: /* bound */
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- if (mod == 3)
- goto illegal_op;
- parse_modrm(s, modrm);
- break;
- case 0x1c8 ... 0x1cf: /* bswap reg */
- break;
- case 0xd6: /* salc */
- break;
- case 0xe0: /* loopnz */
- case 0xe1: /* loopz */
- case 0xe2: /* loop */
- case 0xe3: /* jecxz */
- goto unsupported_op;
-
- case 0x130: /* wrmsr */
- case 0x132: /* rdmsr */
- goto unsupported_op;
- case 0x131: /* rdtsc */
- goto unsupported_op;
- case 0x1a2: /* cpuid */
- goto unsupported_op;
- case 0xf4: /* hlt */
- goto unsupported_op;
- case 0x100:
- goto unsupported_op;
- case 0x101:
- goto unsupported_op;
- case 0x108: /* invd */
- case 0x109: /* wbinvd */
- goto unsupported_op;
- case 0x63: /* arpl */
- goto unsupported_op;
- case 0x102: /* lar */
- case 0x103: /* lsl */
- goto unsupported_op;
- case 0x118:
- goto unsupported_op;
- case 0x120: /* mov reg, crN */
- case 0x122: /* mov crN, reg */
- goto unsupported_op;
- case 0x121: /* mov reg, drN */
- case 0x123: /* mov drN, reg */
- goto unsupported_op;
- case 0x106: /* clts */
- goto unsupported_op;
- default:
- goto illegal_op;
- }
-
- /* just copy the code */
-
- /* no override yet */
- if (!s->dflag)
- gb(s, 0x66);
- if (!s->aflag)
- gb(s, 0x67);
- if (prefixes & PREFIX_REPZ)
- gb(s, 0xf3);
- else if (prefixes & PREFIX_REPNZ)
- gb(s, 0xf2);
- {
- int len, i;
- len = s->pc - pc_start_insn;
- for(i = 0; i < len; i++) {
- *s->gen_code_ptr++ = ldub_code(pc_start_insn + i);
- }
- }
- no_copy:
- return 0;
- illegal_op:
- unsupported_op:
- /* fall back to slower code gen necessary */
- s->pc = pc_start;
- return -1;
-}
-
-#define GEN_CODE_MAX_SIZE 8192
-#define GEN_CODE_MAX_INSN_SIZE 512
-
-static inline int gen_intermediate_code_internal(CPUState *env,
- TranslationBlock *tb,
- uint8_t *gen_code_ptr,
- int *gen_code_size_ptr,
- int search_pc,
- uint8_t *tc_ptr)
-{
- DisasContext dc1, *dc = &dc1;
- target_ulong pc_insn, pc_start, cs_base;
- uint8_t *gen_code_end;
- int flags, ret;
-
- if (env->nb_breakpoints > 0 ||
- env->singlestep_enabled)
- return -1;
- flags = tb->flags;
- if (flags & (HF_TF_MASK | HF_ADDSEG_MASK |
- HF_SOFTMMU_MASK | HF_INHIBIT_IRQ_MASK))
- return -1;
- if (!(flags & HF_SS32_MASK))
- return -1;
- if (tb->cflags & CF_SINGLE_INSN)
- return -1;
- gen_code_end = gen_code_ptr +
- GEN_CODE_MAX_SIZE - GEN_CODE_MAX_INSN_SIZE;
- dc->gen_code_ptr = gen_code_ptr;
- dc->gen_code_start = gen_code_ptr;
-
- /* generate intermediate code */
- pc_start = tb->pc;
- cs_base = tb->cs_base;
- dc->pc = pc_start;
- dc->cs_base = cs_base;
- dc->pe = (flags >> HF_PE_SHIFT) & 1;
- dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
- dc->f_st = 0;
- dc->vm86 = (flags >> VM_SHIFT) & 1;
- dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
- dc->iopl = (flags >> IOPL_SHIFT) & 3;
- dc->tb = tb;
- dc->flags = flags;
-
- dc->is_jmp = 0;
-
- for(;;) {
- pc_insn = dc->pc;
- ret = disas_insn(dc);
- if (ret < 0) {
- /* unsupported insn */
- if (dc->pc == pc_start) {
- /* if first instruction, signal that no copying was done */
- return -1;
- } else {
- gen_jmp(dc, dc->pc - dc->cs_base);
- dc->is_jmp = 1;
- }
- }
- if (search_pc) {
- /* search pc mode */
- if (tc_ptr < dc->gen_code_ptr) {
- env->eip = pc_insn - cs_base;
- return 0;
- }
- }
- /* stop translation if indicated */
- if (dc->is_jmp)
- break;
- /* if too long translation, stop generation */
- if (dc->gen_code_ptr >= gen_code_end ||
- (dc->pc - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
- gen_jmp(dc, dc->pc - dc->cs_base);
- break;
- }
- }
-
-#ifdef DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "----------------\n");
- fprintf(logfile, "IN: COPY: %s fpu=%d\n",
- lookup_symbol(pc_start),
- tb->cflags & CF_TB_FP_USED ? 1 : 0);
- target_disas(logfile, pc_start, dc->pc - pc_start, !dc->code32);
- fprintf(logfile, "\n");
- }
-#endif
-
- if (!search_pc) {
- *gen_code_size_ptr = dc->gen_code_ptr - dc->gen_code_start;
- tb->size = dc->pc - pc_start;
- tb->cflags |= CF_CODE_COPY;
- return 0;
- } else {
- return -1;
- }
-}
-
-/* generate code by just copying data. Return -1 if cannot generate
- any code. Return 0 if code was generated */
-int cpu_gen_code_copy(CPUState *env, TranslationBlock *tb,
- int max_code_size, int *gen_code_size_ptr)
-{
- /* generate machine code */
- tb->tb_next_offset[0] = 0xffff;
- tb->tb_next_offset[1] = 0xffff;
-#ifdef USE_DIRECT_JUMP
- /* the following two entries are optional (only used for string ops) */
- tb->tb_jmp_offset[2] = 0xffff;
- tb->tb_jmp_offset[3] = 0xffff;
-#endif
- return gen_intermediate_code_internal(env, tb,
- tb->tc_ptr, gen_code_size_ptr,
- 0, NULL);
-}
-
-static uint8_t dummy_gen_code_buf[GEN_CODE_MAX_SIZE];
-
-int cpu_restore_state_copy(TranslationBlock *tb,
- CPUState *env, unsigned long searched_pc,
- void *puc)
-{
- struct ucontext *uc = puc;
- int ret, eflags;
-
- /* find opc index corresponding to search_pc */
- if (searched_pc < (unsigned long)tb->tc_ptr)
- return -1;
- searched_pc = searched_pc - (long)tb->tc_ptr + (long)dummy_gen_code_buf;
- ret = gen_intermediate_code_internal(env, tb,
- dummy_gen_code_buf, NULL,
- 1, (uint8_t *)searched_pc);
- if (ret < 0)
- return ret;
- /* restore all the CPU state from the CPU context from the
- signal. The FPU context stays in the host CPU. */
-
- env->regs[R_EAX] = uc->uc_mcontext.gregs[REG_EAX];
- env->regs[R_ECX] = uc->uc_mcontext.gregs[REG_ECX];
- env->regs[R_EDX] = uc->uc_mcontext.gregs[REG_EDX];
- env->regs[R_EBX] = uc->uc_mcontext.gregs[REG_EBX];
- env->regs[R_ESP] = uc->uc_mcontext.gregs[REG_ESP];
- env->regs[R_EBP] = uc->uc_mcontext.gregs[REG_EBP];
- env->regs[R_ESI] = uc->uc_mcontext.gregs[REG_ESI];
- env->regs[R_EDI] = uc->uc_mcontext.gregs[REG_EDI];
- eflags = uc->uc_mcontext.gregs[REG_EFL];
- env->df = 1 - (2 * ((eflags >> 10) & 1));
- env->cc_src = eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
- env->cc_op = CC_OP_EFLAGS;
- return 0;
-}
-
-#endif /* USE_CODE_COPY */
diff --git a/target-i386/translate.c b/target-i386/translate.c
deleted file mode 100644
index f905f32..0000000
--- a/target-i386/translate.c
+++ /dev/null
@@ -1,6523 +0,0 @@
-/*
- * i386 translation
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <assert.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-#include "disas.h"
-
-/* XXX: move that elsewhere */
-static uint16_t *gen_opc_ptr;
-static uint32_t *gen_opparam_ptr;
-
-#define PREFIX_REPZ 0x01
-#define PREFIX_REPNZ 0x02
-#define PREFIX_LOCK 0x04
-#define PREFIX_DATA 0x08
-#define PREFIX_ADR 0x10
-
-#ifdef TARGET_X86_64
-#define X86_64_ONLY(x) x
-#define X86_64_DEF(x...) x
-#define CODE64(s) ((s)->code64)
-#define REX_X(s) ((s)->rex_x)
-#define REX_B(s) ((s)->rex_b)
-/* XXX: gcc generates push/pop in some opcodes, so we cannot use them */
-#if 1
-#define BUGGY_64(x) NULL
-#endif
-#else
-#define X86_64_ONLY(x) NULL
-#define X86_64_DEF(x...)
-#define CODE64(s) 0
-#define REX_X(s) 0
-#define REX_B(s) 0
-#endif
-
-#ifdef TARGET_X86_64
-static int x86_64_hregs;
-#endif
-
-#ifdef USE_DIRECT_JUMP
-#define TBPARAM(x)
-#else
-#define TBPARAM(x) (long)(x)
-#endif
-
-typedef struct DisasContext {
- /* current insn context */
- int override; /* -1 if no override */
- int prefix;
- int aflag, dflag;
- target_ulong pc; /* pc = eip + cs_base */
- int is_jmp; /* 1 = means jump (stop translation), 2 means CPU
- static state change (stop translation) */
- /* current block context */
- target_ulong cs_base; /* base of CS segment */
- int pe; /* protected mode */
- int code32; /* 32 bit code segment */
-#ifdef TARGET_X86_64
- int lma; /* long mode active */
- int code64; /* 64 bit code segment */
- int rex_x, rex_b;
-#endif
- int ss32; /* 32 bit stack segment */
- int cc_op; /* current CC operation */
- int addseg; /* non zero if either DS/ES/SS have a non zero base */
- int f_st; /* currently unused */
- int vm86; /* vm86 mode */
- int cpl;
- int iopl;
- int tf; /* TF cpu flag */
- int singlestep_enabled; /* "hardware" single step enabled */
- int jmp_opt; /* use direct block chaining for direct jumps */
- int mem_index; /* select memory access functions */
- int flags; /* all execution flags */
- struct TranslationBlock *tb;
- int popl_esp_hack; /* for correct popl with esp base handling */
- int rip_offset; /* only used in x86_64, but left for simplicity */
- int cpuid_features;
- int cpuid_ext_features;
-} DisasContext;
-
-static void gen_eob(DisasContext *s);
-static void gen_jmp(DisasContext *s, target_ulong eip);
-static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num);
-
-/* i386 arith/logic operations */
-enum {
- OP_ADDL,
- OP_ORL,
- OP_ADCL,
- OP_SBBL,
- OP_ANDL,
- OP_SUBL,
- OP_XORL,
- OP_CMPL,
-};
-
-/* i386 shift ops */
-enum {
- OP_ROL,
- OP_ROR,
- OP_RCL,
- OP_RCR,
- OP_SHL,
- OP_SHR,
- OP_SHL1, /* undocumented */
- OP_SAR = 7,
-};
-
-enum {
-#define DEF(s, n, copy_size) INDEX_op_ ## s,
-#include "opc.h"
-#undef DEF
- NB_OPS,
-};
-
-#include "gen-op.h"
-
-/* operand size */
-enum {
- OT_BYTE = 0,
- OT_WORD,
- OT_LONG,
- OT_QUAD,
-};
-
-enum {
- /* I386 int registers */
- OR_EAX, /* MUST be even numbered */
- OR_ECX,
- OR_EDX,
- OR_EBX,
- OR_ESP,
- OR_EBP,
- OR_ESI,
- OR_EDI,
-
- OR_TMP0 = 16, /* temporary operand register */
- OR_TMP1,
- OR_A0, /* temporary register used when doing address evaluation */
-};
-
-#ifdef TARGET_X86_64
-
-#define NB_OP_SIZES 4
-
-#define DEF_REGS(prefix, suffix) \
- prefix ## EAX ## suffix,\
- prefix ## ECX ## suffix,\
- prefix ## EDX ## suffix,\
- prefix ## EBX ## suffix,\
- prefix ## ESP ## suffix,\
- prefix ## EBP ## suffix,\
- prefix ## ESI ## suffix,\
- prefix ## EDI ## suffix,\
- prefix ## R8 ## suffix,\
- prefix ## R9 ## suffix,\
- prefix ## R10 ## suffix,\
- prefix ## R11 ## suffix,\
- prefix ## R12 ## suffix,\
- prefix ## R13 ## suffix,\
- prefix ## R14 ## suffix,\
- prefix ## R15 ## suffix,
-
-#define DEF_BREGS(prefixb, prefixh, suffix) \
- \
-static void prefixb ## ESP ## suffix ## _wrapper(void) \
-{ \
- if (x86_64_hregs) \
- prefixb ## ESP ## suffix (); \
- else \
- prefixh ## EAX ## suffix (); \
-} \
- \
-static void prefixb ## EBP ## suffix ## _wrapper(void) \
-{ \
- if (x86_64_hregs) \
- prefixb ## EBP ## suffix (); \
- else \
- prefixh ## ECX ## suffix (); \
-} \
- \
-static void prefixb ## ESI ## suffix ## _wrapper(void) \
-{ \
- if (x86_64_hregs) \
- prefixb ## ESI ## suffix (); \
- else \
- prefixh ## EDX ## suffix (); \
-} \
- \
-static void prefixb ## EDI ## suffix ## _wrapper(void) \
-{ \
- if (x86_64_hregs) \
- prefixb ## EDI ## suffix (); \
- else \
- prefixh ## EBX ## suffix (); \
-}
-
-DEF_BREGS(gen_op_movb_, gen_op_movh_, _T0)
-DEF_BREGS(gen_op_movb_, gen_op_movh_, _T1)
-DEF_BREGS(gen_op_movl_T0_, gen_op_movh_T0_, )
-DEF_BREGS(gen_op_movl_T1_, gen_op_movh_T1_, )
-
-#else /* !TARGET_X86_64 */
-
-#define NB_OP_SIZES 3
-
-#define DEF_REGS(prefix, suffix) \
- prefix ## EAX ## suffix,\
- prefix ## ECX ## suffix,\
- prefix ## EDX ## suffix,\
- prefix ## EBX ## suffix,\
- prefix ## ESP ## suffix,\
- prefix ## EBP ## suffix,\
- prefix ## ESI ## suffix,\
- prefix ## EDI ## suffix,
-
-#endif /* !TARGET_X86_64 */
-
-static GenOpFunc *gen_op_mov_reg_T0[NB_OP_SIZES][CPU_NB_REGS] = {
- [OT_BYTE] = {
- gen_op_movb_EAX_T0,
- gen_op_movb_ECX_T0,
- gen_op_movb_EDX_T0,
- gen_op_movb_EBX_T0,
-#ifdef TARGET_X86_64
- gen_op_movb_ESP_T0_wrapper,
- gen_op_movb_EBP_T0_wrapper,
- gen_op_movb_ESI_T0_wrapper,
- gen_op_movb_EDI_T0_wrapper,
- gen_op_movb_R8_T0,
- gen_op_movb_R9_T0,
- gen_op_movb_R10_T0,
- gen_op_movb_R11_T0,
- gen_op_movb_R12_T0,
- gen_op_movb_R13_T0,
- gen_op_movb_R14_T0,
- gen_op_movb_R15_T0,
-#else
- gen_op_movh_EAX_T0,
- gen_op_movh_ECX_T0,
- gen_op_movh_EDX_T0,
- gen_op_movh_EBX_T0,
-#endif
- },
- [OT_WORD] = {
- DEF_REGS(gen_op_movw_, _T0)
- },
- [OT_LONG] = {
- DEF_REGS(gen_op_movl_, _T0)
- },
-#ifdef TARGET_X86_64
- [OT_QUAD] = {
- DEF_REGS(gen_op_movq_, _T0)
- },
-#endif
-};
-
-static GenOpFunc *gen_op_mov_reg_T1[NB_OP_SIZES][CPU_NB_REGS] = {
- [OT_BYTE] = {
- gen_op_movb_EAX_T1,
- gen_op_movb_ECX_T1,
- gen_op_movb_EDX_T1,
- gen_op_movb_EBX_T1,
-#ifdef TARGET_X86_64
- gen_op_movb_ESP_T1_wrapper,
- gen_op_movb_EBP_T1_wrapper,
- gen_op_movb_ESI_T1_wrapper,
- gen_op_movb_EDI_T1_wrapper,
- gen_op_movb_R8_T1,
- gen_op_movb_R9_T1,
- gen_op_movb_R10_T1,
- gen_op_movb_R11_T1,
- gen_op_movb_R12_T1,
- gen_op_movb_R13_T1,
- gen_op_movb_R14_T1,
- gen_op_movb_R15_T1,
-#else
- gen_op_movh_EAX_T1,
- gen_op_movh_ECX_T1,
- gen_op_movh_EDX_T1,
- gen_op_movh_EBX_T1,
-#endif
- },
- [OT_WORD] = {
- DEF_REGS(gen_op_movw_, _T1)
- },
- [OT_LONG] = {
- DEF_REGS(gen_op_movl_, _T1)
- },
-#ifdef TARGET_X86_64
- [OT_QUAD] = {
- DEF_REGS(gen_op_movq_, _T1)
- },
-#endif
-};
-
-static GenOpFunc *gen_op_mov_reg_A0[NB_OP_SIZES - 1][CPU_NB_REGS] = {
- [0] = {
- DEF_REGS(gen_op_movw_, _A0)
- },
- [1] = {
- DEF_REGS(gen_op_movl_, _A0)
- },
-#ifdef TARGET_X86_64
- [2] = {
- DEF_REGS(gen_op_movq_, _A0)
- },
-#endif
-};
-
-static GenOpFunc *gen_op_mov_TN_reg[NB_OP_SIZES][2][CPU_NB_REGS] =
-{
- [OT_BYTE] = {
- {
- gen_op_movl_T0_EAX,
- gen_op_movl_T0_ECX,
- gen_op_movl_T0_EDX,
- gen_op_movl_T0_EBX,
-#ifdef TARGET_X86_64
- gen_op_movl_T0_ESP_wrapper,
- gen_op_movl_T0_EBP_wrapper,
- gen_op_movl_T0_ESI_wrapper,
- gen_op_movl_T0_EDI_wrapper,
- gen_op_movl_T0_R8,
- gen_op_movl_T0_R9,
- gen_op_movl_T0_R10,
- gen_op_movl_T0_R11,
- gen_op_movl_T0_R12,
- gen_op_movl_T0_R13,
- gen_op_movl_T0_R14,
- gen_op_movl_T0_R15,
-#else
- gen_op_movh_T0_EAX,
- gen_op_movh_T0_ECX,
- gen_op_movh_T0_EDX,
- gen_op_movh_T0_EBX,
-#endif
- },
- {
- gen_op_movl_T1_EAX,
- gen_op_movl_T1_ECX,
- gen_op_movl_T1_EDX,
- gen_op_movl_T1_EBX,
-#ifdef TARGET_X86_64
- gen_op_movl_T1_ESP_wrapper,
- gen_op_movl_T1_EBP_wrapper,
- gen_op_movl_T1_ESI_wrapper,
- gen_op_movl_T1_EDI_wrapper,
- gen_op_movl_T1_R8,
- gen_op_movl_T1_R9,
- gen_op_movl_T1_R10,
- gen_op_movl_T1_R11,
- gen_op_movl_T1_R12,
- gen_op_movl_T1_R13,
- gen_op_movl_T1_R14,
- gen_op_movl_T1_R15,
-#else
- gen_op_movh_T1_EAX,
- gen_op_movh_T1_ECX,
- gen_op_movh_T1_EDX,
- gen_op_movh_T1_EBX,
-#endif
- },
- },
- [OT_WORD] = {
- {
- DEF_REGS(gen_op_movl_T0_, )
- },
- {
- DEF_REGS(gen_op_movl_T1_, )
- },
- },
- [OT_LONG] = {
- {
- DEF_REGS(gen_op_movl_T0_, )
- },
- {
- DEF_REGS(gen_op_movl_T1_, )
- },
- },
-#ifdef TARGET_X86_64
- [OT_QUAD] = {
- {
- DEF_REGS(gen_op_movl_T0_, )
- },
- {
- DEF_REGS(gen_op_movl_T1_, )
- },
- },
-#endif
-};
-
-static GenOpFunc *gen_op_movl_A0_reg[CPU_NB_REGS] = {
- DEF_REGS(gen_op_movl_A0_, )
-};
-
-static GenOpFunc *gen_op_addl_A0_reg_sN[4][CPU_NB_REGS] = {
- [0] = {
- DEF_REGS(gen_op_addl_A0_, )
- },
- [1] = {
- DEF_REGS(gen_op_addl_A0_, _s1)
- },
- [2] = {
- DEF_REGS(gen_op_addl_A0_, _s2)
- },
- [3] = {
- DEF_REGS(gen_op_addl_A0_, _s3)
- },
-};
-
-#ifdef TARGET_X86_64
-static GenOpFunc *gen_op_movq_A0_reg[CPU_NB_REGS] = {
- DEF_REGS(gen_op_movq_A0_, )
-};
-
-static GenOpFunc *gen_op_addq_A0_reg_sN[4][CPU_NB_REGS] = {
- [0] = {
- DEF_REGS(gen_op_addq_A0_, )
- },
- [1] = {
- DEF_REGS(gen_op_addq_A0_, _s1)
- },
- [2] = {
- DEF_REGS(gen_op_addq_A0_, _s2)
- },
- [3] = {
- DEF_REGS(gen_op_addq_A0_, _s3)
- },
-};
-#endif
-
-static GenOpFunc *gen_op_cmov_reg_T1_T0[NB_OP_SIZES - 1][CPU_NB_REGS] = {
- [0] = {
- DEF_REGS(gen_op_cmovw_, _T1_T0)
- },
- [1] = {
- DEF_REGS(gen_op_cmovl_, _T1_T0)
- },
-#ifdef TARGET_X86_64
- [2] = {
- DEF_REGS(gen_op_cmovq_, _T1_T0)
- },
-#endif
-};
-
-static GenOpFunc *gen_op_arith_T0_T1_cc[8] = {
- NULL,
- gen_op_orl_T0_T1,
- NULL,
- NULL,
- gen_op_andl_T0_T1,
- NULL,
- gen_op_xorl_T0_T1,
- NULL,
-};
-
-#define DEF_ARITHC(SUFFIX)\
- {\
- gen_op_adcb ## SUFFIX ## _T0_T1_cc,\
- gen_op_sbbb ## SUFFIX ## _T0_T1_cc,\
- },\
- {\
- gen_op_adcw ## SUFFIX ## _T0_T1_cc,\
- gen_op_sbbw ## SUFFIX ## _T0_T1_cc,\
- },\
- {\
- gen_op_adcl ## SUFFIX ## _T0_T1_cc,\
- gen_op_sbbl ## SUFFIX ## _T0_T1_cc,\
- },\
- {\
- X86_64_ONLY(gen_op_adcq ## SUFFIX ## _T0_T1_cc),\
- X86_64_ONLY(gen_op_sbbq ## SUFFIX ## _T0_T1_cc),\
- },
-
-static GenOpFunc *gen_op_arithc_T0_T1_cc[4][2] = {
- DEF_ARITHC( )
-};
-
-static GenOpFunc *gen_op_arithc_mem_T0_T1_cc[3 * 4][2] = {
- DEF_ARITHC(_raw)
-#ifndef CONFIG_USER_ONLY
- DEF_ARITHC(_kernel)
- DEF_ARITHC(_user)
-#endif
-};
-
-static const int cc_op_arithb[8] = {
- CC_OP_ADDB,
- CC_OP_LOGICB,
- CC_OP_ADDB,
- CC_OP_SUBB,
- CC_OP_LOGICB,
- CC_OP_SUBB,
- CC_OP_LOGICB,
- CC_OP_SUBB,
-};
-
-#define DEF_CMPXCHG(SUFFIX)\
- gen_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc,\
- gen_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc,\
- gen_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc,\
- X86_64_ONLY(gen_op_cmpxchgq ## SUFFIX ## _T0_T1_EAX_cc),
-
-static GenOpFunc *gen_op_cmpxchg_T0_T1_EAX_cc[4] = {
- DEF_CMPXCHG( )
-};
-
-static GenOpFunc *gen_op_cmpxchg_mem_T0_T1_EAX_cc[3 * 4] = {
- DEF_CMPXCHG(_raw)
-#ifndef CONFIG_USER_ONLY
- DEF_CMPXCHG(_kernel)
- DEF_CMPXCHG(_user)
-#endif
-};
-
-#define DEF_SHIFT(SUFFIX)\
- {\
- gen_op_rolb ## SUFFIX ## _T0_T1_cc,\
- gen_op_rorb ## SUFFIX ## _T0_T1_cc,\
- gen_op_rclb ## SUFFIX ## _T0_T1_cc,\
- gen_op_rcrb ## SUFFIX ## _T0_T1_cc,\
- gen_op_shlb ## SUFFIX ## _T0_T1_cc,\
- gen_op_shrb ## SUFFIX ## _T0_T1_cc,\
- gen_op_shlb ## SUFFIX ## _T0_T1_cc,\
- gen_op_sarb ## SUFFIX ## _T0_T1_cc,\
- },\
- {\
- gen_op_rolw ## SUFFIX ## _T0_T1_cc,\
- gen_op_rorw ## SUFFIX ## _T0_T1_cc,\
- gen_op_rclw ## SUFFIX ## _T0_T1_cc,\
- gen_op_rcrw ## SUFFIX ## _T0_T1_cc,\
- gen_op_shlw ## SUFFIX ## _T0_T1_cc,\
- gen_op_shrw ## SUFFIX ## _T0_T1_cc,\
- gen_op_shlw ## SUFFIX ## _T0_T1_cc,\
- gen_op_sarw ## SUFFIX ## _T0_T1_cc,\
- },\
- {\
- gen_op_roll ## SUFFIX ## _T0_T1_cc,\
- gen_op_rorl ## SUFFIX ## _T0_T1_cc,\
- gen_op_rcll ## SUFFIX ## _T0_T1_cc,\
- gen_op_rcrl ## SUFFIX ## _T0_T1_cc,\
- gen_op_shll ## SUFFIX ## _T0_T1_cc,\
- gen_op_shrl ## SUFFIX ## _T0_T1_cc,\
- gen_op_shll ## SUFFIX ## _T0_T1_cc,\
- gen_op_sarl ## SUFFIX ## _T0_T1_cc,\
- },\
- {\
- X86_64_ONLY(gen_op_rolq ## SUFFIX ## _T0_T1_cc),\
- X86_64_ONLY(gen_op_rorq ## SUFFIX ## _T0_T1_cc),\
- X86_64_ONLY(gen_op_rclq ## SUFFIX ## _T0_T1_cc),\
- X86_64_ONLY(gen_op_rcrq ## SUFFIX ## _T0_T1_cc),\
- X86_64_ONLY(gen_op_shlq ## SUFFIX ## _T0_T1_cc),\
- X86_64_ONLY(gen_op_shrq ## SUFFIX ## _T0_T1_cc),\
- X86_64_ONLY(gen_op_shlq ## SUFFIX ## _T0_T1_cc),\
- X86_64_ONLY(gen_op_sarq ## SUFFIX ## _T0_T1_cc),\
- },
-
-static GenOpFunc *gen_op_shift_T0_T1_cc[4][8] = {
- DEF_SHIFT( )
-};
-
-static GenOpFunc *gen_op_shift_mem_T0_T1_cc[3 * 4][8] = {
- DEF_SHIFT(_raw)
-#ifndef CONFIG_USER_ONLY
- DEF_SHIFT(_kernel)
- DEF_SHIFT(_user)
-#endif
-};
-
-#define DEF_SHIFTD(SUFFIX, op)\
- {\
- NULL,\
- NULL,\
- },\
- {\
- gen_op_shldw ## SUFFIX ## _T0_T1_ ## op ## _cc,\
- gen_op_shrdw ## SUFFIX ## _T0_T1_ ## op ## _cc,\
- },\
- {\
- gen_op_shldl ## SUFFIX ## _T0_T1_ ## op ## _cc,\
- gen_op_shrdl ## SUFFIX ## _T0_T1_ ## op ## _cc,\
- },\
- {\
-X86_64_DEF(gen_op_shldq ## SUFFIX ## _T0_T1_ ## op ## _cc,\
- gen_op_shrdq ## SUFFIX ## _T0_T1_ ## op ## _cc,)\
- },
-
-static GenOpFunc1 *gen_op_shiftd_T0_T1_im_cc[4][2] = {
- DEF_SHIFTD(, im)
-};
-
-static GenOpFunc *gen_op_shiftd_T0_T1_ECX_cc[4][2] = {
- DEF_SHIFTD(, ECX)
-};
-
-static GenOpFunc1 *gen_op_shiftd_mem_T0_T1_im_cc[3 * 4][2] = {
- DEF_SHIFTD(_raw, im)
-#ifndef CONFIG_USER_ONLY
- DEF_SHIFTD(_kernel, im)
- DEF_SHIFTD(_user, im)
-#endif
-};
-
-static GenOpFunc *gen_op_shiftd_mem_T0_T1_ECX_cc[3 * 4][2] = {
- DEF_SHIFTD(_raw, ECX)
-#ifndef CONFIG_USER_ONLY
- DEF_SHIFTD(_kernel, ECX)
- DEF_SHIFTD(_user, ECX)
-#endif
-};
-
-static GenOpFunc *gen_op_btx_T0_T1_cc[3][4] = {
- [0] = {
- gen_op_btw_T0_T1_cc,
- gen_op_btsw_T0_T1_cc,
- gen_op_btrw_T0_T1_cc,
- gen_op_btcw_T0_T1_cc,
- },
- [1] = {
- gen_op_btl_T0_T1_cc,
- gen_op_btsl_T0_T1_cc,
- gen_op_btrl_T0_T1_cc,
- gen_op_btcl_T0_T1_cc,
- },
-#ifdef TARGET_X86_64
- [2] = {
- gen_op_btq_T0_T1_cc,
- gen_op_btsq_T0_T1_cc,
- gen_op_btrq_T0_T1_cc,
- gen_op_btcq_T0_T1_cc,
- },
-#endif
-};
-
-static GenOpFunc *gen_op_add_bit_A0_T1[3] = {
- gen_op_add_bitw_A0_T1,
- gen_op_add_bitl_A0_T1,
- X86_64_ONLY(gen_op_add_bitq_A0_T1),
-};
-
-static GenOpFunc *gen_op_bsx_T0_cc[3][2] = {
- [0] = {
- gen_op_bsfw_T0_cc,
- gen_op_bsrw_T0_cc,
- },
- [1] = {
- gen_op_bsfl_T0_cc,
- gen_op_bsrl_T0_cc,
- },
-#ifdef TARGET_X86_64
- [2] = {
- gen_op_bsfq_T0_cc,
- gen_op_bsrq_T0_cc,
- },
-#endif
-};
-
-static GenOpFunc *gen_op_lds_T0_A0[3 * 4] = {
- gen_op_ldsb_raw_T0_A0,
- gen_op_ldsw_raw_T0_A0,
- X86_64_ONLY(gen_op_ldsl_raw_T0_A0),
- NULL,
-#ifndef CONFIG_USER_ONLY
- gen_op_ldsb_kernel_T0_A0,
- gen_op_ldsw_kernel_T0_A0,
- X86_64_ONLY(gen_op_ldsl_kernel_T0_A0),
- NULL,
-
- gen_op_ldsb_user_T0_A0,
- gen_op_ldsw_user_T0_A0,
- X86_64_ONLY(gen_op_ldsl_user_T0_A0),
- NULL,
-#endif
-};
-
-static GenOpFunc *gen_op_ldu_T0_A0[3 * 4] = {
- gen_op_ldub_raw_T0_A0,
- gen_op_lduw_raw_T0_A0,
- NULL,
- NULL,
-
-#ifndef CONFIG_USER_ONLY
- gen_op_ldub_kernel_T0_A0,
- gen_op_lduw_kernel_T0_A0,
- NULL,
- NULL,
-
- gen_op_ldub_user_T0_A0,
- gen_op_lduw_user_T0_A0,
- NULL,
- NULL,
-#endif
-};
-
-/* sign does not matter, except for lidt/lgdt call (TODO: fix it) */
-static GenOpFunc *gen_op_ld_T0_A0[3 * 4] = {
- gen_op_ldub_raw_T0_A0,
- gen_op_lduw_raw_T0_A0,
- gen_op_ldl_raw_T0_A0,
- X86_64_ONLY(gen_op_ldq_raw_T0_A0),
-
-#ifndef CONFIG_USER_ONLY
- gen_op_ldub_kernel_T0_A0,
- gen_op_lduw_kernel_T0_A0,
- gen_op_ldl_kernel_T0_A0,
- X86_64_ONLY(gen_op_ldq_kernel_T0_A0),
-
- gen_op_ldub_user_T0_A0,
- gen_op_lduw_user_T0_A0,
- gen_op_ldl_user_T0_A0,
- X86_64_ONLY(gen_op_ldq_user_T0_A0),
-#endif
-};
-
-static GenOpFunc *gen_op_ld_T1_A0[3 * 4] = {
- gen_op_ldub_raw_T1_A0,
- gen_op_lduw_raw_T1_A0,
- gen_op_ldl_raw_T1_A0,
- X86_64_ONLY(gen_op_ldq_raw_T1_A0),
-
-#ifndef CONFIG_USER_ONLY
- gen_op_ldub_kernel_T1_A0,
- gen_op_lduw_kernel_T1_A0,
- gen_op_ldl_kernel_T1_A0,
- X86_64_ONLY(gen_op_ldq_kernel_T1_A0),
-
- gen_op_ldub_user_T1_A0,
- gen_op_lduw_user_T1_A0,
- gen_op_ldl_user_T1_A0,
- X86_64_ONLY(gen_op_ldq_user_T1_A0),
-#endif
-};
-
-static GenOpFunc *gen_op_st_T0_A0[3 * 4] = {
- gen_op_stb_raw_T0_A0,
- gen_op_stw_raw_T0_A0,
- gen_op_stl_raw_T0_A0,
- X86_64_ONLY(gen_op_stq_raw_T0_A0),
-
-#ifndef CONFIG_USER_ONLY
- gen_op_stb_kernel_T0_A0,
- gen_op_stw_kernel_T0_A0,
- gen_op_stl_kernel_T0_A0,
- X86_64_ONLY(gen_op_stq_kernel_T0_A0),
-
- gen_op_stb_user_T0_A0,
- gen_op_stw_user_T0_A0,
- gen_op_stl_user_T0_A0,
- X86_64_ONLY(gen_op_stq_user_T0_A0),
-#endif
-};
-
-static GenOpFunc *gen_op_st_T1_A0[3 * 4] = {
- NULL,
- gen_op_stw_raw_T1_A0,
- gen_op_stl_raw_T1_A0,
- X86_64_ONLY(gen_op_stq_raw_T1_A0),
-
-#ifndef CONFIG_USER_ONLY
- NULL,
- gen_op_stw_kernel_T1_A0,
- gen_op_stl_kernel_T1_A0,
- X86_64_ONLY(gen_op_stq_kernel_T1_A0),
-
- NULL,
- gen_op_stw_user_T1_A0,
- gen_op_stl_user_T1_A0,
- X86_64_ONLY(gen_op_stq_user_T1_A0),
-#endif
-};
-
-static inline void gen_jmp_im(target_ulong pc)
-{
-#ifdef TARGET_X86_64
- if (pc == (uint32_t)pc) {
- gen_op_movl_eip_im(pc);
- } else if (pc == (int32_t)pc) {
- gen_op_movq_eip_im(pc);
- } else {
- gen_op_movq_eip_im64(pc >> 32, pc);
- }
-#else
- gen_op_movl_eip_im(pc);
-#endif
-}
-
-static inline void gen_string_movl_A0_ESI(DisasContext *s)
-{
- int override;
-
- override = s->override;
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- if (override >= 0) {
- gen_op_movq_A0_seg(offsetof(CPUX86State,segs[override].base));
- gen_op_addq_A0_reg_sN[0][R_ESI]();
- } else {
- gen_op_movq_A0_reg[R_ESI]();
- }
- } else
-#endif
- if (s->aflag) {
- /* 32 bit address */
- if (s->addseg && override < 0)
- override = R_DS;
- if (override >= 0) {
- gen_op_movl_A0_seg(offsetof(CPUX86State,segs[override].base));
- gen_op_addl_A0_reg_sN[0][R_ESI]();
- } else {
- gen_op_movl_A0_reg[R_ESI]();
- }
- } else {
- /* 16 address, always override */
- if (override < 0)
- override = R_DS;
- gen_op_movl_A0_reg[R_ESI]();
- gen_op_andl_A0_ffff();
- gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
- }
-}
-
-static inline void gen_string_movl_A0_EDI(DisasContext *s)
-{
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_movq_A0_reg[R_EDI]();
- } else
-#endif
- if (s->aflag) {
- if (s->addseg) {
- gen_op_movl_A0_seg(offsetof(CPUX86State,segs[R_ES].base));
- gen_op_addl_A0_reg_sN[0][R_EDI]();
- } else {
- gen_op_movl_A0_reg[R_EDI]();
- }
- } else {
- gen_op_movl_A0_reg[R_EDI]();
- gen_op_andl_A0_ffff();
- gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_ES].base));
- }
-}
-
-static GenOpFunc *gen_op_movl_T0_Dshift[4] = {
- gen_op_movl_T0_Dshiftb,
- gen_op_movl_T0_Dshiftw,
- gen_op_movl_T0_Dshiftl,
- X86_64_ONLY(gen_op_movl_T0_Dshiftq),
-};
-
-static GenOpFunc1 *gen_op_jnz_ecx[3] = {
- gen_op_jnz_ecxw,
- gen_op_jnz_ecxl,
- X86_64_ONLY(gen_op_jnz_ecxq),
-};
-
-static GenOpFunc1 *gen_op_jz_ecx[3] = {
- gen_op_jz_ecxw,
- gen_op_jz_ecxl,
- X86_64_ONLY(gen_op_jz_ecxq),
-};
-
-static GenOpFunc *gen_op_dec_ECX[3] = {
- gen_op_decw_ECX,
- gen_op_decl_ECX,
- X86_64_ONLY(gen_op_decq_ECX),
-};
-
-static GenOpFunc1 *gen_op_string_jnz_sub[2][4] = {
- {
- gen_op_jnz_subb,
- gen_op_jnz_subw,
- gen_op_jnz_subl,
- X86_64_ONLY(gen_op_jnz_subq),
- },
- {
- gen_op_jz_subb,
- gen_op_jz_subw,
- gen_op_jz_subl,
- X86_64_ONLY(gen_op_jz_subq),
- },
-};
-
-static GenOpFunc *gen_op_in_DX_T0[3] = {
- gen_op_inb_DX_T0,
- gen_op_inw_DX_T0,
- gen_op_inl_DX_T0,
-};
-
-static GenOpFunc *gen_op_out_DX_T0[3] = {
- gen_op_outb_DX_T0,
- gen_op_outw_DX_T0,
- gen_op_outl_DX_T0,
-};
-
-static GenOpFunc *gen_op_in[3] = {
- gen_op_inb_T0_T1,
- gen_op_inw_T0_T1,
- gen_op_inl_T0_T1,
-};
-
-static GenOpFunc *gen_op_out[3] = {
- gen_op_outb_T0_T1,
- gen_op_outw_T0_T1,
- gen_op_outl_T0_T1,
-};
-
-static GenOpFunc *gen_check_io_T0[3] = {
- gen_op_check_iob_T0,
- gen_op_check_iow_T0,
- gen_op_check_iol_T0,
-};
-
-static GenOpFunc *gen_check_io_DX[3] = {
- gen_op_check_iob_DX,
- gen_op_check_iow_DX,
- gen_op_check_iol_DX,
-};
-
-static void gen_check_io(DisasContext *s, int ot, int use_dx, target_ulong cur_eip)
-{
- if (s->pe && (s->cpl > s->iopl || s->vm86)) {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(cur_eip);
- if (use_dx)
- gen_check_io_DX[ot]();
- else
- gen_check_io_T0[ot]();
- }
-}
-
-static inline void gen_movs(DisasContext *s, int ot)
-{
- gen_string_movl_A0_ESI(s);
- gen_op_ld_T0_A0[ot + s->mem_index]();
- gen_string_movl_A0_EDI(s);
- gen_op_st_T0_A0[ot + s->mem_index]();
- gen_op_movl_T0_Dshift[ot]();
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_ESI_T0();
- gen_op_addq_EDI_T0();
- } else
-#endif
- if (s->aflag) {
- gen_op_addl_ESI_T0();
- gen_op_addl_EDI_T0();
- } else {
- gen_op_addw_ESI_T0();
- gen_op_addw_EDI_T0();
- }
-}
-
-static inline void gen_update_cc_op(DisasContext *s)
-{
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- s->cc_op = CC_OP_DYNAMIC;
- }
-}
-
-/* XXX: does not work with gdbstub "ice" single step - not a
- serious problem */
-static int gen_jz_ecx_string(DisasContext *s, target_ulong next_eip)
-{
- int l1, l2;
-
- l1 = gen_new_label();
- l2 = gen_new_label();
- gen_op_jnz_ecx[s->aflag](l1);
- gen_set_label(l2);
- gen_jmp_tb(s, next_eip, 1);
- gen_set_label(l1);
- return l2;
-}
-
-static inline void gen_stos(DisasContext *s, int ot)
-{
- gen_op_mov_TN_reg[OT_LONG][0][R_EAX]();
- gen_string_movl_A0_EDI(s);
- gen_op_st_T0_A0[ot + s->mem_index]();
- gen_op_movl_T0_Dshift[ot]();
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_EDI_T0();
- } else
-#endif
- if (s->aflag) {
- gen_op_addl_EDI_T0();
- } else {
- gen_op_addw_EDI_T0();
- }
-}
-
-static inline void gen_lods(DisasContext *s, int ot)
-{
- gen_string_movl_A0_ESI(s);
- gen_op_ld_T0_A0[ot + s->mem_index]();
- gen_op_mov_reg_T0[ot][R_EAX]();
- gen_op_movl_T0_Dshift[ot]();
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_ESI_T0();
- } else
-#endif
- if (s->aflag) {
- gen_op_addl_ESI_T0();
- } else {
- gen_op_addw_ESI_T0();
- }
-}
-
-static inline void gen_scas(DisasContext *s, int ot)
-{
- gen_op_mov_TN_reg[OT_LONG][0][R_EAX]();
- gen_string_movl_A0_EDI(s);
- gen_op_ld_T1_A0[ot + s->mem_index]();
- gen_op_cmpl_T0_T1_cc();
- gen_op_movl_T0_Dshift[ot]();
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_EDI_T0();
- } else
-#endif
- if (s->aflag) {
- gen_op_addl_EDI_T0();
- } else {
- gen_op_addw_EDI_T0();
- }
-}
-
-static inline void gen_cmps(DisasContext *s, int ot)
-{
- gen_string_movl_A0_ESI(s);
- gen_op_ld_T0_A0[ot + s->mem_index]();
- gen_string_movl_A0_EDI(s);
- gen_op_ld_T1_A0[ot + s->mem_index]();
- gen_op_cmpl_T0_T1_cc();
- gen_op_movl_T0_Dshift[ot]();
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_ESI_T0();
- gen_op_addq_EDI_T0();
- } else
-#endif
- if (s->aflag) {
- gen_op_addl_ESI_T0();
- gen_op_addl_EDI_T0();
- } else {
- gen_op_addw_ESI_T0();
- gen_op_addw_EDI_T0();
- }
-}
-
-static inline void gen_ins(DisasContext *s, int ot)
-{
- gen_string_movl_A0_EDI(s);
- gen_op_movl_T0_0();
- gen_op_st_T0_A0[ot + s->mem_index]();
- gen_op_in_DX_T0[ot]();
- gen_op_st_T0_A0[ot + s->mem_index]();
- gen_op_movl_T0_Dshift[ot]();
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_EDI_T0();
- } else
-#endif
- if (s->aflag) {
- gen_op_addl_EDI_T0();
- } else {
- gen_op_addw_EDI_T0();
- }
-}
-
-static inline void gen_outs(DisasContext *s, int ot)
-{
- gen_string_movl_A0_ESI(s);
- gen_op_ld_T0_A0[ot + s->mem_index]();
- gen_op_out_DX_T0[ot]();
- gen_op_movl_T0_Dshift[ot]();
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_ESI_T0();
- } else
-#endif
- if (s->aflag) {
- gen_op_addl_ESI_T0();
- } else {
- gen_op_addw_ESI_T0();
- }
-}
-
-/* same method as Valgrind : we generate jumps to current or next
- instruction */
-#define GEN_REPZ(op) \
-static inline void gen_repz_ ## op(DisasContext *s, int ot, \
- target_ulong cur_eip, target_ulong next_eip) \
-{ \
- int l2;\
- gen_update_cc_op(s); \
- l2 = gen_jz_ecx_string(s, next_eip); \
- gen_ ## op(s, ot); \
- gen_op_dec_ECX[s->aflag](); \
- /* a loop would cause two single step exceptions if ECX = 1 \
- before rep string_insn */ \
- if (!s->jmp_opt) \
- gen_op_jz_ecx[s->aflag](l2); \
- gen_jmp(s, cur_eip); \
-}
-
-#define GEN_REPZ2(op) \
-static inline void gen_repz_ ## op(DisasContext *s, int ot, \
- target_ulong cur_eip, \
- target_ulong next_eip, \
- int nz) \
-{ \
- int l2;\
- gen_update_cc_op(s); \
- l2 = gen_jz_ecx_string(s, next_eip); \
- gen_ ## op(s, ot); \
- gen_op_dec_ECX[s->aflag](); \
- gen_op_set_cc_op(CC_OP_SUBB + ot); \
- gen_op_string_jnz_sub[nz][ot](l2);\
- if (!s->jmp_opt) \
- gen_op_jz_ecx[s->aflag](l2); \
- gen_jmp(s, cur_eip); \
-}
-
-GEN_REPZ(movs)
-GEN_REPZ(stos)
-GEN_REPZ(lods)
-GEN_REPZ(ins)
-GEN_REPZ(outs)
-GEN_REPZ2(scas)
-GEN_REPZ2(cmps)
-
-enum {
- JCC_O,
- JCC_B,
- JCC_Z,
- JCC_BE,
- JCC_S,
- JCC_P,
- JCC_L,
- JCC_LE,
-};
-
-static GenOpFunc1 *gen_jcc_sub[4][8] = {
- [OT_BYTE] = {
- NULL,
- gen_op_jb_subb,
- gen_op_jz_subb,
- gen_op_jbe_subb,
- gen_op_js_subb,
- NULL,
- gen_op_jl_subb,
- gen_op_jle_subb,
- },
- [OT_WORD] = {
- NULL,
- gen_op_jb_subw,
- gen_op_jz_subw,
- gen_op_jbe_subw,
- gen_op_js_subw,
- NULL,
- gen_op_jl_subw,
- gen_op_jle_subw,
- },
- [OT_LONG] = {
- NULL,
- gen_op_jb_subl,
- gen_op_jz_subl,
- gen_op_jbe_subl,
- gen_op_js_subl,
- NULL,
- gen_op_jl_subl,
- gen_op_jle_subl,
- },
-#ifdef TARGET_X86_64
- [OT_QUAD] = {
- NULL,
- BUGGY_64(gen_op_jb_subq),
- gen_op_jz_subq,
- BUGGY_64(gen_op_jbe_subq),
- gen_op_js_subq,
- NULL,
- BUGGY_64(gen_op_jl_subq),
- BUGGY_64(gen_op_jle_subq),
- },
-#endif
-};
-static GenOpFunc1 *gen_op_loop[3][4] = {
- [0] = {
- gen_op_loopnzw,
- gen_op_loopzw,
- gen_op_jnz_ecxw,
- },
- [1] = {
- gen_op_loopnzl,
- gen_op_loopzl,
- gen_op_jnz_ecxl,
- },
-#ifdef TARGET_X86_64
- [2] = {
- gen_op_loopnzq,
- gen_op_loopzq,
- gen_op_jnz_ecxq,
- },
-#endif
-};
-
-static GenOpFunc *gen_setcc_slow[8] = {
- gen_op_seto_T0_cc,
- gen_op_setb_T0_cc,
- gen_op_setz_T0_cc,
- gen_op_setbe_T0_cc,
- gen_op_sets_T0_cc,
- gen_op_setp_T0_cc,
- gen_op_setl_T0_cc,
- gen_op_setle_T0_cc,
-};
-
-static GenOpFunc *gen_setcc_sub[4][8] = {
- [OT_BYTE] = {
- NULL,
- gen_op_setb_T0_subb,
- gen_op_setz_T0_subb,
- gen_op_setbe_T0_subb,
- gen_op_sets_T0_subb,
- NULL,
- gen_op_setl_T0_subb,
- gen_op_setle_T0_subb,
- },
- [OT_WORD] = {
- NULL,
- gen_op_setb_T0_subw,
- gen_op_setz_T0_subw,
- gen_op_setbe_T0_subw,
- gen_op_sets_T0_subw,
- NULL,
- gen_op_setl_T0_subw,
- gen_op_setle_T0_subw,
- },
- [OT_LONG] = {
- NULL,
- gen_op_setb_T0_subl,
- gen_op_setz_T0_subl,
- gen_op_setbe_T0_subl,
- gen_op_sets_T0_subl,
- NULL,
- gen_op_setl_T0_subl,
- gen_op_setle_T0_subl,
- },
-#ifdef TARGET_X86_64
- [OT_QUAD] = {
- NULL,
- gen_op_setb_T0_subq,
- gen_op_setz_T0_subq,
- gen_op_setbe_T0_subq,
- gen_op_sets_T0_subq,
- NULL,
- gen_op_setl_T0_subq,
- gen_op_setle_T0_subq,
- },
-#endif
-};
-
-static GenOpFunc *gen_op_fp_arith_ST0_FT0[8] = {
- gen_op_fadd_ST0_FT0,
- gen_op_fmul_ST0_FT0,
- gen_op_fcom_ST0_FT0,
- gen_op_fcom_ST0_FT0,
- gen_op_fsub_ST0_FT0,
- gen_op_fsubr_ST0_FT0,
- gen_op_fdiv_ST0_FT0,
- gen_op_fdivr_ST0_FT0,
-};
-
-/* NOTE the exception in "r" op ordering */
-static GenOpFunc1 *gen_op_fp_arith_STN_ST0[8] = {
- gen_op_fadd_STN_ST0,
- gen_op_fmul_STN_ST0,
- NULL,
- NULL,
- gen_op_fsubr_STN_ST0,
- gen_op_fsub_STN_ST0,
- gen_op_fdivr_STN_ST0,
- gen_op_fdiv_STN_ST0,
-};
-
-/* if d == OR_TMP0, it means memory operand (address in A0) */
-static void gen_op(DisasContext *s1, int op, int ot, int d)
-{
- GenOpFunc *gen_update_cc;
-
- if (d != OR_TMP0) {
- gen_op_mov_TN_reg[ot][0][d]();
- } else {
- gen_op_ld_T0_A0[ot + s1->mem_index]();
- }
- switch(op) {
- case OP_ADCL:
- case OP_SBBL:
- if (s1->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s1->cc_op);
- if (d != OR_TMP0) {
- gen_op_arithc_T0_T1_cc[ot][op - OP_ADCL]();
- gen_op_mov_reg_T0[ot][d]();
- } else {
- gen_op_arithc_mem_T0_T1_cc[ot + s1->mem_index][op - OP_ADCL]();
- }
- s1->cc_op = CC_OP_DYNAMIC;
- goto the_end;
- case OP_ADDL:
- gen_op_addl_T0_T1();
- s1->cc_op = CC_OP_ADDB + ot;
- gen_update_cc = gen_op_update2_cc;
- break;
- case OP_SUBL:
- gen_op_subl_T0_T1();
- s1->cc_op = CC_OP_SUBB + ot;
- gen_update_cc = gen_op_update2_cc;
- break;
- default:
- case OP_ANDL:
- case OP_ORL:
- case OP_XORL:
- gen_op_arith_T0_T1_cc[op]();
- s1->cc_op = CC_OP_LOGICB + ot;
- gen_update_cc = gen_op_update1_cc;
- break;
- case OP_CMPL:
- gen_op_cmpl_T0_T1_cc();
- s1->cc_op = CC_OP_SUBB + ot;
- gen_update_cc = NULL;
- break;
- }
- if (op != OP_CMPL) {
- if (d != OR_TMP0)
- gen_op_mov_reg_T0[ot][d]();
- else
- gen_op_st_T0_A0[ot + s1->mem_index]();
- }
- /* the flags update must happen after the memory write (precise
- exception support) */
- if (gen_update_cc)
- gen_update_cc();
- the_end: ;
-}
-
-/* if d == OR_TMP0, it means memory operand (address in A0) */
-static void gen_inc(DisasContext *s1, int ot, int d, int c)
-{
- if (d != OR_TMP0)
- gen_op_mov_TN_reg[ot][0][d]();
- else
- gen_op_ld_T0_A0[ot + s1->mem_index]();
- if (s1->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s1->cc_op);
- if (c > 0) {
- gen_op_incl_T0();
- s1->cc_op = CC_OP_INCB + ot;
- } else {
- gen_op_decl_T0();
- s1->cc_op = CC_OP_DECB + ot;
- }
- if (d != OR_TMP0)
- gen_op_mov_reg_T0[ot][d]();
- else
- gen_op_st_T0_A0[ot + s1->mem_index]();
- gen_op_update_inc_cc();
-}
-
-static void gen_shift(DisasContext *s1, int op, int ot, int d, int s)
-{
- if (d != OR_TMP0)
- gen_op_mov_TN_reg[ot][0][d]();
- else
- gen_op_ld_T0_A0[ot + s1->mem_index]();
- if (s != OR_TMP1)
- gen_op_mov_TN_reg[ot][1][s]();
- /* for zero counts, flags are not updated, so must do it dynamically */
- if (s1->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s1->cc_op);
-
- if (d != OR_TMP0)
- gen_op_shift_T0_T1_cc[ot][op]();
- else
- gen_op_shift_mem_T0_T1_cc[ot + s1->mem_index][op]();
- if (d != OR_TMP0)
- gen_op_mov_reg_T0[ot][d]();
- s1->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
-}
-
-static void gen_shifti(DisasContext *s1, int op, int ot, int d, int c)
-{
- /* currently not optimized */
- gen_op_movl_T1_im(c);
- gen_shift(s1, op, ot, d, OR_TMP1);
-}
-
-static void gen_lea_modrm(DisasContext *s, int modrm, int *reg_ptr, int *offset_ptr)
-{
- target_long disp;
- int havesib;
- int base;
- int index;
- int scale;
- int opreg;
- int mod, rm, code, override, must_add_seg;
-
- override = s->override;
- must_add_seg = s->addseg;
- if (override >= 0)
- must_add_seg = 1;
- mod = (modrm >> 6) & 3;
- rm = modrm & 7;
-
- if (s->aflag) {
-
- havesib = 0;
- base = rm;
- index = 0;
- scale = 0;
-
- if (base == 4) {
- havesib = 1;
- code = ldub_code(s->pc++);
- scale = (code >> 6) & 3;
- index = ((code >> 3) & 7) | REX_X(s);
- base = (code & 7);
- }
- base |= REX_B(s);
-
- switch (mod) {
- case 0:
- if ((base & 7) == 5) {
- base = -1;
- disp = (int32_t)ldl_code(s->pc);
- s->pc += 4;
- if (CODE64(s) && !havesib) {
- disp += s->pc + s->rip_offset;
- }
- } else {
- disp = 0;
- }
- break;
- case 1:
- disp = (int8_t)ldub_code(s->pc++);
- break;
- default:
- case 2:
- disp = ldl_code(s->pc);
- s->pc += 4;
- break;
- }
-
- if (base >= 0) {
- /* for correct popl handling with esp */
- if (base == 4 && s->popl_esp_hack)
- disp += s->popl_esp_hack;
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_movq_A0_reg[base]();
- if (disp != 0) {
- if ((int32_t)disp == disp)
- gen_op_addq_A0_im(disp);
- else
- gen_op_addq_A0_im64(disp >> 32, disp);
- }
- } else
-#endif
- {
- gen_op_movl_A0_reg[base]();
- if (disp != 0)
- gen_op_addl_A0_im(disp);
- }
- } else {
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- if ((int32_t)disp == disp)
- gen_op_movq_A0_im(disp);
- else
- gen_op_movq_A0_im64(disp >> 32, disp);
- } else
-#endif
- {
- gen_op_movl_A0_im(disp);
- }
- }
- /* XXX: index == 4 is always invalid */
- if (havesib && (index != 4 || scale != 0)) {
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_A0_reg_sN[scale][index]();
- } else
-#endif
- {
- gen_op_addl_A0_reg_sN[scale][index]();
- }
- }
- if (must_add_seg) {
- if (override < 0) {
- if (base == R_EBP || base == R_ESP)
- override = R_SS;
- else
- override = R_DS;
- }
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base));
- } else
-#endif
- {
- gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
- }
- }
- } else {
- switch (mod) {
- case 0:
- if (rm == 6) {
- disp = lduw_code(s->pc);
- s->pc += 2;
- gen_op_movl_A0_im(disp);
- rm = 0; /* avoid SS override */
- goto no_rm;
- } else {
- disp = 0;
- }
- break;
- case 1:
- disp = (int8_t)ldub_code(s->pc++);
- break;
- default:
- case 2:
- disp = lduw_code(s->pc);
- s->pc += 2;
- break;
- }
- switch(rm) {
- case 0:
- gen_op_movl_A0_reg[R_EBX]();
- gen_op_addl_A0_reg_sN[0][R_ESI]();
- break;
- case 1:
- gen_op_movl_A0_reg[R_EBX]();
- gen_op_addl_A0_reg_sN[0][R_EDI]();
- break;
- case 2:
- gen_op_movl_A0_reg[R_EBP]();
- gen_op_addl_A0_reg_sN[0][R_ESI]();
- break;
- case 3:
- gen_op_movl_A0_reg[R_EBP]();
- gen_op_addl_A0_reg_sN[0][R_EDI]();
- break;
- case 4:
- gen_op_movl_A0_reg[R_ESI]();
- break;
- case 5:
- gen_op_movl_A0_reg[R_EDI]();
- break;
- case 6:
- gen_op_movl_A0_reg[R_EBP]();
- break;
- default:
- case 7:
- gen_op_movl_A0_reg[R_EBX]();
- break;
- }
- if (disp != 0)
- gen_op_addl_A0_im(disp);
- gen_op_andl_A0_ffff();
- no_rm:
- if (must_add_seg) {
- if (override < 0) {
- if (rm == 2 || rm == 3 || rm == 6)
- override = R_SS;
- else
- override = R_DS;
- }
- gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
- }
- }
-
- opreg = OR_A0;
- disp = 0;
- *reg_ptr = opreg;
- *offset_ptr = disp;
-}
-
-/* used for LEA and MOV AX, mem */
-static void gen_add_A0_ds_seg(DisasContext *s)
-{
- int override, must_add_seg;
- must_add_seg = s->addseg;
- override = R_DS;
- if (s->override >= 0) {
- override = s->override;
- must_add_seg = 1;
- } else {
- override = R_DS;
- }
- if (must_add_seg) {
-#ifdef TARGET_X86_64
- if (CODE64(s)) {
- gen_op_addq_A0_seg(offsetof(CPUX86State,segs[override].base));
- } else
-#endif
- {
- gen_op_addl_A0_seg(offsetof(CPUX86State,segs[override].base));
- }
- }
-}
-
-/* generate modrm memory load or store of 'reg'. TMP0 is used if reg !=
- OR_TMP0 */
-static void gen_ldst_modrm(DisasContext *s, int modrm, int ot, int reg, int is_store)
-{
- int mod, rm, opreg, disp;
-
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
- if (mod == 3) {
- if (is_store) {
- if (reg != OR_TMP0)
- gen_op_mov_TN_reg[ot][0][reg]();
- gen_op_mov_reg_T0[ot][rm]();
- } else {
- gen_op_mov_TN_reg[ot][0][rm]();
- if (reg != OR_TMP0)
- gen_op_mov_reg_T0[ot][reg]();
- }
- } else {
- gen_lea_modrm(s, modrm, &opreg, &disp);
- if (is_store) {
- if (reg != OR_TMP0)
- gen_op_mov_TN_reg[ot][0][reg]();
- gen_op_st_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_ld_T0_A0[ot + s->mem_index]();
- if (reg != OR_TMP0)
- gen_op_mov_reg_T0[ot][reg]();
- }
- }
-}
-
-static inline uint32_t insn_get(DisasContext *s, int ot)
-{
- uint32_t ret;
-
- switch(ot) {
- case OT_BYTE:
- ret = ldub_code(s->pc);
- s->pc++;
- break;
- case OT_WORD:
- ret = lduw_code(s->pc);
- s->pc += 2;
- break;
- default:
- case OT_LONG:
- ret = ldl_code(s->pc);
- s->pc += 4;
- break;
- }
- return ret;
-}
-
-static inline int insn_const_size(unsigned int ot)
-{
- if (ot <= OT_LONG)
- return 1 << ot;
- else
- return 4;
-}
-
-static inline void gen_goto_tb(DisasContext *s, int tb_num, target_ulong eip)
-{
- TranslationBlock *tb;
- target_ulong pc;
-
- pc = s->cs_base + eip;
- tb = s->tb;
- /* NOTE: we handle the case where the TB spans two pages here */
- if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) ||
- (pc & TARGET_PAGE_MASK) == ((s->pc - 1) & TARGET_PAGE_MASK)) {
- /* jump to same page: we can use a direct jump */
- if (tb_num == 0)
- gen_op_goto_tb0(TBPARAM(tb));
- else
- gen_op_goto_tb1(TBPARAM(tb));
- gen_jmp_im(eip);
- gen_op_movl_T0_im((long)tb + tb_num);
- gen_op_exit_tb();
- } else {
- /* jump to another page: currently not optimized */
- gen_jmp_im(eip);
- gen_eob(s);
- }
-}
-
-static inline void gen_jcc(DisasContext *s, int b,
- target_ulong val, target_ulong next_eip)
-{
- TranslationBlock *tb;
- int inv, jcc_op;
- GenOpFunc1 *func;
- target_ulong tmp;
- int l1, l2;
-
- inv = b & 1;
- jcc_op = (b >> 1) & 7;
-
- if (s->jmp_opt) {
- switch(s->cc_op) {
- /* we optimize the cmp/jcc case */
- case CC_OP_SUBB:
- case CC_OP_SUBW:
- case CC_OP_SUBL:
- case CC_OP_SUBQ:
- func = gen_jcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
- break;
-
- /* some jumps are easy to compute */
- case CC_OP_ADDB:
- case CC_OP_ADDW:
- case CC_OP_ADDL:
- case CC_OP_ADDQ:
-
- case CC_OP_ADCB:
- case CC_OP_ADCW:
- case CC_OP_ADCL:
- case CC_OP_ADCQ:
-
- case CC_OP_SBBB:
- case CC_OP_SBBW:
- case CC_OP_SBBL:
- case CC_OP_SBBQ:
-
- case CC_OP_LOGICB:
- case CC_OP_LOGICW:
- case CC_OP_LOGICL:
- case CC_OP_LOGICQ:
-
- case CC_OP_INCB:
- case CC_OP_INCW:
- case CC_OP_INCL:
- case CC_OP_INCQ:
-
- case CC_OP_DECB:
- case CC_OP_DECW:
- case CC_OP_DECL:
- case CC_OP_DECQ:
-
- case CC_OP_SHLB:
- case CC_OP_SHLW:
- case CC_OP_SHLL:
- case CC_OP_SHLQ:
-
- case CC_OP_SARB:
- case CC_OP_SARW:
- case CC_OP_SARL:
- case CC_OP_SARQ:
- switch(jcc_op) {
- case JCC_Z:
- func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op];
- break;
- case JCC_S:
- func = gen_jcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op];
- break;
- default:
- func = NULL;
- break;
- }
- break;
- default:
- func = NULL;
- break;
- }
-
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- s->cc_op = CC_OP_DYNAMIC;
- }
-
- if (!func) {
- gen_setcc_slow[jcc_op]();
- func = gen_op_jnz_T0_label;
- }
-
- if (inv) {
- tmp = val;
- val = next_eip;
- next_eip = tmp;
- }
- tb = s->tb;
-
- l1 = gen_new_label();
- func(l1);
-
- gen_goto_tb(s, 0, next_eip);
-
- gen_set_label(l1);
- gen_goto_tb(s, 1, val);
-
- s->is_jmp = 3;
- } else {
-
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- s->cc_op = CC_OP_DYNAMIC;
- }
- gen_setcc_slow[jcc_op]();
- if (inv) {
- tmp = val;
- val = next_eip;
- next_eip = tmp;
- }
- l1 = gen_new_label();
- l2 = gen_new_label();
- gen_op_jnz_T0_label(l1);
- gen_jmp_im(next_eip);
- gen_op_jmp_label(l2);
- gen_set_label(l1);
- gen_jmp_im(val);
- gen_set_label(l2);
- gen_eob(s);
- }
-}
-
-static void gen_setcc(DisasContext *s, int b)
-{
- int inv, jcc_op;
- GenOpFunc *func;
-
- inv = b & 1;
- jcc_op = (b >> 1) & 7;
- switch(s->cc_op) {
- /* we optimize the cmp/jcc case */
- case CC_OP_SUBB:
- case CC_OP_SUBW:
- case CC_OP_SUBL:
- case CC_OP_SUBQ:
- func = gen_setcc_sub[s->cc_op - CC_OP_SUBB][jcc_op];
- if (!func)
- goto slow_jcc;
- break;
-
- /* some jumps are easy to compute */
- case CC_OP_ADDB:
- case CC_OP_ADDW:
- case CC_OP_ADDL:
- case CC_OP_ADDQ:
-
- case CC_OP_LOGICB:
- case CC_OP_LOGICW:
- case CC_OP_LOGICL:
- case CC_OP_LOGICQ:
-
- case CC_OP_INCB:
- case CC_OP_INCW:
- case CC_OP_INCL:
- case CC_OP_INCQ:
-
- case CC_OP_DECB:
- case CC_OP_DECW:
- case CC_OP_DECL:
- case CC_OP_DECQ:
-
- case CC_OP_SHLB:
- case CC_OP_SHLW:
- case CC_OP_SHLL:
- case CC_OP_SHLQ:
- switch(jcc_op) {
- case JCC_Z:
- func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op];
- break;
- case JCC_S:
- func = gen_setcc_sub[(s->cc_op - CC_OP_ADDB) % 4][jcc_op];
- break;
- default:
- goto slow_jcc;
- }
- break;
- default:
- slow_jcc:
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- func = gen_setcc_slow[jcc_op];
- break;
- }
- func();
- if (inv) {
- gen_op_xor_T0_1();
- }
-}
-
-/* move T0 to seg_reg and compute if the CPU state may change. Never
- call this function with seg_reg == R_CS */
-static void gen_movl_seg_T0(DisasContext *s, int seg_reg, target_ulong cur_eip)
-{
- if (s->pe && !s->vm86) {
- /* XXX: optimize by finding processor state dynamically */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(cur_eip);
- gen_op_movl_seg_T0(seg_reg);
- /* abort translation because the addseg value may change or
- because ss32 may change. For R_SS, translation must always
- stop as a special handling must be done to disable hardware
- interrupts for the next instruction */
- if (seg_reg == R_SS || (s->code32 && seg_reg < R_FS))
- s->is_jmp = 3;
- } else {
- gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[seg_reg]));
- if (seg_reg == R_SS)
- s->is_jmp = 3;
- }
-}
-
-static inline void gen_stack_update(DisasContext *s, int addend)
-{
-#ifdef TARGET_X86_64
- if (CODE64(s)) {
- if (addend == 8)
- gen_op_addq_ESP_8();
- else
- gen_op_addq_ESP_im(addend);
- } else
-#endif
- if (s->ss32) {
- if (addend == 2)
- gen_op_addl_ESP_2();
- else if (addend == 4)
- gen_op_addl_ESP_4();
- else
- gen_op_addl_ESP_im(addend);
- } else {
- if (addend == 2)
- gen_op_addw_ESP_2();
- else if (addend == 4)
- gen_op_addw_ESP_4();
- else
- gen_op_addw_ESP_im(addend);
- }
-}
-
-/* generate a push. It depends on ss32, addseg and dflag */
-static void gen_push_T0(DisasContext *s)
-{
-#ifdef TARGET_X86_64
- if (CODE64(s)) {
- gen_op_movq_A0_reg[R_ESP]();
- if (s->dflag) {
- gen_op_subq_A0_8();
- gen_op_st_T0_A0[OT_QUAD + s->mem_index]();
- } else {
- gen_op_subq_A0_2();
- gen_op_st_T0_A0[OT_WORD + s->mem_index]();
- }
- gen_op_movq_ESP_A0();
- } else
-#endif
- {
- gen_op_movl_A0_reg[R_ESP]();
- if (!s->dflag)
- gen_op_subl_A0_2();
- else
- gen_op_subl_A0_4();
- if (s->ss32) {
- if (s->addseg) {
- gen_op_movl_T1_A0();
- gen_op_addl_A0_SS();
- }
- } else {
- gen_op_andl_A0_ffff();
- gen_op_movl_T1_A0();
- gen_op_addl_A0_SS();
- }
- gen_op_st_T0_A0[s->dflag + 1 + s->mem_index]();
- if (s->ss32 && !s->addseg)
- gen_op_movl_ESP_A0();
- else
- gen_op_mov_reg_T1[s->ss32 + 1][R_ESP]();
- }
-}
-
-/* generate a push. It depends on ss32, addseg and dflag */
-/* slower version for T1, only used for call Ev */
-static void gen_push_T1(DisasContext *s)
-{
-#ifdef TARGET_X86_64
- if (CODE64(s)) {
- gen_op_movq_A0_reg[R_ESP]();
- if (s->dflag) {
- gen_op_subq_A0_8();
- gen_op_st_T1_A0[OT_QUAD + s->mem_index]();
- } else {
- gen_op_subq_A0_2();
- gen_op_st_T0_A0[OT_WORD + s->mem_index]();
- }
- gen_op_movq_ESP_A0();
- } else
-#endif
- {
- gen_op_movl_A0_reg[R_ESP]();
- if (!s->dflag)
- gen_op_subl_A0_2();
- else
- gen_op_subl_A0_4();
- if (s->ss32) {
- if (s->addseg) {
- gen_op_addl_A0_SS();
- }
- } else {
- gen_op_andl_A0_ffff();
- gen_op_addl_A0_SS();
- }
- gen_op_st_T1_A0[s->dflag + 1 + s->mem_index]();
-
- if (s->ss32 && !s->addseg)
- gen_op_movl_ESP_A0();
- else
- gen_stack_update(s, (-2) << s->dflag);
- }
-}
-
-/* two step pop is necessary for precise exceptions */
-static void gen_pop_T0(DisasContext *s)
-{
-#ifdef TARGET_X86_64
- if (CODE64(s)) {
- gen_op_movq_A0_reg[R_ESP]();
- gen_op_ld_T0_A0[(s->dflag ? OT_QUAD : OT_WORD) + s->mem_index]();
- } else
-#endif
- {
- gen_op_movl_A0_reg[R_ESP]();
- if (s->ss32) {
- if (s->addseg)
- gen_op_addl_A0_SS();
- } else {
- gen_op_andl_A0_ffff();
- gen_op_addl_A0_SS();
- }
- gen_op_ld_T0_A0[s->dflag + 1 + s->mem_index]();
- }
-}
-
-static void gen_pop_update(DisasContext *s)
-{
-#ifdef TARGET_X86_64
- if (CODE64(s) && s->dflag) {
- gen_stack_update(s, 8);
- } else
-#endif
- {
- gen_stack_update(s, 2 << s->dflag);
- }
-}
-
-static void gen_stack_A0(DisasContext *s)
-{
- gen_op_movl_A0_ESP();
- if (!s->ss32)
- gen_op_andl_A0_ffff();
- gen_op_movl_T1_A0();
- if (s->addseg)
- gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
-}
-
-/* NOTE: wrap around in 16 bit not fully handled */
-static void gen_pusha(DisasContext *s)
-{
- int i;
- gen_op_movl_A0_ESP();
- gen_op_addl_A0_im(-16 << s->dflag);
- if (!s->ss32)
- gen_op_andl_A0_ffff();
- gen_op_movl_T1_A0();
- if (s->addseg)
- gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
- for(i = 0;i < 8; i++) {
- gen_op_mov_TN_reg[OT_LONG][0][7 - i]();
- gen_op_st_T0_A0[OT_WORD + s->dflag + s->mem_index]();
- gen_op_addl_A0_im(2 << s->dflag);
- }
- gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP]();
-}
-
-/* NOTE: wrap around in 16 bit not fully handled */
-static void gen_popa(DisasContext *s)
-{
- int i;
- gen_op_movl_A0_ESP();
- if (!s->ss32)
- gen_op_andl_A0_ffff();
- gen_op_movl_T1_A0();
- gen_op_addl_T1_im(16 << s->dflag);
- if (s->addseg)
- gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
- for(i = 0;i < 8; i++) {
- /* ESP is not reloaded */
- if (i != 3) {
- gen_op_ld_T0_A0[OT_WORD + s->dflag + s->mem_index]();
- gen_op_mov_reg_T0[OT_WORD + s->dflag][7 - i]();
- }
- gen_op_addl_A0_im(2 << s->dflag);
- }
- gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP]();
-}
-
-static void gen_enter(DisasContext *s, int esp_addend, int level)
-{
- int ot, opsize;
-
- level &= 0x1f;
-#ifdef TARGET_X86_64
- if (CODE64(s)) {
- ot = s->dflag ? OT_QUAD : OT_WORD;
- opsize = 1 << ot;
-
- gen_op_movl_A0_ESP();
- gen_op_addq_A0_im(-opsize);
- gen_op_movl_T1_A0();
-
- /* push bp */
- gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
- gen_op_st_T0_A0[ot + s->mem_index]();
- if (level) {
- gen_op_enter64_level(level, (ot == OT_QUAD));
- }
- gen_op_mov_reg_T1[ot][R_EBP]();
- gen_op_addl_T1_im( -esp_addend + (-opsize * level) );
- gen_op_mov_reg_T1[OT_QUAD][R_ESP]();
- } else
-#endif
- {
- ot = s->dflag + OT_WORD;
- opsize = 2 << s->dflag;
-
- gen_op_movl_A0_ESP();
- gen_op_addl_A0_im(-opsize);
- if (!s->ss32)
- gen_op_andl_A0_ffff();
- gen_op_movl_T1_A0();
- if (s->addseg)
- gen_op_addl_A0_seg(offsetof(CPUX86State,segs[R_SS].base));
- /* push bp */
- gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
- gen_op_st_T0_A0[ot + s->mem_index]();
- if (level) {
- gen_op_enter_level(level, s->dflag);
- }
- gen_op_mov_reg_T1[ot][R_EBP]();
- gen_op_addl_T1_im( -esp_addend + (-opsize * level) );
- gen_op_mov_reg_T1[OT_WORD + s->ss32][R_ESP]();
- }
-}
-
-static void gen_exception(DisasContext *s, int trapno, target_ulong cur_eip)
-{
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(cur_eip);
- gen_op_raise_exception(trapno);
- s->is_jmp = 3;
-}
-
-/* an interrupt is different from an exception because of the
- priviledge checks */
-static void gen_interrupt(DisasContext *s, int intno,
- target_ulong cur_eip, target_ulong next_eip)
-{
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(cur_eip);
- gen_op_raise_interrupt(intno, (int)(next_eip - cur_eip));
- s->is_jmp = 3;
-}
-
-static void gen_debug(DisasContext *s, target_ulong cur_eip)
-{
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(cur_eip);
- gen_op_debug();
- s->is_jmp = 3;
-}
-
-/* generate a generic end of block. Trace exception is also generated
- if needed */
-static void gen_eob(DisasContext *s)
-{
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- if (s->tb->flags & HF_INHIBIT_IRQ_MASK) {
- gen_op_reset_inhibit_irq();
- }
- if (s->singlestep_enabled) {
- gen_op_debug();
- } else if (s->tf) {
- gen_op_raise_exception(EXCP01_SSTP);
- } else {
- gen_op_movl_T0_0();
- gen_op_exit_tb();
- }
- s->is_jmp = 3;
-}
-
-/* generate a jump to eip. No segment change must happen before as a
- direct call to the next block may occur */
-static void gen_jmp_tb(DisasContext *s, target_ulong eip, int tb_num)
-{
- if (s->jmp_opt) {
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- s->cc_op = CC_OP_DYNAMIC;
- }
- gen_goto_tb(s, tb_num, eip);
- s->is_jmp = 3;
- } else {
- gen_jmp_im(eip);
- gen_eob(s);
- }
-}
-
-static void gen_jmp(DisasContext *s, target_ulong eip)
-{
- gen_jmp_tb(s, eip, 0);
-}
-
-static void gen_movtl_T0_im(target_ulong val)
-{
-#ifdef TARGET_X86_64
- if ((int32_t)val == val) {
- gen_op_movl_T0_im(val);
- } else {
- gen_op_movq_T0_im64(val >> 32, val);
- }
-#else
- gen_op_movl_T0_im(val);
-#endif
-}
-
-static void gen_movtl_T1_im(target_ulong val)
-{
-#ifdef TARGET_X86_64
- if ((int32_t)val == val) {
- gen_op_movl_T1_im(val);
- } else {
- gen_op_movq_T1_im64(val >> 32, val);
- }
-#else
- gen_op_movl_T1_im(val);
-#endif
-}
-
-static void gen_add_A0_im(DisasContext *s, int val)
-{
-#ifdef TARGET_X86_64
- if (CODE64(s))
- gen_op_addq_A0_im(val);
- else
-#endif
- gen_op_addl_A0_im(val);
-}
-
-static GenOpFunc1 *gen_ldq_env_A0[3] = {
- gen_op_ldq_raw_env_A0,
-#ifndef CONFIG_USER_ONLY
- gen_op_ldq_kernel_env_A0,
- gen_op_ldq_user_env_A0,
-#endif
-};
-
-static GenOpFunc1 *gen_stq_env_A0[3] = {
- gen_op_stq_raw_env_A0,
-#ifndef CONFIG_USER_ONLY
- gen_op_stq_kernel_env_A0,
- gen_op_stq_user_env_A0,
-#endif
-};
-
-static GenOpFunc1 *gen_ldo_env_A0[3] = {
- gen_op_ldo_raw_env_A0,
-#ifndef CONFIG_USER_ONLY
- gen_op_ldo_kernel_env_A0,
- gen_op_ldo_user_env_A0,
-#endif
-};
-
-static GenOpFunc1 *gen_sto_env_A0[3] = {
- gen_op_sto_raw_env_A0,
-#ifndef CONFIG_USER_ONLY
- gen_op_sto_kernel_env_A0,
- gen_op_sto_user_env_A0,
-#endif
-};
-
-#define SSE_SPECIAL ((GenOpFunc2 *)1)
-
-#define MMX_OP2(x) { gen_op_ ## x ## _mmx, gen_op_ ## x ## _xmm }
-#define SSE_FOP(x) { gen_op_ ## x ## ps, gen_op_ ## x ## pd, \
- gen_op_ ## x ## ss, gen_op_ ## x ## sd, }
-
-static GenOpFunc2 *sse_op_table1[256][4] = {
- /* pure SSE operations */
- [0x10] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */
- [0x11] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movups, movupd, movss, movsd */
- [0x12] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd, movsldup, movddup */
- [0x13] = { SSE_SPECIAL, SSE_SPECIAL }, /* movlps, movlpd */
- [0x14] = { gen_op_punpckldq_xmm, gen_op_punpcklqdq_xmm },
- [0x15] = { gen_op_punpckhdq_xmm, gen_op_punpckhqdq_xmm },
- [0x16] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd, movshdup */
- [0x17] = { SSE_SPECIAL, SSE_SPECIAL }, /* movhps, movhpd */
-
- [0x28] = { SSE_SPECIAL, SSE_SPECIAL }, /* movaps, movapd */
- [0x29] = { SSE_SPECIAL, SSE_SPECIAL }, /* movaps, movapd */
- [0x2a] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtpi2ps, cvtpi2pd, cvtsi2ss, cvtsi2sd */
- [0x2b] = { SSE_SPECIAL, SSE_SPECIAL }, /* movntps, movntpd */
- [0x2c] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvttps2pi, cvttpd2pi, cvttsd2si, cvttss2si */
- [0x2d] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* cvtps2pi, cvtpd2pi, cvtsd2si, cvtss2si */
- [0x2e] = { gen_op_ucomiss, gen_op_ucomisd },
- [0x2f] = { gen_op_comiss, gen_op_comisd },
- [0x50] = { SSE_SPECIAL, SSE_SPECIAL }, /* movmskps, movmskpd */
- [0x51] = SSE_FOP(sqrt),
- [0x52] = { gen_op_rsqrtps, NULL, gen_op_rsqrtss, NULL },
- [0x53] = { gen_op_rcpps, NULL, gen_op_rcpss, NULL },
- [0x54] = { gen_op_pand_xmm, gen_op_pand_xmm }, /* andps, andpd */
- [0x55] = { gen_op_pandn_xmm, gen_op_pandn_xmm }, /* andnps, andnpd */
- [0x56] = { gen_op_por_xmm, gen_op_por_xmm }, /* orps, orpd */
- [0x57] = { gen_op_pxor_xmm, gen_op_pxor_xmm }, /* xorps, xorpd */
- [0x58] = SSE_FOP(add),
- [0x59] = SSE_FOP(mul),
- [0x5a] = { gen_op_cvtps2pd, gen_op_cvtpd2ps,
- gen_op_cvtss2sd, gen_op_cvtsd2ss },
- [0x5b] = { gen_op_cvtdq2ps, gen_op_cvtps2dq, gen_op_cvttps2dq },
- [0x5c] = SSE_FOP(sub),
- [0x5d] = SSE_FOP(min),
- [0x5e] = SSE_FOP(div),
- [0x5f] = SSE_FOP(max),
-
- [0xc2] = SSE_FOP(cmpeq),
- [0xc6] = { (GenOpFunc2 *)gen_op_shufps, (GenOpFunc2 *)gen_op_shufpd },
-
- /* MMX ops and their SSE extensions */
- [0x60] = MMX_OP2(punpcklbw),
- [0x61] = MMX_OP2(punpcklwd),
- [0x62] = MMX_OP2(punpckldq),
- [0x63] = MMX_OP2(packsswb),
- [0x64] = MMX_OP2(pcmpgtb),
- [0x65] = MMX_OP2(pcmpgtw),
- [0x66] = MMX_OP2(pcmpgtl),
- [0x67] = MMX_OP2(packuswb),
- [0x68] = MMX_OP2(punpckhbw),
- [0x69] = MMX_OP2(punpckhwd),
- [0x6a] = MMX_OP2(punpckhdq),
- [0x6b] = MMX_OP2(packssdw),
- [0x6c] = { NULL, gen_op_punpcklqdq_xmm },
- [0x6d] = { NULL, gen_op_punpckhqdq_xmm },
- [0x6e] = { SSE_SPECIAL, SSE_SPECIAL }, /* movd mm, ea */
- [0x6f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, , movqdu */
- [0x70] = { (GenOpFunc2 *)gen_op_pshufw_mmx,
- (GenOpFunc2 *)gen_op_pshufd_xmm,
- (GenOpFunc2 *)gen_op_pshufhw_xmm,
- (GenOpFunc2 *)gen_op_pshuflw_xmm },
- [0x71] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftw */
- [0x72] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftd */
- [0x73] = { SSE_SPECIAL, SSE_SPECIAL }, /* shiftq */
- [0x74] = MMX_OP2(pcmpeqb),
- [0x75] = MMX_OP2(pcmpeqw),
- [0x76] = MMX_OP2(pcmpeql),
- [0x77] = { SSE_SPECIAL }, /* emms */
- [0x7c] = { NULL, gen_op_haddpd, NULL, gen_op_haddps },
- [0x7d] = { NULL, gen_op_hsubpd, NULL, gen_op_hsubps },
- [0x7e] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movd, movd, , movq */
- [0x7f] = { SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL }, /* movq, movdqa, movdqu */
- [0xc4] = { SSE_SPECIAL, SSE_SPECIAL }, /* pinsrw */
- [0xc5] = { SSE_SPECIAL, SSE_SPECIAL }, /* pextrw */
- [0xd0] = { NULL, gen_op_addsubpd, NULL, gen_op_addsubps },
- [0xd1] = MMX_OP2(psrlw),
- [0xd2] = MMX_OP2(psrld),
- [0xd3] = MMX_OP2(psrlq),
- [0xd4] = MMX_OP2(paddq),
- [0xd5] = MMX_OP2(pmullw),
- [0xd6] = { NULL, SSE_SPECIAL, SSE_SPECIAL, SSE_SPECIAL },
- [0xd7] = { SSE_SPECIAL, SSE_SPECIAL }, /* pmovmskb */
- [0xd8] = MMX_OP2(psubusb),
- [0xd9] = MMX_OP2(psubusw),
- [0xda] = MMX_OP2(pminub),
- [0xdb] = MMX_OP2(pand),
- [0xdc] = MMX_OP2(paddusb),
- [0xdd] = MMX_OP2(paddusw),
- [0xde] = MMX_OP2(pmaxub),
- [0xdf] = MMX_OP2(pandn),
- [0xe0] = MMX_OP2(pavgb),
- [0xe1] = MMX_OP2(psraw),
- [0xe2] = MMX_OP2(psrad),
- [0xe3] = MMX_OP2(pavgw),
- [0xe4] = MMX_OP2(pmulhuw),
- [0xe5] = MMX_OP2(pmulhw),
- [0xe6] = { NULL, gen_op_cvttpd2dq, gen_op_cvtdq2pd, gen_op_cvtpd2dq },
- [0xe7] = { SSE_SPECIAL , SSE_SPECIAL }, /* movntq, movntq */
- [0xe8] = MMX_OP2(psubsb),
- [0xe9] = MMX_OP2(psubsw),
- [0xea] = MMX_OP2(pminsw),
- [0xeb] = MMX_OP2(por),
- [0xec] = MMX_OP2(paddsb),
- [0xed] = MMX_OP2(paddsw),
- [0xee] = MMX_OP2(pmaxsw),
- [0xef] = MMX_OP2(pxor),
- [0xf0] = { NULL, NULL, NULL, SSE_SPECIAL }, /* lddqu */
- [0xf1] = MMX_OP2(psllw),
- [0xf2] = MMX_OP2(pslld),
- [0xf3] = MMX_OP2(psllq),
- [0xf4] = MMX_OP2(pmuludq),
- [0xf5] = MMX_OP2(pmaddwd),
- [0xf6] = MMX_OP2(psadbw),
- [0xf7] = MMX_OP2(maskmov),
- [0xf8] = MMX_OP2(psubb),
- [0xf9] = MMX_OP2(psubw),
- [0xfa] = MMX_OP2(psubl),
- [0xfb] = MMX_OP2(psubq),
- [0xfc] = MMX_OP2(paddb),
- [0xfd] = MMX_OP2(paddw),
- [0xfe] = MMX_OP2(paddl),
-};
-
-static GenOpFunc2 *sse_op_table2[3 * 8][2] = {
- [0 + 2] = MMX_OP2(psrlw),
- [0 + 4] = MMX_OP2(psraw),
- [0 + 6] = MMX_OP2(psllw),
- [8 + 2] = MMX_OP2(psrld),
- [8 + 4] = MMX_OP2(psrad),
- [8 + 6] = MMX_OP2(pslld),
- [16 + 2] = MMX_OP2(psrlq),
- [16 + 3] = { NULL, gen_op_psrldq_xmm },
- [16 + 6] = MMX_OP2(psllq),
- [16 + 7] = { NULL, gen_op_pslldq_xmm },
-};
-
-static GenOpFunc1 *sse_op_table3[4 * 3] = {
- gen_op_cvtsi2ss,
- gen_op_cvtsi2sd,
- X86_64_ONLY(gen_op_cvtsq2ss),
- X86_64_ONLY(gen_op_cvtsq2sd),
-
- gen_op_cvttss2si,
- gen_op_cvttsd2si,
- X86_64_ONLY(gen_op_cvttss2sq),
- X86_64_ONLY(gen_op_cvttsd2sq),
-
- gen_op_cvtss2si,
- gen_op_cvtsd2si,
- X86_64_ONLY(gen_op_cvtss2sq),
- X86_64_ONLY(gen_op_cvtsd2sq),
-};
-
-static GenOpFunc2 *sse_op_table4[8][4] = {
- SSE_FOP(cmpeq),
- SSE_FOP(cmplt),
- SSE_FOP(cmple),
- SSE_FOP(cmpunord),
- SSE_FOP(cmpneq),
- SSE_FOP(cmpnlt),
- SSE_FOP(cmpnle),
- SSE_FOP(cmpord),
-};
-
-static void gen_sse(DisasContext *s, int b, target_ulong pc_start, int rex_r)
-{
- int b1, op1_offset, op2_offset, is_xmm, val, ot;
- int modrm, mod, rm, reg, reg_addr, offset_addr;
- GenOpFunc2 *sse_op2;
- GenOpFunc3 *sse_op3;
-
- b &= 0xff;
- if (s->prefix & PREFIX_DATA)
- b1 = 1;
- else if (s->prefix & PREFIX_REPZ)
- b1 = 2;
- else if (s->prefix & PREFIX_REPNZ)
- b1 = 3;
- else
- b1 = 0;
- sse_op2 = sse_op_table1[b][b1];
- if (!sse_op2)
- goto illegal_op;
- if (b <= 0x5f || b == 0xc6 || b == 0xc2) {
- is_xmm = 1;
- } else {
- if (b1 == 0) {
- /* MMX case */
- is_xmm = 0;
- } else {
- is_xmm = 1;
- }
- }
- /* simple MMX/SSE operation */
- if (s->flags & HF_TS_MASK) {
- gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
- return;
- }
- if (s->flags & HF_EM_MASK) {
- illegal_op:
- gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
- return;
- }
- if (is_xmm && !(s->flags & HF_OSFXSR_MASK))
- goto illegal_op;
- if (b == 0x77) {
- /* emms */
- gen_op_emms();
- return;
- }
- /* prepare MMX state (XXX: optimize by storing fptt and fptags in
- the static cpu state) */
- if (!is_xmm) {
- gen_op_enter_mmx();
- }
-
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7);
- if (is_xmm)
- reg |= rex_r;
- mod = (modrm >> 6) & 3;
- if (sse_op2 == SSE_SPECIAL) {
- b |= (b1 << 8);
- switch(b) {
- case 0x0e7: /* movntq */
- if (mod == 3)
- goto illegal_op;
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx));
- break;
- case 0x1e7: /* movntdq */
- case 0x02b: /* movntps */
- case 0x12b: /* movntps */
- case 0x3f0: /* lddqu */
- if (mod == 3)
- goto illegal_op;
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- 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));
- 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]));
- break;
- case 0x6f: /* movq mm, ea */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx));
- } else {
- rm = (modrm & 7);
- gen_op_movq(offsetof(CPUX86State,fpregs[reg].mmx),
- offsetof(CPUX86State,fpregs[rm].mmx));
- }
- break;
- case 0x010: /* movups */
- case 0x110: /* movupd */
- case 0x028: /* movaps */
- case 0x128: /* movapd */
- case 0x16f: /* movdqa xmm, ea */
- case 0x26f: /* movdqu xmm, ea */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg]));
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movo(offsetof(CPUX86State,xmm_regs[reg]),
- offsetof(CPUX86State,xmm_regs[rm]));
- }
- break;
- case 0x210: /* movss xmm, ea */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_T0_A0[OT_LONG + s->mem_index]();
- gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
- gen_op_movl_T0_0();
- gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)));
- gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)));
- gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)));
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)),
- offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)));
- }
- break;
- case 0x310: /* movsd xmm, ea */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
- gen_op_movl_T0_0();
- gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)));
- gen_op_movl_env_T0(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)));
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
- offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
- }
- break;
- case 0x012: /* movlps */
- case 0x112: /* movlpd */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
- } else {
- /* movhlps */
- rm = (modrm & 7) | REX_B(s);
- gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
- offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1)));
- }
- break;
- case 0x212: /* movsldup */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg]));
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)),
- offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)));
- gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)),
- offsetof(CPUX86State,xmm_regs[rm].XMM_L(2)));
- }
- gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)),
- offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
- gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)),
- offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)));
- break;
- case 0x312: /* movddup */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
- offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
- }
- gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)),
- offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
- break;
- case 0x016: /* movhps */
- case 0x116: /* movhpd */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
- } else {
- /* movlhps */
- rm = (modrm & 7) | REX_B(s);
- gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)),
- offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
- }
- break;
- case 0x216: /* movshdup */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_ldo_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg]));
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)),
- offsetof(CPUX86State,xmm_regs[rm].XMM_L(1)));
- gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)),
- offsetof(CPUX86State,xmm_regs[rm].XMM_L(3)));
- }
- gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)),
- offsetof(CPUX86State,xmm_regs[reg].XMM_L(1)));
- gen_op_movl(offsetof(CPUX86State,xmm_regs[reg].XMM_L(2)),
- 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);
- 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);
- break;
- case 0x27e: /* movq xmm, ea */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
- offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
- }
- gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
- break;
- case 0x7f: /* movq ea, mm */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,fpregs[reg].mmx));
- } else {
- rm = (modrm & 7);
- gen_op_movq(offsetof(CPUX86State,fpregs[rm].mmx),
- offsetof(CPUX86State,fpregs[reg].mmx));
- }
- break;
- case 0x011: /* movups */
- case 0x111: /* movupd */
- case 0x029: /* movaps */
- case 0x129: /* movapd */
- case 0x17f: /* movdqa ea, xmm */
- case 0x27f: /* movdqu ea, xmm */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg]));
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movo(offsetof(CPUX86State,xmm_regs[rm]),
- offsetof(CPUX86State,xmm_regs[reg]));
- }
- break;
- case 0x211: /* movss ea, xmm */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_movl_T0_env(offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
- gen_op_st_T0_A0[OT_LONG + s->mem_index]();
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movl(offsetof(CPUX86State,xmm_regs[rm].XMM_L(0)),
- offsetof(CPUX86State,xmm_regs[reg].XMM_L(0)));
- }
- break;
- case 0x311: /* movsd ea, xmm */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)),
- offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
- }
- break;
- case 0x013: /* movlps */
- case 0x113: /* movlpd */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
- } else {
- goto illegal_op;
- }
- break;
- case 0x017: /* movhps */
- case 0x117: /* movhpd */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
- } else {
- goto illegal_op;
- }
- break;
- case 0x71: /* shift mm, im */
- case 0x72:
- case 0x73:
- case 0x171: /* shift xmm, im */
- case 0x172:
- case 0x173:
- val = ldub_code(s->pc++);
- if (is_xmm) {
- gen_op_movl_T0_im(val);
- gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(0)));
- gen_op_movl_T0_0();
- gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(1)));
- op1_offset = offsetof(CPUX86State,xmm_t0);
- } else {
- gen_op_movl_T0_im(val);
- gen_op_movl_env_T0(offsetof(CPUX86State,mmx_t0.MMX_L(0)));
- gen_op_movl_T0_0();
- gen_op_movl_env_T0(offsetof(CPUX86State,mmx_t0.MMX_L(1)));
- op1_offset = offsetof(CPUX86State,mmx_t0);
- }
- sse_op2 = sse_op_table2[((b - 1) & 3) * 8 + (((modrm >> 3)) & 7)][b1];
- if (!sse_op2)
- goto illegal_op;
- if (is_xmm) {
- rm = (modrm & 7) | REX_B(s);
- op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
- } else {
- rm = (modrm & 7);
- op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
- }
- sse_op2(op2_offset, op1_offset);
- break;
- case 0x050: /* movmskps */
- rm = (modrm & 7) | REX_B(s);
- gen_op_movmskps(offsetof(CPUX86State,xmm_regs[rm]));
- gen_op_mov_reg_T0[OT_LONG][reg]();
- break;
- case 0x150: /* movmskpd */
- rm = (modrm & 7) | REX_B(s);
- gen_op_movmskpd(offsetof(CPUX86State,xmm_regs[rm]));
- gen_op_mov_reg_T0[OT_LONG][reg]();
- break;
- case 0x02a: /* cvtpi2ps */
- case 0x12a: /* cvtpi2pd */
- gen_op_enter_mmx();
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- op2_offset = offsetof(CPUX86State,mmx_t0);
- gen_ldq_env_A0[s->mem_index >> 2](op2_offset);
- } else {
- rm = (modrm & 7);
- op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
- }
- op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
- switch(b >> 8) {
- case 0x0:
- gen_op_cvtpi2ps(op1_offset, op2_offset);
- break;
- default:
- case 0x1:
- gen_op_cvtpi2pd(op1_offset, op2_offset);
- break;
- }
- break;
- case 0x22a: /* cvtsi2ss */
- case 0x32a: /* cvtsi2sd */
- ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
- gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
- op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
- sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2)](op1_offset);
- break;
- case 0x02c: /* cvttps2pi */
- case 0x12c: /* cvttpd2pi */
- case 0x02d: /* cvtps2pi */
- case 0x12d: /* cvtpd2pi */
- gen_op_enter_mmx();
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- op2_offset = offsetof(CPUX86State,xmm_t0);
- gen_ldo_env_A0[s->mem_index >> 2](op2_offset);
- } else {
- rm = (modrm & 7) | REX_B(s);
- op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
- }
- op1_offset = offsetof(CPUX86State,fpregs[reg & 7].mmx);
- switch(b) {
- case 0x02c:
- gen_op_cvttps2pi(op1_offset, op2_offset);
- break;
- case 0x12c:
- gen_op_cvttpd2pi(op1_offset, op2_offset);
- break;
- case 0x02d:
- gen_op_cvtps2pi(op1_offset, op2_offset);
- break;
- case 0x12d:
- gen_op_cvtpd2pi(op1_offset, op2_offset);
- break;
- }
- break;
- case 0x22c: /* cvttss2si */
- case 0x32c: /* cvttsd2si */
- case 0x22d: /* cvtss2si */
- case 0x32d: /* cvtsd2si */
- ot = (s->dflag == 2) ? OT_QUAD : OT_LONG;
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- if ((b >> 8) & 1) {
- gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_t0.XMM_Q(0)));
- } else {
- gen_op_ld_T0_A0[OT_LONG + s->mem_index]();
- gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(0)));
- }
- op2_offset = offsetof(CPUX86State,xmm_t0);
- } else {
- rm = (modrm & 7) | REX_B(s);
- op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
- }
- sse_op_table3[(s->dflag == 2) * 2 + ((b >> 8) - 2) + 4 +
- (b & 1) * 4](op2_offset);
- gen_op_mov_reg_T0[ot][reg]();
- break;
- case 0xc4: /* pinsrw */
- case 0x1c4:
- s->rip_offset = 1;
- gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
- val = ldub_code(s->pc++);
- if (b1) {
- val &= 7;
- gen_op_pinsrw_xmm(offsetof(CPUX86State,xmm_regs[reg]), val);
- } else {
- val &= 3;
- gen_op_pinsrw_mmx(offsetof(CPUX86State,fpregs[reg].mmx), val);
- }
- break;
- case 0xc5: /* pextrw */
- case 0x1c5:
- if (mod != 3)
- goto illegal_op;
- val = ldub_code(s->pc++);
- if (b1) {
- val &= 7;
- rm = (modrm & 7) | REX_B(s);
- gen_op_pextrw_xmm(offsetof(CPUX86State,xmm_regs[rm]), val);
- } else {
- val &= 3;
- rm = (modrm & 7);
- gen_op_pextrw_mmx(offsetof(CPUX86State,fpregs[rm].mmx), val);
- }
- reg = ((modrm >> 3) & 7) | rex_r;
- gen_op_mov_reg_T0[OT_LONG][reg]();
- break;
- case 0x1d6: /* movq ea, xmm */
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_stq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_movq(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)),
- offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)));
- gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[rm].XMM_Q(1)));
- }
- break;
- case 0x2d6: /* movq2dq */
- gen_op_enter_mmx();
- rm = (modrm & 7);
- gen_op_movq(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(0)),
- offsetof(CPUX86State,fpregs[rm].mmx));
- gen_op_movq_env_0(offsetof(CPUX86State,xmm_regs[reg].XMM_Q(1)));
- break;
- case 0x3d6: /* movdq2q */
- gen_op_enter_mmx();
- rm = (modrm & 7) | REX_B(s);
- gen_op_movq(offsetof(CPUX86State,fpregs[reg & 7].mmx),
- offsetof(CPUX86State,xmm_regs[rm].XMM_Q(0)));
- break;
- case 0xd7: /* pmovmskb */
- case 0x1d7:
- if (mod != 3)
- goto illegal_op;
- if (b1) {
- rm = (modrm & 7) | REX_B(s);
- gen_op_pmovmskb_xmm(offsetof(CPUX86State,xmm_regs[rm]));
- } else {
- rm = (modrm & 7);
- gen_op_pmovmskb_mmx(offsetof(CPUX86State,fpregs[rm].mmx));
- }
- reg = ((modrm >> 3) & 7) | rex_r;
- gen_op_mov_reg_T0[OT_LONG][reg]();
- break;
- default:
- goto illegal_op;
- }
- } else {
- /* generic MMX or SSE operation */
- switch(b) {
- case 0xf7:
- /* maskmov : we must prepare A0 */
- if (mod != 3)
- goto illegal_op;
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_movq_A0_reg[R_EDI]();
- } else
-#endif
- {
- gen_op_movl_A0_reg[R_EDI]();
- if (s->aflag == 0)
- gen_op_andl_A0_ffff();
- }
- gen_add_A0_ds_seg(s);
- break;
- case 0x70: /* pshufx insn */
- case 0xc6: /* pshufx insn */
- case 0xc2: /* compare insns */
- s->rip_offset = 1;
- break;
- default:
- break;
- }
- if (is_xmm) {
- op1_offset = offsetof(CPUX86State,xmm_regs[reg]);
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- op2_offset = offsetof(CPUX86State,xmm_t0);
- if (b1 >= 2 && ((b >= 0x50 && b <= 0x5f && b != 0x5b) ||
- b == 0xc2)) {
- /* specific case for SSE single instructions */
- if (b1 == 2) {
- /* 32 bit access */
- gen_op_ld_T0_A0[OT_LONG + s->mem_index]();
- gen_op_movl_env_T0(offsetof(CPUX86State,xmm_t0.XMM_L(0)));
- } else {
- /* 64 bit access */
- gen_ldq_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_t0.XMM_D(0)));
- }
- } else {
- gen_ldo_env_A0[s->mem_index >> 2](op2_offset);
- }
- } else {
- rm = (modrm & 7) | REX_B(s);
- op2_offset = offsetof(CPUX86State,xmm_regs[rm]);
- }
- } else {
- op1_offset = offsetof(CPUX86State,fpregs[reg].mmx);
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- op2_offset = offsetof(CPUX86State,mmx_t0);
- gen_ldq_env_A0[s->mem_index >> 2](op2_offset);
- } else {
- rm = (modrm & 7);
- op2_offset = offsetof(CPUX86State,fpregs[rm].mmx);
- }
- }
- switch(b) {
- case 0x70: /* pshufx insn */
- case 0xc6: /* pshufx insn */
- val = ldub_code(s->pc++);
- sse_op3 = (GenOpFunc3 *)sse_op2;
- sse_op3(op1_offset, op2_offset, val);
- break;
- case 0xc2:
- /* compare insns */
- val = ldub_code(s->pc++);
- if (val >= 8)
- goto illegal_op;
- sse_op2 = sse_op_table4[val][b1];
- sse_op2(op1_offset, op2_offset);
- break;
- default:
- sse_op2(op1_offset, op2_offset);
- break;
- }
- if (b == 0x2e || b == 0x2f) {
- s->cc_op = CC_OP_EFLAGS;
- }
- }
-}
-
-
-/* convert one instruction. s->is_jmp is set if the translation must
- be stopped. Return the next pc value */
-static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
-{
- int b, prefixes, aflag, dflag;
- int shift, ot;
- int modrm, reg, rm, mod, reg_addr, op, opreg, offset_addr, val;
- target_ulong next_eip, tval;
- int rex_w, rex_r;
-
- s->pc = pc_start;
- prefixes = 0;
- aflag = s->code32;
- dflag = s->code32;
- s->override = -1;
- rex_w = -1;
- rex_r = 0;
-#ifdef TARGET_X86_64
- s->rex_x = 0;
- s->rex_b = 0;
- x86_64_hregs = 0;
-#endif
- s->rip_offset = 0; /* for relative ip address */
- next_byte:
- b = ldub_code(s->pc);
- s->pc++;
- /* check prefixes */
-#ifdef TARGET_X86_64
- if (CODE64(s)) {
- switch (b) {
- case 0xf3:
- prefixes |= PREFIX_REPZ;
- goto next_byte;
- case 0xf2:
- prefixes |= PREFIX_REPNZ;
- goto next_byte;
- case 0xf0:
- prefixes |= PREFIX_LOCK;
- goto next_byte;
- case 0x2e:
- s->override = R_CS;
- goto next_byte;
- case 0x36:
- s->override = R_SS;
- goto next_byte;
- case 0x3e:
- s->override = R_DS;
- goto next_byte;
- case 0x26:
- s->override = R_ES;
- goto next_byte;
- case 0x64:
- s->override = R_FS;
- goto next_byte;
- case 0x65:
- s->override = R_GS;
- goto next_byte;
- case 0x66:
- prefixes |= PREFIX_DATA;
- goto next_byte;
- case 0x67:
- prefixes |= PREFIX_ADR;
- goto next_byte;
- case 0x40 ... 0x4f:
- /* REX prefix */
- rex_w = (b >> 3) & 1;
- rex_r = (b & 0x4) << 1;
- s->rex_x = (b & 0x2) << 2;
- REX_B(s) = (b & 0x1) << 3;
- x86_64_hregs = 1; /* select uniform byte register addressing */
- goto next_byte;
- }
- if (rex_w == 1) {
- /* 0x66 is ignored if rex.w is set */
- dflag = 2;
- } else {
- if (prefixes & PREFIX_DATA)
- dflag ^= 1;
- }
- if (!(prefixes & PREFIX_ADR))
- aflag = 2;
- } else
-#endif
- {
- switch (b) {
- case 0xf3:
- prefixes |= PREFIX_REPZ;
- goto next_byte;
- case 0xf2:
- prefixes |= PREFIX_REPNZ;
- goto next_byte;
- case 0xf0:
- prefixes |= PREFIX_LOCK;
- goto next_byte;
- case 0x2e:
- s->override = R_CS;
- goto next_byte;
- case 0x36:
- s->override = R_SS;
- goto next_byte;
- case 0x3e:
- s->override = R_DS;
- goto next_byte;
- case 0x26:
- s->override = R_ES;
- goto next_byte;
- case 0x64:
- s->override = R_FS;
- goto next_byte;
- case 0x65:
- s->override = R_GS;
- goto next_byte;
- case 0x66:
- prefixes |= PREFIX_DATA;
- goto next_byte;
- case 0x67:
- prefixes |= PREFIX_ADR;
- goto next_byte;
- }
- if (prefixes & PREFIX_DATA)
- dflag ^= 1;
- if (prefixes & PREFIX_ADR)
- aflag ^= 1;
- }
-
- s->prefix = prefixes;
- s->aflag = aflag;
- s->dflag = dflag;
-
- /* lock generation */
- if (prefixes & PREFIX_LOCK)
- gen_op_lock();
-
- /* now check op code */
- reswitch:
- switch(b) {
- case 0x0f:
- /**************************/
- /* extended op code */
- b = ldub_code(s->pc++) | 0x100;
- goto reswitch;
-
- /**************************/
- /* arith & logic */
- case 0x00 ... 0x05:
- case 0x08 ... 0x0d:
- case 0x10 ... 0x15:
- case 0x18 ... 0x1d:
- case 0x20 ... 0x25:
- case 0x28 ... 0x2d:
- case 0x30 ... 0x35:
- case 0x38 ... 0x3d:
- {
- int op, f, val;
- op = (b >> 3) & 7;
- f = (b >> 1) & 3;
-
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
-
- switch(f) {
- case 0: /* OP Ev, Gv */
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- opreg = OR_TMP0;
- } else if (op == OP_XORL && rm == reg) {
- xor_zero:
- /* xor reg, reg optimisation */
- gen_op_movl_T0_0();
- s->cc_op = CC_OP_LOGICB + ot;
- gen_op_mov_reg_T0[ot][reg]();
- gen_op_update1_cc();
- break;
- } else {
- opreg = rm;
- }
- gen_op_mov_TN_reg[ot][1][reg]();
- gen_op(s, op, ot, opreg);
- break;
- case 1: /* OP Gv, Ev */
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- reg = ((modrm >> 3) & 7) | rex_r;
- rm = (modrm & 7) | REX_B(s);
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_T1_A0[ot + s->mem_index]();
- } else if (op == OP_XORL && rm == reg) {
- goto xor_zero;
- } else {
- gen_op_mov_TN_reg[ot][1][rm]();
- }
- gen_op(s, op, ot, reg);
- break;
- case 2: /* OP A, Iv */
- val = insn_get(s, ot);
- gen_op_movl_T1_im(val);
- gen_op(s, op, ot, OR_EAX);
- break;
- }
- }
- break;
-
- case 0x80: /* GRP1 */
- case 0x81:
- case 0x82:
- case 0x83:
- {
- int val;
-
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
-
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
- op = (modrm >> 3) & 7;
-
- if (mod != 3) {
- if (b == 0x83)
- s->rip_offset = 1;
- else
- s->rip_offset = insn_const_size(ot);
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- opreg = OR_TMP0;
- } else {
- opreg = rm;
- }
-
- switch(b) {
- default:
- case 0x80:
- case 0x81:
- case 0x82:
- val = insn_get(s, ot);
- break;
- case 0x83:
- val = (int8_t)insn_get(s, OT_BYTE);
- break;
- }
- gen_op_movl_T1_im(val);
- gen_op(s, op, ot, opreg);
- }
- break;
-
- /**************************/
- /* inc, dec, and other misc arith */
- case 0x40 ... 0x47: /* inc Gv */
- ot = dflag ? OT_LONG : OT_WORD;
- gen_inc(s, ot, OR_EAX + (b & 7), 1);
- break;
- case 0x48 ... 0x4f: /* dec Gv */
- ot = dflag ? OT_LONG : OT_WORD;
- gen_inc(s, ot, OR_EAX + (b & 7), -1);
- break;
- case 0xf6: /* GRP3 */
- case 0xf7:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
-
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
- op = (modrm >> 3) & 7;
- if (mod != 3) {
- if (op == 0)
- s->rip_offset = insn_const_size(ot);
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_mov_TN_reg[ot][0][rm]();
- }
-
- switch(op) {
- case 0: /* test */
- val = insn_get(s, ot);
- gen_op_movl_T1_im(val);
- gen_op_testl_T0_T1_cc();
- s->cc_op = CC_OP_LOGICB + ot;
- break;
- case 2: /* not */
- gen_op_notl_T0();
- if (mod != 3) {
- gen_op_st_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_mov_reg_T0[ot][rm]();
- }
- break;
- case 3: /* neg */
- gen_op_negl_T0();
- if (mod != 3) {
- gen_op_st_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_mov_reg_T0[ot][rm]();
- }
- gen_op_update_neg_cc();
- s->cc_op = CC_OP_SUBB + ot;
- break;
- case 4: /* mul */
- switch(ot) {
- case OT_BYTE:
- gen_op_mulb_AL_T0();
- s->cc_op = CC_OP_MULB;
- break;
- case OT_WORD:
- gen_op_mulw_AX_T0();
- s->cc_op = CC_OP_MULW;
- break;
- default:
- case OT_LONG:
- gen_op_mull_EAX_T0();
- s->cc_op = CC_OP_MULL;
- break;
-#ifdef TARGET_X86_64
- case OT_QUAD:
- gen_op_mulq_EAX_T0();
- s->cc_op = CC_OP_MULQ;
- break;
-#endif
- }
- break;
- case 5: /* imul */
- switch(ot) {
- case OT_BYTE:
- gen_op_imulb_AL_T0();
- s->cc_op = CC_OP_MULB;
- break;
- case OT_WORD:
- gen_op_imulw_AX_T0();
- s->cc_op = CC_OP_MULW;
- break;
- default:
- case OT_LONG:
- gen_op_imull_EAX_T0();
- s->cc_op = CC_OP_MULL;
- break;
-#ifdef TARGET_X86_64
- case OT_QUAD:
- gen_op_imulq_EAX_T0();
- s->cc_op = CC_OP_MULQ;
- break;
-#endif
- }
- break;
- case 6: /* div */
- switch(ot) {
- case OT_BYTE:
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_divb_AL_T0();
- break;
- case OT_WORD:
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_divw_AX_T0();
- break;
- default:
- case OT_LONG:
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_divl_EAX_T0();
- break;
-#ifdef TARGET_X86_64
- case OT_QUAD:
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_divq_EAX_T0();
- break;
-#endif
- }
- break;
- case 7: /* idiv */
- switch(ot) {
- case OT_BYTE:
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_idivb_AL_T0();
- break;
- case OT_WORD:
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_idivw_AX_T0();
- break;
- default:
- case OT_LONG:
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_idivl_EAX_T0();
- break;
-#ifdef TARGET_X86_64
- case OT_QUAD:
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_idivq_EAX_T0();
- break;
-#endif
- }
- break;
- default:
- goto illegal_op;
- }
- break;
-
- case 0xfe: /* GRP4 */
- case 0xff: /* GRP5 */
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
-
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
- op = (modrm >> 3) & 7;
- if (op >= 2 && b == 0xfe) {
- goto illegal_op;
- }
- if (CODE64(s)) {
- if (op == 2 || op == 4) {
- /* operand size for jumps is 64 bit */
- ot = OT_QUAD;
- } else if (op == 3 || op == 5) {
- /* for call calls, the operand is 16 or 32 bit, even
- in long mode */
- ot = dflag ? OT_LONG : OT_WORD;
- } else if (op == 6) {
- /* default push size is 64 bit */
- ot = dflag ? OT_QUAD : OT_WORD;
- }
- }
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- if (op >= 2 && op != 3 && op != 5)
- gen_op_ld_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_mov_TN_reg[ot][0][rm]();
- }
-
- switch(op) {
- case 0: /* inc Ev */
- if (mod != 3)
- opreg = OR_TMP0;
- else
- opreg = rm;
- gen_inc(s, ot, opreg, 1);
- break;
- case 1: /* dec Ev */
- if (mod != 3)
- opreg = OR_TMP0;
- else
- opreg = rm;
- gen_inc(s, ot, opreg, -1);
- break;
- case 2: /* call Ev */
- /* XXX: optimize if memory (no 'and' is necessary) */
- if (s->dflag == 0)
- gen_op_andl_T0_ffff();
- next_eip = s->pc - s->cs_base;
- gen_movtl_T1_im(next_eip);
- gen_push_T1(s);
- gen_op_jmp_T0();
- gen_eob(s);
- break;
- case 3: /* lcall Ev */
- gen_op_ld_T1_A0[ot + s->mem_index]();
- gen_add_A0_im(s, 1 << (ot - OT_WORD + 1));
- gen_op_ldu_T0_A0[OT_WORD + s->mem_index]();
- do_lcall:
- if (s->pe && !s->vm86) {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_lcall_protected_T0_T1(dflag, s->pc - pc_start);
- } else {
- gen_op_lcall_real_T0_T1(dflag, s->pc - s->cs_base);
- }
- gen_eob(s);
- break;
- case 4: /* jmp Ev */
- if (s->dflag == 0)
- gen_op_andl_T0_ffff();
- gen_op_jmp_T0();
- gen_eob(s);
- break;
- case 5: /* ljmp Ev */
- gen_op_ld_T1_A0[ot + s->mem_index]();
- gen_add_A0_im(s, 1 << (ot - OT_WORD + 1));
- gen_op_ldu_T0_A0[OT_WORD + s->mem_index]();
- do_ljmp:
- if (s->pe && !s->vm86) {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_ljmp_protected_T0_T1(s->pc - pc_start);
- } else {
- gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
- gen_op_movl_T0_T1();
- gen_op_jmp_T0();
- }
- gen_eob(s);
- break;
- case 6: /* push Ev */
- gen_push_T0(s);
- break;
- default:
- goto illegal_op;
- }
- break;
-
- case 0x84: /* test Ev, Gv */
- case 0x85:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
-
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
- reg = ((modrm >> 3) & 7) | rex_r;
-
- gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
- gen_op_mov_TN_reg[ot][1][reg]();
- gen_op_testl_T0_T1_cc();
- s->cc_op = CC_OP_LOGICB + ot;
- break;
-
- case 0xa8: /* test eAX, Iv */
- case 0xa9:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
- val = insn_get(s, ot);
-
- gen_op_mov_TN_reg[ot][0][OR_EAX]();
- gen_op_movl_T1_im(val);
- gen_op_testl_T0_T1_cc();
- s->cc_op = CC_OP_LOGICB + ot;
- break;
-
- case 0x98: /* CWDE/CBW */
-#ifdef TARGET_X86_64
- if (dflag == 2) {
- gen_op_movslq_RAX_EAX();
- } else
-#endif
- if (dflag == 1)
- gen_op_movswl_EAX_AX();
- else
- gen_op_movsbw_AX_AL();
- break;
- case 0x99: /* CDQ/CWD */
-#ifdef TARGET_X86_64
- if (dflag == 2) {
- gen_op_movsqo_RDX_RAX();
- } else
-#endif
- if (dflag == 1)
- gen_op_movslq_EDX_EAX();
- else
- gen_op_movswl_DX_AX();
- break;
- case 0x1af: /* imul Gv, Ev */
- case 0x69: /* imul Gv, Ev, I */
- case 0x6b:
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- if (b == 0x69)
- s->rip_offset = insn_const_size(ot);
- else if (b == 0x6b)
- s->rip_offset = 1;
- gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
- if (b == 0x69) {
- val = insn_get(s, ot);
- gen_op_movl_T1_im(val);
- } else if (b == 0x6b) {
- val = (int8_t)insn_get(s, OT_BYTE);
- gen_op_movl_T1_im(val);
- } else {
- gen_op_mov_TN_reg[ot][1][reg]();
- }
-
-#ifdef TARGET_X86_64
- if (ot == OT_QUAD) {
- gen_op_imulq_T0_T1();
- } else
-#endif
- if (ot == OT_LONG) {
- gen_op_imull_T0_T1();
- } else {
- gen_op_imulw_T0_T1();
- }
- gen_op_mov_reg_T0[ot][reg]();
- s->cc_op = CC_OP_MULB + ot;
- break;
- case 0x1c0:
- case 0x1c1: /* xadd Ev, Gv */
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- mod = (modrm >> 6) & 3;
- if (mod == 3) {
- rm = (modrm & 7) | REX_B(s);
- gen_op_mov_TN_reg[ot][0][reg]();
- gen_op_mov_TN_reg[ot][1][rm]();
- gen_op_addl_T0_T1();
- gen_op_mov_reg_T1[ot][reg]();
- gen_op_mov_reg_T0[ot][rm]();
- } else {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_mov_TN_reg[ot][0][reg]();
- gen_op_ld_T1_A0[ot + s->mem_index]();
- gen_op_addl_T0_T1();
- gen_op_st_T0_A0[ot + s->mem_index]();
- gen_op_mov_reg_T1[ot][reg]();
- }
- gen_op_update2_cc();
- s->cc_op = CC_OP_ADDB + ot;
- break;
- case 0x1b0:
- case 0x1b1: /* cmpxchg Ev, Gv */
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- mod = (modrm >> 6) & 3;
- gen_op_mov_TN_reg[ot][1][reg]();
- if (mod == 3) {
- rm = (modrm & 7) | REX_B(s);
- gen_op_mov_TN_reg[ot][0][rm]();
- gen_op_cmpxchg_T0_T1_EAX_cc[ot]();
- gen_op_mov_reg_T0[ot][rm]();
- } else {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_T0_A0[ot + s->mem_index]();
- gen_op_cmpxchg_mem_T0_T1_EAX_cc[ot + s->mem_index]();
- }
- s->cc_op = CC_OP_SUBB + ot;
- break;
- case 0x1c7: /* cmpxchg8b */
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- if (mod == 3)
- goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_cmpxchg8b();
- s->cc_op = CC_OP_EFLAGS;
- break;
-
- /**************************/
- /* push/pop */
- case 0x50 ... 0x57: /* push */
- gen_op_mov_TN_reg[OT_LONG][0][(b & 7) | REX_B(s)]();
- gen_push_T0(s);
- break;
- case 0x58 ... 0x5f: /* pop */
- if (CODE64(s)) {
- ot = dflag ? OT_QUAD : OT_WORD;
- } else {
- ot = dflag + OT_WORD;
- }
- gen_pop_T0(s);
- /* NOTE: order is important for pop %sp */
- gen_pop_update(s);
- gen_op_mov_reg_T0[ot][(b & 7) | REX_B(s)]();
- break;
- case 0x60: /* pusha */
- if (CODE64(s))
- goto illegal_op;
- gen_pusha(s);
- break;
- case 0x61: /* popa */
- if (CODE64(s))
- goto illegal_op;
- gen_popa(s);
- break;
- case 0x68: /* push Iv */
- case 0x6a:
- if (CODE64(s)) {
- ot = dflag ? OT_QUAD : OT_WORD;
- } else {
- ot = dflag + OT_WORD;
- }
- if (b == 0x68)
- val = insn_get(s, ot);
- else
- val = (int8_t)insn_get(s, OT_BYTE);
- gen_op_movl_T0_im(val);
- gen_push_T0(s);
- break;
- case 0x8f: /* pop Ev */
- if (CODE64(s)) {
- ot = dflag ? OT_QUAD : OT_WORD;
- } else {
- ot = dflag + OT_WORD;
- }
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- gen_pop_T0(s);
- if (mod == 3) {
- /* NOTE: order is important for pop %sp */
- gen_pop_update(s);
- rm = (modrm & 7) | REX_B(s);
- gen_op_mov_reg_T0[ot][rm]();
- } else {
- /* NOTE: order is important too for MMU exceptions */
- s->popl_esp_hack = 1 << ot;
- gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
- s->popl_esp_hack = 0;
- gen_pop_update(s);
- }
- break;
- case 0xc8: /* enter */
- {
- int level;
- val = lduw_code(s->pc);
- s->pc += 2;
- level = ldub_code(s->pc++);
- gen_enter(s, val, level);
- }
- break;
- case 0xc9: /* leave */
- /* XXX: exception not precise (ESP is updated before potential exception) */
- if (CODE64(s)) {
- gen_op_mov_TN_reg[OT_QUAD][0][R_EBP]();
- gen_op_mov_reg_T0[OT_QUAD][R_ESP]();
- } else if (s->ss32) {
- gen_op_mov_TN_reg[OT_LONG][0][R_EBP]();
- gen_op_mov_reg_T0[OT_LONG][R_ESP]();
- } else {
- gen_op_mov_TN_reg[OT_WORD][0][R_EBP]();
- gen_op_mov_reg_T0[OT_WORD][R_ESP]();
- }
- gen_pop_T0(s);
- if (CODE64(s)) {
- ot = dflag ? OT_QUAD : OT_WORD;
- } else {
- ot = dflag + OT_WORD;
- }
- gen_op_mov_reg_T0[ot][R_EBP]();
- gen_pop_update(s);
- break;
- case 0x06: /* push es */
- case 0x0e: /* push cs */
- case 0x16: /* push ss */
- case 0x1e: /* push ds */
- if (CODE64(s))
- goto illegal_op;
- gen_op_movl_T0_seg(b >> 3);
- gen_push_T0(s);
- break;
- case 0x1a0: /* push fs */
- case 0x1a8: /* push gs */
- gen_op_movl_T0_seg((b >> 3) & 7);
- gen_push_T0(s);
- break;
- case 0x07: /* pop es */
- case 0x17: /* pop ss */
- case 0x1f: /* pop ds */
- if (CODE64(s))
- goto illegal_op;
- reg = b >> 3;
- gen_pop_T0(s);
- gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
- gen_pop_update(s);
- if (reg == R_SS) {
- /* if reg == SS, inhibit interrupts/trace. */
- /* If several instructions disable interrupts, only the
- _first_ does it */
- if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
- gen_op_set_inhibit_irq();
- s->tf = 0;
- }
- if (s->is_jmp) {
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- }
- break;
- case 0x1a1: /* pop fs */
- case 0x1a9: /* pop gs */
- gen_pop_T0(s);
- gen_movl_seg_T0(s, (b >> 3) & 7, pc_start - s->cs_base);
- gen_pop_update(s);
- if (s->is_jmp) {
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- }
- break;
-
- /**************************/
- /* mov */
- case 0x88:
- case 0x89: /* mov Gv, Ev */
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
-
- /* generate a generic store */
- gen_ldst_modrm(s, modrm, ot, reg, 1);
- break;
- case 0xc6:
- case 0xc7: /* mov Ev, Iv */
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- if (mod != 3) {
- s->rip_offset = insn_const_size(ot);
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- }
- val = insn_get(s, ot);
- gen_op_movl_T0_im(val);
- if (mod != 3)
- gen_op_st_T0_A0[ot + s->mem_index]();
- else
- gen_op_mov_reg_T0[ot][(modrm & 7) | REX_B(s)]();
- break;
- case 0x8a:
- case 0x8b: /* mov Ev, Gv */
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = OT_WORD + dflag;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
-
- gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
- gen_op_mov_reg_T0[ot][reg]();
- break;
- case 0x8e: /* mov seg, Gv */
- modrm = ldub_code(s->pc++);
- reg = (modrm >> 3) & 7;
- if (reg >= 6 || reg == R_CS)
- goto illegal_op;
- gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
- gen_movl_seg_T0(s, reg, pc_start - s->cs_base);
- if (reg == R_SS) {
- /* if reg == SS, inhibit interrupts/trace */
- /* If several instructions disable interrupts, only the
- _first_ does it */
- if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
- gen_op_set_inhibit_irq();
- s->tf = 0;
- }
- if (s->is_jmp) {
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- }
- break;
- case 0x8c: /* mov Gv, seg */
- modrm = ldub_code(s->pc++);
- reg = (modrm >> 3) & 7;
- mod = (modrm >> 6) & 3;
- if (reg >= 6)
- goto illegal_op;
- gen_op_movl_T0_seg(reg);
- if (mod == 3)
- ot = OT_WORD + dflag;
- else
- ot = OT_WORD;
- gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
- break;
-
- case 0x1b6: /* movzbS Gv, Eb */
- case 0x1b7: /* movzwS Gv, Eb */
- case 0x1be: /* movsbS Gv, Eb */
- case 0x1bf: /* movswS Gv, Eb */
- {
- int d_ot;
- /* d_ot is the size of destination */
- d_ot = dflag + OT_WORD;
- /* ot is the size of source */
- ot = (b & 1) + OT_BYTE;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
-
- if (mod == 3) {
- gen_op_mov_TN_reg[ot][0][rm]();
- switch(ot | (b & 8)) {
- case OT_BYTE:
- gen_op_movzbl_T0_T0();
- break;
- case OT_BYTE | 8:
- gen_op_movsbl_T0_T0();
- break;
- case OT_WORD:
- gen_op_movzwl_T0_T0();
- break;
- default:
- case OT_WORD | 8:
- gen_op_movswl_T0_T0();
- break;
- }
- gen_op_mov_reg_T0[d_ot][reg]();
- } else {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- if (b & 8) {
- gen_op_lds_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_ldu_T0_A0[ot + s->mem_index]();
- }
- gen_op_mov_reg_T0[d_ot][reg]();
- }
- }
- break;
-
- case 0x8d: /* lea */
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- if (mod == 3)
- goto illegal_op;
- reg = ((modrm >> 3) & 7) | rex_r;
- /* we must ensure that no segment is added */
- s->override = -1;
- val = s->addseg;
- s->addseg = 0;
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- s->addseg = val;
- gen_op_mov_reg_A0[ot - OT_WORD][reg]();
- break;
-
- case 0xa0: /* mov EAX, Ov */
- case 0xa1:
- case 0xa2: /* mov Ov, EAX */
- case 0xa3:
- {
- target_ulong offset_addr;
-
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- offset_addr = ldq_code(s->pc);
- s->pc += 8;
- if (offset_addr == (int32_t)offset_addr)
- gen_op_movq_A0_im(offset_addr);
- else
- gen_op_movq_A0_im64(offset_addr >> 32, offset_addr);
- } else
-#endif
- {
- if (s->aflag) {
- offset_addr = insn_get(s, OT_LONG);
- } else {
- offset_addr = insn_get(s, OT_WORD);
- }
- gen_op_movl_A0_im(offset_addr);
- }
- gen_add_A0_ds_seg(s);
- if ((b & 2) == 0) {
- gen_op_ld_T0_A0[ot + s->mem_index]();
- gen_op_mov_reg_T0[ot][R_EAX]();
- } else {
- gen_op_mov_TN_reg[ot][0][R_EAX]();
- gen_op_st_T0_A0[ot + s->mem_index]();
- }
- }
- break;
- case 0xd7: /* xlat */
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_movq_A0_reg[R_EBX]();
- gen_op_addq_A0_AL();
- } else
-#endif
- {
- gen_op_movl_A0_reg[R_EBX]();
- gen_op_addl_A0_AL();
- if (s->aflag == 0)
- gen_op_andl_A0_ffff();
- }
- gen_add_A0_ds_seg(s);
- gen_op_ldu_T0_A0[OT_BYTE + s->mem_index]();
- gen_op_mov_reg_T0[OT_BYTE][R_EAX]();
- break;
- case 0xb0 ... 0xb7: /* mov R, Ib */
- val = insn_get(s, OT_BYTE);
- gen_op_movl_T0_im(val);
- gen_op_mov_reg_T0[OT_BYTE][(b & 7) | REX_B(s)]();
- break;
- case 0xb8 ... 0xbf: /* mov R, Iv */
-#ifdef TARGET_X86_64
- if (dflag == 2) {
- uint64_t tmp;
- /* 64 bit case */
- tmp = ldq_code(s->pc);
- s->pc += 8;
- reg = (b & 7) | REX_B(s);
- gen_movtl_T0_im(tmp);
- gen_op_mov_reg_T0[OT_QUAD][reg]();
- } else
-#endif
- {
- ot = dflag ? OT_LONG : OT_WORD;
- val = insn_get(s, ot);
- reg = (b & 7) | REX_B(s);
- gen_op_movl_T0_im(val);
- gen_op_mov_reg_T0[ot][reg]();
- }
- break;
-
- case 0x91 ... 0x97: /* xchg R, EAX */
- ot = dflag + OT_WORD;
- reg = (b & 7) | REX_B(s);
- rm = R_EAX;
- goto do_xchg_reg;
- case 0x86:
- case 0x87: /* xchg Ev, Gv */
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- mod = (modrm >> 6) & 3;
- if (mod == 3) {
- rm = (modrm & 7) | REX_B(s);
- do_xchg_reg:
- gen_op_mov_TN_reg[ot][0][reg]();
- gen_op_mov_TN_reg[ot][1][rm]();
- gen_op_mov_reg_T0[ot][rm]();
- gen_op_mov_reg_T1[ot][reg]();
- } else {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_mov_TN_reg[ot][0][reg]();
- /* for xchg, lock is implicit */
- if (!(prefixes & PREFIX_LOCK))
- gen_op_lock();
- gen_op_ld_T1_A0[ot + s->mem_index]();
- gen_op_st_T0_A0[ot + s->mem_index]();
- if (!(prefixes & PREFIX_LOCK))
- gen_op_unlock();
- gen_op_mov_reg_T1[ot][reg]();
- }
- break;
- case 0xc4: /* les Gv */
- if (CODE64(s))
- goto illegal_op;
- op = R_ES;
- goto do_lxx;
- case 0xc5: /* lds Gv */
- if (CODE64(s))
- goto illegal_op;
- op = R_DS;
- goto do_lxx;
- case 0x1b2: /* lss Gv */
- op = R_SS;
- goto do_lxx;
- case 0x1b4: /* lfs Gv */
- op = R_FS;
- goto do_lxx;
- case 0x1b5: /* lgs Gv */
- op = R_GS;
- do_lxx:
- ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- mod = (modrm >> 6) & 3;
- if (mod == 3)
- goto illegal_op;
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_T1_A0[ot + s->mem_index]();
- gen_add_A0_im(s, 1 << (ot - OT_WORD + 1));
- /* load the segment first to handle exceptions properly */
- gen_op_ldu_T0_A0[OT_WORD + s->mem_index]();
- gen_movl_seg_T0(s, op, pc_start - s->cs_base);
- /* then put the data */
- gen_op_mov_reg_T1[ot][reg]();
- if (s->is_jmp) {
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- }
- break;
-
- /************************/
- /* shifts */
- case 0xc0:
- case 0xc1:
- /* shift Ev,Ib */
- shift = 2;
- grp2:
- {
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
-
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- op = (modrm >> 3) & 7;
-
- if (mod != 3) {
- if (shift == 2) {
- s->rip_offset = 1;
- }
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- opreg = OR_TMP0;
- } else {
- opreg = (modrm & 7) | REX_B(s);
- }
-
- /* simpler op */
- if (shift == 0) {
- gen_shift(s, op, ot, opreg, OR_ECX);
- } else {
- if (shift == 2) {
- shift = ldub_code(s->pc++);
- }
- gen_shifti(s, op, ot, opreg, shift);
- }
- }
- break;
- case 0xd0:
- case 0xd1:
- /* shift Ev,1 */
- shift = 1;
- goto grp2;
- case 0xd2:
- case 0xd3:
- /* shift Ev,cl */
- shift = 0;
- goto grp2;
-
- case 0x1a4: /* shld imm */
- op = 0;
- shift = 1;
- goto do_shiftd;
- case 0x1a5: /* shld cl */
- op = 0;
- shift = 0;
- goto do_shiftd;
- case 0x1ac: /* shrd imm */
- op = 1;
- shift = 1;
- goto do_shiftd;
- case 0x1ad: /* shrd cl */
- op = 1;
- shift = 0;
- do_shiftd:
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
- reg = ((modrm >> 3) & 7) | rex_r;
-
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_mov_TN_reg[ot][0][rm]();
- }
- gen_op_mov_TN_reg[ot][1][reg]();
-
- if (shift) {
- val = ldub_code(s->pc++);
- if (ot == OT_QUAD)
- val &= 0x3f;
- else
- val &= 0x1f;
- if (val) {
- if (mod == 3)
- gen_op_shiftd_T0_T1_im_cc[ot][op](val);
- else
- gen_op_shiftd_mem_T0_T1_im_cc[ot + s->mem_index][op](val);
- if (op == 0 && ot != OT_WORD)
- s->cc_op = CC_OP_SHLB + ot;
- else
- s->cc_op = CC_OP_SARB + ot;
- }
- } else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- if (mod == 3)
- gen_op_shiftd_T0_T1_ECX_cc[ot][op]();
- else
- gen_op_shiftd_mem_T0_T1_ECX_cc[ot + s->mem_index][op]();
- s->cc_op = CC_OP_DYNAMIC; /* cannot predict flags after */
- }
- if (mod == 3) {
- gen_op_mov_reg_T0[ot][rm]();
- }
- break;
-
- /************************/
- /* floats */
- case 0xd8 ... 0xdf:
- if (s->flags & (HF_EM_MASK | HF_TS_MASK)) {
- /* if CR0.EM or CR0.TS are set, generate an FPU exception */
- /* XXX: what to do if illegal op ? */
- gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
- break;
- }
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- rm = modrm & 7;
- op = ((b & 7) << 3) | ((modrm >> 3) & 7);
- if (mod != 3) {
- /* memory op */
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- switch(op) {
- case 0x00 ... 0x07: /* fxxxs */
- case 0x10 ... 0x17: /* fixxxl */
- case 0x20 ... 0x27: /* fxxxl */
- case 0x30 ... 0x37: /* fixxx */
- {
- int op1;
- op1 = op & 7;
-
- switch(op >> 4) {
- case 0:
- gen_op_flds_FT0_A0();
- break;
- case 1:
- gen_op_fildl_FT0_A0();
- break;
- case 2:
- gen_op_fldl_FT0_A0();
- break;
- case 3:
- default:
- gen_op_fild_FT0_A0();
- break;
- }
-
- gen_op_fp_arith_ST0_FT0[op1]();
- if (op1 == 3) {
- /* fcomp needs pop */
- gen_op_fpop();
- }
- }
- break;
- case 0x08: /* flds */
- case 0x0a: /* fsts */
- case 0x0b: /* fstps */
- case 0x18 ... 0x1b: /* fildl, fisttpl, fistl, fistpl */
- case 0x28 ... 0x2b: /* fldl, fisttpll, fstl, fstpl */
- case 0x38 ... 0x3b: /* filds, fisttps, fists, fistps */
- switch(op & 7) {
- case 0:
- switch(op >> 4) {
- case 0:
- gen_op_flds_ST0_A0();
- break;
- case 1:
- gen_op_fildl_ST0_A0();
- break;
- case 2:
- gen_op_fldl_ST0_A0();
- break;
- case 3:
- default:
- gen_op_fild_ST0_A0();
- break;
- }
- break;
- case 1:
- switch(op >> 4) {
- case 1:
- gen_op_fisttl_ST0_A0();
- break;
- case 2:
- gen_op_fisttll_ST0_A0();
- break;
- case 3:
- default:
- gen_op_fistt_ST0_A0();
- }
- gen_op_fpop();
- break;
- default:
- switch(op >> 4) {
- case 0:
- gen_op_fsts_ST0_A0();
- break;
- case 1:
- gen_op_fistl_ST0_A0();
- break;
- case 2:
- gen_op_fstl_ST0_A0();
- break;
- case 3:
- default:
- gen_op_fist_ST0_A0();
- break;
- }
- if ((op & 7) == 3)
- gen_op_fpop();
- break;
- }
- break;
- case 0x0c: /* fldenv mem */
- gen_op_fldenv_A0(s->dflag);
- break;
- case 0x0d: /* fldcw mem */
- gen_op_fldcw_A0();
- break;
- case 0x0e: /* fnstenv mem */
- gen_op_fnstenv_A0(s->dflag);
- break;
- case 0x0f: /* fnstcw mem */
- gen_op_fnstcw_A0();
- break;
- case 0x1d: /* fldt mem */
- gen_op_fldt_ST0_A0();
- break;
- case 0x1f: /* fstpt mem */
- gen_op_fstt_ST0_A0();
- gen_op_fpop();
- break;
- case 0x2c: /* frstor mem */
- gen_op_frstor_A0(s->dflag);
- break;
- case 0x2e: /* fnsave mem */
- gen_op_fnsave_A0(s->dflag);
- break;
- case 0x2f: /* fnstsw mem */
- gen_op_fnstsw_A0();
- break;
- case 0x3c: /* fbld */
- gen_op_fbld_ST0_A0();
- break;
- case 0x3e: /* fbstp */
- gen_op_fbst_ST0_A0();
- gen_op_fpop();
- break;
- case 0x3d: /* fildll */
- gen_op_fildll_ST0_A0();
- break;
- case 0x3f: /* fistpll */
- gen_op_fistll_ST0_A0();
- gen_op_fpop();
- break;
- default:
- goto illegal_op;
- }
- } else {
- /* register float ops */
- opreg = rm;
-
- switch(op) {
- case 0x08: /* fld sti */
- gen_op_fpush();
- gen_op_fmov_ST0_STN((opreg + 1) & 7);
- break;
- case 0x09: /* fxchg sti */
- case 0x29: /* fxchg4 sti, undocumented op */
- case 0x39: /* fxchg7 sti, undocumented op */
- gen_op_fxchg_ST0_STN(opreg);
- break;
- case 0x0a: /* grp d9/2 */
- switch(rm) {
- case 0: /* fnop */
- /* check exceptions (FreeBSD FPU probe) */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_fwait();
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x0c: /* grp d9/4 */
- switch(rm) {
- case 0: /* fchs */
- gen_op_fchs_ST0();
- break;
- case 1: /* fabs */
- gen_op_fabs_ST0();
- break;
- case 4: /* ftst */
- gen_op_fldz_FT0();
- gen_op_fcom_ST0_FT0();
- break;
- case 5: /* fxam */
- gen_op_fxam_ST0();
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x0d: /* grp d9/5 */
- {
- switch(rm) {
- case 0:
- gen_op_fpush();
- gen_op_fld1_ST0();
- break;
- case 1:
- gen_op_fpush();
- gen_op_fldl2t_ST0();
- break;
- case 2:
- gen_op_fpush();
- gen_op_fldl2e_ST0();
- break;
- case 3:
- gen_op_fpush();
- gen_op_fldpi_ST0();
- break;
- case 4:
- gen_op_fpush();
- gen_op_fldlg2_ST0();
- break;
- case 5:
- gen_op_fpush();
- gen_op_fldln2_ST0();
- break;
- case 6:
- gen_op_fpush();
- gen_op_fldz_ST0();
- break;
- default:
- goto illegal_op;
- }
- }
- break;
- case 0x0e: /* grp d9/6 */
- switch(rm) {
- case 0: /* f2xm1 */
- gen_op_f2xm1();
- break;
- case 1: /* fyl2x */
- gen_op_fyl2x();
- break;
- case 2: /* fptan */
- gen_op_fptan();
- break;
- case 3: /* fpatan */
- gen_op_fpatan();
- break;
- case 4: /* fxtract */
- gen_op_fxtract();
- break;
- case 5: /* fprem1 */
- gen_op_fprem1();
- break;
- case 6: /* fdecstp */
- gen_op_fdecstp();
- break;
- default:
- case 7: /* fincstp */
- gen_op_fincstp();
- break;
- }
- break;
- case 0x0f: /* grp d9/7 */
- switch(rm) {
- case 0: /* fprem */
- gen_op_fprem();
- break;
- case 1: /* fyl2xp1 */
- gen_op_fyl2xp1();
- break;
- case 2: /* fsqrt */
- gen_op_fsqrt();
- break;
- case 3: /* fsincos */
- gen_op_fsincos();
- break;
- case 5: /* fscale */
- gen_op_fscale();
- break;
- case 4: /* frndint */
- gen_op_frndint();
- break;
- case 6: /* fsin */
- gen_op_fsin();
- break;
- default:
- case 7: /* fcos */
- gen_op_fcos();
- break;
- }
- break;
- case 0x00: case 0x01: case 0x04 ... 0x07: /* fxxx st, sti */
- case 0x20: case 0x21: case 0x24 ... 0x27: /* fxxx sti, st */
- case 0x30: case 0x31: case 0x34 ... 0x37: /* fxxxp sti, st */
- {
- int op1;
-
- op1 = op & 7;
- if (op >= 0x20) {
- gen_op_fp_arith_STN_ST0[op1](opreg);
- if (op >= 0x30)
- gen_op_fpop();
- } else {
- gen_op_fmov_FT0_STN(opreg);
- gen_op_fp_arith_ST0_FT0[op1]();
- }
- }
- break;
- case 0x02: /* fcom */
- case 0x22: /* fcom2, undocumented op */
- gen_op_fmov_FT0_STN(opreg);
- gen_op_fcom_ST0_FT0();
- break;
- case 0x03: /* fcomp */
- case 0x23: /* fcomp3, undocumented op */
- case 0x32: /* fcomp5, undocumented op */
- gen_op_fmov_FT0_STN(opreg);
- gen_op_fcom_ST0_FT0();
- gen_op_fpop();
- break;
- case 0x15: /* da/5 */
- switch(rm) {
- case 1: /* fucompp */
- gen_op_fmov_FT0_STN(1);
- gen_op_fucom_ST0_FT0();
- gen_op_fpop();
- gen_op_fpop();
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x1c:
- switch(rm) {
- case 0: /* feni (287 only, just do nop here) */
- break;
- case 1: /* fdisi (287 only, just do nop here) */
- break;
- case 2: /* fclex */
- gen_op_fclex();
- break;
- case 3: /* fninit */
- gen_op_fninit();
- break;
- case 4: /* fsetpm (287 only, just do nop here) */
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x1d: /* fucomi */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_fmov_FT0_STN(opreg);
- gen_op_fucomi_ST0_FT0();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0x1e: /* fcomi */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_fmov_FT0_STN(opreg);
- gen_op_fcomi_ST0_FT0();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0x28: /* ffree sti */
- gen_op_ffree_STN(opreg);
- break;
- case 0x2a: /* fst sti */
- gen_op_fmov_STN_ST0(opreg);
- break;
- case 0x2b: /* fstp sti */
- case 0x0b: /* fstp1 sti, undocumented op */
- case 0x3a: /* fstp8 sti, undocumented op */
- case 0x3b: /* fstp9 sti, undocumented op */
- gen_op_fmov_STN_ST0(opreg);
- gen_op_fpop();
- break;
- case 0x2c: /* fucom st(i) */
- gen_op_fmov_FT0_STN(opreg);
- gen_op_fucom_ST0_FT0();
- break;
- case 0x2d: /* fucomp st(i) */
- gen_op_fmov_FT0_STN(opreg);
- gen_op_fucom_ST0_FT0();
- gen_op_fpop();
- break;
- case 0x33: /* de/3 */
- switch(rm) {
- case 1: /* fcompp */
- gen_op_fmov_FT0_STN(1);
- gen_op_fcom_ST0_FT0();
- gen_op_fpop();
- gen_op_fpop();
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x38: /* ffreep sti, undocumented op */
- gen_op_ffree_STN(opreg);
- gen_op_fpop();
- break;
- case 0x3c: /* df/4 */
- switch(rm) {
- case 0:
- gen_op_fnstsw_EAX();
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x3d: /* fucomip */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_fmov_FT0_STN(opreg);
- gen_op_fucomi_ST0_FT0();
- gen_op_fpop();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0x3e: /* fcomip */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_fmov_FT0_STN(opreg);
- gen_op_fcomi_ST0_FT0();
- gen_op_fpop();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0x10 ... 0x13: /* fcmovxx */
- case 0x18 ... 0x1b:
- {
- int op1;
- const static uint8_t fcmov_cc[8] = {
- (JCC_B << 1),
- (JCC_Z << 1),
- (JCC_BE << 1),
- (JCC_P << 1),
- };
- op1 = fcmov_cc[op & 3] | ((op >> 3) & 1);
- gen_setcc(s, op1);
- gen_op_fcmov_ST0_STN_T0(opreg);
- }
- break;
- default:
- goto illegal_op;
- }
- }
-#ifdef USE_CODE_COPY
- s->tb->cflags |= CF_TB_FP_USED;
-#endif
- break;
- /************************/
- /* string ops */
-
- case 0xa4: /* movsS */
- case 0xa5:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
-
- if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
- gen_repz_movs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
- } else {
- gen_movs(s, ot);
- }
- break;
-
- case 0xaa: /* stosS */
- case 0xab:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
-
- if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
- gen_repz_stos(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
- } else {
- gen_stos(s, ot);
- }
- break;
- case 0xac: /* lodsS */
- case 0xad:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
- if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
- gen_repz_lods(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
- } else {
- gen_lods(s, ot);
- }
- break;
- case 0xae: /* scasS */
- case 0xaf:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
- if (prefixes & PREFIX_REPNZ) {
- gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
- } else if (prefixes & PREFIX_REPZ) {
- gen_repz_scas(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
- } else {
- gen_scas(s, ot);
- s->cc_op = CC_OP_SUBB + ot;
- }
- break;
-
- case 0xa6: /* cmpsS */
- case 0xa7:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag + OT_WORD;
- if (prefixes & PREFIX_REPNZ) {
- gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 1);
- } else if (prefixes & PREFIX_REPZ) {
- gen_repz_cmps(s, ot, pc_start - s->cs_base, s->pc - s->cs_base, 0);
- } else {
- gen_cmps(s, ot);
- s->cc_op = CC_OP_SUBB + ot;
- }
- break;
- case 0x6c: /* insS */
- case 0x6d:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- gen_check_io(s, ot, 1, pc_start - s->cs_base);
- if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
- gen_repz_ins(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
- } else {
- gen_ins(s, ot);
- }
- break;
- case 0x6e: /* outsS */
- case 0x6f:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- gen_check_io(s, ot, 1, pc_start - s->cs_base);
- if (prefixes & (PREFIX_REPZ | PREFIX_REPNZ)) {
- gen_repz_outs(s, ot, pc_start - s->cs_base, s->pc - s->cs_base);
- } else {
- gen_outs(s, ot);
- }
- break;
-
- /************************/
- /* port I/O */
- case 0xe4:
- case 0xe5:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- val = ldub_code(s->pc++);
- gen_op_movl_T0_im(val);
- gen_check_io(s, ot, 0, pc_start - s->cs_base);
- gen_op_in[ot]();
- gen_op_mov_reg_T1[ot][R_EAX]();
- break;
- case 0xe6:
- case 0xe7:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- val = ldub_code(s->pc++);
- gen_op_movl_T0_im(val);
- gen_check_io(s, ot, 0, pc_start - s->cs_base);
- gen_op_mov_TN_reg[ot][1][R_EAX]();
- gen_op_out[ot]();
- break;
- case 0xec:
- case 0xed:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
- gen_op_andl_T0_ffff();
- gen_check_io(s, ot, 0, pc_start - s->cs_base);
- gen_op_in[ot]();
- gen_op_mov_reg_T1[ot][R_EAX]();
- break;
- case 0xee:
- case 0xef:
- if ((b & 1) == 0)
- ot = OT_BYTE;
- else
- ot = dflag ? OT_LONG : OT_WORD;
- gen_op_mov_TN_reg[OT_WORD][0][R_EDX]();
- gen_op_andl_T0_ffff();
- gen_check_io(s, ot, 0, pc_start - s->cs_base);
- gen_op_mov_TN_reg[ot][1][R_EAX]();
- gen_op_out[ot]();
- break;
-
- /************************/
- /* control */
- case 0xc2: /* ret im */
- val = ldsw_code(s->pc);
- s->pc += 2;
- gen_pop_T0(s);
- if (CODE64(s) && s->dflag)
- s->dflag = 2;
- gen_stack_update(s, val + (2 << s->dflag));
- if (s->dflag == 0)
- gen_op_andl_T0_ffff();
- gen_op_jmp_T0();
- gen_eob(s);
- break;
- case 0xc3: /* ret */
- gen_pop_T0(s);
- gen_pop_update(s);
- if (s->dflag == 0)
- gen_op_andl_T0_ffff();
- gen_op_jmp_T0();
- gen_eob(s);
- break;
- case 0xca: /* lret im */
- val = ldsw_code(s->pc);
- s->pc += 2;
- do_lret:
- if (s->pe && !s->vm86) {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_lret_protected(s->dflag, val);
- } else {
- gen_stack_A0(s);
- /* pop offset */
- gen_op_ld_T0_A0[1 + s->dflag + s->mem_index]();
- if (s->dflag == 0)
- gen_op_andl_T0_ffff();
- /* NOTE: keeping EIP updated is not a problem in case of
- exception */
- gen_op_jmp_T0();
- /* pop selector */
- gen_op_addl_A0_im(2 << s->dflag);
- gen_op_ld_T0_A0[1 + s->dflag + s->mem_index]();
- gen_op_movl_seg_T0_vm(offsetof(CPUX86State,segs[R_CS]));
- /* add stack offset */
- gen_stack_update(s, val + (4 << s->dflag));
- }
- gen_eob(s);
- break;
- case 0xcb: /* lret */
- val = 0;
- goto do_lret;
- case 0xcf: /* iret */
- if (!s->pe) {
- /* real mode */
- gen_op_iret_real(s->dflag);
- s->cc_op = CC_OP_EFLAGS;
- } else if (s->vm86) {
- if (s->iopl != 3) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_op_iret_real(s->dflag);
- s->cc_op = CC_OP_EFLAGS;
- }
- } else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_iret_protected(s->dflag, s->pc - s->cs_base);
- s->cc_op = CC_OP_EFLAGS;
- }
- gen_eob(s);
- break;
- case 0xe8: /* call im */
- {
- if (dflag)
- tval = (int32_t)insn_get(s, OT_LONG);
- else
- tval = (int16_t)insn_get(s, OT_WORD);
- next_eip = s->pc - s->cs_base;
- tval += next_eip;
- if (s->dflag == 0)
- tval &= 0xffff;
- gen_movtl_T0_im(next_eip);
- gen_push_T0(s);
- gen_jmp(s, tval);
- }
- break;
- case 0x9a: /* lcall im */
- {
- unsigned int selector, offset;
-
- if (CODE64(s))
- goto illegal_op;
- ot = dflag ? OT_LONG : OT_WORD;
- offset = insn_get(s, ot);
- selector = insn_get(s, OT_WORD);
-
- gen_op_movl_T0_im(selector);
- gen_op_movl_T1_imu(offset);
- }
- goto do_lcall;
- case 0xe9: /* jmp im */
- if (dflag)
- tval = (int32_t)insn_get(s, OT_LONG);
- else
- tval = (int16_t)insn_get(s, OT_WORD);
- tval += s->pc - s->cs_base;
- if (s->dflag == 0)
- tval &= 0xffff;
- gen_jmp(s, tval);
- break;
- case 0xea: /* ljmp im */
- {
- unsigned int selector, offset;
-
- if (CODE64(s))
- goto illegal_op;
- ot = dflag ? OT_LONG : OT_WORD;
- offset = insn_get(s, ot);
- selector = insn_get(s, OT_WORD);
-
- gen_op_movl_T0_im(selector);
- gen_op_movl_T1_imu(offset);
- }
- goto do_ljmp;
- case 0xeb: /* jmp Jb */
- tval = (int8_t)insn_get(s, OT_BYTE);
- tval += s->pc - s->cs_base;
- if (s->dflag == 0)
- tval &= 0xffff;
- gen_jmp(s, tval);
- break;
- case 0x70 ... 0x7f: /* jcc Jb */
- tval = (int8_t)insn_get(s, OT_BYTE);
- goto do_jcc;
- case 0x180 ... 0x18f: /* jcc Jv */
- if (dflag) {
- tval = (int32_t)insn_get(s, OT_LONG);
- } else {
- tval = (int16_t)insn_get(s, OT_WORD);
- }
- do_jcc:
- next_eip = s->pc - s->cs_base;
- tval += next_eip;
- if (s->dflag == 0)
- tval &= 0xffff;
- gen_jcc(s, b, tval, next_eip);
- break;
-
- case 0x190 ... 0x19f: /* setcc Gv */
- modrm = ldub_code(s->pc++);
- gen_setcc(s, b);
- gen_ldst_modrm(s, modrm, OT_BYTE, OR_TMP0, 1);
- break;
- case 0x140 ... 0x14f: /* cmov Gv, Ev */
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- mod = (modrm >> 6) & 3;
- gen_setcc(s, b);
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_T1_A0[ot + s->mem_index]();
- } else {
- rm = (modrm & 7) | REX_B(s);
- gen_op_mov_TN_reg[ot][1][rm]();
- }
- gen_op_cmov_reg_T1_T0[ot - OT_WORD][reg]();
- break;
-
- /************************/
- /* flags */
- case 0x9c: /* pushf */
- if (s->vm86 && s->iopl != 3) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_movl_T0_eflags();
- gen_push_T0(s);
- }
- break;
- case 0x9d: /* popf */
- if (s->vm86 && s->iopl != 3) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_pop_T0(s);
- if (s->cpl == 0) {
- if (s->dflag) {
- gen_op_movl_eflags_T0_cpl0();
- } else {
- gen_op_movw_eflags_T0_cpl0();
- }
- } else {
- if (s->cpl <= s->iopl) {
- if (s->dflag) {
- gen_op_movl_eflags_T0_io();
- } else {
- gen_op_movw_eflags_T0_io();
- }
- } else {
- if (s->dflag) {
- gen_op_movl_eflags_T0();
- } else {
- gen_op_movw_eflags_T0();
- }
- }
- }
- gen_pop_update(s);
- s->cc_op = CC_OP_EFLAGS;
- /* abort translation because TF flag may change */
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- }
- break;
- case 0x9e: /* sahf */
- if (CODE64(s))
- goto illegal_op;
- gen_op_mov_TN_reg[OT_BYTE][0][R_AH]();
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_movb_eflags_T0();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0x9f: /* lahf */
- if (CODE64(s))
- goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_movl_T0_eflags();
- gen_op_mov_reg_T0[OT_BYTE][R_AH]();
- break;
- case 0xf5: /* cmc */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_cmc();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0xf8: /* clc */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_clc();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0xf9: /* stc */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_stc();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0xfc: /* cld */
- gen_op_cld();
- break;
- case 0xfd: /* std */
- gen_op_std();
- break;
-
- /************************/
- /* bit operations */
- case 0x1ba: /* bt/bts/btr/btc Gv, im */
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- op = (modrm >> 3) & 7;
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
- if (mod != 3) {
- s->rip_offset = 1;
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_mov_TN_reg[ot][0][rm]();
- }
- /* load shift */
- val = ldub_code(s->pc++);
- gen_op_movl_T1_im(val);
- if (op < 4)
- goto illegal_op;
- op -= 4;
- gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();
- s->cc_op = CC_OP_SARB + ot;
- if (op != 0) {
- if (mod != 3)
- gen_op_st_T0_A0[ot + s->mem_index]();
- else
- gen_op_mov_reg_T0[ot][rm]();
- gen_op_update_bt_cc();
- }
- break;
- case 0x1a3: /* bt Gv, Ev */
- op = 0;
- goto do_btx;
- case 0x1ab: /* bts */
- op = 1;
- goto do_btx;
- case 0x1b3: /* btr */
- op = 2;
- goto do_btx;
- case 0x1bb: /* btc */
- op = 3;
- do_btx:
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
- gen_op_mov_TN_reg[OT_LONG][1][reg]();
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- /* specific case: we need to add a displacement */
- gen_op_add_bit_A0_T1[ot - OT_WORD]();
- gen_op_ld_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_mov_TN_reg[ot][0][rm]();
- }
- gen_op_btx_T0_T1_cc[ot - OT_WORD][op]();
- s->cc_op = CC_OP_SARB + ot;
- if (op != 0) {
- if (mod != 3)
- gen_op_st_T0_A0[ot + s->mem_index]();
- else
- gen_op_mov_reg_T0[ot][rm]();
- gen_op_update_bt_cc();
- }
- break;
- case 0x1bc: /* bsf */
- case 0x1bd: /* bsr */
- ot = dflag + OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
- /* NOTE: in order to handle the 0 case, we must load the
- result. It could be optimized with a generated jump */
- gen_op_mov_TN_reg[ot][1][reg]();
- gen_op_bsx_T0_cc[ot - OT_WORD][b & 1]();
- gen_op_mov_reg_T1[ot][reg]();
- s->cc_op = CC_OP_LOGICB + ot;
- break;
- /************************/
- /* bcd */
- case 0x27: /* daa */
- if (CODE64(s))
- goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_daa();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0x2f: /* das */
- if (CODE64(s))
- goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_das();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0x37: /* aaa */
- if (CODE64(s))
- goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_aaa();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0x3f: /* aas */
- if (CODE64(s))
- goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_aas();
- s->cc_op = CC_OP_EFLAGS;
- break;
- case 0xd4: /* aam */
- if (CODE64(s))
- goto illegal_op;
- val = ldub_code(s->pc++);
- gen_op_aam(val);
- s->cc_op = CC_OP_LOGICB;
- break;
- case 0xd5: /* aad */
- if (CODE64(s))
- goto illegal_op;
- val = ldub_code(s->pc++);
- gen_op_aad(val);
- s->cc_op = CC_OP_LOGICB;
- break;
- /************************/
- /* misc */
- case 0x90: /* nop */
- /* XXX: xchg + rex handling */
- /* XXX: correct lock test for all insn */
- if (prefixes & PREFIX_LOCK)
- goto illegal_op;
- break;
- case 0x9b: /* fwait */
- if ((s->flags & (HF_MP_MASK | HF_TS_MASK)) ==
- (HF_MP_MASK | HF_TS_MASK)) {
- gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
- } else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_fwait();
- }
- break;
- case 0xcc: /* int3 */
- gen_interrupt(s, EXCP03_INT3, pc_start - s->cs_base, s->pc - s->cs_base);
- break;
- case 0xcd: /* int N */
- val = ldub_code(s->pc++);
- if (s->vm86 && s->iopl != 3) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_interrupt(s, val, pc_start - s->cs_base, s->pc - s->cs_base);
- }
- break;
- case 0xce: /* into */
- if (CODE64(s))
- goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_into(s->pc - pc_start);
- break;
- case 0xf1: /* icebp (undocumented, exits to external debugger) */
-#if 1
- gen_debug(s, pc_start - s->cs_base);
-#else
- /* start debug */
- tb_flush(cpu_single_env);
- cpu_set_log(CPU_LOG_INT | CPU_LOG_TB_IN_ASM);
-#endif
- break;
- case 0xfa: /* cli */
- if (!s->vm86) {
- if (s->cpl <= s->iopl) {
- gen_op_cli();
- } else {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- }
- } else {
- if (s->iopl == 3) {
- gen_op_cli();
- } else {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- }
- }
- break;
- case 0xfb: /* sti */
- if (!s->vm86) {
- if (s->cpl <= s->iopl) {
- gen_sti:
- gen_op_sti();
- /* interruptions are enabled only the first insn after sti */
- /* If several instructions disable interrupts, only the
- _first_ does it */
- if (!(s->tb->flags & HF_INHIBIT_IRQ_MASK))
- gen_op_set_inhibit_irq();
- /* give a chance to handle pending irqs */
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- } else {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- }
- } else {
- if (s->iopl == 3) {
- goto gen_sti;
- } else {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- }
- }
- break;
- case 0x62: /* bound */
- if (CODE64(s))
- goto illegal_op;
- ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = (modrm >> 3) & 7;
- mod = (modrm >> 6) & 3;
- if (mod == 3)
- goto illegal_op;
- gen_op_mov_TN_reg[ot][0][reg]();
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_jmp_im(pc_start - s->cs_base);
- if (ot == OT_WORD)
- gen_op_boundw();
- else
- gen_op_boundl();
- break;
- case 0x1c8 ... 0x1cf: /* bswap reg */
- reg = (b & 7) | REX_B(s);
-#ifdef TARGET_X86_64
- if (dflag == 2) {
- gen_op_mov_TN_reg[OT_QUAD][0][reg]();
- gen_op_bswapq_T0();
- gen_op_mov_reg_T0[OT_QUAD][reg]();
- } else
-#endif
- {
- gen_op_mov_TN_reg[OT_LONG][0][reg]();
- gen_op_bswapl_T0();
- gen_op_mov_reg_T0[OT_LONG][reg]();
- }
- break;
- case 0xd6: /* salc */
- if (CODE64(s))
- goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_salc();
- break;
- case 0xe0: /* loopnz */
- case 0xe1: /* loopz */
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- /* FALL THRU */
- case 0xe2: /* loop */
- case 0xe3: /* jecxz */
- {
- int l1, l2;
-
- tval = (int8_t)insn_get(s, OT_BYTE);
- next_eip = s->pc - s->cs_base;
- tval += next_eip;
- if (s->dflag == 0)
- tval &= 0xffff;
-
- l1 = gen_new_label();
- l2 = gen_new_label();
- b &= 3;
- if (b == 3) {
- gen_op_jz_ecx[s->aflag](l1);
- } else {
- gen_op_dec_ECX[s->aflag]();
- if (b <= 1)
- gen_op_mov_T0_cc();
- gen_op_loop[s->aflag][b](l1);
- }
-
- gen_jmp_im(next_eip);
- gen_op_jmp_label(l2);
- gen_set_label(l1);
- gen_jmp_im(tval);
- gen_set_label(l2);
- gen_eob(s);
- }
- break;
- case 0x130: /* wrmsr */
- case 0x132: /* rdmsr */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- if (b & 2)
- gen_op_rdmsr();
- else
- gen_op_wrmsr();
- }
- break;
- case 0x131: /* rdtsc */
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_rdtsc();
- break;
- case 0x134: /* sysenter */
- if (CODE64(s))
- goto illegal_op;
- if (!s->pe) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- s->cc_op = CC_OP_DYNAMIC;
- }
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_sysenter();
- gen_eob(s);
- }
- break;
- case 0x135: /* sysexit */
- if (CODE64(s))
- goto illegal_op;
- if (!s->pe) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- s->cc_op = CC_OP_DYNAMIC;
- }
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_sysexit();
- gen_eob(s);
- }
- break;
-#ifdef TARGET_X86_64
- case 0x105: /* syscall */
- /* XXX: is it usable in real mode ? */
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- s->cc_op = CC_OP_DYNAMIC;
- }
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_syscall(s->pc - pc_start);
- gen_eob(s);
- break;
- case 0x107: /* sysret */
- if (!s->pe) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- s->cc_op = CC_OP_DYNAMIC;
- }
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_sysret(s->dflag);
- /* condition codes are modified only in long mode */
- if (s->lma)
- s->cc_op = CC_OP_EFLAGS;
- gen_eob(s);
- }
- break;
-#endif
- case 0x1a2: /* cpuid */
- gen_op_cpuid();
- break;
- case 0xf4: /* hlt */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_jmp_im(s->pc - s->cs_base);
- gen_op_hlt();
- s->is_jmp = 3;
- }
- break;
- case 0x100:
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- op = (modrm >> 3) & 7;
- switch(op) {
- case 0: /* sldt */
- if (!s->pe || s->vm86)
- goto illegal_op;
- gen_op_movl_T0_env(offsetof(CPUX86State,ldt.selector));
- ot = OT_WORD;
- if (mod == 3)
- ot += s->dflag;
- gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
- break;
- case 2: /* lldt */
- if (!s->pe || s->vm86)
- goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_lldt_T0();
- }
- break;
- case 1: /* str */
- if (!s->pe || s->vm86)
- goto illegal_op;
- gen_op_movl_T0_env(offsetof(CPUX86State,tr.selector));
- ot = OT_WORD;
- if (mod == 3)
- ot += s->dflag;
- gen_ldst_modrm(s, modrm, ot, OR_TMP0, 1);
- break;
- case 3: /* ltr */
- if (!s->pe || s->vm86)
- goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
- gen_jmp_im(pc_start - s->cs_base);
- gen_op_ltr_T0();
- }
- break;
- case 4: /* verr */
- case 5: /* verw */
- if (!s->pe || s->vm86)
- goto illegal_op;
- gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- if (op == 4)
- gen_op_verr();
- else
- gen_op_verw();
- s->cc_op = CC_OP_EFLAGS;
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x101:
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- op = (modrm >> 3) & 7;
- rm = modrm & 7;
- switch(op) {
- case 0: /* sgdt */
- if (mod == 3)
- goto illegal_op;
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_movl_T0_env(offsetof(CPUX86State, gdt.limit));
- gen_op_st_T0_A0[OT_WORD + s->mem_index]();
- gen_add_A0_im(s, 2);
- gen_op_movtl_T0_env(offsetof(CPUX86State, gdt.base));
- if (!s->dflag)
- gen_op_andl_T0_im(0xffffff);
- gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index]();
- break;
- case 1:
- if (mod == 3) {
- switch (rm) {
- case 0: /* monitor */
- if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
- s->cpl != 0)
- goto illegal_op;
- gen_jmp_im(pc_start - s->cs_base);
-#ifdef TARGET_X86_64
- if (s->aflag == 2) {
- gen_op_movq_A0_reg[R_EBX]();
- gen_op_addq_A0_AL();
- } else
-#endif
- {
- gen_op_movl_A0_reg[R_EBX]();
- gen_op_addl_A0_AL();
- if (s->aflag == 0)
- gen_op_andl_A0_ffff();
- }
- gen_add_A0_ds_seg(s);
- gen_op_monitor();
- break;
- case 1: /* mwait */
- if (!(s->cpuid_ext_features & CPUID_EXT_MONITOR) ||
- s->cpl != 0)
- goto illegal_op;
- if (s->cc_op != CC_OP_DYNAMIC) {
- gen_op_set_cc_op(s->cc_op);
- s->cc_op = CC_OP_DYNAMIC;
- }
- gen_jmp_im(s->pc - s->cs_base);
- gen_op_mwait();
- gen_eob(s);
- break;
- default:
- goto illegal_op;
- }
- } else { /* sidt */
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_movl_T0_env(offsetof(CPUX86State, idt.limit));
- gen_op_st_T0_A0[OT_WORD + s->mem_index]();
- gen_add_A0_im(s, 2);
- gen_op_movtl_T0_env(offsetof(CPUX86State, idt.base));
- if (!s->dflag)
- gen_op_andl_T0_im(0xffffff);
- gen_op_st_T0_A0[CODE64(s) + OT_LONG + s->mem_index]();
- }
- break;
- case 2: /* lgdt */
- case 3: /* lidt */
- if (mod == 3)
- goto illegal_op;
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_T1_A0[OT_WORD + s->mem_index]();
- gen_add_A0_im(s, 2);
- gen_op_ld_T0_A0[CODE64(s) + OT_LONG + s->mem_index]();
- if (!s->dflag)
- gen_op_andl_T0_im(0xffffff);
- if (op == 2) {
- gen_op_movtl_env_T0(offsetof(CPUX86State,gdt.base));
- gen_op_movl_env_T1(offsetof(CPUX86State,gdt.limit));
- } else {
- gen_op_movtl_env_T0(offsetof(CPUX86State,idt.base));
- gen_op_movl_env_T1(offsetof(CPUX86State,idt.limit));
- }
- }
- break;
- case 4: /* smsw */
- gen_op_movl_T0_env(offsetof(CPUX86State,cr[0]));
- gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 1);
- break;
- case 6: /* lmsw */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_ldst_modrm(s, modrm, OT_WORD, OR_TMP0, 0);
- gen_op_lmsw_T0();
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- }
- break;
- case 7: /* invlpg */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- if (mod == 3) {
-#ifdef TARGET_X86_64
- if (CODE64(s) && rm == 0) {
- /* swapgs */
- gen_op_movtl_T0_env(offsetof(CPUX86State,segs[R_GS].base));
- gen_op_movtl_T1_env(offsetof(CPUX86State,kernelgsbase));
- gen_op_movtl_env_T1(offsetof(CPUX86State,segs[R_GS].base));
- gen_op_movtl_env_T0(offsetof(CPUX86State,kernelgsbase));
- } else
-#endif
- {
- goto illegal_op;
- }
- } else {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_invlpg_A0();
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- }
- }
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x108: /* invd */
- case 0x109: /* wbinvd */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- /* nothing to do */
- }
- break;
- case 0x63: /* arpl or movslS (x86_64) */
-#ifdef TARGET_X86_64
- if (CODE64(s)) {
- int d_ot;
- /* d_ot is the size of destination */
- d_ot = dflag + OT_WORD;
-
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- mod = (modrm >> 6) & 3;
- rm = (modrm & 7) | REX_B(s);
-
- if (mod == 3) {
- gen_op_mov_TN_reg[OT_LONG][0][rm]();
- /* sign extend */
- if (d_ot == OT_QUAD)
- gen_op_movslq_T0_T0();
- gen_op_mov_reg_T0[d_ot][reg]();
- } else {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- if (d_ot == OT_QUAD) {
- gen_op_lds_T0_A0[OT_LONG + s->mem_index]();
- } else {
- gen_op_ld_T0_A0[OT_LONG + s->mem_index]();
- }
- gen_op_mov_reg_T0[d_ot][reg]();
- }
- } else
-#endif
- {
- if (!s->pe || s->vm86)
- goto illegal_op;
- ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = (modrm >> 3) & 7;
- mod = (modrm >> 6) & 3;
- rm = modrm & 7;
- if (mod != 3) {
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_ld_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_mov_TN_reg[ot][0][rm]();
- }
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- gen_op_arpl();
- s->cc_op = CC_OP_EFLAGS;
- if (mod != 3) {
- gen_op_st_T0_A0[ot + s->mem_index]();
- } else {
- gen_op_mov_reg_T0[ot][rm]();
- }
- gen_op_arpl_update();
- }
- break;
- case 0x102: /* lar */
- case 0x103: /* lsl */
- if (!s->pe || s->vm86)
- goto illegal_op;
- ot = dflag ? OT_LONG : OT_WORD;
- modrm = ldub_code(s->pc++);
- reg = ((modrm >> 3) & 7) | rex_r;
- gen_ldst_modrm(s, modrm, ot, OR_TMP0, 0);
- gen_op_mov_TN_reg[ot][1][reg]();
- if (s->cc_op != CC_OP_DYNAMIC)
- gen_op_set_cc_op(s->cc_op);
- if (b == 0x102)
- gen_op_lar();
- else
- gen_op_lsl();
- s->cc_op = CC_OP_EFLAGS;
- gen_op_mov_reg_T1[ot][reg]();
- break;
- case 0x118:
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- op = (modrm >> 3) & 7;
- switch(op) {
- case 0: /* prefetchnta */
- case 1: /* prefetchnt0 */
- case 2: /* prefetchnt0 */
- case 3: /* prefetchnt0 */
- if (mod == 3)
- goto illegal_op;
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- /* nothing more to do */
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x120: /* mov reg, crN */
- case 0x122: /* mov crN, reg */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- modrm = ldub_code(s->pc++);
- if ((modrm & 0xc0) != 0xc0)
- goto illegal_op;
- rm = (modrm & 7) | REX_B(s);
- reg = ((modrm >> 3) & 7) | rex_r;
- if (CODE64(s))
- ot = OT_QUAD;
- else
- ot = OT_LONG;
- switch(reg) {
- case 0:
- case 2:
- case 3:
- case 4:
- case 8:
- if (b & 2) {
- gen_op_mov_TN_reg[ot][0][rm]();
- gen_op_movl_crN_T0(reg);
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- } else {
-#if !defined(CONFIG_USER_ONLY)
- if (reg == 8)
- gen_op_movtl_T0_cr8();
- else
-#endif
- gen_op_movtl_T0_env(offsetof(CPUX86State,cr[reg]));
- gen_op_mov_reg_T0[ot][rm]();
- }
- break;
- default:
- goto illegal_op;
- }
- }
- break;
- case 0x121: /* mov reg, drN */
- case 0x123: /* mov drN, reg */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- modrm = ldub_code(s->pc++);
- if ((modrm & 0xc0) != 0xc0)
- goto illegal_op;
- rm = (modrm & 7) | REX_B(s);
- reg = ((modrm >> 3) & 7) | rex_r;
- if (CODE64(s))
- ot = OT_QUAD;
- else
- ot = OT_LONG;
- /* XXX: do it dynamically with CR4.DE bit */
- if (reg == 4 || reg == 5 || reg >= 8)
- goto illegal_op;
- if (b & 2) {
- gen_op_mov_TN_reg[ot][0][rm]();
- gen_op_movl_drN_T0(reg);
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- } else {
- gen_op_movtl_T0_env(offsetof(CPUX86State,dr[reg]));
- gen_op_mov_reg_T0[ot][rm]();
- }
- }
- break;
- case 0x106: /* clts */
- if (s->cpl != 0) {
- gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
- } else {
- gen_op_clts();
- /* abort block because static cpu state changed */
- gen_jmp_im(s->pc - s->cs_base);
- gen_eob(s);
- }
- break;
- /* MMX/SSE/SSE2/PNI support */
- case 0x1c3: /* MOVNTI reg, mem */
- if (!(s->cpuid_features & CPUID_SSE2))
- goto illegal_op;
- ot = s->dflag == 2 ? OT_QUAD : OT_LONG;
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- if (mod == 3)
- goto illegal_op;
- reg = ((modrm >> 3) & 7) | rex_r;
- /* generate a generic store */
- gen_ldst_modrm(s, modrm, ot, reg, 1);
- break;
- case 0x1ae:
- modrm = ldub_code(s->pc++);
- mod = (modrm >> 6) & 3;
- op = (modrm >> 3) & 7;
- switch(op) {
- case 0: /* fxsave */
- if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
- (s->flags & HF_EM_MASK))
- goto illegal_op;
- if (s->flags & HF_TS_MASK) {
- gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
- break;
- }
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_fxsave_A0((s->dflag == 2));
- break;
- case 1: /* fxrstor */
- if (mod == 3 || !(s->cpuid_features & CPUID_FXSR) ||
- (s->flags & HF_EM_MASK))
- goto illegal_op;
- if (s->flags & HF_TS_MASK) {
- gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
- break;
- }
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- gen_op_fxrstor_A0((s->dflag == 2));
- break;
- case 2: /* ldmxcsr */
- case 3: /* stmxcsr */
- if (s->flags & HF_TS_MASK) {
- gen_exception(s, EXCP07_PREX, pc_start - s->cs_base);
- break;
- }
- if ((s->flags & HF_EM_MASK) || !(s->flags & HF_OSFXSR_MASK) ||
- mod == 3)
- goto illegal_op;
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- if (op == 2) {
- gen_op_ld_T0_A0[OT_LONG + s->mem_index]();
- gen_op_movl_env_T0(offsetof(CPUX86State, mxcsr));
- } else {
- gen_op_movl_T0_env(offsetof(CPUX86State, mxcsr));
- gen_op_st_T0_A0[OT_LONG + s->mem_index]();
- }
- break;
- case 5: /* lfence */
- case 6: /* mfence */
- if ((modrm & 0xc7) != 0xc0 || !(s->cpuid_features & CPUID_SSE))
- goto illegal_op;
- break;
- case 7: /* sfence / clflush */
- if ((modrm & 0xc7) == 0xc0) {
- /* sfence */
- if (!(s->cpuid_features & CPUID_SSE))
- goto illegal_op;
- } else {
- /* clflush */
- if (!(s->cpuid_features & CPUID_CLFLUSH))
- goto illegal_op;
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- }
- break;
- default:
- goto illegal_op;
- }
- break;
- case 0x10d: /* prefetch */
- modrm = ldub_code(s->pc++);
- gen_lea_modrm(s, modrm, &reg_addr, &offset_addr);
- /* ignore for now */
- break;
- case 0x110 ... 0x117:
- case 0x128 ... 0x12f:
- case 0x150 ... 0x177:
- case 0x17c ... 0x17f:
- case 0x1c2:
- case 0x1c4 ... 0x1c6:
- case 0x1d0 ... 0x1fe:
- gen_sse(s, b, pc_start, rex_r);
- break;
- default:
- goto illegal_op;
- }
- /* lock generation */
- if (s->prefix & PREFIX_LOCK)
- gen_op_unlock();
- return s->pc;
- illegal_op:
- if (s->prefix & PREFIX_LOCK)
- gen_op_unlock();
- /* XXX: ensure that no lock was generated */
- gen_exception(s, EXCP06_ILLOP, pc_start - s->cs_base);
- return s->pc;
-}
-
-#define CC_OSZAPC (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C)
-#define CC_OSZAP (CC_O | CC_S | CC_Z | CC_A | CC_P)
-
-/* flags read by an operation */
-static uint16_t opc_read_flags[NB_OPS] = {
- [INDEX_op_aas] = CC_A,
- [INDEX_op_aaa] = CC_A,
- [INDEX_op_das] = CC_A | CC_C,
- [INDEX_op_daa] = CC_A | CC_C,
-
- /* subtle: due to the incl/decl implementation, C is used */
- [INDEX_op_update_inc_cc] = CC_C,
-
- [INDEX_op_into] = CC_O,
-
- [INDEX_op_jb_subb] = CC_C,
- [INDEX_op_jb_subw] = CC_C,
- [INDEX_op_jb_subl] = CC_C,
-
- [INDEX_op_jz_subb] = CC_Z,
- [INDEX_op_jz_subw] = CC_Z,
- [INDEX_op_jz_subl] = CC_Z,
-
- [INDEX_op_jbe_subb] = CC_Z | CC_C,
- [INDEX_op_jbe_subw] = CC_Z | CC_C,
- [INDEX_op_jbe_subl] = CC_Z | CC_C,
-
- [INDEX_op_js_subb] = CC_S,
- [INDEX_op_js_subw] = CC_S,
- [INDEX_op_js_subl] = CC_S,
-
- [INDEX_op_jl_subb] = CC_O | CC_S,
- [INDEX_op_jl_subw] = CC_O | CC_S,
- [INDEX_op_jl_subl] = CC_O | CC_S,
-
- [INDEX_op_jle_subb] = CC_O | CC_S | CC_Z,
- [INDEX_op_jle_subw] = CC_O | CC_S | CC_Z,
- [INDEX_op_jle_subl] = CC_O | CC_S | CC_Z,
-
- [INDEX_op_loopnzw] = CC_Z,
- [INDEX_op_loopnzl] = CC_Z,
- [INDEX_op_loopzw] = CC_Z,
- [INDEX_op_loopzl] = CC_Z,
-
- [INDEX_op_seto_T0_cc] = CC_O,
- [INDEX_op_setb_T0_cc] = CC_C,
- [INDEX_op_setz_T0_cc] = CC_Z,
- [INDEX_op_setbe_T0_cc] = CC_Z | CC_C,
- [INDEX_op_sets_T0_cc] = CC_S,
- [INDEX_op_setp_T0_cc] = CC_P,
- [INDEX_op_setl_T0_cc] = CC_O | CC_S,
- [INDEX_op_setle_T0_cc] = CC_O | CC_S | CC_Z,
-
- [INDEX_op_setb_T0_subb] = CC_C,
- [INDEX_op_setb_T0_subw] = CC_C,
- [INDEX_op_setb_T0_subl] = CC_C,
-
- [INDEX_op_setz_T0_subb] = CC_Z,
- [INDEX_op_setz_T0_subw] = CC_Z,
- [INDEX_op_setz_T0_subl] = CC_Z,
-
- [INDEX_op_setbe_T0_subb] = CC_Z | CC_C,
- [INDEX_op_setbe_T0_subw] = CC_Z | CC_C,
- [INDEX_op_setbe_T0_subl] = CC_Z | CC_C,
-
- [INDEX_op_sets_T0_subb] = CC_S,
- [INDEX_op_sets_T0_subw] = CC_S,
- [INDEX_op_sets_T0_subl] = CC_S,
-
- [INDEX_op_setl_T0_subb] = CC_O | CC_S,
- [INDEX_op_setl_T0_subw] = CC_O | CC_S,
- [INDEX_op_setl_T0_subl] = CC_O | CC_S,
-
- [INDEX_op_setle_T0_subb] = CC_O | CC_S | CC_Z,
- [INDEX_op_setle_T0_subw] = CC_O | CC_S | CC_Z,
- [INDEX_op_setle_T0_subl] = CC_O | CC_S | CC_Z,
-
- [INDEX_op_movl_T0_eflags] = CC_OSZAPC,
- [INDEX_op_cmc] = CC_C,
- [INDEX_op_salc] = CC_C,
-
- /* needed for correct flag optimisation before string ops */
- [INDEX_op_jnz_ecxw] = CC_OSZAPC,
- [INDEX_op_jnz_ecxl] = CC_OSZAPC,
- [INDEX_op_jz_ecxw] = CC_OSZAPC,
- [INDEX_op_jz_ecxl] = CC_OSZAPC,
-
-#ifdef TARGET_X86_64
- [INDEX_op_jb_subq] = CC_C,
- [INDEX_op_jz_subq] = CC_Z,
- [INDEX_op_jbe_subq] = CC_Z | CC_C,
- [INDEX_op_js_subq] = CC_S,
- [INDEX_op_jl_subq] = CC_O | CC_S,
- [INDEX_op_jle_subq] = CC_O | CC_S | CC_Z,
-
- [INDEX_op_loopnzq] = CC_Z,
- [INDEX_op_loopzq] = CC_Z,
-
- [INDEX_op_setb_T0_subq] = CC_C,
- [INDEX_op_setz_T0_subq] = CC_Z,
- [INDEX_op_setbe_T0_subq] = CC_Z | CC_C,
- [INDEX_op_sets_T0_subq] = CC_S,
- [INDEX_op_setl_T0_subq] = CC_O | CC_S,
- [INDEX_op_setle_T0_subq] = CC_O | CC_S | CC_Z,
-
- [INDEX_op_jnz_ecxq] = CC_OSZAPC,
- [INDEX_op_jz_ecxq] = CC_OSZAPC,
-#endif
-
-#define DEF_READF(SUFFIX)\
- [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_C,\
- [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_C,\
- [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_C,\
- X86_64_DEF([INDEX_op_adcq ## SUFFIX ## _T0_T1_cc] = CC_C,)\
- [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_C,\
- [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_C,\
- [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_C,\
- X86_64_DEF([INDEX_op_sbbq ## SUFFIX ## _T0_T1_cc] = CC_C,)\
-\
- [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_C,\
- [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_C,\
- [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_C,\
- X86_64_DEF([INDEX_op_rclq ## SUFFIX ## _T0_T1_cc] = CC_C,)\
- [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_C,\
- [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_C,\
- [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_C,\
- X86_64_DEF([INDEX_op_rcrq ## SUFFIX ## _T0_T1_cc] = CC_C,)
-
- DEF_READF( )
- DEF_READF(_raw)
-#ifndef CONFIG_USER_ONLY
- DEF_READF(_kernel)
- DEF_READF(_user)
-#endif
-};
-
-/* flags written by an operation */
-static uint16_t opc_write_flags[NB_OPS] = {
- [INDEX_op_update2_cc] = CC_OSZAPC,
- [INDEX_op_update1_cc] = CC_OSZAPC,
- [INDEX_op_cmpl_T0_T1_cc] = CC_OSZAPC,
- [INDEX_op_update_neg_cc] = CC_OSZAPC,
- /* subtle: due to the incl/decl implementation, C is used */
- [INDEX_op_update_inc_cc] = CC_OSZAPC,
- [INDEX_op_testl_T0_T1_cc] = CC_OSZAPC,
-
- [INDEX_op_mulb_AL_T0] = CC_OSZAPC,
- [INDEX_op_mulw_AX_T0] = CC_OSZAPC,
- [INDEX_op_mull_EAX_T0] = CC_OSZAPC,
- X86_64_DEF([INDEX_op_mulq_EAX_T0] = CC_OSZAPC,)
- [INDEX_op_imulb_AL_T0] = CC_OSZAPC,
- [INDEX_op_imulw_AX_T0] = CC_OSZAPC,
- [INDEX_op_imull_EAX_T0] = CC_OSZAPC,
- X86_64_DEF([INDEX_op_imulq_EAX_T0] = CC_OSZAPC,)
- [INDEX_op_imulw_T0_T1] = CC_OSZAPC,
- [INDEX_op_imull_T0_T1] = CC_OSZAPC,
- X86_64_DEF([INDEX_op_imulq_T0_T1] = CC_OSZAPC,)
-
- /* sse */
- [INDEX_op_ucomiss] = CC_OSZAPC,
- [INDEX_op_ucomisd] = CC_OSZAPC,
- [INDEX_op_comiss] = CC_OSZAPC,
- [INDEX_op_comisd] = CC_OSZAPC,
-
- /* bcd */
- [INDEX_op_aam] = CC_OSZAPC,
- [INDEX_op_aad] = CC_OSZAPC,
- [INDEX_op_aas] = CC_OSZAPC,
- [INDEX_op_aaa] = CC_OSZAPC,
- [INDEX_op_das] = CC_OSZAPC,
- [INDEX_op_daa] = CC_OSZAPC,
-
- [INDEX_op_movb_eflags_T0] = CC_S | CC_Z | CC_A | CC_P | CC_C,
- [INDEX_op_movw_eflags_T0] = CC_OSZAPC,
- [INDEX_op_movl_eflags_T0] = CC_OSZAPC,
- [INDEX_op_movw_eflags_T0_io] = CC_OSZAPC,
- [INDEX_op_movl_eflags_T0_io] = CC_OSZAPC,
- [INDEX_op_movw_eflags_T0_cpl0] = CC_OSZAPC,
- [INDEX_op_movl_eflags_T0_cpl0] = CC_OSZAPC,
- [INDEX_op_clc] = CC_C,
- [INDEX_op_stc] = CC_C,
- [INDEX_op_cmc] = CC_C,
-
- [INDEX_op_btw_T0_T1_cc] = CC_OSZAPC,
- [INDEX_op_btl_T0_T1_cc] = CC_OSZAPC,
- X86_64_DEF([INDEX_op_btq_T0_T1_cc] = CC_OSZAPC,)
- [INDEX_op_btsw_T0_T1_cc] = CC_OSZAPC,
- [INDEX_op_btsl_T0_T1_cc] = CC_OSZAPC,
- X86_64_DEF([INDEX_op_btsq_T0_T1_cc] = CC_OSZAPC,)
- [INDEX_op_btrw_T0_T1_cc] = CC_OSZAPC,
- [INDEX_op_btrl_T0_T1_cc] = CC_OSZAPC,
- X86_64_DEF([INDEX_op_btrq_T0_T1_cc] = CC_OSZAPC,)
- [INDEX_op_btcw_T0_T1_cc] = CC_OSZAPC,
- [INDEX_op_btcl_T0_T1_cc] = CC_OSZAPC,
- X86_64_DEF([INDEX_op_btcq_T0_T1_cc] = CC_OSZAPC,)
-
- [INDEX_op_bsfw_T0_cc] = CC_OSZAPC,
- [INDEX_op_bsfl_T0_cc] = CC_OSZAPC,
- X86_64_DEF([INDEX_op_bsfq_T0_cc] = CC_OSZAPC,)
- [INDEX_op_bsrw_T0_cc] = CC_OSZAPC,
- [INDEX_op_bsrl_T0_cc] = CC_OSZAPC,
- X86_64_DEF([INDEX_op_bsrq_T0_cc] = CC_OSZAPC,)
-
- [INDEX_op_cmpxchgb_T0_T1_EAX_cc] = CC_OSZAPC,
- [INDEX_op_cmpxchgw_T0_T1_EAX_cc] = CC_OSZAPC,
- [INDEX_op_cmpxchgl_T0_T1_EAX_cc] = CC_OSZAPC,
- X86_64_DEF([INDEX_op_cmpxchgq_T0_T1_EAX_cc] = CC_OSZAPC,)
-
- [INDEX_op_cmpxchg8b] = CC_Z,
- [INDEX_op_lar] = CC_Z,
- [INDEX_op_lsl] = CC_Z,
- [INDEX_op_verr] = CC_Z,
- [INDEX_op_verw] = CC_Z,
- [INDEX_op_fcomi_ST0_FT0] = CC_Z | CC_P | CC_C,
- [INDEX_op_fucomi_ST0_FT0] = CC_Z | CC_P | CC_C,
-
-#define DEF_WRITEF(SUFFIX)\
- [INDEX_op_adcb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- [INDEX_op_adcw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- [INDEX_op_adcl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- X86_64_DEF([INDEX_op_adcq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\
- [INDEX_op_sbbb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- [INDEX_op_sbbw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- [INDEX_op_sbbl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- X86_64_DEF([INDEX_op_sbbq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\
-\
- [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- X86_64_DEF([INDEX_op_rolq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\
- [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- X86_64_DEF([INDEX_op_rorq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\
-\
- [INDEX_op_rclb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- [INDEX_op_rclw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- [INDEX_op_rcll ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- X86_64_DEF([INDEX_op_rclq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\
- [INDEX_op_rcrb ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- [INDEX_op_rcrw ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- [INDEX_op_rcrl ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,\
- X86_64_DEF([INDEX_op_rcrq ## SUFFIX ## _T0_T1_cc] = CC_O | CC_C,)\
-\
- [INDEX_op_shlb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- [INDEX_op_shlw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- [INDEX_op_shll ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- X86_64_DEF([INDEX_op_shlq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\
-\
- [INDEX_op_shrb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- [INDEX_op_shrw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- [INDEX_op_shrl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- X86_64_DEF([INDEX_op_shrq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\
-\
- [INDEX_op_sarb ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- [INDEX_op_sarw ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- [INDEX_op_sarl ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,\
- X86_64_DEF([INDEX_op_sarq ## SUFFIX ## _T0_T1_cc] = CC_OSZAPC,)\
-\
- [INDEX_op_shldw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
- [INDEX_op_shldl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
- X86_64_DEF([INDEX_op_shldq ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,)\
- [INDEX_op_shldw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
- [INDEX_op_shldl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
- X86_64_DEF([INDEX_op_shldq ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,)\
-\
- [INDEX_op_shrdw ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
- [INDEX_op_shrdl ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,\
- X86_64_DEF([INDEX_op_shrdq ## SUFFIX ## _T0_T1_ECX_cc] = CC_OSZAPC,)\
- [INDEX_op_shrdw ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
- [INDEX_op_shrdl ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,\
- X86_64_DEF([INDEX_op_shrdq ## SUFFIX ## _T0_T1_im_cc] = CC_OSZAPC,)\
-\
- [INDEX_op_cmpxchgb ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\
- [INDEX_op_cmpxchgw ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\
- [INDEX_op_cmpxchgl ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,\
- X86_64_DEF([INDEX_op_cmpxchgq ## SUFFIX ## _T0_T1_EAX_cc] = CC_OSZAPC,)
-
-
- DEF_WRITEF( )
- DEF_WRITEF(_raw)
-#ifndef CONFIG_USER_ONLY
- DEF_WRITEF(_kernel)
- DEF_WRITEF(_user)
-#endif
-};
-
-/* simpler form of an operation if no flags need to be generated */
-static uint16_t opc_simpler[NB_OPS] = {
- [INDEX_op_update2_cc] = INDEX_op_nop,
- [INDEX_op_update1_cc] = INDEX_op_nop,
- [INDEX_op_update_neg_cc] = INDEX_op_nop,
-#if 0
- /* broken: CC_OP logic must be rewritten */
- [INDEX_op_update_inc_cc] = INDEX_op_nop,
-#endif
-
- [INDEX_op_shlb_T0_T1_cc] = INDEX_op_shlb_T0_T1,
- [INDEX_op_shlw_T0_T1_cc] = INDEX_op_shlw_T0_T1,
- [INDEX_op_shll_T0_T1_cc] = INDEX_op_shll_T0_T1,
- X86_64_DEF([INDEX_op_shlq_T0_T1_cc] = INDEX_op_shlq_T0_T1,)
-
- [INDEX_op_shrb_T0_T1_cc] = INDEX_op_shrb_T0_T1,
- [INDEX_op_shrw_T0_T1_cc] = INDEX_op_shrw_T0_T1,
- [INDEX_op_shrl_T0_T1_cc] = INDEX_op_shrl_T0_T1,
- X86_64_DEF([INDEX_op_shrq_T0_T1_cc] = INDEX_op_shrq_T0_T1,)
-
- [INDEX_op_sarb_T0_T1_cc] = INDEX_op_sarb_T0_T1,
- [INDEX_op_sarw_T0_T1_cc] = INDEX_op_sarw_T0_T1,
- [INDEX_op_sarl_T0_T1_cc] = INDEX_op_sarl_T0_T1,
- X86_64_DEF([INDEX_op_sarq_T0_T1_cc] = INDEX_op_sarq_T0_T1,)
-
-#define DEF_SIMPLER(SUFFIX)\
- [INDEX_op_rolb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolb ## SUFFIX ## _T0_T1,\
- [INDEX_op_rolw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolw ## SUFFIX ## _T0_T1,\
- [INDEX_op_roll ## SUFFIX ## _T0_T1_cc] = INDEX_op_roll ## SUFFIX ## _T0_T1,\
- X86_64_DEF([INDEX_op_rolq ## SUFFIX ## _T0_T1_cc] = INDEX_op_rolq ## SUFFIX ## _T0_T1,)\
-\
- [INDEX_op_rorb ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorb ## SUFFIX ## _T0_T1,\
- [INDEX_op_rorw ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorw ## SUFFIX ## _T0_T1,\
- [INDEX_op_rorl ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorl ## SUFFIX ## _T0_T1,\
- X86_64_DEF([INDEX_op_rorq ## SUFFIX ## _T0_T1_cc] = INDEX_op_rorq ## SUFFIX ## _T0_T1,)
-
- DEF_SIMPLER( )
- DEF_SIMPLER(_raw)
-#ifndef CONFIG_USER_ONLY
- DEF_SIMPLER(_kernel)
- DEF_SIMPLER(_user)
-#endif
-};
-
-void optimize_flags_init(void)
-{
- int i;
- /* put default values in arrays */
- for(i = 0; i < NB_OPS; i++) {
- if (opc_simpler[i] == 0)
- opc_simpler[i] = i;
- }
-}
-
-/* CPU flags computation optimization: we move backward thru the
- generated code to see which flags are needed. The operation is
- modified if suitable */
-static void optimize_flags(uint16_t *opc_buf, int opc_buf_len)
-{
- uint16_t *opc_ptr;
- int live_flags, write_flags, op;
-
- opc_ptr = opc_buf + opc_buf_len;
- /* live_flags contains the flags needed by the next instructions
- in the code. At the end of the bloc, we consider that all the
- flags are live. */
- live_flags = CC_OSZAPC;
- while (opc_ptr > opc_buf) {
- op = *--opc_ptr;
- /* if none of the flags written by the instruction is used,
- then we can try to find a simpler instruction */
- write_flags = opc_write_flags[op];
- if ((live_flags & write_flags) == 0) {
- *opc_ptr = opc_simpler[op];
- }
- /* compute the live flags before the instruction */
- live_flags &= ~write_flags;
- live_flags |= opc_read_flags[op];
- }
-}
-
-/* generate intermediate code in gen_opc_buf and gen_opparam_buf for
- basic block 'tb'. If search_pc is TRUE, also generate PC
- information for each intermediate instruction. */
-static inline int gen_intermediate_code_internal(CPUState *env,
- TranslationBlock *tb,
- int search_pc)
-{
- DisasContext dc1, *dc = &dc1;
- target_ulong pc_ptr;
- uint16_t *gen_opc_end;
- int flags, j, lj, cflags;
- target_ulong pc_start;
- target_ulong cs_base;
-
- /* generate intermediate code */
- pc_start = tb->pc;
- cs_base = tb->cs_base;
- flags = tb->flags;
- cflags = tb->cflags;
-
- dc->pe = (flags >> HF_PE_SHIFT) & 1;
- dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
- dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
- dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
- dc->f_st = 0;
- dc->vm86 = (flags >> VM_SHIFT) & 1;
- dc->cpl = (flags >> HF_CPL_SHIFT) & 3;
- dc->iopl = (flags >> IOPL_SHIFT) & 3;
- dc->tf = (flags >> TF_SHIFT) & 1;
- dc->singlestep_enabled = env->singlestep_enabled;
- dc->cc_op = CC_OP_DYNAMIC;
- dc->cs_base = cs_base;
- dc->tb = tb;
- dc->popl_esp_hack = 0;
- /* select memory access functions */
- dc->mem_index = 0;
- if (flags & HF_SOFTMMU_MASK) {
- if (dc->cpl == 3)
- dc->mem_index = 2 * 4;
- else
- dc->mem_index = 1 * 4;
- }
- dc->cpuid_features = env->cpuid_features;
- dc->cpuid_ext_features = env->cpuid_ext_features;
-#ifdef TARGET_X86_64
- dc->lma = (flags >> HF_LMA_SHIFT) & 1;
- dc->code64 = (flags >> HF_CS64_SHIFT) & 1;
-#endif
- dc->flags = flags;
- dc->jmp_opt = !(dc->tf || env->singlestep_enabled ||
- (flags & HF_INHIBIT_IRQ_MASK)
-#ifndef CONFIG_SOFTMMU
- || (flags & HF_SOFTMMU_MASK)
-#endif
- );
-#if 0
- /* check addseg logic */
- if (!dc->addseg && (dc->vm86 || !dc->pe || !dc->code32))
- printf("ERROR addseg\n");
-#endif
-
- 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;
-
- dc->is_jmp = DISAS_NEXT;
- pc_ptr = pc_start;
- lj = -1;
-
- for(;;) {
- if (env->nb_breakpoints > 0) {
- for(j = 0; j < env->nb_breakpoints; j++) {
- if (env->breakpoints[j] == pc_ptr) {
- gen_debug(dc, pc_ptr - dc->cs_base);
- 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] = pc_ptr;
- gen_opc_cc_op[lj] = dc->cc_op;
- gen_opc_instr_start[lj] = 1;
- }
- pc_ptr = disas_insn(dc, pc_ptr);
- /* stop translation if indicated */
- if (dc->is_jmp)
- break;
- /* if single step mode, we generate only one instruction and
- generate an exception */
- /* if irq were inhibited with HF_INHIBIT_IRQ_MASK, we clear
- the flag and abort the translation to give the irqs a
- change to be happen */
- if (dc->tf || dc->singlestep_enabled ||
- (flags & HF_INHIBIT_IRQ_MASK) ||
- (cflags & CF_SINGLE_INSN)) {
- gen_jmp_im(pc_ptr - dc->cs_base);
- gen_eob(dc);
- break;
- }
- /* if too long translation, stop generation too */
- if (gen_opc_ptr >= gen_opc_end ||
- (pc_ptr - pc_start) >= (TARGET_PAGE_SIZE - 32)) {
- gen_jmp_im(pc_ptr - dc->cs_base);
- gen_eob(dc);
- break;
- }
- }
- *gen_opc_ptr = INDEX_op_end;
- /* we don't forget to fill the last values */
- if (search_pc) {
- j = gen_opc_ptr - gen_opc_buf;
- lj++;
- while (lj <= j)
- gen_opc_instr_start[lj++] = 0;
- }
-
-#ifdef DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_CPU) {
- cpu_dump_state(env, logfile, fprintf, X86_DUMP_CCOP);
- }
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- int disas_flags;
- fprintf(logfile, "----------------\n");
- fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
-#ifdef TARGET_X86_64
- if (dc->code64)
- disas_flags = 2;
- else
-#endif
- disas_flags = !dc->code32;
- target_disas(logfile, pc_start, pc_ptr - pc_start, disas_flags);
- 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
-
- /* optimize flag computations */
- optimize_flags(gen_opc_buf, gen_opc_ptr - gen_opc_buf);
-
-#ifdef DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_OP_OPT) {
- fprintf(logfile, "AFTER FLAGS OPT:\n");
- dump_ops(gen_opc_buf, gen_opparam_buf);
- fprintf(logfile, "\n");
- }
-#endif
- if (!search_pc)
- tb->size = pc_ptr - pc_start;
- return 0;
-}
-
-int gen_intermediate_code(CPUState *env, TranslationBlock *tb)
-{
- return gen_intermediate_code_internal(env, tb, 0);
-}
-
-int gen_intermediate_code_pc(CPUState *env, TranslationBlock *tb)
-{
- return gen_intermediate_code_internal(env, tb, 1);
-}
-
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
deleted file mode 100644
index 330f9eb..0000000
--- a/target-mips/cpu.h
+++ /dev/null
@@ -1,279 +0,0 @@
-#if !defined (__MIPS_CPU_H__)
-#define __MIPS_CPU_H__
-
-#define TARGET_HAS_ICE 1
-
-#include "config.h"
-#include "mips-defs.h"
-#include "cpu-defs.h"
-#include "softfloat.h"
-
-// uint_fast8_t and uint_fast16_t not in <sys/int_types.h>
-// XXX: move that elsewhere
-#if defined(HOST_SOLARIS) && SOLARISREV < 10
-typedef unsigned char uint_fast8_t;
-typedef unsigned int uint_fast16_t;
-#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 */
- uint32_t w[2]; /* binary single fixed-point */
-};
-/* define FP_ENDIAN_IDX to access the same location
- * in the fpr_t union regardless of the host endianess
- */
-#if defined(WORDS_BIGENDIAN)
-# define FP_ENDIAN_IDX 1
-#else
-# define FP_ENDIAN_IDX 0
-#endif
-
-#if defined(MIPS_USES_R4K_TLB)
-typedef struct tlb_t tlb_t;
-struct tlb_t {
- target_ulong VPN;
- target_ulong end;
- target_ulong end2;
- uint_fast8_t ASID;
- uint_fast16_t G:1;
- uint_fast16_t C0:3;
- uint_fast16_t C1:3;
- uint_fast16_t V0:1;
- uint_fast16_t V1:1;
- uint_fast16_t D0:1;
- uint_fast16_t D1:1;
- target_ulong PFN[2];
-};
-#endif
-
-typedef struct CPUMIPSState CPUMIPSState;
-struct CPUMIPSState {
- /* General integer registers */
- target_ulong gpr[32];
- /* Special registers */
- target_ulong PC;
- uint32_t 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])
-
-#ifndef USE_HOST_FLOAT_REGS
- fpr_t ft0;
- fpr_t ft1;
- fpr_t ft2;
-#endif
- float_status fp_status;
- /* fpu implementation/revision register */
- uint32_t fcr0;
- /* 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 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_NB];
-#endif
- uint32_t CP0_index;
- uint32_t CP0_random;
- uint32_t CP0_EntryLo0;
- uint32_t CP0_EntryLo1;
- uint32_t CP0_Context;
- uint32_t CP0_PageMask;
- uint32_t CP0_Wired;
- uint32_t CP0_BadVAddr;
- uint32_t CP0_Count;
- uint32_t CP0_EntryHi;
- uint32_t CP0_Compare;
- uint32_t CP0_Status;
-#define CP0St_CU3 31
-#define CP0St_CU2 30
-#define CP0St_CU1 29
-#define CP0St_CU0 28
-#define CP0St_RP 27
-#define CP0St_FR 26
-#define CP0St_RE 25
-#define CP0St_BEV 22
-#define CP0St_TS 21
-#define CP0St_SR 20
-#define CP0St_NMI 19
-#define CP0St_IM 8
-#define CP0St_UM 4
-#define CP0St_ERL 2
-#define CP0St_EXL 1
-#define CP0St_IE 0
- uint32_t CP0_Cause;
-#define CP0Ca_IV 23
- uint32_t CP0_EPC;
- uint32_t CP0_PRid;
- uint32_t CP0_Config0;
-#define CP0C0_M 31
-#define CP0C0_K23 28
-#define CP0C0_KU 25
-#define CP0C0_MDU 20
-#define CP0C0_MM 17
-#define CP0C0_BM 16
-#define CP0C0_BE 15
-#define CP0C0_AT 13
-#define CP0C0_AR 10
-#define CP0C0_MT 7
-#define CP0C0_K0 0
- uint32_t CP0_Config1;
-#define CP0C1_MMU 25
-#define CP0C1_IS 22
-#define CP0C1_IL 19
-#define CP0C1_IA 16
-#define CP0C1_DS 13
-#define CP0C1_DL 10
-#define CP0C1_DA 7
-#define CP0C1_PC 4
-#define CP0C1_WR 3
-#define CP0C1_CA 2
-#define CP0C1_EP 1
-#define CP0C1_FP 0
- uint32_t CP0_LLAddr;
- uint32_t CP0_WatchLo;
- uint32_t CP0_WatchHi;
- uint32_t CP0_Debug;
-#define CPDB_DBD 31
-#define CP0DB_DM 30
-#define CP0DB_LSNM 28
-#define CP0DB_Doze 27
-#define CP0DB_Halt 26
-#define CP0DB_CNT 25
-#define CP0DB_IBEP 24
-#define CP0DB_DBEP 21
-#define CP0DB_IEXI 20
-#define CP0DB_VER 15
-#define CP0DB_DEC 10
-#define CP0DB_SSt 8
-#define CP0DB_DINT 5
-#define CP0DB_DIB 4
-#define CP0DB_DDBS 3
-#define CP0DB_DDBL 2
-#define CP0DB_DBp 1
-#define CP0DB_DSS 0
- uint32_t CP0_DEPC;
- uint32_t CP0_TagLo;
- uint32_t CP0_DataLo;
- uint32_t CP0_ErrorEPC;
- uint32_t CP0_DESAVE;
- /* Qemu */
- struct QEMUTimer *timer; /* Internal timer */
- int interrupt_request;
- jmp_buf jmp_env;
- int exception_index;
- int error_code;
- int user_mode_only; /* user mode only simulation */
- uint32_t hflags; /* CPU State */
- /* TMASK defines different execution modes */
-#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 */
- /* If translation is interrupted between the branch instruction and
- * the delay slot, record what type of branch it is so that we can
- * resume translation properly. It might be possible to reduce
- * this from three bits to two. */
-#define MIPS_HFLAG_BMASK 0x0380
-#define MIPS_HFLAG_B 0x0080 /* Unconditional branch */
-#define MIPS_HFLAG_BC 0x0100 /* Conditional branch */
-#define MIPS_HFLAG_BL 0x0180 /* Likely branch */
-#define MIPS_HFLAG_BR 0x0200 /* branch to register (can't link TB) */
- target_ulong btarget; /* Jump / branch target */
- int bcond; /* Branch condition (if needed) */
-
- int halted; /* TRUE if the CPU is in suspend state */
-
- CPU_COMMON
-};
-
-#include "cpu-all.h"
-
-/* Memory access type :
- * may be needed for precise access rights control and precise exceptions.
- */
-enum {
- /* 1 bit to define user level / supervisor access */
- ACCESS_USER = 0x00,
- ACCESS_SUPER = 0x01,
- /* 1 bit to indicate direction */
- ACCESS_STORE = 0x02,
- /* Type of instruction that generated the access */
- ACCESS_CODE = 0x10, /* Code fetch access */
- ACCESS_INT = 0x20, /* Integer load/store access */
- ACCESS_FLOAT = 0x30, /* floating point load/store access */
-};
-
-/* Exceptions */
-enum {
- EXCP_NONE = -1,
- EXCP_RESET = 0,
- EXCP_SRESET,
- EXCP_DSS,
- EXCP_DINT,
- EXCP_NMI,
- EXCP_MCHECK,
- EXCP_EXT_INTERRUPT,
- EXCP_DFWATCH,
- EXCP_DIB, /* 8 */
- EXCP_IWATCH,
- EXCP_AdEL,
- EXCP_AdES,
- EXCP_TLBF,
- EXCP_IBE,
- EXCP_DBp,
- EXCP_SYSCALL,
- EXCP_BREAK, /* 16 */
- EXCP_CpU,
- EXCP_RI,
- EXCP_OVERFLOW,
- EXCP_TRAP,
- EXCP_DDBS,
- EXCP_DWATCH,
- EXCP_LAE,
- EXCP_SAE, /* 24 */
- EXCP_LTLBL,
- EXCP_TLBL,
- EXCP_TLBS,
- EXCP_DBE,
- EXCP_DDBL,
- EXCP_MTCP0 = 0x104, /* mtmsr instruction: */
- /* may change privilege level */
- EXCP_BRANCH = 0x108, /* branch instruction */
- EXCP_ERET = 0x10C, /* return from interrupt */
- EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */
- EXCP_FLUSH = 0x109,
-};
-
-int cpu_mips_exec(CPUMIPSState *s);
-CPUMIPSState *cpu_mips_init(void);
-uint32_t cpu_mips_get_clock (void);
-
-#endif /* !defined (__MIPS_CPU_H__) */
diff --git a/target-mips/exec.h b/target-mips/exec.h
deleted file mode 100644
index 93014d6..0000000
--- a/target-mips/exec.h
+++ /dev/null
@@ -1,119 +0,0 @@
-#if !defined(__QEMU_MIPS_EXEC_H__)
-#define __QEMU_MIPS_EXEC_H__
-
-//#define DEBUG_OP
-
-#include "mips-defs.h"
-#include "dyngen-exec.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
-
-register host_uint_t T0 asm(AREG1);
-register host_uint_t T1 asm(AREG2);
-register host_uint_t T2 asm(AREG3);
-
-#if defined (USE_HOST_FLOAT_REGS)
-#error "implement me."
-#else
-#define FDT0 (env->ft0.fd)
-#define FDT1 (env->ft1.fd)
-#define FDT2 (env->ft2.fd)
-#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 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])
-#endif
-
-#if defined (DEBUG_OP)
-#define RETURN() __asm__ __volatile__("nop");
-#else
-#define RETURN() __asm__ __volatile__("");
-#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)
-{
-}
-
-#if (HOST_LONG_BITS == 32)
-void do_mult (void);
-void do_multu (void);
-void do_madd (void);
-void do_maddu (void);
-void do_msub (void);
-void do_msubu (void);
-#endif
-void do_mfc0(int reg, int sel);
-void do_mtc0(int reg, int sel);
-void do_tlbwi (void);
-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);
-#if !defined(CONFIG_USER_ONLY)
-void do_lwl_user (uint32_t);
-void do_lwl_kernel (uint32_t);
-void do_lwr_user (uint32_t);
-void do_lwr_kernel (uint32_t);
-uint32_t do_swl_user (uint32_t);
-uint32_t do_swl_kernel (uint32_t);
-uint32_t do_swr_user (uint32_t);
-uint32_t do_swr_kernel (uint32_t);
-#endif
-void do_pmon (int function);
-
-void dump_sc (void);
-
-int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int is_user, int is_softmmu);
-void do_interrupt (CPUState *env);
-
-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 (uint32_t exception);
-
-void cpu_dump_state(CPUState *env, FILE *f,
- int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
- int flags);
-void cpu_mips_irqctrl_init (void);
-uint32_t cpu_mips_get_random (CPUState *env);
-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_clock_init (CPUState *env);
-
-#endif /* !defined(__QEMU_MIPS_EXEC_H__) */
diff --git a/target-mips/fop_template.c b/target-mips/fop_template.c
deleted file mode 100644
index bc0a6e0..0000000
--- a/target-mips/fop_template.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * MIPS emulation micro-operations templates for floating point reg
- * load & store for qemu.
- *
- * Copyright (c) 2006 Marius Groeger
- *
- * 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(SFREG)
-
-#define OP_WLOAD_FREG(treg, tregname, SFREG) \
- void glue(glue(op_load_fpr_,tregname), SFREG) (void) \
- { \
- treg = FPR_W(env, SFREG); \
- RETURN(); \
- }
-
-#define OP_WSTORE_FREG(treg, tregname, SFREG) \
- void glue(glue(op_store_fpr_,tregname), SFREG) (void)\
- { \
- FPR_W(env, SFREG) = 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)
-
-OP_WLOAD_FREG(WT1, WT1_fpr, SFREG)
-OP_WSTORE_FREG(WT1, WT1_fpr, SFREG)
-
-OP_WLOAD_FREG(WT2, WT2_fpr, SFREG)
-OP_WSTORE_FREG(WT2, WT2_fpr, SFREG)
-
-#endif
-
-#if defined(DFREG)
-
-#define OP_DLOAD_FREG(treg, tregname, DFREG) \
- void glue(glue(op_load_fpr_,tregname), DFREG) (void) \
- { \
- treg = FPR_D(env, DFREG); \
- RETURN(); \
- }
-
-#define OP_DSTORE_FREG(treg, tregname, DFREG) \
- void glue(glue(op_store_fpr_,tregname), DFREG) (void)\
- { \
- FPR_D(env, DFREG) = treg; \
- RETURN(); \
- }
-
-OP_DLOAD_FREG(DT0, DT0_fpr, DFREG)
-OP_DSTORE_FREG(DT0, DT0_fpr, DFREG)
-
-OP_DLOAD_FREG(DT1, DT1_fpr, DFREG)
-OP_DSTORE_FREG(DT1, DT1_fpr, DFREG)
-
-OP_DLOAD_FREG(DT2, DT2_fpr, DFREG)
-OP_DSTORE_FREG(DT2, DT2_fpr, DFREG)
-
-#endif
-
-#if defined (FTN)
-
-#define SET_RESET(treg, tregname) \
- void glue(op_set, tregname)(void) \
- { \
- treg = PARAM1; \
- RETURN(); \
- } \
- void glue(op_reset, tregname)(void) \
- { \
- treg = 0; \
- RETURN(); \
- } \
-
-SET_RESET(WT0, _WT0)
-SET_RESET(WT1, _WT1)
-SET_RESET(WT2, _WT2)
-SET_RESET(DT0, _DT0)
-SET_RESET(DT1, _DT1)
-SET_RESET(DT2, _DT2)
-
-#endif
diff --git a/target-mips/helper.c b/target-mips/helper.c
deleted file mode 100644
index 9c8e4f6..0000000
--- a/target-mips/helper.c
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * MIPS emulation helpers for qemu.
- *
- * Copyright (c) 2004-2005 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 <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <assert.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-
-enum {
- TLBRET_DIRTY = -4,
- TLBRET_INVALID = -3,
- TLBRET_NOMATCH = -2,
- TLBRET_BADADDR = -1,
- TLBRET_MATCH = 0
-};
-
-/* MIPS32 4K MMU emulation */
-#ifdef MIPS_USES_R4K_TLB
-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;
-
- for (i = 0; i < MIPS_TLB_NB; i++) {
- tlb = &env->tlb[i];
- /* Check ASID, virtual page number & size */
- if ((tlb->G == 1 || tlb->ASID == ASID) &&
- tlb->VPN == tag && address < tlb->end2) {
- /* TLB match */
- n = (address >> TARGET_PAGE_BITS) & 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);
- *prot = PAGE_READ;
- if (n ? tlb->D1 : tlb->D0)
- *prot |= PAGE_WRITE;
- return TLBRET_MATCH;
- }
- return TLBRET_DIRTY;
- }
- }
- return TLBRET_NOMATCH;
-}
-#endif
-
-static int get_physical_address (CPUState *env, target_ulong *physical,
- int *prot, target_ulong address,
- int rw, int access_type)
-{
- /* User mode can only access useg */
- int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
- int ret = TLBRET_MATCH;
-
-#if 0
- if (logfile) {
- fprintf(logfile, "user mode %d h %08x\n",
- user_mode, env->hflags);
- }
-#endif
- if (user_mode && address > 0x7FFFFFFFUL)
- return TLBRET_BADADDR;
- if (address < 0x80000000UL) {
- if (!(env->hflags & MIPS_HFLAG_ERL)) {
-#ifdef MIPS_USES_R4K_TLB
- ret = map_address(env, physical, prot, address, rw, access_type);
-#else
- *physical = address + 0x40000000UL;
- *prot = PAGE_READ | PAGE_WRITE;
-#endif
- } else {
- *physical = address;
- *prot = PAGE_READ | PAGE_WRITE;
- }
- } else if (address < 0xA0000000UL) {
- /* kseg0 */
- /* XXX: check supervisor mode */
- *physical = address - 0x80000000UL;
- *prot = PAGE_READ | PAGE_WRITE;
- } else if (address < 0xC0000000UL) {
- /* kseg1 */
- /* XXX: check supervisor mode */
- *physical = address - 0xA0000000UL;
- *prot = PAGE_READ | PAGE_WRITE;
- } else if (address < 0xE0000000UL) {
- /* kseg2 */
-#ifdef MIPS_USES_R4K_TLB
- ret = map_address(env, physical, prot, address, rw, access_type);
-#else
- *physical = address;
- *prot = PAGE_READ | PAGE_WRITE;
-#endif
- } else {
- /* kseg3 */
- /* XXX: check supervisor mode */
- /* XXX: debug segment is not emulated */
-#ifdef MIPS_USES_R4K_TLB
- ret = map_address(env, physical, prot, address, rw, access_type);
-#else
- *physical = address;
- *prot = PAGE_READ | PAGE_WRITE;
-#endif
- }
-#if 0
- if (logfile) {
- fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw,
- access_type, *physical, *prot, ret);
- }
-#endif
-
- return ret;
-}
-
-#if defined(CONFIG_USER_ONLY)
-target_ulong 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_ulong phys_addr;
- int prot;
-
- if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
- return -1;
- return phys_addr;
-}
-
-void cpu_mips_init_mmu (CPUState *env)
-{
-}
-#endif /* !defined(CONFIG_USER_ONLY) */
-
-int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int is_user, int is_softmmu)
-{
- target_ulong physical;
- int prot;
- int exception = 0, error_code = 0;
- int access_type;
- int ret = 0;
-
- if (logfile) {
-#if 0
- cpu_dump_state(env, logfile, fprintf, 0);
-#endif
- fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
- __func__, env->PC, address, rw, is_user, is_softmmu);
- }
-
- rw &= 1;
-
- /* data access */
- /* XXX: put correct access by using cpu_restore_state()
- correctly */
- access_type = ACCESS_INT;
- if (env->user_mode_only) {
- /* user mode only emulation */
- ret = TLBRET_NOMATCH;
- goto do_fault;
- }
- ret = get_physical_address(env, &physical, &prot,
- address, rw, access_type);
- if (logfile) {
- fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
- __func__, address, ret, physical, prot);
- }
- if (ret == TLBRET_MATCH) {
- ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
- physical & TARGET_PAGE_MASK, prot,
- is_user, is_softmmu);
- } else if (ret < 0) {
- do_fault:
- switch (ret) {
- default:
- case TLBRET_BADADDR:
- /* Reference to kernel address from user mode or supervisor mode */
- /* Reference to supervisor address from user mode */
- if (rw)
- exception = EXCP_AdES;
- else
- exception = EXCP_AdEL;
- break;
- case TLBRET_NOMATCH:
- /* No TLB match for a mapped address */
- if (rw)
- exception = EXCP_TLBS;
- else
- exception = EXCP_TLBL;
- error_code = 1;
- break;
- case TLBRET_INVALID:
- /* TLB match with no valid bit */
- if (rw)
- exception = EXCP_TLBS;
- else
- exception = EXCP_TLBL;
- break;
- case TLBRET_DIRTY:
- /* TLB match but 'D' bit is cleared */
- exception = EXCP_LTLBL;
- break;
-
- }
- /* Raise exception */
- env->CP0_BadVAddr = address;
- env->CP0_Context = (env->CP0_Context & 0xff800000) |
- ((address >> 9) & 0x007ffff0);
- env->CP0_EntryHi =
- (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
- env->exception_index = exception;
- env->error_code = error_code;
- ret = 1;
- }
-
- return ret;
-}
-
-void do_interrupt (CPUState *env)
-{
- target_ulong pc, offset;
- int cause = -1;
-
- if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
- fprintf(logfile, "%s enter: PC %08x EPC %08x cause %d excp %d\n",
- __func__, env->PC, env->CP0_EPC, cause, env->exception_index);
- }
- if (env->exception_index == EXCP_EXT_INTERRUPT &&
- (env->hflags & MIPS_HFLAG_DM))
- env->exception_index = EXCP_DINT;
- offset = 0x180;
- switch (env->exception_index) {
- case EXCP_DSS:
- env->CP0_Debug |= 1 << CP0DB_DSS;
- /* Debug single step cannot be raised inside a delay slot and
- * resume will always occur on the next instruction
- * (but we assume the pc has always been updated during
- * code translation).
- */
- env->CP0_DEPC = env->PC;
- goto enter_debug_mode;
- case EXCP_DINT:
- env->CP0_Debug |= 1 << CP0DB_DINT;
- goto set_DEPC;
- case EXCP_DIB:
- env->CP0_Debug |= 1 << CP0DB_DIB;
- goto set_DEPC;
- case EXCP_DBp:
- env->CP0_Debug |= 1 << CP0DB_DBp;
- goto set_DEPC;
- case EXCP_DDBS:
- env->CP0_Debug |= 1 << CP0DB_DDBS;
- 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,
- * come back to the jump
- */
- env->CP0_DEPC = env->PC - 4;
- env->hflags &= ~MIPS_HFLAG_BMASK;
- } else {
- env->CP0_DEPC = env->PC;
- }
- enter_debug_mode:
- env->hflags |= MIPS_HFLAG_DM;
- /* EJTAG probe trap enable is not implemented... */
- pc = 0xBFC00480;
- break;
- case EXCP_RESET:
-#ifdef MIPS_USES_R4K_TLB
- env->CP0_random = MIPS_TLB_NB - 1;
-#endif
- env->CP0_Wired = 0;
- env->CP0_Config0 = MIPS_CONFIG0;
-#if defined (MIPS_CONFIG1)
- env->CP0_Config1 = MIPS_CONFIG1;
-#endif
-#if defined (MIPS_CONFIG2)
- env->CP0_Config2 = MIPS_CONFIG2;
-#endif
-#if defined (MIPS_CONFIG3)
- env->CP0_Config3 = MIPS_CONFIG3;
-#endif
- env->CP0_WatchLo = 0;
- env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
- goto set_error_EPC;
- case EXCP_SRESET:
- env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
- (1 << CP0St_SR);
- env->CP0_WatchLo = 0;
- goto set_error_EPC;
- case EXCP_NMI:
- env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
- (1 << CP0St_NMI);
- set_error_EPC:
- if (env->hflags & MIPS_HFLAG_BMASK) {
- /* If the exception was raised from a delay slot,
- * come back to the jump
- */
- env->CP0_ErrorEPC = env->PC - 4;
- env->hflags &= ~MIPS_HFLAG_BMASK;
- } else {
- env->CP0_ErrorEPC = env->PC;
- }
- env->hflags |= MIPS_HFLAG_ERL;
- env->CP0_Status |= (1 << CP0St_ERL);
- pc = 0xBFC00000;
- break;
- case EXCP_MCHECK:
- cause = 24;
- goto set_EPC;
- case EXCP_EXT_INTERRUPT:
- cause = 0;
- if (env->CP0_Cause & (1 << CP0Ca_IV))
- offset = 0x200;
- goto set_EPC;
- case EXCP_DWATCH:
- cause = 23;
- /* XXX: TODO: manage defered watch exceptions */
- goto set_EPC;
- case EXCP_AdEL:
- case EXCP_AdES:
- cause = 4;
- goto set_EPC;
- case EXCP_TLBL:
- cause = 2;
- if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
- offset = 0x000;
- goto set_EPC;
- case EXCP_IBE:
- cause = 6;
- goto set_EPC;
- case EXCP_DBE:
- cause = 7;
- goto set_EPC;
- case EXCP_SYSCALL:
- cause = 8;
- goto set_EPC;
- case EXCP_BREAK:
- cause = 9;
- goto set_EPC;
- case EXCP_RI:
- cause = 10;
- goto set_EPC;
- case EXCP_CpU:
- cause = 11;
- env->CP0_Cause = (env->CP0_Cause & ~0x03000000) | (env->error_code << 28);
- goto set_EPC;
- case EXCP_OVERFLOW:
- cause = 12;
- goto set_EPC;
- case EXCP_TRAP:
- cause = 13;
- 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))
- offset = 0x000;
- goto set_EPC;
- set_EPC:
- if (env->CP0_Status & (1 << CP0St_BEV)) {
- pc = 0xBFC00200;
- } else {
- pc = 0x80000000;
- }
- env->hflags |= MIPS_HFLAG_EXL;
- env->CP0_Status |= (1 << CP0St_EXL);
- pc += offset;
- env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2);
- 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;
- }
- break;
- default:
- if (logfile) {
- fprintf(logfile, "Invalid MIPS exception %d. Exiting\n",
- env->exception_index);
- }
- printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
- exit(1);
- }
- env->PC = pc;
- if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
- fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n"
- " S %08x C %08x A %08x D %08x\n",
- __func__, env->PC, env->CP0_EPC, cause, env->exception_index,
- env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
- env->CP0_DEPC);
- }
- env->exception_index = EXCP_NONE;
-}
diff --git a/target-mips/mips-defs.h b/target-mips/mips-defs.h
deleted file mode 100644
index c6f9e9c..0000000
--- a/target-mips/mips-defs.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#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 */
-#define TARGET_LONG_BITS 32
-/* 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
-/* 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, uses TLB */
-#define MIPS_CONFIG0_1 \
-((1 << CP0C0_M) | (0 << CP0C0_K23) | (0 << CP0C0_KU) | \
- (1 << CP0C0_MT) | (2 << CP0C0_K0))
-#ifdef TARGET_WORDS_BIGENDIAN
-#define MIPS_CONFIG0 (MIPS_CONFIG0_1 | (1 << CP0C0_BE))
-#else
-#define MIPS_CONFIG0 MIPS_CONFIG0_1
-#endif
-/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache,
- * 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
- * no performance counters, watch registers present, no code compression,
- * EJTAG present, FPU enable bit depending on MIPS_USES_FPU
- */
-#define MIPS_CONFIG1 \
-((15 << CP0C1_MMU) | \
- (0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \
- (0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \
- (0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \
- (1 << CP0C1_EP) | (MIPS_USES_FPU << CP0C1_FP))
-#elif (MIPS_CPU == MIPS_R4Kp)
-/* 32 bits target */
-#define TARGET_LONG_BITS 32
-/* 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"
-/* Remainder for other flags */
-//#define TARGET_MIPS64
-//#define MIPS_USES_FPU
-#endif
-
-#endif /* !defined (__QEMU_MIPS_DEFS_H__) */
diff --git a/target-mips/op.c b/target-mips/op.c
deleted file mode 100644
index 4575517..0000000
--- a/target-mips/op.c
+++ /dev/null
@@ -1,1155 +0,0 @@
-/*
- * MIPS emulation micro-operations for qemu.
- *
- * Copyright (c) 2004-2005 Jocelyn Mayer
- * Copyright (c) 2006 Marius Groeger (FPU operations)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include "config.h"
-#include "exec.h"
-
-#ifndef CALL_FROM_TB0
-#define CALL_FROM_TB0(func) func();
-#endif
-#ifndef CALL_FROM_TB1
-#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);
-#endif
-#ifndef CALL_FROM_TB2
-#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);
-#endif
-#ifndef CALL_FROM_TB3
-#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);
-#endif
-
-#define REG 1
-#include "op_template.c"
-#undef REG
-#define REG 2
-#include "op_template.c"
-#undef REG
-#define REG 3
-#include "op_template.c"
-#undef REG
-#define REG 4
-#include "op_template.c"
-#undef REG
-#define REG 5
-#include "op_template.c"
-#undef REG
-#define REG 6
-#include "op_template.c"
-#undef REG
-#define REG 7
-#include "op_template.c"
-#undef REG
-#define REG 8
-#include "op_template.c"
-#undef REG
-#define REG 9
-#include "op_template.c"
-#undef REG
-#define REG 10
-#include "op_template.c"
-#undef REG
-#define REG 11
-#include "op_template.c"
-#undef REG
-#define REG 12
-#include "op_template.c"
-#undef REG
-#define REG 13
-#include "op_template.c"
-#undef REG
-#define REG 14
-#include "op_template.c"
-#undef REG
-#define REG 15
-#include "op_template.c"
-#undef REG
-#define REG 16
-#include "op_template.c"
-#undef REG
-#define REG 17
-#include "op_template.c"
-#undef REG
-#define REG 18
-#include "op_template.c"
-#undef REG
-#define REG 19
-#include "op_template.c"
-#undef REG
-#define REG 20
-#include "op_template.c"
-#undef REG
-#define REG 21
-#include "op_template.c"
-#undef REG
-#define REG 22
-#include "op_template.c"
-#undef REG
-#define REG 23
-#include "op_template.c"
-#undef REG
-#define REG 24
-#include "op_template.c"
-#undef REG
-#define REG 25
-#include "op_template.c"
-#undef REG
-#define REG 26
-#include "op_template.c"
-#undef REG
-#define REG 27
-#include "op_template.c"
-#undef REG
-#define REG 28
-#include "op_template.c"
-#undef REG
-#define REG 29
-#include "op_template.c"
-#undef REG
-#define REG 30
-#include "op_template.c"
-#undef REG
-#define REG 31
-#include "op_template.c"
-#undef REG
-
-#define TN T0
-#include "op_template.c"
-#undef TN
-#define TN T1
-#include "op_template.c"
-#undef TN
-#define TN T2
-#include "op_template.c"
-#undef TN
-
-#ifdef MIPS_USES_FPU
-
-#define SFREG 0
-#define DFREG 0
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 1
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 2
-#define DFREG 2
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 3
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 4
-#define DFREG 4
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 5
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 6
-#define DFREG 6
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 7
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 8
-#define DFREG 8
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 9
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 10
-#define DFREG 10
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 11
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 12
-#define DFREG 12
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 13
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 14
-#define DFREG 14
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 15
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 16
-#define DFREG 16
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 17
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 18
-#define DFREG 18
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 19
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 20
-#define DFREG 20
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 21
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 22
-#define DFREG 22
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 23
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 24
-#define DFREG 24
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 25
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 26
-#define DFREG 26
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 27
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 28
-#define DFREG 28
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 29
-#include "fop_template.c"
-#undef SFREG
-#define SFREG 30
-#define DFREG 30
-#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 31
-#include "fop_template.c"
-#undef SFREG
-
-#define FTN
-#include "fop_template.c"
-#undef FTN
-
-#endif
-
-void op_dup_T0 (void)
-{
- T2 = T0;
- RETURN();
-}
-
-void op_load_HI (void)
-{
- T0 = env->HI;
- RETURN();
-}
-
-void op_store_HI (void)
-{
- env->HI = T0;
- RETURN();
-}
-
-void op_load_LO (void)
-{
- T0 = env->LO;
- RETURN();
-}
-
-void op_store_LO (void)
-{
- env->LO = T0;
- RETURN();
-}
-
-/* Load and store */
-#define MEMSUFFIX _raw
-#include "op_mem.c"
-#undef MEMSUFFIX
-#if !defined(CONFIG_USER_ONLY)
-#define MEMSUFFIX _user
-#include "op_mem.c"
-#undef MEMSUFFIX
-
-#define MEMSUFFIX _kernel
-#include "op_mem.c"
-#undef MEMSUFFIX
-#endif
-
-/* Arithmetic */
-void op_add (void)
-{
- T0 += T1;
- RETURN();
-}
-
-void op_addo (void)
-{
- target_ulong tmp;
-
- tmp = T0;
- T0 += T1;
- if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) {
- /* operands of same sign, result different sign */
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
- }
- RETURN();
-}
-
-void op_sub (void)
-{
- T0 -= T1;
- RETURN();
-}
-
-void op_subo (void)
-{
- target_ulong tmp;
-
- tmp = T0;
- 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);
- }
- RETURN();
-}
-
-void op_mul (void)
-{
- T0 = (int32_t)T0 * (int32_t)T1;
- RETURN();
-}
-
-void op_div (void)
-{
- if (T1 != 0) {
- env->LO = (int32_t)T0 / (int32_t)T1;
- env->HI = (int32_t)T0 % (int32_t)T1;
- }
- RETURN();
-}
-
-void op_divu (void)
-{
- if (T1 != 0) {
- env->LO = T0 / T1;
- env->HI = T0 % T1;
- }
- RETURN();
-}
-
-/* Logical */
-void op_and (void)
-{
- T0 &= T1;
- RETURN();
-}
-
-void op_nor (void)
-{
- T0 = ~(T0 | T1);
- RETURN();
-}
-
-void op_or (void)
-{
- T0 |= T1;
- RETURN();
-}
-
-void op_xor (void)
-{
- T0 ^= T1;
- RETURN();
-}
-
-void op_sll (void)
-{
- T0 = T0 << T1;
- RETURN();
-}
-
-void op_sra (void)
-{
- T0 = (int32_t)T0 >> T1;
- RETURN();
-}
-
-void op_srl (void)
-{
- T0 = T0 >> T1;
- RETURN();
-}
-
-void op_sllv (void)
-{
- T0 = T1 << (T0 & 0x1F);
- RETURN();
-}
-
-void op_srav (void)
-{
- T0 = (int32_t)T1 >> (T0 & 0x1F);
- RETURN();
-}
-
-void op_srlv (void)
-{
- T0 = T1 >> (T0 & 0x1F);
- RETURN();
-}
-
-void op_clo (void)
-{
- int n;
-
- if (T0 == (target_ulong)-1) {
- T0 = 32;
- } else {
- for (n = 0; n < 32; n++) {
- if (!(T0 & (1 << 31)))
- break;
- T0 = T0 << 1;
- }
- T0 = n;
- }
- RETURN();
-}
-
-void op_clz (void)
-{
- int n;
-
- if (T0 == 0) {
- T0 = 32;
- } else {
- for (n = 0; n < 32; n++) {
- if (T0 & (1 << 31))
- break;
- T0 = T0 << 1;
- }
- T0 = n;
- }
- RETURN();
-}
-
-/* 64 bits arithmetic */
-#if (HOST_LONG_BITS == 64)
-static inline uint64_t get_HILO (void)
-{
- return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
-}
-
-static inline void set_HILO (uint64_t HILO)
-{
- env->LO = HILO & 0xFFFFFFFF;
- env->HI = HILO >> 32;
-}
-
-void op_mult (void)
-{
- set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
- RETURN();
-}
-
-void op_multu (void)
-{
- set_HILO((uint64_t)T0 * (uint64_t)T1);
- RETURN();
-}
-
-void op_madd (void)
-{
- int64_t tmp;
-
- tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
- set_HILO((int64_t)get_HILO() + tmp);
- RETURN();
-}
-
-void op_maddu (void)
-{
- uint64_t tmp;
-
- tmp = ((uint64_t)T0 * (uint64_t)T1);
- set_HILO(get_HILO() + tmp);
- RETURN();
-}
-
-void op_msub (void)
-{
- int64_t tmp;
-
- tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
- set_HILO((int64_t)get_HILO() - tmp);
- RETURN();
-}
-
-void op_msubu (void)
-{
- uint64_t tmp;
-
- tmp = ((uint64_t)T0 * (uint64_t)T1);
- set_HILO(get_HILO() - tmp);
- RETURN();
-}
-#else
-void op_mult (void)
-{
- CALL_FROM_TB0(do_mult);
- RETURN();
-}
-
-void op_multu (void)
-{
- CALL_FROM_TB0(do_multu);
- RETURN();
-}
-
-void op_madd (void)
-{
- CALL_FROM_TB0(do_madd);
- RETURN();
-}
-
-void op_maddu (void)
-{
- CALL_FROM_TB0(do_maddu);
- RETURN();
-}
-
-void op_msub (void)
-{
- CALL_FROM_TB0(do_msub);
- RETURN();
-}
-
-void op_msubu (void)
-{
- CALL_FROM_TB0(do_msubu);
- RETURN();
-}
-#endif
-
-/* Conditional moves */
-void op_movn (void)
-{
- if (T1 != 0)
- env->gpr[PARAM1] = T0;
- RETURN();
-}
-
-void op_movz (void)
-{
- if (T1 == 0)
- env->gpr[PARAM1] = T0;
- RETURN();
-}
-
-/* Tests */
-#define OP_COND(name, cond) \
-void glue(op_, name) (void) \
-{ \
- if (cond) { \
- T0 = 1; \
- } else { \
- T0 = 0; \
- } \
- RETURN(); \
-}
-
-OP_COND(eq, T0 == T1);
-OP_COND(ne, T0 != T1);
-OP_COND(ge, (int32_t)T0 >= (int32_t)T1);
-OP_COND(geu, T0 >= T1);
-OP_COND(lt, (int32_t)T0 < (int32_t)T1);
-OP_COND(ltu, T0 < T1);
-OP_COND(gez, (int32_t)T0 >= 0);
-OP_COND(gtz, (int32_t)T0 > 0);
-OP_COND(lez, (int32_t)T0 <= 0);
-OP_COND(ltz, (int32_t)T0 < 0);
-
-/* Branchs */
-//#undef USE_DIRECT_JUMP
-
-void OPPROTO op_goto_tb0(void)
-{
- GOTO_TB(op_goto_tb0, PARAM1, 0);
-}
-
-void OPPROTO op_goto_tb1(void)
-{
- GOTO_TB(op_goto_tb1, PARAM1, 1);
-}
-
-/* Branch to register */
-void op_save_breg_target (void)
-{
- env->btarget = T2;
-}
-
-void op_restore_breg_target (void)
-{
- T2 = env->btarget;
-}
-
-void op_breg (void)
-{
- env->PC = T2;
- RETURN();
-}
-
-void op_save_btarget (void)
-{
- env->btarget = PARAM1;
- RETURN();
-}
-
-/* Conditional branch */
-void op_set_bcond (void)
-{
- T2 = T0;
- RETURN();
-}
-
-void op_save_bcond (void)
-{
- env->bcond = T2;
- RETURN();
-}
-
-void op_restore_bcond (void)
-{
- T2 = env->bcond;
- RETURN();
-}
-
-void op_jnz_T2 (void)
-{
- if (T2)
- GOTO_LABEL_PARAM(1);
- RETURN();
-}
-
-/* CP0 functions */
-void op_mfc0 (void)
-{
- CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
- RETURN();
-}
-
-void op_mtc0 (void)
-{
- CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
- RETURN();
-}
-
-#ifdef MIPS_USES_FPU
-
-#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)
-{
- if (!(env->CP0_Status & (1 << CP0St_CU1))) {
- CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1);
- }
- RETURN();
-}
-
-/* CP1 functions */
-void op_cfc1 (void)
-{
- if (T1 == 0) {
- T0 = env->fcr0;
- }
- else {
- /* fetch fcr31, masking unused bits */
- T0 = env->fcr31 & 0x0183FFFF;
- }
- DEBUG_FPU_STATE();
- RETURN();
-}
-
-/* convert MIPS rounding mode in FCR31 to IEEE library */
-unsigned int ieee_rm[] = {
- float_round_nearest_even,
- float_round_to_zero,
- float_round_up,
- float_round_down
-};
-
-#define RESTORE_ROUNDING_MODE \
- set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
-
-void op_ctc1 (void)
-{
- 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;
-
- /* set rounding mode */
- RESTORE_ROUNDING_MODE;
-
-#ifndef CONFIG_SOFTFLOAT
- /* no floating point exception for native float */
- SET_FP_ENABLE(env->fcr31, 0);
-#endif
- }
- DEBUG_FPU_STATE();
- RETURN();
-}
-
-void op_mfc1 (void)
-{
- T0 = WT0;
- DEBUG_FPU_STATE();
- RETURN();
-}
-
-void op_mtc1 (void)
-{
- WT0 = T0;
- DEBUG_FPU_STATE();
- RETURN();
-}
-
-/* Float support.
- Single precition routines have a "s" suffix, double precision a
- "d" suffix. */
-
-#define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void)
-
-FLOAT_OP(cvtd, w)
-{
- FDT2 = int32_to_float64(WT0, &env->fp_status);
- DEBUG_FPU_STATE();
- RETURN();
-}
-FLOAT_OP(cvts, w)
-{
- FST2 = int32_to_float32(WT0, &env->fp_status);
- DEBUG_FPU_STATE();
- RETURN();
-}
-FLOAT_OP(cvtw, s)
-{
- WT2 = float32_to_int32(FST0, &env->fp_status);
- DEBUG_FPU_STATE();
- RETURN();
-}
-FLOAT_OP(cvtw, d)
-{
- WT2 = float64_to_int32(FDT0, &env->fp_status);
- 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();
-}
-FLOAT_OP(roundw, s)
-{
- set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
- WT2 = float32_round_to_int(FST0, &env->fp_status);
- RESTORE_ROUNDING_MODE;
- DEBUG_FPU_STATE();
- RETURN();
-}
-
-FLOAT_OP(truncw, d)
-{
- WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
- DEBUG_FPU_STATE();
- RETURN();
-}
-FLOAT_OP(truncw, s)
-{
- WT2 = float32_to_int32_round_to_zero(FST0, &env->fp_status);
- 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();
-}
-FLOAT_OP(ceilw, s)
-{
- set_float_rounding_mode(float_round_up, &env->fp_status);
- WT2 = 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();
-}
-FLOAT_OP(floorw, s)
-{
- set_float_rounding_mode(float_round_down, &env->fp_status);
- WT2 = float32_round_to_int(FST0, &env->fp_status);
- RESTORE_ROUNDING_MODE;
- DEBUG_FPU_STATE();
- RETURN();
-}
-
-/* binary operations */
-#define FLOAT_BINOP(name) \
-FLOAT_OP(name, d) \
-{ \
- FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \
- DEBUG_FPU_STATE(); \
-} \
-FLOAT_OP(name, s) \
-{ \
- FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \
- DEBUG_FPU_STATE(); \
-}
-FLOAT_BINOP(add)
-FLOAT_BINOP(sub)
-FLOAT_BINOP(mul)
-FLOAT_BINOP(div)
-#undef FLOAT_BINOP
-
-/* unary operations, modifying fp status */
-#define FLOAT_UNOP(name) \
-FLOAT_OP(name, d) \
-{ \
- FDT2 = float64_ ## name(FDT0, &env->fp_status); \
- DEBUG_FPU_STATE(); \
-} \
-FLOAT_OP(name, s) \
-{ \
- FST2 = float32_ ## name(FST0, &env->fp_status); \
- DEBUG_FPU_STATE(); \
-}
-FLOAT_UNOP(sqrt)
-#undef FLOAT_UNOP
-
-/* unary operations, not modifying fp status */
-#define FLOAT_UNOP(name) \
-FLOAT_OP(name, d) \
-{ \
- FDT2 = float64_ ## name(FDT0); \
- DEBUG_FPU_STATE(); \
-} \
-FLOAT_OP(name, s) \
-{ \
- FST2 = float32_ ## name(FST0); \
- DEBUG_FPU_STATE(); \
-}
-FLOAT_UNOP(abs)
-FLOAT_UNOP(chs)
-#undef FLOAT_UNOP
-
-FLOAT_OP(mov, d)
-{
- FDT2 = FDT0;
- DEBUG_FPU_STATE();
- RETURN();
-}
-FLOAT_OP(mov, s)
-{
- FST2 = FST0;
- DEBUG_FPU_STATE();
- RETURN();
-}
-
-#ifdef CONFIG_SOFTFLOAT
-#define clear_invalid() do { \
- int flags = get_float_exception_flags(&env->fp_status); \
- flags &= ~float_flag_invalid; \
- set_float_exception_flags(flags, &env->fp_status); \
-} while(0)
-#else
-#define clear_invalid() do { } while(0)
-#endif
-
-extern void dump_fpu_s(CPUState *env);
-
-#define FOP_COND(fmt, op, sig, cond) \
-void op_cmp_ ## fmt ## _ ## op (void) \
-{ \
- if (cond) \
- SET_FP_COND(env->fcr31); \
- else \
- CLEAR_FP_COND(env->fcr31); \
- if (!sig) \
- clear_invalid(); \
- /*CALL_FROM_TB1(dump_fpu_s, env);*/ \
- DEBUG_FPU_STATE(); \
- RETURN(); \
-}
-
-flag float64_is_unordered(float64 a, float64 b STATUS_PARAM)
-{
- extern flag float64_is_nan( float64 a );
- if (float64_is_nan(a) || float64_is_nan(b)) {
- float_raise(float_flag_invalid, status);
- 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))
-
-flag float32_is_unordered(float32 a, float32 b STATUS_PARAM)
-{
- extern flag float32_is_nan( float32 a );
- if (float32_is_nan(a) || float32_is_nan(b)) {
- float_raise(float_flag_invalid, status);
- 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))
-/* 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))
-
-void op_bc1f (void)
-{
- T0 = ! IS_FP_COND_SET(env->fcr31);
- DEBUG_FPU_STATE();
- RETURN();
-}
-
-void op_bc1t (void)
-{
- T0 = IS_FP_COND_SET(env->fcr31);
- DEBUG_FPU_STATE();
- RETURN();
-}
-#endif /* MIPS_USES_FPU */
-
-#if defined(MIPS_USES_R4K_TLB)
-void op_tlbwi (void)
-{
- CALL_FROM_TB0(do_tlbwi);
- RETURN();
-}
-
-void op_tlbwr (void)
-{
- CALL_FROM_TB0(do_tlbwr);
- RETURN();
-}
-
-void op_tlbp (void)
-{
- CALL_FROM_TB0(do_tlbp);
- RETURN();
-}
-
-void op_tlbr (void)
-{
- CALL_FROM_TB0(do_tlbr);
- RETURN();
-}
-#endif
-
-/* Specials */
-void op_pmon (void)
-{
- CALL_FROM_TB1(do_pmon, PARAM1);
-}
-
-void op_trap (void)
-{
- if (T0) {
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_TRAP);
- }
- RETURN();
-}
-
-void op_debug (void)
-{
- CALL_FROM_TB1(do_raise_exception, EXCP_DEBUG);
-}
-
-void op_set_lladdr (void)
-{
- env->CP0_LLAddr = T2;
-}
-
-void debug_eret (void);
-void op_eret (void)
-{
- CALL_FROM_TB0(debug_eret);
- if (env->hflags & MIPS_HFLAG_ERL) {
- env->PC = env->CP0_ErrorEPC;
- env->hflags &= ~MIPS_HFLAG_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_LLAddr = 1;
-}
-
-void op_deret (void)
-{
- CALL_FROM_TB0(debug_eret);
- env->PC = env->CP0_DEPC;
-}
-
-void op_save_state (void)
-{
- env->hflags = PARAM1;
- RETURN();
-}
-
-void op_save_pc (void)
-{
- env->PC = PARAM1;
- RETURN();
-}
-
-void op_raise_exception (void)
-{
- CALL_FROM_TB1(do_raise_exception, PARAM1);
- RETURN();
-}
-
-void op_raise_exception_err (void)
-{
- CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
- RETURN();
-}
-
-void op_exit_tb (void)
-{
- EXIT_TB();
-}
-
-void op_wait (void)
-{
- env->halted = 1;
- CALL_FROM_TB1(do_raise_exception, EXCP_HLT);
-}
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
deleted file mode 100644
index bf397c9..0000000
--- a/target-mips/op_helper.c
+++ /dev/null
@@ -1,786 +0,0 @@
-/*
- * MIPS emulation helpers for qemu.
- *
- * Copyright (c) 2004-2005 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"
-
-#define MIPS_DEBUG_DISAS
-
-#define GETPC() (__builtin_return_address(0))
-
-/*****************************************************************************/
-/* Exceptions processing helpers */
-void cpu_loop_exit(void)
-{
- longjmp(env->jmp_env, 1);
-}
-
-void do_raise_exception_err (uint32_t exception, int error_code)
-{
-#if 1
- if (logfile && exception < 0x100)
- fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
-#endif
- env->exception_index = exception;
- env->error_code = error_code;
- T0 = 0;
- cpu_loop_exit();
-}
-
-void do_raise_exception (uint32_t exception)
-{
- do_raise_exception_err(exception, 0);
-}
-
-void do_restore_state (void *pc_ptr)
-{
- TranslationBlock *tb;
- unsigned long pc = (unsigned long) pc_ptr;
-
- tb = tb_find_pc (pc);
- cpu_restore_state (tb, env, pc, NULL);
-}
-
-void do_raise_exception_direct (uint32_t exception)
-{
- do_restore_state (GETPC ());
- do_raise_exception_err (exception, 0);
-}
-
-#define MEMSUFFIX _raw
-#include "op_helper_mem.c"
-#undef MEMSUFFIX
-#if !defined(CONFIG_USER_ONLY)
-#define MEMSUFFIX _user
-#include "op_helper_mem.c"
-#undef MEMSUFFIX
-#define MEMSUFFIX _kernel
-#include "op_helper_mem.c"
-#undef MEMSUFFIX
-#endif
-
-/* 64 bits arithmetic for 32 bits hosts */
-#if (HOST_LONG_BITS == 32)
-static inline uint64_t get_HILO (void)
-{
- return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
-}
-
-static inline void set_HILO (uint64_t HILO)
-{
- env->LO = HILO & 0xFFFFFFFF;
- env->HI = HILO >> 32;
-}
-
-void do_mult (void)
-{
- set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
-}
-
-void do_multu (void)
-{
- set_HILO((uint64_t)T0 * (uint64_t)T1);
-}
-
-void do_madd (void)
-{
- int64_t tmp;
-
- tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
- set_HILO((int64_t)get_HILO() + tmp);
-}
-
-void do_maddu (void)
-{
- uint64_t tmp;
-
- tmp = ((uint64_t)T0 * (uint64_t)T1);
- set_HILO(get_HILO() + tmp);
-}
-
-void do_msub (void)
-{
- int64_t tmp;
-
- tmp = ((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
- set_HILO((int64_t)get_HILO() - tmp);
-}
-
-void do_msubu (void)
-{
- uint64_t tmp;
-
- tmp = ((uint64_t)T0 * (uint64_t)T1);
- set_HILO(get_HILO() - tmp);
-}
-#endif
-
-#if defined(CONFIG_USER_ONLY)
-void do_mfc0 (int reg, int sel)
-{
- cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel);
-}
-void do_mtc0 (int reg, int sel)
-{
- cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
-}
-
-void do_tlbwi (void)
-{
- cpu_abort(env, "tlbwi\n");
-}
-
-void do_tlbwr (void)
-{
- cpu_abort(env, "tlbwr\n");
-}
-
-void do_tlbp (void)
-{
- cpu_abort(env, "tlbp\n");
-}
-
-void do_tlbr (void)
-{
- cpu_abort(env, "tlbr\n");
-}
-#else
-
-/* CP0 helpers */
-void do_mfc0 (int reg, int sel)
-{
- const unsigned char *rn;
-
- if (sel != 0 && reg != 16 && reg != 28) {
- rn = "invalid";
- goto print;
- }
- switch (reg) {
- case 0:
- T0 = env->CP0_index;
- rn = "Index";
- break;
- case 1:
- T0 = cpu_mips_get_random(env);
- rn = "Random";
- break;
- case 2:
- T0 = env->CP0_EntryLo0;
- rn = "EntryLo0";
- break;
- case 3:
- T0 = env->CP0_EntryLo1;
- rn = "EntryLo1";
- break;
- case 4:
- T0 = env->CP0_Context;
- rn = "Context";
- break;
- case 5:
- T0 = env->CP0_PageMask;
- rn = "PageMask";
- break;
- case 6:
- T0 = env->CP0_Wired;
- rn = "Wired";
- break;
- case 8:
- T0 = env->CP0_BadVAddr;
- rn = "BadVaddr";
- break;
- case 9:
- T0 = cpu_mips_get_count(env);
- rn = "Count";
- break;
- case 10:
- T0 = env->CP0_EntryHi;
- rn = "EntryHi";
- break;
- case 11:
- T0 = env->CP0_Compare;
- rn = "Compare";
- break;
- case 12:
- T0 = env->CP0_Status;
- if (env->hflags & MIPS_HFLAG_UM)
- T0 |= (1 << CP0St_UM);
- rn = "Status";
- break;
- case 13:
- T0 = env->CP0_Cause;
- rn = "Cause";
- break;
- case 14:
- T0 = env->CP0_EPC;
- rn = "EPC";
- break;
- case 15:
- T0 = env->CP0_PRid;
- rn = "PRid";
- break;
- case 16:
- switch (sel) {
- case 0:
- T0 = env->CP0_Config0;
- rn = "Config";
- break;
- case 1:
- T0 = env->CP0_Config1;
- rn = "Config1";
- break;
- default:
- rn = "Unknown config register";
- break;
- }
- break;
- case 17:
- T0 = env->CP0_LLAddr >> 4;
- rn = "LLAddr";
- break;
- case 18:
- T0 = env->CP0_WatchLo;
- rn = "WatchLo";
- break;
- case 19:
- T0 = env->CP0_WatchHi;
- rn = "WatchHi";
- break;
- case 23:
- T0 = env->CP0_Debug;
- if (env->hflags & MIPS_HFLAG_DM)
- T0 |= 1 << CP0DB_DM;
- rn = "Debug";
- break;
- case 24:
- T0 = env->CP0_DEPC;
- rn = "DEPC";
- break;
- case 28:
- switch (sel) {
- case 0:
- T0 = env->CP0_TagLo;
- rn = "TagLo";
- break;
- case 1:
- T0 = env->CP0_DataLo;
- rn = "DataLo";
- break;
- default:
- rn = "unknown sel";
- break;
- }
- break;
- case 30:
- T0 = env->CP0_ErrorEPC;
- rn = "ErrorEPC";
- break;
- case 31:
- T0 = env->CP0_DESAVE;
- rn = "DESAVE";
- break;
- default:
- rn = "unknown";
- break;
- }
- print:
-#if defined MIPS_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
- env->PC, rn, T0, reg, sel);
- }
-#endif
- return;
-}
-
-void do_mtc0 (int reg, int sel)
-{
- const unsigned char *rn;
- uint32_t val, old, mask;
-
- if (sel != 0 && reg != 16 && reg != 28) {
- val = -1;
- old = -1;
- rn = "invalid";
- goto print;
- }
- switch (reg) {
- case 0:
- val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
- old = env->CP0_index;
- env->CP0_index = val;
- rn = "Index";
- break;
- case 2:
- val = T0 & 0x3FFFFFFF;
- old = env->CP0_EntryLo0;
- env->CP0_EntryLo0 = val;
- rn = "EntryLo0";
- break;
- case 3:
- val = T0 & 0x3FFFFFFF;
- old = env->CP0_EntryLo1;
- env->CP0_EntryLo1 = val;
- rn = "EntryLo1";
- break;
- case 4:
- val = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0);
- old = env->CP0_Context;
- env->CP0_Context = val;
- rn = "Context";
- break;
- case 5:
- val = T0 & 0x01FFE000;
- old = env->CP0_PageMask;
- env->CP0_PageMask = val;
- rn = "PageMask";
- break;
- case 6:
- val = T0 & 0x0000000F;
- old = env->CP0_Wired;
- env->CP0_Wired = val;
- rn = "Wired";
- break;
- case 9:
- val = T0;
- old = cpu_mips_get_count(env);
- cpu_mips_store_count(env, val);
- rn = "Count";
- break;
- case 10:
- val = T0 & 0xFFFFE0FF;
- old = env->CP0_EntryHi;
- env->CP0_EntryHi = val;
- /* If the ASID changes, flush qemu's TLB. */
- if ((old & 0xFF) != (val & 0xFF))
- tlb_flush (env, 1);
- rn = "EntryHi";
- break;
- case 11:
- val = T0;
- old = env->CP0_Compare;
- cpu_mips_store_compare(env, val);
- rn = "Compare";
- break;
- case 12:
- val = T0 & 0xFA78FF01;
- if (T0 & (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;
- old = env->CP0_Status;
- env->CP0_Status = val;
- /* If we unmasked an asserted IRQ, raise it */
- mask = 0x0000FF00;
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
- old, val, env->CP0_Cause, old & mask, val & mask,
- env->CP0_Cause & mask);
- }
- 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)) {
- if (logfile)
- fprintf(logfile, "Raise pending IRQs\n");
- env->interrupt_request |= CPU_INTERRUPT_HARD;
- } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
- env->interrupt_request &= ~CPU_INTERRUPT_HARD;
- }
- rn = "Status";
- break;
- case 13:
- val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
- old = env->CP0_Cause;
- env->CP0_Cause = val;
-#if 0
- {
- int i;
- /* Check if we ever asserted a software IRQ */
- for (i = 0; i < 2; i++) {
- mask = 0x100 << i;
- if ((val & mask) & !(old & mask))
- mips_set_irq(i);
- }
- }
-#endif
- rn = "Cause";
- break;
- case 14:
- val = T0;
- old = env->CP0_EPC;
- env->CP0_EPC = val;
- rn = "EPC";
- break;
- case 16:
- switch (sel) {
- case 0:
-#if defined(MIPS_USES_R4K_TLB)
- val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
-#else
- val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
-#endif
- old = env->CP0_Config0;
- env->CP0_Config0 = val;
- rn = "Config0";
- break;
- default:
- val = -1;
- old = -1;
- rn = "bad config selector";
- break;
- }
- break;
- case 18:
- val = T0;
- old = env->CP0_WatchLo;
- env->CP0_WatchLo = val;
- rn = "WatchLo";
- break;
- case 19:
- val = T0 & 0x40FF0FF8;
- old = env->CP0_WatchHi;
- env->CP0_WatchHi = val;
- rn = "WatchHi";
- break;
- case 23:
- val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
- if (T0 & (1 << CP0DB_DM))
- env->hflags |= MIPS_HFLAG_DM;
- else
- env->hflags &= ~MIPS_HFLAG_DM;
- old = env->CP0_Debug;
- env->CP0_Debug = val;
- rn = "Debug";
- break;
- case 24:
- val = T0;
- old = env->CP0_DEPC;
- env->CP0_DEPC = val;
- rn = "DEPC";
- break;
- case 28:
- switch (sel) {
- case 0:
- val = T0 & 0xFFFFFCF6;
- old = env->CP0_TagLo;
- env->CP0_TagLo = val;
- rn = "TagLo";
- break;
- default:
- val = -1;
- old = -1;
- rn = "invalid sel";
- break;
- }
- break;
- case 30:
- val = T0;
- old = env->CP0_ErrorEPC;
- env->CP0_ErrorEPC = val;
- rn = "EPC";
- break;
- case 31:
- val = T0;
- old = env->CP0_DESAVE;
- env->CP0_DESAVE = val;
- rn = "DESAVE";
- break;
- default:
- val = -1;
- old = -1;
- rn = "unknown";
- break;
- }
- print:
-#if defined MIPS_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
- env->PC, rn, T0, val, reg, sel, old);
- }
-#endif
- return;
-}
-
-#ifdef MIPS_USES_FPU
-#include "softfloat.h"
-
-void fpu_handle_exception(void)
-{
-#ifdef CONFIG_SOFTFLOAT
- int flags = get_float_exception_flags(&env->fp_status);
- unsigned int cpuflags = 0, enable, cause = 0;
-
- enable = GET_FP_ENABLE(env->fcr31);
-
- /* determine current flags */
- if (flags & float_flag_invalid) {
- cpuflags |= FP_INVALID;
- cause |= FP_INVALID & enable;
- }
- if (flags & float_flag_divbyzero) {
- cpuflags |= FP_DIV0;
- cause |= FP_DIV0 & enable;
- }
- if (flags & float_flag_overflow) {
- cpuflags |= FP_OVERFLOW;
- cause |= FP_OVERFLOW & enable;
- }
- if (flags & float_flag_underflow) {
- cpuflags |= FP_UNDERFLOW;
- cause |= FP_UNDERFLOW & enable;
- }
- if (flags & float_flag_inexact) {
- cpuflags |= FP_INEXACT;
- cause |= FP_INEXACT & enable;
- }
- SET_FP_FLAGS(env->fcr31, cpuflags);
- SET_FP_CAUSE(env->fcr31, cause);
-#else
- SET_FP_FLAGS(env->fcr31, 0);
- SET_FP_CAUSE(env->fcr31, 0);
-#endif
-}
-#endif /* MIPS_USES_FPU */
-
-/* TLB management */
-#if defined(MIPS_USES_R4K_TLB)
-static void invalidate_tlb (int idx)
-{
- tlb_t *tlb;
- target_ulong addr;
-
- tlb = &env->tlb[idx];
- if (tlb->V0) {
- tb_invalidate_page_range(tlb->PFN[0], tlb->end - tlb->VPN);
- addr = tlb->VPN;
- while (addr < tlb->end) {
- tlb_flush_page (env, addr);
- addr += TARGET_PAGE_SIZE;
- }
- }
- if (tlb->V1) {
- tb_invalidate_page_range(tlb->PFN[1], tlb->end2 - tlb->end);
- addr = tlb->end;
- while (addr < tlb->end2) {
- tlb_flush_page (env, addr);
- addr += TARGET_PAGE_SIZE;
- }
- }
-}
-
-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 & 0xFFFFE000;
- 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->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
- tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
- tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
- tlb->C0 = (env->CP0_EntryLo0 >> 3) & 0x7;
- tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
- tlb->V1 = (env->CP0_EntryLo1 & 2) != 0;
- tlb->D1 = (env->CP0_EntryLo1 & 4) != 0;
- tlb->C1 = (env->CP0_EntryLo1 >> 3) & 0x7;
- tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
-}
-
-void do_tlbwi (void)
-{
- /* 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->CP0_index & (MIPS_TLB_NB - 1));
- fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1));
-}
-
-void do_tlbwr (void)
-{
- int r = cpu_mips_get_random(env);
-
- invalidate_tlb(r);
- fill_tlb(r);
-}
-
-void do_tlbp (void)
-{
- tlb_t *tlb;
- target_ulong tag;
- uint8_t ASID;
- int i;
-
- tag = env->CP0_EntryHi & 0xFFFFE000;
- ASID = env->CP0_EntryHi & 0xFF;
- for (i = 0; i < MIPS_TLB_NB; 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;
- break;
- }
- }
- if (i == MIPS_TLB_NB) {
- env->CP0_index |= 0x80000000;
- }
-}
-
-void do_tlbr (void)
-{
- tlb_t *tlb;
- uint8_t ASID;
- int size;
-
- ASID = env->CP0_EntryHi & 0xFF;
- tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)];
-
- /* If this will change the current ASID, flush qemu's TLB. */
- if (ASID != tlb->ASID && tlb->G != 1)
- tlb_flush (env, 1);
-
- env->CP0_EntryHi = tlb->VPN | tlb->ASID;
- size = (tlb->end - tlb->VPN) >> 12;
- env->CP0_PageMask = (size - 1) << 13;
- 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)
- | (tlb->C1 << 3) | (tlb->PFN[1] >> 6);
-}
-#endif
-
-#endif /* !CONFIG_USER_ONLY */
-
-void op_dump_ldst (const unsigned char *func)
-{
- if (loglevel)
- fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
-}
-
-void dump_sc (void)
-{
- if (loglevel) {
- fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
- T1, T0, env->CP0_LLAddr);
- }
-}
-
-void debug_eret (void)
-{
- if (loglevel) {
- fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
- env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
- env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
- }
-}
-
-void do_pmon (int function)
-{
- function /= 2;
- switch (function) {
- case 2: /* TODO: char inbyte(int waitflag); */
- if (env->gpr[4] == 0)
- env->gpr[2] = -1;
- /* Fall through */
- case 11: /* TODO: char inbyte (void); */
- env->gpr[2] = -1;
- break;
- case 3:
- case 12:
- printf("%c", env->gpr[4] & 0xFF);
- break;
- case 17:
- break;
- case 158:
- {
- unsigned char *fmt = (void *)env->gpr[4];
- printf("%s", fmt);
- }
- break;
- }
-}
-
-#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 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"
-
-static void do_unaligned_access (target_ulong addr, int is_write, int is_user, void *retaddr)
-{
- env->CP0_BadVAddr = addr;
- do_restore_state (retaddr);
- do_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL);
-}
-
-void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
-{
- TranslationBlock *tb;
- CPUState *saved_env;
- unsigned long pc;
- int ret;
-
- /* XXX: hack to restore env in all cases, even if not called from
- generated code */
- saved_env = env;
- env = cpu_single_env;
- ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1);
- if (ret) {
- if (retaddr) {
- /* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
- if (tb) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, pc, NULL);
- }
- }
- do_raise_exception_err(env->exception_index, env->error_code);
- }
- env = saved_env;
-}
-
-#endif
diff --git a/target-mips/op_helper_mem.c b/target-mips/op_helper_mem.c
deleted file mode 100644
index 4711f7a..0000000
--- a/target-mips/op_helper_mem.c
+++ /dev/null
@@ -1,141 +0,0 @@
-#ifdef TARGET_WORDS_BIGENDIAN
-#define GET_LMASK(v) ((v) & 3)
-#else
-#define GET_LMASK(v) (((v) & 3) ^ 3)
-#endif
-
-void glue(do_lwl, MEMSUFFIX) (uint32_t tmp)
-{
-#if defined (DEBUG_OP)
- target_ulong sav = T0;
-#endif
-
- /* XXX: this is valid only in big-endian mode
- * should be reverted for little-endian...
- */
- switch (GET_LMASK(T0)) {
- case 0:
- T0 = tmp;
- break;
- case 1:
- T0 = (tmp << 8) | (T1 & 0x000000FF);
- break;
- case 2:
- T0 = (tmp << 16) | (T1 & 0x0000FFFF);
- break;
- case 3:
- T0 = (tmp << 24) | (T1 & 0x00FFFFFF);
- break;
- }
-#if defined (DEBUG_OP)
- if (logfile) {
- fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
- __func__, sav, tmp, T1, T0);
- }
-#endif
- RETURN();
-}
-
-void glue(do_lwr, MEMSUFFIX) (uint32_t tmp)
-{
-#if defined (DEBUG_OP)
- target_ulong sav = T0;
-#endif
-
- /* XXX: this is valid only in big-endian mode
- * should be reverted for little-endian...
- */
- switch (GET_LMASK(T0)) {
- case 0:
- T0 = (tmp >> 24) | (T1 & 0xFFFFFF00);
- break;
- case 1:
- T0 = (tmp >> 16) | (T1 & 0xFFFF0000);
- break;
- case 2:
- T0 = (tmp >> 8) | (T1 & 0xFF000000);
- break;
- case 3:
- T0 = tmp;
- break;
- }
-#if defined (DEBUG_OP)
- if (logfile) {
- fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
- __func__, sav, tmp, T1, T0);
- }
-#endif
- RETURN();
-}
-
-uint32_t glue(do_swl, MEMSUFFIX) (uint32_t tmp)
-{
-#if defined (DEBUG_OP)
- target_ulong sav;
-#endif
-
-#if defined (DEBUG_OP)
- sav = tmp;
-#endif
- /* XXX: this is valid only in big-endian mode
- * should be reverted for little-endian...
- */
- switch (GET_LMASK(T0)) {
- case 0:
- tmp = T1;
- break;
- case 1:
- tmp = (tmp & 0xFF000000) | (T1 >> 8);
- break;
- case 2:
- tmp = (tmp & 0xFFFF0000) | (T1 >> 16);
- break;
- case 3:
- tmp = (tmp & 0xFFFFFF00) | (T1 >> 24);
- break;
- }
-#if defined (DEBUG_OP)
- if (logfile) {
- fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
- __func__, T0, sav, T1, tmp);
- }
-#endif
- RETURN();
- return tmp;
-}
-
-uint32_t glue(do_swr, MEMSUFFIX) (uint32_t tmp)
-{
-#if defined (DEBUG_OP)
- target_ulong sav;
-#endif
-
-#if defined (DEBUG_OP)
- sav = tmp;
-#endif
- /* XXX: this is valid only in big-endian mode
- * should be reverted for little-endian...
- */
- switch (GET_LMASK(T0)) {
- case 0:
- tmp = (tmp & 0x00FFFFFF) | (T1 << 24);
- break;
- case 1:
- tmp = (tmp & 0x0000FFFF) | (T1 << 16);
- break;
- case 2:
- tmp = (tmp & 0x000000FF) | (T1 << 8);
- break;
- case 3:
- tmp = T1;
- break;
- }
-#if defined (DEBUG_OP)
- if (logfile) {
- fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
- __func__, T0, sav, T1, tmp);
- }
-#endif
- RETURN();
- return tmp;
-}
diff --git a/target-mips/op_mem.c b/target-mips/op_mem.c
deleted file mode 100644
index 35ccd44..0000000
--- a/target-mips/op_mem.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * MIPS emulation memory micro-operations for qemu.
- *
- * Copyright (c) 2004-2005 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
- */
-
-/* Standard loads and stores */
-void glue(op_lb, MEMSUFFIX) (void)
-{
- T0 = glue(ldsb, MEMSUFFIX)(T0);
- RETURN();
-}
-
-void glue(op_lbu, MEMSUFFIX) (void)
-{
- T0 = glue(ldub, MEMSUFFIX)(T0);
- RETURN();
-}
-
-void glue(op_sb, MEMSUFFIX) (void)
-{
- glue(stb, MEMSUFFIX)(T0, T1);
- RETURN();
-}
-
-void glue(op_lh, MEMSUFFIX) (void)
-{
- T0 = glue(ldsw, MEMSUFFIX)(T0);
- RETURN();
-}
-
-void glue(op_lhu, MEMSUFFIX) (void)
-{
- T0 = glue(lduw, MEMSUFFIX)(T0);
- RETURN();
-}
-
-void glue(op_sh, MEMSUFFIX) (void)
-{
- glue(stw, MEMSUFFIX)(T0, T1);
- RETURN();
-}
-
-void glue(op_lw, MEMSUFFIX) (void)
-{
- T0 = glue(ldl, MEMSUFFIX)(T0);
- RETURN();
-}
-
-void glue(op_lwu, MEMSUFFIX) (void)
-{
- T0 = glue(ldl, MEMSUFFIX)(T0);
- RETURN();
-}
-
-void glue(op_sw, MEMSUFFIX) (void)
-{
- glue(stl, MEMSUFFIX)(T0, T1);
- RETURN();
-}
-
-/* "half" load and stores. We must do the memory access inline,
- or fault handling won't work. */
-void glue(op_lwl, MEMSUFFIX) (void)
-{
- uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
- CALL_FROM_TB1(glue(do_lwl, MEMSUFFIX), tmp);
- RETURN();
-}
-
-void glue(op_lwr, MEMSUFFIX) (void)
-{
- uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
- CALL_FROM_TB1(glue(do_lwr, MEMSUFFIX), tmp);
- RETURN();
-}
-
-void glue(op_swl, MEMSUFFIX) (void)
-{
- uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
- tmp = CALL_FROM_TB1(glue(do_swl, MEMSUFFIX), tmp);
- glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
- RETURN();
-}
-
-void glue(op_swr, MEMSUFFIX) (void)
-{
- uint32_t tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
- tmp = CALL_FROM_TB1(glue(do_swr, MEMSUFFIX), tmp);
- glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
- RETURN();
-}
-
-void glue(op_ll, MEMSUFFIX) (void)
-{
- T1 = T0;
- T0 = glue(ldl, MEMSUFFIX)(T0);
- env->CP0_LLAddr = T1;
- RETURN();
-}
-
-void glue(op_sc, MEMSUFFIX) (void)
-{
- CALL_FROM_TB0(dump_sc);
- if (T0 == env->CP0_LLAddr) {
- glue(stl, MEMSUFFIX)(T0, T1);
- T0 = 1;
- } else {
- T0 = 0;
- }
- RETURN();
-}
-
-#ifdef MIPS_USES_FPU
-void glue(op_lwc1, MEMSUFFIX) (void)
-{
- WT0 = glue(ldl, MEMSUFFIX)(T0);
- RETURN();
-}
-void glue(op_swc1, MEMSUFFIX) (void)
-{
- glue(stl, MEMSUFFIX)(T0, WT0);
- RETURN();
-}
-void glue(op_ldc1, MEMSUFFIX) (void)
-{
- DT0 = glue(ldq, MEMSUFFIX)(T0);
- RETURN();
-}
-void glue(op_sdc1, MEMSUFFIX) (void)
-{
- glue(stq, MEMSUFFIX)(T0, DT0);
- RETURN();
-}
-#endif
diff --git a/target-mips/op_template.c b/target-mips/op_template.c
deleted file mode 100644
index 9314c95..0000000
--- a/target-mips/op_template.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * MIPS emulation micro-operations templates for reg load & store for qemu.
- *
- * Copyright (c) 2004-2005 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(REG)
-void glue(op_load_gpr_T0_gpr, REG) (void)
-{
- T0 = env->gpr[REG];
- RETURN();
-}
-
-void glue(op_store_T0_gpr_gpr, REG) (void)
-{
- env->gpr[REG] = T0;
- RETURN();
-}
-
-void glue(op_load_gpr_T1_gpr, REG) (void)
-{
- T1 = env->gpr[REG];
- RETURN();
-}
-
-void glue(op_store_T1_gpr_gpr, REG) (void)
-{
- env->gpr[REG] = T1;
- RETURN();
-}
-
-void glue(op_load_gpr_T2_gpr, REG) (void)
-{
- T2 = env->gpr[REG];
- RETURN();
-}
-#endif
-
-#if defined (TN)
-void glue(op_set_, TN) (void)
-{
- TN = PARAM1;
- RETURN();
-}
-
-void glue (op_reset_, TN) (void)
-{
- TN = 0;
- RETURN();
-}
-#endif
diff --git a/target-mips/translate.c b/target-mips/translate.c
deleted file mode 100644
index 7ad8ebd..0000000
--- a/target-mips/translate.c
+++ /dev/null
@@ -1,2443 +0,0 @@
-/*
- * MIPS32 emulation for qemu: main translation routines.
- *
- * Copyright (c) 2004-2005 Jocelyn Mayer
- * Copyright (c) 2006 Marius Groeger (FPU operations)
- *
- * 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 <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-#include "disas.h"
-
-//#define MIPS_DEBUG_DISAS
-//#define MIPS_SINGLE_STEP
-
-#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"
-
-/* MIPS opcodes */
-#define EXT_SPECIAL 0x100
-#define EXT_SPECIAL2 0x200
-#define EXT_REGIMM 0x300
-#define EXT_CP0 0x400
-#define EXT_CP1 0x500
-#define EXT_CP2 0x600
-#define EXT_CP3 0x700
-
-enum {
- /* indirect opcode tables */
- OPC_SPECIAL = 0x00,
- OPC_BREGIMM = 0x01,
- OPC_CP0 = 0x10,
- OPC_CP1 = 0x11,
- OPC_CP2 = 0x12,
- OPC_CP3 = 0x13,
- OPC_SPECIAL2 = 0x1C,
- /* arithmetic with immediate */
- OPC_ADDI = 0x08,
- OPC_ADDIU = 0x09,
- OPC_SLTI = 0x0A,
- OPC_SLTIU = 0x0B,
- OPC_ANDI = 0x0C,
- OPC_ORI = 0x0D,
- OPC_XORI = 0x0E,
- OPC_LUI = 0x0F,
- /* Jump and branches */
- OPC_J = 0x02,
- OPC_JAL = 0x03,
- OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */
- OPC_BEQL = 0x14,
- OPC_BNE = 0x05,
- OPC_BNEL = 0x15,
- OPC_BLEZ = 0x06,
- OPC_BLEZL = 0x16,
- OPC_BGTZ = 0x07,
- OPC_BGTZL = 0x17,
- OPC_JALX = 0x1D, /* MIPS 16 only */
- /* Load and stores */
- OPC_LB = 0x20,
- OPC_LH = 0x21,
- OPC_LWL = 0x22,
- OPC_LW = 0x23,
- OPC_LBU = 0x24,
- OPC_LHU = 0x25,
- OPC_LWR = 0x26,
- OPC_LWU = 0x27,
- OPC_SB = 0x28,
- OPC_SH = 0x29,
- OPC_SWL = 0x2A,
- OPC_SW = 0x2B,
- OPC_SWR = 0x2E,
- OPC_LL = 0x30,
- OPC_SC = 0x38,
- /* Floating point load/store */
- OPC_LWC1 = 0x31,
- OPC_LWC2 = 0x32,
- OPC_LDC1 = 0x35,
- OPC_LDC2 = 0x36,
- OPC_SWC1 = 0x39,
- OPC_SWC2 = 0x3A,
- OPC_SDC1 = 0x3D,
- OPC_SDC2 = 0x3E,
- /* Cache and prefetch */
- OPC_CACHE = 0x2F,
- OPC_PREF = 0x33,
-};
-
-/* MIPS special opcodes */
-enum {
- /* Shifts */
- OPC_SLL = 0x00 | EXT_SPECIAL,
- /* NOP is SLL r0, r0, 0 */
- /* SSNOP is SLL r0, r0, 1 */
- OPC_SRL = 0x02 | EXT_SPECIAL,
- OPC_SRA = 0x03 | EXT_SPECIAL,
- OPC_SLLV = 0x04 | EXT_SPECIAL,
- OPC_SRLV = 0x06 | EXT_SPECIAL,
- OPC_SRAV = 0x07 | EXT_SPECIAL,
- /* Multiplication / division */
- OPC_MULT = 0x18 | EXT_SPECIAL,
- OPC_MULTU = 0x19 | EXT_SPECIAL,
- OPC_DIV = 0x1A | EXT_SPECIAL,
- OPC_DIVU = 0x1B | EXT_SPECIAL,
- /* 2 registers arithmetic / logic */
- OPC_ADD = 0x20 | EXT_SPECIAL,
- OPC_ADDU = 0x21 | EXT_SPECIAL,
- OPC_SUB = 0x22 | EXT_SPECIAL,
- OPC_SUBU = 0x23 | EXT_SPECIAL,
- OPC_AND = 0x24 | EXT_SPECIAL,
- OPC_OR = 0x25 | EXT_SPECIAL,
- OPC_XOR = 0x26 | EXT_SPECIAL,
- OPC_NOR = 0x27 | EXT_SPECIAL,
- OPC_SLT = 0x2A | EXT_SPECIAL,
- OPC_SLTU = 0x2B | EXT_SPECIAL,
- /* Jumps */
- OPC_JR = 0x08 | EXT_SPECIAL,
- OPC_JALR = 0x09 | EXT_SPECIAL,
- /* Traps */
- OPC_TGE = 0x30 | EXT_SPECIAL,
- OPC_TGEU = 0x31 | EXT_SPECIAL,
- OPC_TLT = 0x32 | EXT_SPECIAL,
- OPC_TLTU = 0x33 | EXT_SPECIAL,
- OPC_TEQ = 0x34 | EXT_SPECIAL,
- OPC_TNE = 0x36 | EXT_SPECIAL,
- /* HI / LO registers load & stores */
- OPC_MFHI = 0x10 | EXT_SPECIAL,
- OPC_MTHI = 0x11 | EXT_SPECIAL,
- OPC_MFLO = 0x12 | EXT_SPECIAL,
- OPC_MTLO = 0x13 | EXT_SPECIAL,
- /* Conditional moves */
- OPC_MOVZ = 0x0A | EXT_SPECIAL,
- OPC_MOVN = 0x0B | EXT_SPECIAL,
-
- OPC_MOVCI = 0x01 | EXT_SPECIAL,
-
- /* Special */
- OPC_PMON = 0x05 | EXT_SPECIAL,
- OPC_SYSCALL = 0x0C | EXT_SPECIAL,
- OPC_BREAK = 0x0D | EXT_SPECIAL,
- OPC_SYNC = 0x0F | EXT_SPECIAL,
-};
-
-enum {
- /* Mutiply & xxx operations */
- OPC_MADD = 0x00 | EXT_SPECIAL2,
- OPC_MADDU = 0x01 | EXT_SPECIAL2,
- OPC_MUL = 0x02 | EXT_SPECIAL2,
- OPC_MSUB = 0x04 | EXT_SPECIAL2,
- OPC_MSUBU = 0x05 | EXT_SPECIAL2,
- /* Misc */
- OPC_CLZ = 0x20 | EXT_SPECIAL2,
- OPC_CLO = 0x21 | EXT_SPECIAL2,
- /* Special */
- OPC_SDBBP = 0x3F | EXT_SPECIAL2,
-};
-
-/* Branch REGIMM */
-enum {
- OPC_BLTZ = 0x00 | EXT_REGIMM,
- OPC_BLTZL = 0x02 | EXT_REGIMM,
- OPC_BGEZ = 0x01 | EXT_REGIMM,
- OPC_BGEZL = 0x03 | EXT_REGIMM,
- OPC_BLTZAL = 0x10 | EXT_REGIMM,
- OPC_BLTZALL = 0x12 | EXT_REGIMM,
- OPC_BGEZAL = 0x11 | EXT_REGIMM,
- OPC_BGEZALL = 0x13 | EXT_REGIMM,
- OPC_TGEI = 0x08 | EXT_REGIMM,
- OPC_TGEIU = 0x09 | EXT_REGIMM,
- OPC_TLTI = 0x0A | EXT_REGIMM,
- OPC_TLTIU = 0x0B | EXT_REGIMM,
- OPC_TEQI = 0x0C | EXT_REGIMM,
- OPC_TNEI = 0x0E | EXT_REGIMM,
-};
-
-enum {
- /* Coprocessor 0 (MMU) */
- OPC_MFC0 = 0x00 | EXT_CP0,
- OPC_MTC0 = 0x04 | EXT_CP0,
- OPC_TLBR = 0x01 | EXT_CP0,
- OPC_TLBWI = 0x02 | EXT_CP0,
- OPC_TLBWR = 0x06 | EXT_CP0,
- OPC_TLBP = 0x08 | EXT_CP0,
- OPC_ERET = 0x18 | EXT_CP0,
- OPC_DERET = 0x1F | EXT_CP0,
- OPC_WAIT = 0x20 | EXT_CP0,
-};
-
-#ifdef MIPS_USES_FPU
-enum {
- /* Coprocessor 1 (FPU) */
- OPC_MFC1 = 0x00 | EXT_CP1,
- OPC_MTC1 = 0x04 | EXT_CP1,
- OPC_CFC1 = 0x02 | EXT_CP1,
- OPC_CTC1 = 0x06 | EXT_CP1,
-};
-#endif
-
-const unsigned char *regnames[] =
- { "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
- "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
-
-/* 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](); \
-}
-
-/* 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);
-GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
-
-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
-const unsigned 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 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](); \
-}
-
-SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr);
-SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_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);
-
-SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr);
-SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_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);
-
-DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr);
-DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_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);
-
-#define FOP_CONDS(fmt) \
-static GenOpFunc * cond_ ## fmt ## _table[16] = { \
- gen_op_cmp_ ## fmt ## _f, \
- gen_op_cmp_ ## fmt ## _un, \
- gen_op_cmp_ ## fmt ## _eq, \
- gen_op_cmp_ ## fmt ## _ueq, \
- gen_op_cmp_ ## fmt ## _olt, \
- gen_op_cmp_ ## fmt ## _ult, \
- gen_op_cmp_ ## fmt ## _ole, \
- gen_op_cmp_ ## fmt ## _ule, \
- gen_op_cmp_ ## fmt ## _sf, \
- gen_op_cmp_ ## fmt ## _ngle, \
- gen_op_cmp_ ## fmt ## _seq, \
- gen_op_cmp_ ## fmt ## _ngl, \
- gen_op_cmp_ ## fmt ## _lt, \
- gen_op_cmp_ ## fmt ## _nge, \
- gen_op_cmp_ ## fmt ## _le, \
- gen_op_cmp_ ## fmt ## _ngt, \
-}; \
-static inline void gen_cmp_ ## fmt(int n) \
-{ \
- cond_ ## fmt ## _table[n](); \
-}
-
-FOP_CONDS(d)
-FOP_CONDS(s)
-
-#endif
-
-typedef struct DisasContext {
- struct TranslationBlock *tb;
- target_ulong pc, saved_pc;
- uint32_t opcode;
- /* Routine used to access memory */
- int mem_idx;
- uint32_t hflags, saved_hflags;
- uint32_t CP0_Status;
- int bstate;
- target_ulong btarget;
-} DisasContext;
-
-enum {
- BS_NONE = 0, /* We go out of the TB without reaching a branch or an
- * exception condition
- */
- BS_STOP = 1, /* We want to stop translation for any reason */
- BS_BRANCH = 2, /* We reached a branch condition */
- BS_EXCP = 3, /* We reached an exception condition */
-};
-
-#if defined MIPS_DEBUG_DISAS
-#define MIPS_DEBUG(fmt, args...) \
-do { \
- if (loglevel & CPU_LOG_TB_IN_ASM) { \
- fprintf(logfile, "%08x: %08x " fmt "\n", \
- ctx->pc, ctx->opcode , ##args); \
- } \
-} while (0)
-#else
-#define MIPS_DEBUG(fmt, args...) do { } while(0)
-#endif
-
-#define MIPS_INVAL(op) \
-do { \
- MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26, \
- ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \
-} while (0)
-
-#define GEN_LOAD_REG_TN(Tn, Rn) \
-do { \
- if (Rn == 0) { \
- glue(gen_op_reset_, Tn)(); \
- } else { \
- glue(gen_op_load_gpr_, Tn)(Rn); \
- } \
-} while (0)
-
-#define GEN_LOAD_IMM_TN(Tn, Imm) \
-do { \
- if (Imm == 0) { \
- glue(gen_op_reset_, Tn)(); \
- } else { \
- glue(gen_op_set_, Tn)(Imm); \
- } \
-} while (0)
-
-#define GEN_STORE_TN_REG(Rn, Tn) \
-do { \
- if (Rn != 0) { \
- glue(glue(gen_op_store_, Tn),_gpr)(Rn); \
- } \
-} while (0)
-
-#ifdef MIPS_USES_FPU
-
-# define GEN_LOAD_FREG_FTN(FTn, Fn) \
-do { \
- glue(gen_op_load_fpr_, FTn)(Fn); \
-} while (0)
-
-#define GEN_STORE_FTN_FREG(Fn, FTn) \
-do { \
- glue(gen_op_store_fpr_, FTn)(Fn); \
-} while (0)
-
-#endif
-
-static inline void save_cpu_state (DisasContext *ctx, int do_save_pc)
-{
-#if defined MIPS_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "hflags %08x saved %08x\n",
- ctx->hflags, ctx->saved_hflags);
- }
-#endif
- if (do_save_pc && ctx->pc != ctx->saved_pc) {
- gen_op_save_pc(ctx->pc);
- ctx->saved_pc = ctx->pc;
- }
- if (ctx->hflags != ctx->saved_hflags) {
- gen_op_save_state(ctx->hflags);
- ctx->saved_hflags = ctx->hflags;
- if (ctx->hflags & 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) {
- gen_op_save_bcond();
- gen_op_save_btarget(ctx->btarget);
- }
- }
-}
-
-static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
-{
-#if defined MIPS_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM)
- fprintf(logfile, "%s: raise exception %d\n", __func__, excp);
-#endif
- save_cpu_state(ctx, 1);
- if (err == 0)
- gen_op_raise_exception(excp);
- else
- gen_op_raise_exception_err(excp, err);
- ctx->bstate = BS_EXCP;
-}
-
-static inline void generate_exception (DisasContext *ctx, int excp)
-{
- generate_exception_err (ctx, excp, 0);
-}
-
-#if defined(CONFIG_USER_ONLY)
-#define op_ldst(name) gen_op_##name##_raw()
-#define OP_LD_TABLE(width)
-#define OP_ST_TABLE(width)
-#else
-#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
-#define OP_LD_TABLE(width) \
-static GenOpFunc *gen_op_l##width[] = { \
- &gen_op_l##width##_user, \
- &gen_op_l##width##_kernel, \
-}
-#define OP_ST_TABLE(width) \
-static GenOpFunc *gen_op_s##width[] = { \
- &gen_op_s##width##_user, \
- &gen_op_s##width##_kernel, \
-}
-#endif
-
-#ifdef TARGET_MIPS64
-OP_LD_TABLE(d);
-OP_LD_TABLE(dl);
-OP_LD_TABLE(dr);
-OP_ST_TABLE(d);
-OP_ST_TABLE(dl);
-OP_ST_TABLE(dr);
-#endif
-OP_LD_TABLE(w);
-OP_LD_TABLE(wu);
-OP_LD_TABLE(wl);
-OP_LD_TABLE(wr);
-OP_ST_TABLE(w);
-OP_ST_TABLE(wl);
-OP_ST_TABLE(wr);
-OP_LD_TABLE(h);
-OP_LD_TABLE(hu);
-OP_ST_TABLE(h);
-OP_LD_TABLE(b);
-OP_LD_TABLE(bu);
-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
-
-/* Load and store */
-static void gen_ldst (DisasContext *ctx, uint16_t opc, int rt,
- int base, int16_t offset)
-{
- const unsigned char *opn = "unk";
-
- if (base == 0) {
- GEN_LOAD_IMM_TN(T0, offset);
- } else if (offset == 0) {
- gen_op_load_gpr_T0(base);
- } else {
- gen_op_load_gpr_T0(base);
- gen_op_set_T1(offset);
- gen_op_add();
- }
- /* Don't do NOP if destination is zero: we must perform the actual
- * memory access
- */
- switch (opc) {
-#if defined(TARGET_MIPS64)
- case OPC_LD:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_ULD:
-#endif
- op_ldst(ld);
- GEN_STORE_TN_REG(rt, T0);
- opn = "ld";
- break;
- case OPC_SD:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_USD:
-#endif
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(sd);
- opn = "sd";
- break;
- case OPC_LDL:
- op_ldst(ldl);
- GEN_STORE_TN_REG(rt, T0);
- opn = "ldl";
- break;
- case OPC_SDL:
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(sdl);
- opn = "sdl";
- break;
- case OPC_LDR:
- op_ldst(ldr);
- GEN_STORE_TN_REG(rt, T0);
- opn = "ldr";
- break;
- case OPC_SDR:
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(sdr);
- opn = "sdr";
- break;
-#endif
- case OPC_LW:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_ULW:
-#endif
- op_ldst(lw);
- GEN_STORE_TN_REG(rt, T0);
- opn = "lw";
- break;
- case OPC_LWU:
- op_ldst(lwu);
- GEN_STORE_TN_REG(rt, T0);
- opn = "lwu";
- break;
- case OPC_SW:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_USW:
-#endif
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(sw);
- opn = "sw";
- break;
- case OPC_LH:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_ULH:
-#endif
- op_ldst(lh);
- GEN_STORE_TN_REG(rt, T0);
- opn = "lh";
- break;
- case OPC_SH:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_USH:
-#endif
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(sh);
- opn = "sh";
- break;
- case OPC_LHU:
-#if defined (MIPS_HAS_UNALIGNED_LS)
- case OPC_ULHU:
-#endif
- op_ldst(lhu);
- GEN_STORE_TN_REG(rt, T0);
- opn = "lhu";
- break;
- case OPC_LB:
- op_ldst(lb);
- GEN_STORE_TN_REG(rt, T0);
- opn = "lb";
- break;
- case OPC_SB:
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(sb);
- opn = "sb";
- break;
- case OPC_LBU:
- op_ldst(lbu);
- GEN_STORE_TN_REG(rt, T0);
- opn = "lbu";
- break;
- case OPC_LWL:
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(lwl);
- GEN_STORE_TN_REG(rt, T0);
- opn = "lwl";
- break;
- case OPC_SWL:
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(swl);
- opn = "swr";
- break;
- case OPC_LWR:
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(lwr);
- GEN_STORE_TN_REG(rt, T0);
- opn = "lwr";
- break;
- case OPC_SWR:
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(swr);
- opn = "swr";
- break;
- case OPC_LL:
- op_ldst(ll);
- GEN_STORE_TN_REG(rt, T0);
- opn = "ll";
- break;
- case OPC_SC:
- GEN_LOAD_REG_TN(T1, rt);
- op_ldst(sc);
- GEN_STORE_TN_REG(rt, T0);
- opn = "sc";
- break;
- default:
- MIPS_INVAL("load/store");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- 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, uint16_t opc, int ft,
- int base, int16_t offset)
-{
- const unsigned char *opn = "unk";
-
- if (base == 0) {
- GEN_LOAD_IMM_TN(T0, offset);
- } else if (offset == 0) {
- gen_op_load_gpr_T0(base);
- } else {
- gen_op_load_gpr_T0(base);
- gen_op_set_T1(offset);
- gen_op_add();
- }
- /* Don't do NOP if destination is zero: we must perform the actual
- * memory access
- */
- switch (opc) {
- case OPC_LWC1:
- op_ldst(lwc1);
- GEN_STORE_FTN_FREG(ft, WT0);
- opn = "lwc1";
- break;
- case OPC_SWC1:
- GEN_LOAD_FREG_FTN(WT0, ft);
- op_ldst(swc1);
- opn = "swc1";
- break;
- case OPC_LDC1:
- op_ldst(ldc1);
- GEN_STORE_FTN_FREG(ft, DT0);
- opn = "ldc1";
- break;
- case OPC_SDC1:
- GEN_LOAD_FREG_FTN(DT0, ft);
- op_ldst(sdc1);
- opn = "sdc1";
- break;
- default:
- MIPS_INVAL("float load/store");
- generate_exception(ctx, EXCP_CpU);
- return;
- }
- MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
-}
-#endif
-
-/* Arithmetic with immediate operand */
-static void gen_arith_imm (DisasContext *ctx, uint16_t opc, int rt,
- int rs, int16_t imm)
-{
- uint32_t uimm;
- const unsigned char *opn = "unk";
-
- if (rt == 0 && opc != OPC_ADDI) {
- /* if no destination, treat it as a NOP
- * For addi, we must generate the overflow exception when needed.
- */
- MIPS_DEBUG("NOP");
- return;
- }
- if (opc == OPC_ADDI || opc == OPC_ADDIU ||
- opc == OPC_SLTI || opc == OPC_SLTIU)
- uimm = (int32_t)imm; /* Sign extent to 32 bits */
- else
- uimm = (uint16_t)imm;
- if (opc != OPC_LUI) {
- GEN_LOAD_REG_TN(T0, rs);
- GEN_LOAD_IMM_TN(T1, uimm);
- } else {
- uimm = uimm << 16;
- GEN_LOAD_IMM_TN(T0, uimm);
- }
- switch (opc) {
- case OPC_ADDI:
- save_cpu_state(ctx, 1);
- gen_op_addo();
- opn = "addi";
- break;
- case OPC_ADDIU:
- gen_op_add();
- opn = "addiu";
- break;
- case OPC_SLTI:
- gen_op_lt();
- opn = "slti";
- break;
- case OPC_SLTIU:
- gen_op_ltu();
- opn = "sltiu";
- break;
- case OPC_ANDI:
- gen_op_and();
- opn = "andi";
- break;
- case OPC_ORI:
- gen_op_or();
- opn = "ori";
- break;
- case OPC_XORI:
- gen_op_xor();
- opn = "xori";
- break;
- case OPC_LUI:
- opn = "lui";
- break;
- case OPC_SLL:
- gen_op_sll();
- opn = "sll";
- break;
- case OPC_SRA:
- gen_op_sra();
- opn = "sra";
- break;
- case OPC_SRL:
- gen_op_srl();
- opn = "srl";
- break;
- default:
- MIPS_INVAL("imm arith");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- GEN_STORE_TN_REG(rt, T0);
- MIPS_DEBUG("%s %s, %s, %x", opn, regnames[rt], regnames[rs], uimm);
-}
-
-/* Arithmetic */
-static void gen_arith (DisasContext *ctx, uint16_t opc,
- int rd, int rs, int rt)
-{
- const unsigned char *opn = "unk";
-
- if (rd == 0 && opc != OPC_ADD && opc != OPC_SUB) {
- /* if no destination, treat it as a NOP
- * For add & sub, we must generate the overflow exception when needed.
- */
- MIPS_DEBUG("NOP");
- return;
- }
- GEN_LOAD_REG_TN(T0, rs);
- GEN_LOAD_REG_TN(T1, rt);
- switch (opc) {
- case OPC_ADD:
- save_cpu_state(ctx, 1);
- gen_op_addo();
- opn = "add";
- break;
- case OPC_ADDU:
- gen_op_add();
- opn = "addu";
- break;
- case OPC_SUB:
- save_cpu_state(ctx, 1);
- gen_op_subo();
- opn = "sub";
- break;
- case OPC_SUBU:
- gen_op_sub();
- opn = "subu";
- break;
- case OPC_SLT:
- gen_op_lt();
- opn = "slt";
- break;
- case OPC_SLTU:
- gen_op_ltu();
- opn = "sltu";
- break;
- case OPC_AND:
- gen_op_and();
- opn = "and";
- break;
- case OPC_NOR:
- gen_op_nor();
- opn = "nor";
- break;
- case OPC_OR:
- gen_op_or();
- opn = "or";
- break;
- case OPC_XOR:
- gen_op_xor();
- opn = "xor";
- break;
- case OPC_MUL:
- gen_op_mul();
- opn = "mul";
- break;
- case OPC_MOVN:
- gen_op_movn(rd);
- opn = "movn";
- goto print;
- case OPC_MOVZ:
- gen_op_movz(rd);
- opn = "movz";
- goto print;
- case OPC_SLLV:
- gen_op_sllv();
- opn = "sllv";
- break;
- case OPC_SRAV:
- gen_op_srav();
- opn = "srav";
- break;
- case OPC_SRLV:
- gen_op_srlv();
- opn = "srlv";
- break;
- default:
- MIPS_INVAL("arith");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- GEN_STORE_TN_REG(rd, T0);
- print:
- MIPS_DEBUG("%s %s, %s, %s", opn, regnames[rd], regnames[rs], regnames[rt]);
-}
-
-/* Arithmetic on HI/LO registers */
-static void gen_HILO (DisasContext *ctx, uint16_t opc, int reg)
-{
- const unsigned char *opn = "unk";
-
- if (reg == 0 && (opc == OPC_MFHI || opc == OPC_MFLO)) {
- /* Treat as a NOP */
- MIPS_DEBUG("NOP");
- return;
- }
- switch (opc) {
- case OPC_MFHI:
- gen_op_load_HI();
- GEN_STORE_TN_REG(reg, T0);
- opn = "mfhi";
- break;
- case OPC_MFLO:
- gen_op_load_LO();
- GEN_STORE_TN_REG(reg, T0);
- opn = "mflo";
- break;
- case OPC_MTHI:
- GEN_LOAD_REG_TN(T0, reg);
- gen_op_store_HI();
- opn = "mthi";
- break;
- case OPC_MTLO:
- GEN_LOAD_REG_TN(T0, reg);
- gen_op_store_LO();
- opn = "mtlo";
- break;
- default:
- MIPS_INVAL("HILO");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- MIPS_DEBUG("%s %s", opn, regnames[reg]);
-}
-
-static void gen_muldiv (DisasContext *ctx, uint16_t opc,
- int rs, int rt)
-{
- const unsigned char *opn = "unk";
-
- GEN_LOAD_REG_TN(T0, rs);
- GEN_LOAD_REG_TN(T1, rt);
- switch (opc) {
- case OPC_DIV:
- gen_op_div();
- opn = "div";
- break;
- case OPC_DIVU:
- gen_op_divu();
- opn = "divu";
- break;
- case OPC_MULT:
- gen_op_mult();
- opn = "mult";
- break;
- case OPC_MULTU:
- gen_op_multu();
- opn = "multu";
- break;
- case OPC_MADD:
- gen_op_madd();
- opn = "madd";
- break;
- case OPC_MADDU:
- gen_op_maddu();
- opn = "maddu";
- break;
- case OPC_MSUB:
- gen_op_msub();
- opn = "msub";
- break;
- case OPC_MSUBU:
- gen_op_msubu();
- opn = "msubu";
- break;
- default:
- MIPS_INVAL("mul/div");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- MIPS_DEBUG("%s %s %s", opn, regnames[rs], regnames[rt]);
-}
-
-static void gen_cl (DisasContext *ctx, uint16_t opc,
- int rd, int rs)
-{
- const unsigned char *opn = "unk";
- if (rd == 0) {
- /* Treat as a NOP */
- MIPS_DEBUG("NOP");
- return;
- }
- GEN_LOAD_REG_TN(T0, rs);
- switch (opc) {
- case OPC_CLO:
- /* CLO */
- gen_op_clo();
- opn = "clo";
- break;
- case OPC_CLZ:
- /* CLZ */
- gen_op_clz();
- opn = "clz";
- break;
- default:
- MIPS_INVAL("CLx");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- gen_op_store_T0_gpr(rd);
- MIPS_DEBUG("%s %s, %s", opn, regnames[rd], regnames[rs]);
-}
-
-/* Traps */
-static void gen_trap (DisasContext *ctx, uint16_t opc,
- int rs, int rt, int16_t imm)
-{
- int cond;
-
- cond = 0;
- /* Load needed operands */
- switch (opc) {
- case OPC_TEQ:
- case OPC_TGE:
- case OPC_TGEU:
- case OPC_TLT:
- case OPC_TLTU:
- case OPC_TNE:
- /* Compare two registers */
- if (rs != rt) {
- GEN_LOAD_REG_TN(T0, rs);
- GEN_LOAD_REG_TN(T1, rt);
- cond = 1;
- }
- case OPC_TEQI:
- case OPC_TGEI:
- case OPC_TGEIU:
- case OPC_TLTI:
- case OPC_TLTIU:
- case OPC_TNEI:
- /* Compare register to immediate */
- if (rs != 0 || imm != 0) {
- GEN_LOAD_REG_TN(T0, rs);
- GEN_LOAD_IMM_TN(T1, (int32_t)imm);
- cond = 1;
- }
- break;
- }
- if (cond == 0) {
- switch (opc) {
- case OPC_TEQ: /* rs == rs */
- case OPC_TEQI: /* r0 == 0 */
- case OPC_TGE: /* rs >= rs */
- case OPC_TGEI: /* r0 >= 0 */
- case OPC_TGEU: /* rs >= rs unsigned */
- case OPC_TGEIU: /* r0 >= 0 unsigned */
- /* Always trap */
- gen_op_set_T0(1);
- break;
- case OPC_TLT: /* rs < rs */
- case OPC_TLTI: /* r0 < 0 */
- case OPC_TLTU: /* rs < rs unsigned */
- case OPC_TLTIU: /* r0 < 0 unsigned */
- case OPC_TNE: /* rs != rs */
- case OPC_TNEI: /* r0 != 0 */
- /* Never trap: treat as NOP */
- return;
- default:
- MIPS_INVAL("TRAP");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- } else {
- switch (opc) {
- case OPC_TEQ:
- case OPC_TEQI:
- gen_op_eq();
- break;
- case OPC_TGE:
- case OPC_TGEI:
- gen_op_ge();
- break;
- case OPC_TGEU:
- case OPC_TGEIU:
- gen_op_geu();
- break;
- case OPC_TLT:
- case OPC_TLTI:
- gen_op_lt();
- break;
- case OPC_TLTU:
- case OPC_TLTIU:
- gen_op_ltu();
- break;
- case OPC_TNE:
- case OPC_TNEI:
- gen_op_ne();
- break;
- default:
- MIPS_INVAL("TRAP");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- }
- save_cpu_state(ctx, 1);
- gen_op_trap();
- ctx->bstate = BS_STOP;
-}
-
-static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
-{
- TranslationBlock *tb;
- tb = ctx->tb;
- if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
- if (n == 0)
- gen_op_goto_tb0(TBPARAM(tb));
- else
- 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();
- }
-}
-
-/* Branches (before delay slot) */
-static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
- int rs, int rt, int32_t offset)
-{
- target_ulong btarget;
- int blink, bcond;
-
- btarget = -1;
- blink = 0;
- bcond = 0;
- /* Load needed operands */
- switch (opc) {
- case OPC_BEQ:
- case OPC_BEQL:
- case OPC_BNE:
- case OPC_BNEL:
- /* Compare two registers */
- if (rs != rt) {
- GEN_LOAD_REG_TN(T0, rs);
- GEN_LOAD_REG_TN(T1, rt);
- bcond = 1;
- }
- btarget = ctx->pc + 4 + offset;
- break;
- case OPC_BGEZ:
- case OPC_BGEZAL:
- case OPC_BGEZALL:
- case OPC_BGEZL:
- case OPC_BGTZ:
- case OPC_BGTZL:
- case OPC_BLEZ:
- case OPC_BLEZL:
- case OPC_BLTZ:
- case OPC_BLTZAL:
- case OPC_BLTZALL:
- case OPC_BLTZL:
- /* Compare to zero */
- if (rs != 0) {
- gen_op_load_gpr_T0(rs);
- bcond = 1;
- }
- btarget = ctx->pc + 4 + offset;
- break;
- case OPC_J:
- case OPC_JAL:
- /* Jump to immediate */
- btarget = ((ctx->pc + 4) & 0xF0000000) | offset;
- break;
- case OPC_JR:
- case OPC_JALR:
- /* Jump to register */
- if (offset != 0) {
- /* Only hint = 0 is valid */
- generate_exception(ctx, EXCP_RI);
- return;
- }
- GEN_LOAD_REG_TN(T2, rs);
- break;
- default:
- MIPS_INVAL("branch/jump");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- if (bcond == 0) {
- /* No condition to be computed */
- switch (opc) {
- case OPC_BEQ: /* rx == rx */
- case OPC_BEQL: /* rx == rx likely */
- case OPC_BGEZ: /* 0 >= 0 */
- case OPC_BGEZL: /* 0 >= 0 likely */
- case OPC_BLEZ: /* 0 <= 0 */
- case OPC_BLEZL: /* 0 <= 0 likely */
- /* Always take */
- ctx->hflags |= MIPS_HFLAG_B;
- MIPS_DEBUG("balways");
- break;
- case OPC_BGEZAL: /* 0 >= 0 */
- case OPC_BGEZALL: /* 0 >= 0 likely */
- /* Always take and link */
- blink = 31;
- ctx->hflags |= MIPS_HFLAG_B;
- MIPS_DEBUG("balways and link");
- break;
- case OPC_BNE: /* rx != rx */
- case OPC_BGTZ: /* 0 > 0 */
- case OPC_BLTZ: /* 0 < 0 */
- /* Treated as NOP */
- MIPS_DEBUG("bnever (NOP)");
- return;
- case OPC_BLTZAL: /* 0 < 0 */
- gen_op_set_T0(ctx->pc + 8);
- gen_op_store_T0_gpr(31);
- 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);
- 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);
- return;
- case OPC_J:
- ctx->hflags |= MIPS_HFLAG_B;
- MIPS_DEBUG("j %08x", btarget);
- break;
- case OPC_JAL:
- blink = 31;
- ctx->hflags |= MIPS_HFLAG_B;
- MIPS_DEBUG("jal %08x", btarget);
- break;
- case OPC_JR:
- ctx->hflags |= MIPS_HFLAG_BR;
- MIPS_DEBUG("jr %s", regnames[rs]);
- break;
- case OPC_JALR:
- blink = rt;
- ctx->hflags |= MIPS_HFLAG_BR;
- MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
- break;
- default:
- MIPS_INVAL("branch/jump");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- } else {
- switch (opc) {
- case OPC_BEQ:
- gen_op_eq();
- MIPS_DEBUG("beq %s, %s, %08x",
- regnames[rs], regnames[rt], btarget);
- goto not_likely;
- case OPC_BEQL:
- gen_op_eq();
- MIPS_DEBUG("beql %s, %s, %08x",
- regnames[rs], regnames[rt], btarget);
- goto likely;
- case OPC_BNE:
- gen_op_ne();
- MIPS_DEBUG("bne %s, %s, %08x",
- regnames[rs], regnames[rt], btarget);
- goto not_likely;
- case OPC_BNEL:
- gen_op_ne();
- MIPS_DEBUG("bnel %s, %s, %08x",
- regnames[rs], regnames[rt], btarget);
- goto likely;
- case OPC_BGEZ:
- gen_op_gez();
- MIPS_DEBUG("bgez %s, %08x", regnames[rs], btarget);
- goto not_likely;
- case OPC_BGEZL:
- gen_op_gez();
- MIPS_DEBUG("bgezl %s, %08x", regnames[rs], btarget);
- goto likely;
- case OPC_BGEZAL:
- gen_op_gez();
- MIPS_DEBUG("bgezal %s, %08x", regnames[rs], btarget);
- blink = 31;
- goto not_likely;
- case OPC_BGEZALL:
- gen_op_gez();
- blink = 31;
- MIPS_DEBUG("bgezall %s, %08x", regnames[rs], btarget);
- goto likely;
- case OPC_BGTZ:
- gen_op_gtz();
- MIPS_DEBUG("bgtz %s, %08x", regnames[rs], btarget);
- goto not_likely;
- case OPC_BGTZL:
- gen_op_gtz();
- MIPS_DEBUG("bgtzl %s, %08x", regnames[rs], btarget);
- goto likely;
- case OPC_BLEZ:
- gen_op_lez();
- MIPS_DEBUG("blez %s, %08x", regnames[rs], btarget);
- goto not_likely;
- case OPC_BLEZL:
- gen_op_lez();
- MIPS_DEBUG("blezl %s, %08x", regnames[rs], btarget);
- goto likely;
- case OPC_BLTZ:
- gen_op_ltz();
- MIPS_DEBUG("bltz %s, %08x", regnames[rs], btarget);
- goto not_likely;
- case OPC_BLTZL:
- gen_op_ltz();
- MIPS_DEBUG("bltzl %s, %08x", regnames[rs], btarget);
- goto likely;
- case OPC_BLTZAL:
- gen_op_ltz();
- blink = 31;
- MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
- not_likely:
- ctx->hflags |= MIPS_HFLAG_BC;
- break;
- case OPC_BLTZALL:
- gen_op_ltz();
- blink = 31;
- MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
- likely:
- ctx->hflags |= MIPS_HFLAG_BL;
- break;
- }
- gen_op_set_bcond();
- }
- MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
- blink, ctx->hflags, btarget);
- ctx->btarget = btarget;
- if (blink > 0) {
- gen_op_set_T0(ctx->pc + 8);
- gen_op_store_T0_gpr(blink);
- }
- return;
-}
-
-/* CP0 (MMU and control) */
-static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
-{
- const unsigned char *opn = "unk";
-
- 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");
- }
- generate_exception_err (ctx, EXCP_CpU, 0);
- return;
- }
-
- switch (opc) {
- case OPC_MFC0:
- if (rt == 0) {
- /* Treat as NOP */
- return;
- }
- gen_op_mfc0(rd, ctx->opcode & 0x7);
- gen_op_store_T0_gpr(rt);
- opn = "mfc0";
- break;
- case OPC_MTC0:
- /* If we get an exception, we want to restart at next instruction */
- ctx->pc += 4;
- save_cpu_state(ctx, 1);
- ctx->pc -= 4;
- GEN_LOAD_REG_TN(T0, rt);
- gen_op_mtc0(rd, ctx->opcode & 0x7);
- /* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
- opn = "mtc0";
- break;
-#if defined(MIPS_USES_R4K_TLB)
- case OPC_TLBWI:
- gen_op_tlbwi();
- opn = "tlbwi";
- break;
- case OPC_TLBWR:
- gen_op_tlbwr();
- opn = "tlbwr";
- break;
- case OPC_TLBP:
- gen_op_tlbp();
- opn = "tlbp";
- break;
- case OPC_TLBR:
- gen_op_tlbr();
- opn = "tlbr";
- break;
-#endif
- case OPC_ERET:
- opn = "eret";
- save_cpu_state(ctx, 0);
- gen_op_eret();
- ctx->bstate = BS_EXCP;
- break;
- case OPC_DERET:
- opn = "deret";
- if (!(ctx->hflags & MIPS_HFLAG_DM)) {
- generate_exception(ctx, EXCP_RI);
- } else {
- save_cpu_state(ctx, 0);
- gen_op_deret();
- ctx->bstate = BS_EXCP;
- }
- break;
- case OPC_WAIT:
- opn = "wait";
- /* If we get an exception, we want to restart at next instruction */
- ctx->pc += 4;
- save_cpu_state(ctx, 1);
- ctx->pc -= 4;
- gen_op_wait();
- ctx->bstate = BS_EXCP;
- break;
- default:
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "Invalid CP0 opcode: %08x %03x %03x %03x\n",
- ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
- ((ctx->opcode >> 16) & 0x1F));
- }
- generate_exception(ctx, EXCP_RI);
- return;
- }
- 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, uint16_t cond,
- int32_t offset)
-{
- target_ulong btarget;
-
- btarget = ctx->pc + 4 + offset;
-
- switch (cond) {
- case 0x0000: /* bc1f */
- gen_op_bc1f();
- MIPS_DEBUG("bc1f %08x", btarget);
- goto not_likely;
- case 0x0002: /* bc1fl */
- gen_op_bc1f();
- MIPS_DEBUG("bc1fl %08x", btarget);
- goto likely;
- case 0x0001: /* bc1t */
- gen_op_bc1t();
- MIPS_DEBUG("bc1t %08x", btarget);
- not_likely:
- ctx->hflags |= MIPS_HFLAG_BC;
- break;
- case 0x0003: /* bc1tl */
- gen_op_bc1t();
- MIPS_DEBUG("bc1tl %08x", btarget);
- likely:
- ctx->hflags |= MIPS_HFLAG_BL;
- break;
- default:
- MIPS_INVAL("cp1 branch/jump");
- generate_exception(ctx, EXCP_RI);
- return;
- }
- gen_op_set_bcond();
-
- MIPS_DEBUG("enter ds: cond %02x target %08x",
- ctx->hflags, btarget);
- ctx->btarget = btarget;
-
- return;
-}
-
-/* Coprocessor 1 (FPU) */
-static void gen_cp1 (DisasContext *ctx, uint16_t opc, int rt, int fs)
-{
- const unsigned char *opn = "unk";
-
- switch (opc) {
- case OPC_MFC1:
- GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_mfc1();
- GEN_STORE_TN_REG(rt, T0);
- opn = "mfc1";
- break;
- case OPC_MTC1:
- GEN_LOAD_REG_TN(T0, rt);
- gen_op_mtc1();
- GEN_STORE_FTN_FREG(fs, WT0);
- opn = "mtc1";
- break;
- case OPC_CFC1:
- if (fs != 0 && fs != 31) {
- MIPS_INVAL("cfc1 freg");
- generate_exception(ctx, EXCP_RI);
- 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(ctx, EXCP_RI);
- return;
- }
- GEN_LOAD_IMM_TN(T1, fs);
- GEN_LOAD_REG_TN(T0, rt);
- gen_op_ctc1();
- opn = "ctc1";
- 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(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(ctx, EXCP_RI); \
- return; \
- } \
- } while(0)
-
-#define FOP(func, fmt) (((fmt) << 21) | (func))
-
-static void gen_farith (DisasContext *ctx, int fmt, int ft, int fs, int fd, int func)
-{
- const unsigned char *opn = "unk";
- const char *condnames[] = {
- "c.f",
- "c.un",
- "c.eq",
- "c.ueq",
- "c.olt",
- "c.ult",
- "c.ole",
- "c.ule",
- "c.sf",
- "c.ngle",
- "c.seq",
- "c.ngl",
- "c.lt",
- "c.nge",
- "c.le",
- "c.ngt",
- };
- int binary = 0;
-
- switch (ctx->opcode & FOP(0x3f, 0x1f)) {
- case FOP(0, 17):
- CHECK_FR(ctx, fs | ft | fd);
- GEN_LOAD_FREG_FTN(DT0, fs);
- GEN_LOAD_FREG_FTN(DT1, ft);
- gen_op_float_add_d();
- GEN_STORE_FTN_FREG(fd, DT2);
- opn = "add.d";
- binary = 1;
- break;
- case FOP(1, 17):
- CHECK_FR(ctx, fs | ft | fd);
- GEN_LOAD_FREG_FTN(DT0, fs);
- GEN_LOAD_FREG_FTN(DT1, ft);
- gen_op_float_sub_d();
- GEN_STORE_FTN_FREG(fd, DT2);
- opn = "sub.d";
- binary = 1;
- break;
- case FOP(2, 17):
- CHECK_FR(ctx, fs | ft | fd);
- GEN_LOAD_FREG_FTN(DT0, fs);
- GEN_LOAD_FREG_FTN(DT1, ft);
- gen_op_float_mul_d();
- GEN_STORE_FTN_FREG(fd, DT2);
- opn = "mul.d";
- binary = 1;
- break;
- case FOP(3, 17):
- CHECK_FR(ctx, fs | ft | fd);
- GEN_LOAD_FREG_FTN(DT0, fs);
- GEN_LOAD_FREG_FTN(DT1, ft);
- gen_op_float_div_d();
- GEN_STORE_FTN_FREG(fd, DT2);
- opn = "div.d";
- binary = 1;
- break;
- case FOP(4, 17):
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(DT0, fs);
- gen_op_float_sqrt_d();
- GEN_STORE_FTN_FREG(fd, DT2);
- opn = "sqrt.d";
- break;
- case FOP(5, 17):
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(DT0, fs);
- gen_op_float_abs_d();
- GEN_STORE_FTN_FREG(fd, DT2);
- opn = "abs.d";
- break;
- case FOP(6, 17):
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(DT0, fs);
- gen_op_float_mov_d();
- GEN_STORE_FTN_FREG(fd, DT2);
- opn = "mov.d";
- break;
- case FOP(7, 17):
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(DT0, fs);
- gen_op_float_chs_d();
- GEN_STORE_FTN_FREG(fd, DT2);
- opn = "neg.d";
- break;
- /* 8 - round.l */
- /* 9 - trunc.l */
- /* 10 - ceil.l */
- /* 11 - floor.l */
- case FOP(12, 17):
- CHECK_FR(ctx, fs | fd);
- 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);
- 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);
- 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);
- GEN_LOAD_FREG_FTN(DT0, fs);
- gen_op_float_floorw_d();
- GEN_STORE_FTN_FREG(fd, WT2);
- opn = "ceil.w.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();
- GEN_STORE_FTN_FREG(fd, DT2);
- opn = "cvt.d.w";
- break;
- case FOP(48, 17):
- case FOP(49, 17):
- case FOP(50, 17):
- case FOP(51, 17):
- case FOP(52, 17):
- case FOP(53, 17):
- case FOP(54, 17):
- case FOP(55, 17):
- case FOP(56, 17):
- case FOP(57, 17):
- case FOP(58, 17):
- case FOP(59, 17):
- case FOP(60, 17):
- case FOP(61, 17):
- case FOP(62, 17):
- case FOP(63, 17):
- CHECK_FR(ctx, fs | ft);
- GEN_LOAD_FREG_FTN(DT0, fs);
- GEN_LOAD_FREG_FTN(DT1, ft);
- gen_cmp_d(func-48);
- opn = condnames[func-48];
- break;
- case FOP(0, 16):
- CHECK_FR(ctx, fs | ft | fd);
- 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):
- CHECK_FR(ctx, fs | ft | fd);
- 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):
- CHECK_FR(ctx, fs | ft | fd);
- 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):
- CHECK_FR(ctx, fs | ft | fd);
- 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):
- CHECK_FR(ctx, fs | fd);
- 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):
- CHECK_FR(ctx, fs | fd);
- 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):
- CHECK_FR(ctx, fs | fd);
- 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):
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_chs_s();
- GEN_STORE_FTN_FREG(fd, WT2);
- opn = "neg.s";
- break;
- case FOP(12, 16):
- CHECK_FR(ctx, fs | fd);
- 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):
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_truncw_s();
- GEN_STORE_FTN_FREG(fd, WT2);
- opn = "trunc.w.s";
- break;
- case FOP(32, 20): /* cvt.s.w */
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_cvts_w();
- GEN_STORE_FTN_FREG(fd, WT2);
- opn = "cvt.s.w";
- break;
- case FOP(36, 16): /* cvt.w.s */
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_cvtw_s();
- GEN_STORE_FTN_FREG(fd, WT2);
- opn = "cvt.w.s";
- break;
- case FOP(36, 17): /* cvt.w.d */
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_cvtw_d();
- GEN_STORE_FTN_FREG(fd, WT2);
- opn = "cvt.w.d";
- 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):
- CHECK_FR(ctx, fs | ft);
- GEN_LOAD_FREG_FTN(WT0, fs);
- GEN_LOAD_FREG_FTN(WT1, ft);
- gen_cmp_s(func-48);
- opn = condnames[func-48];
- break;
- default:
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "Invalid arith function: %08x %03x %03x %03x\n",
- ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
- ((ctx->opcode >> 16) & 0x1F));
- }
- generate_exception(ctx, EXCP_RI);
- return;
- }
- if (binary)
- MIPS_DEBUG("%s %s, %s, %s", opn, fregnames[fd], fregnames[fs], fregnames[ft]);
- else
- MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
-}
-#endif
-
-/* ISA extensions */
-/* MIPS16 extension to MIPS32 */
-/* SmartMIPS extension to MIPS32 */
-
-#ifdef TARGET_MIPS64
-static void gen_arith64 (DisasContext *ctx, uint16_t opc)
-{
- if (func == 0x02 && rd == 0) {
- /* NOP */
- return;
- }
- if (rs == 0 || rt == 0) {
- gen_op_reset_T0();
- gen_op_save64();
- } else {
- gen_op_load_gpr_T0(rs);
- gen_op_load_gpr_T1(rt);
- gen_op_save64();
- if (func & 0x01)
- gen_op_mul64u();
- else
- gen_op_mul64s();
- }
- if (func & 0x02)
- gen_op_add64();
- else
- gen_op_sub64();
-}
-
-/* Coprocessor 3 (FPU) */
-
-/* MDMX extension to MIPS64 */
-/* MIPS-3D extension to MIPS64 */
-
-#endif
-
-static void gen_blikely(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;
- uint16_t op, op1;
- int16_t imm;
-
- /* make sure instructions are on a word boundary */
- if (ctx->pc & 0x3) {
- generate_exception(ctx, EXCP_AdEL);
- return;
- }
-
- if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
- /* Handle blikely not taken case */
- MIPS_DEBUG("blikely condition (%08x)", ctx->pc + 4);
- gen_blikely(ctx);
- }
- op = ctx->opcode >> 26;
- rs = ((ctx->opcode >> 21) & 0x1F);
- rt = ((ctx->opcode >> 16) & 0x1F);
- rd = ((ctx->opcode >> 11) & 0x1F);
- sa = ((ctx->opcode >> 6) & 0x1F);
- imm = (int16_t)ctx->opcode;
- switch (op) {
- case 0x00: /* Special opcode */
- op1 = ctx->opcode & 0x3F;
- switch (op1) {
- case 0x00: /* Arithmetic with immediate */
- case 0x02 ... 0x03:
- gen_arith_imm(ctx, op1 | EXT_SPECIAL, rd, rt, sa);
- break;
- case 0x04: /* Arithmetic */
- case 0x06 ... 0x07:
- case 0x0A ... 0x0B:
- case 0x20 ... 0x27:
- case 0x2A ... 0x2B:
- gen_arith(ctx, op1 | EXT_SPECIAL, rd, rs, rt);
- break;
- case 0x18 ... 0x1B: /* MULT / DIV */
- gen_muldiv(ctx, op1 | EXT_SPECIAL, rs, rt);
- break;
- case 0x08 ... 0x09: /* Jumps */
- gen_compute_branch(ctx, op1 | EXT_SPECIAL, rs, rd, sa);
- return;
- case 0x30 ... 0x34: /* Traps */
- case 0x36:
- gen_trap(ctx, op1 | EXT_SPECIAL, rs, rt, -1);
- break;
- case 0x10: /* Move from HI/LO */
- case 0x12:
- gen_HILO(ctx, op1 | EXT_SPECIAL, rd);
- break;
- case 0x11:
- case 0x13: /* Move to HI/LO */
- gen_HILO(ctx, op1 | EXT_SPECIAL, rs);
- break;
- case 0x0C: /* SYSCALL */
- generate_exception(ctx, EXCP_SYSCALL);
- break;
- case 0x0D: /* BREAK */
- generate_exception(ctx, EXCP_BREAK);
- break;
- case 0x0F: /* SYNC */
- /* Treat as a noop */
- break;
- case 0x05: /* Pmon entry point */
- gen_op_pmon((ctx->opcode >> 6) & 0x1F);
- break;
-
- case 0x01: /* MOVCI */
-#if defined (MIPS_HAS_MOVCI)
- /* XXX */
-#else
- /* Not implemented */
- generate_exception_err (ctx, EXCP_CpU, 1);
-#endif
- break;
-
-#if defined (TARGET_MIPS64)
- case 0x14: /* MIPS64 specific opcodes */
- case 0x16:
- case 0x17:
- case 0x1C ... 0x1F:
- case 0x2C ... 0x2F:
- case 0x37:
- case 0x39 ... 0x3B:
- case 0x3E ... 0x3F:
-#endif
- default: /* Invalid */
- MIPS_INVAL("special");
- generate_exception(ctx, EXCP_RI);
- break;
- }
- break;
- case 0x1C: /* Special2 opcode */
- op1 = ctx->opcode & 0x3F;
- switch (op1) {
-#if defined (MIPS_USES_R4K_EXT)
- /* Those instructions are not part of MIPS32 core */
- case 0x00 ... 0x01: /* Multiply and add/sub */
- case 0x04 ... 0x05:
- gen_muldiv(ctx, op1 | EXT_SPECIAL2, rs, rt);
- break;
- case 0x02: /* MUL */
- gen_arith(ctx, op1 | EXT_SPECIAL2, rd, rs, rt);
- break;
- case 0x20 ... 0x21: /* CLO / CLZ */
- gen_cl(ctx, op1 | EXT_SPECIAL2, rd, rs);
- break;
-#endif
- case 0x3F: /* SDBBP */
- /* XXX: not clear which exception should be raised
- * when in debug mode...
- */
- if (!(ctx->hflags & MIPS_HFLAG_DM)) {
- generate_exception(ctx, EXCP_DBp);
- } else {
- generate_exception(ctx, EXCP_DBp);
- }
- /* Treat as a noop */
- break;
- default: /* Invalid */
- MIPS_INVAL("special2");
- generate_exception(ctx, EXCP_RI);
- break;
- }
- break;
- case 0x01: /* B REGIMM opcode */
- op1 = ((ctx->opcode >> 16) & 0x1F);
- switch (op1) {
- case 0x00 ... 0x03: /* REGIMM branches */
- case 0x10 ... 0x13:
- gen_compute_branch(ctx, op1 | EXT_REGIMM, rs, -1, imm << 2);
- return;
- case 0x08 ... 0x0C: /* Traps */
- case 0x0E:
- gen_trap(ctx, op1 | EXT_REGIMM, rs, -1, imm);
- break;
- default: /* Invalid */
- MIPS_INVAL("REGIMM");
- generate_exception(ctx, EXCP_RI);
- break;
- }
- break;
- case 0x10: /* CP0 opcode */
- op1 = ((ctx->opcode >> 21) & 0x1F);
- switch (op1) {
- case 0x00:
- case 0x04:
- gen_cp0(ctx, op1 | EXT_CP0, rt, rd);
- break;
- default:
- gen_cp0(ctx, (ctx->opcode & 0x3F) | EXT_CP0, rt, rd);
- break;
- }
- break;
- case 0x08 ... 0x0F: /* Arithmetic with immediate opcode */
- gen_arith_imm(ctx, op, rt, rs, imm);
- break;
- case 0x02 ... 0x03: /* Jump */
- offset = (int32_t)(ctx->opcode & 0x03FFFFFF) << 2;
- gen_compute_branch(ctx, op, rs, rt, offset);
- return;
- case 0x04 ... 0x07: /* Branch */
- case 0x14 ... 0x17:
- gen_compute_branch(ctx, op, rs, rt, imm << 2);
- return;
- case 0x20 ... 0x2E: /* Load and stores */
- case 0x30:
- case 0x38:
- gen_ldst(ctx, op, rt, rs, imm);
- break;
- case 0x2F: /* Cache operation */
- /* Treat as a noop */
- break;
- case 0x33: /* Prefetch */
- /* Treat as a noop */
- break;
- case 0x3F: /* HACK */
- break;
-
- /* Floating point. */
- case 0x31: /* LWC1 */
- case 0x35: /* LDC1 */
- case 0x39: /* SWC1 */
- case 0x3D: /* SDC1 */
-#if defined(MIPS_USES_FPU)
- gen_op_cp1_enabled();
- gen_flt_ldst(ctx, op, rt, rs, imm);
-#else
- generate_exception_err(ctx, EXCP_CpU, 1);
-#endif
- break;
-
- case 0x11: /* CP1 opcode */
-#if defined(MIPS_USES_FPU)
- gen_op_cp1_enabled();
- op1 = ((ctx->opcode >> 21) & 0x1F);
- switch (op1) {
- case 0x00: /* mfc1 */
- case 0x02: /* cfc1 */
- case 0x04: /* mtc1 */
- case 0x06: /* ctc1 */
- gen_cp1(ctx, op1 | EXT_CP1, rt, rd);
- break;
- case 0x08: /* bc */
- gen_compute_branch1(ctx, rt, imm << 2);
- return;
- case 0x10: /* 16: fmt=single fp */
- case 0x11: /* 17: fmt=double fp */
- case 0x14: /* 20: fmt=32bit fixed */
- case 0x15: /* 21: fmt=64bit fixed */
- gen_farith(ctx, op1, rt, rd, sa, ctx->opcode & 0x3f);
- break;
- default:
- generate_exception_err(ctx, EXCP_RI, 1);
- break;
- }
- break;
-#else
- generate_exception_err(ctx, EXCP_CpU, 1);
-#endif
- break;
-
- /* COP2. */
- case 0x32: /* LWC2 */
- case 0x36: /* LDC2 */
- case 0x3A: /* SWC2 */
- case 0x3E: /* SDC2 */
- case 0x12: /* CP2 opcode */
- /* Not implemented */
- generate_exception_err(ctx, EXCP_CpU, 2);
- break;
-
- case 0x13: /* CP3 opcode */
- /* Not implemented */
- generate_exception_err(ctx, EXCP_CpU, 3);
- break;
-
-#if defined (TARGET_MIPS64)
- case 0x18 ... 0x1B:
- case 0x27:
- case 0x34:
- case 0x37:
- /* MIPS64 opcodes */
-#endif
-#if defined (MIPS_HAS_JALX)
- case 0x1D:
- /* JALX: not implemented */
-#endif
- case 0x1E:
- /* ASE specific */
- default: /* Invalid */
- MIPS_INVAL("");
- generate_exception(ctx, EXCP_RI);
- break;
- }
- if (ctx->hflags & MIPS_HFLAG_BMASK) {
- int hflags = ctx->hflags;
- /* Branches completion */
- ctx->hflags &= ~MIPS_HFLAG_BMASK;
- ctx->bstate = BS_BRANCH;
- save_cpu_state(ctx, 0);
- switch (hflags & MIPS_HFLAG_BMASK) {
- case MIPS_HFLAG_B:
- /* unconditional branch */
- MIPS_DEBUG("unconditional branch");
- gen_goto_tb(ctx, 0, ctx->btarget);
- break;
- case MIPS_HFLAG_BL:
- /* blikely taken case */
- MIPS_DEBUG("blikely branch taken");
- gen_goto_tb(ctx, 0, ctx->btarget);
- break;
- case MIPS_HFLAG_BC:
- /* Conditional branch */
- MIPS_DEBUG("conditional branch");
- {
- int l1;
- l1 = gen_new_label();
- gen_op_jnz_T2(l1);
- gen_goto_tb(ctx, 1, ctx->pc + 4);
- gen_set_label(l1);
- gen_goto_tb(ctx, 0, ctx->btarget);
- }
- break;
- case MIPS_HFLAG_BR:
- /* unconditional branch to register */
- MIPS_DEBUG("branch to register");
- gen_op_breg();
- break;
- default:
- MIPS_DEBUG("unknown branch");
- break;
- }
- }
-}
-
-int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
- int search_pc)
-{
- DisasContext ctx, *ctxp = &ctx;
- target_ulong pc_start;
- uint16_t *gen_opc_end;
- int j, lj = -1;
-
- if (search_pc && loglevel)
- fprintf (logfile, "search pc %d\n", search_pc);
-
- 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.saved_pc = -1;
- ctx.tb = tb;
- ctx.bstate = BS_NONE;
- /* Restore delay slot state from the tb context. */
- ctx.hflags = tb->flags;
- ctx.saved_hflags = ctx.hflags;
- if (ctx.hflags & MIPS_HFLAG_BR) {
- gen_op_restore_breg_target();
- } else if (ctx.hflags & 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
- */
- ctx.btarget = env->btarget;
- gen_op_restore_bcond();
- }
-#if defined(CONFIG_USER_ONLY)
- ctx.mem_idx = 0;
-#else
- ctx.mem_idx = !((ctx.hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
-#endif
- ctx.CP0_Status = env->CP0_Status;
-#ifdef DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_CPU) {
- fprintf(logfile, "------------------------------------------------\n");
- /* FIXME: This may print out stale hflags from env... */
- cpu_dump_state(env, logfile, fprintf, 0);
- }
-#endif
-#if defined MIPS_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM)
- fprintf(logfile, "\ntb %p super %d cond %04x\n",
- tb, ctx.mem_idx, ctx.hflags);
-#endif
- while (ctx.bstate == BS_NONE && gen_opc_ptr < gen_opc_end) {
- if (env->nb_breakpoints > 0) {
- for(j = 0; j < env->nb_breakpoints; j++) {
- if (env->breakpoints[j] == ctx.pc) {
- save_cpu_state(ctxp, 1);
- ctx.bstate = BS_BRANCH;
- gen_op_debug();
- goto done_generating;
- }
- }
- }
-
- 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_hflags[lj] = ctx.hflags & MIPS_HFLAG_BMASK;
- gen_opc_instr_start[lj] = 1;
- }
- ctx.opcode = ldl_code(ctx.pc);
- decode_opc(&ctx);
- ctx.pc += 4;
-
- if (env->singlestep_enabled)
- break;
-
- if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
- break;
-
-#if defined (MIPS_SINGLE_STEP)
- break;
-#endif
- }
- if (env->singlestep_enabled) {
- save_cpu_state(ctxp, ctx.bstate == BS_NONE);
- gen_op_debug();
- goto done_generating;
- }
- 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) {
- 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;
- }
-#ifdef DEBUG_DISAS
-#if defined MIPS_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM)
- fprintf(logfile, "\n");
-#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);
- fprintf(logfile, "\n");
- }
- if (loglevel & CPU_LOG_TB_OP) {
- fprintf(logfile, "OP:\n");
- dump_ops(gen_opc_buf, gen_opparam_buf);
- fprintf(logfile, "\n");
- }
- if (loglevel & CPU_LOG_TB_CPU) {
- fprintf(logfile, "---------------- %d %08x\n", ctx.bstate, ctx.hflags);
- }
-#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);
-}
-
-#ifdef MIPS_USES_FPU
-void fpu_dump_state(CPUState *env, FILE *f,
- int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
- int flags)
-{
- int i;
-
-# 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]); \
- } 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, "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, "f%02d: ", i);
- printfpr(FPR(env, i));
- }
-
-#undef printfpr
-}
-
-void dump_fpu(CPUState *env)
-{
- if (loglevel) {
- fprintf(logfile, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %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 */
-
-void cpu_dump_state (CPUState *env, FILE *f,
- int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
- int flags)
-{
- uint32_t c0_status;
- int i;
-
- cpu_fprintf(f, "pc=0x%08x HI=0x%08x LO=0x%08x ds %04x %08x %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 %08x", 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%08x\n",
- c0_status, env->CP0_Cause, env->CP0_EPC);
- cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x%08x\n",
- env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
-#ifdef MIPS_USES_FPU
- fpu_dump_state(env, f, cpu_fprintf, flags);
-#endif
-}
-
-CPUMIPSState *cpu_mips_init (void)
-{
- CPUMIPSState *env;
-
- env = qemu_mallocz(sizeof(CPUMIPSState));
- if (!env)
- return NULL;
- cpu_exec_init(env);
- tlb_flush(env, 1);
- /* Minimal init */
- env->PC = 0xBFC00000;
-#if defined (MIPS_USES_R4K_TLB)
- env->CP0_random = MIPS_TLB_NB - 1;
-#endif
- env->CP0_Wired = 0;
- env->CP0_Config0 = MIPS_CONFIG0;
-#if defined (MIPS_CONFIG1)
- env->CP0_Config1 = MIPS_CONFIG1;
-#endif
-#if defined (MIPS_CONFIG2)
- env->CP0_Config2 = MIPS_CONFIG2;
-#endif
-#if defined (MIPS_CONFIG3)
- env->CP0_Config3 = MIPS_CONFIG3;
-#endif
- env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
- env->CP0_WatchLo = 0;
- env->hflags = MIPS_HFLAG_ERL;
- /* Count register increments in debug mode, EJTAG version 1 */
- env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
- env->CP0_PRid = MIPS_CPU;
- env->exception_index = EXCP_NONE;
-#if defined(CONFIG_USER_ONLY)
- env->hflags |= MIPS_HFLAG_UM;
-#endif
-#ifdef MIPS_USES_FPU
- env->fcr0 = MIPS_FCR0;
-#endif
- return env;
-}
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
deleted file mode 100644
index 88d9135..0000000
--- a/target-ppc/cpu.h
+++ /dev/null
@@ -1,1025 +0,0 @@
-/*
- * PowerPC emulation cpu definitions for qemu.
- *
- * Copyright (c) 2003-2005 Jocelyn Mayer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#if !defined (__CPU_PPC_H__)
-#define __CPU_PPC_H__
-
-#include "config.h"
-
-#define TARGET_LONG_BITS 32
-
-#include "cpu-defs.h"
-
-#include <setjmp.h>
-
-#include "softfloat.h"
-
-#define TARGET_HAS_ICE 1
-
-/* XXX: this should be tunable: PowerPC 601 & 64 bits PowerPC
- * have different cache line sizes
- */
-#define ICACHE_LINE_SIZE 32
-#define DCACHE_LINE_SIZE 32
-
-/* XXX: put this in a common place */
-#define likely(x) __builtin_expect(!!(x), 1)
-
-/*****************************************************************************/
-/* PVR definitions for most known PowerPC */
-enum {
- /* PowerPC 401 cores */
- CPU_PPC_401A1 = 0x00210000,
- CPU_PPC_401B2 = 0x00220000,
- CPU_PPC_401C2 = 0x00230000,
- CPU_PPC_401D2 = 0x00240000,
- CPU_PPC_401E2 = 0x00250000,
- CPU_PPC_401F2 = 0x00260000,
- CPU_PPC_401G2 = 0x00270000,
- CPU_PPC_IOP480 = 0x40100000,
- /* PowerPC 403 cores */
- CPU_PPC_403GA = 0x00200000,
- CPU_PPC_403GB = 0x00200100,
- CPU_PPC_403GC = 0x00200200,
- CPU_PPC_403GCX = 0x00201400,
- /* PowerPC 405 cores */
- CPU_PPC_405 = 0x40110000,
- CPU_PPC_405EP = 0x51210000,
- CPU_PPC_405GPR = 0x50910000,
- CPU_PPC_405D2 = 0x20010000,
- CPU_PPC_405D4 = 0x41810000,
- CPU_PPC_NPE405H = 0x41410000,
- CPU_PPC_NPE405L = 0x41610000,
-#if 0
- CPU_PPC_STB02 = xxx,
-#endif
- CPU_PPC_STB03 = 0x40310000,
-#if 0
- CPU_PPC_STB04 = xxx,
-#endif
- CPU_PPC_STB25 = 0x51510000,
-#if 0
- CPU_PPC_STB130 = xxx,
-#endif
- /* 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_8xx = 0x00500000,
- CPU_PPC_8240 = 0x00810100,
- CPU_PPC_8245 = 0x00811014,
- /* 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_604 = 0x00040000,
- CPU_PPC_604E = 0x00090000,
- CPU_PPC_604R = 0x000a0000,
- /* PowerPC 74x/75x cores (aka G3) */
- CPU_PPC_74x = 0x00080000,
- CPU_PPC_755 = 0x00083000,
- CPU_PPC_74xP = 0x10080000,
- CPU_PPC_750CXE22 = 0x00082202,
- 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,
- /* PowerPC 74xx cores (aka G4) */
- CPU_PPC_7400 = 0x000C0000,
- CPU_PPC_7410 = 0x800C0000,
- CPU_PPC_7441 = 0x80000200,
- CPU_PPC_7450 = 0x80000000,
- CPU_PPC_7451 = 0x80000203,
- CPU_PPC_7455 = 0x80010000,
- CPU_PPC_7457 = 0x80020000,
- CPU_PPC_7457A = 0x80030000,
- /* 64 bits PowerPC */
- CPU_PPC_620 = 0x00140000,
- CPU_PPC_630 = 0x00400000,
- CPU_PPC_631 = 0x00410000,
- CPU_PPC_POWER4 = 0x00350000,
- CPU_PPC_POWER4P = 0x00380000,
- CPU_PPC_POWER5 = 0x003A0000,
- CPU_PPC_POWER5P = 0x003B0000,
- CPU_PPC_970 = 0x00390000,
- CPU_PPC_970FX = 0x003C0000,
- CPU_PPC_RS64 = 0x00330000,
- CPU_PPC_RS64II = 0x00340000,
- CPU_PPC_RS64III = 0x00360000,
- CPU_PPC_RS64IV = 0x00370000,
- /* Original POWER */
- /* XXX: should be POWER (RIOS), RSC3308, RSC4608,
- * POWER2 (RIOS2) & RSC2 (P2SC) here
- */
-#if 0
- CPU_POWER = xxx,
-#endif
-#if 0
- CPU_POWER2 = xxx,
-#endif
-};
-
-/* System version register (used on MPC 8xx) */
-enum {
- PPC_SVR_8540 = 0x80300000,
- PPC_SVR_8541E = 0x807A0000,
- PPC_SVR_8555E = 0x80790000,
- PPC_SVR_8560 = 0x80700000,
-};
-
-/*****************************************************************************/
-/* Instruction types */
-enum {
- PPC_NONE = 0x00000000,
- /* integer operations instructions */
- /* flow control instructions */
- /* virtual memory instructions */
- /* ld/st with reservation instructions */
- /* cache control instructions */
- /* spr/msr access instructions */
- PPC_INSNS_BASE = 0x00000001,
-#define PPC_INTEGER PPC_INSNS_BASE
-#define PPC_FLOW PPC_INSNS_BASE
-#define PPC_MEM PPC_INSNS_BASE
-#define PPC_RES PPC_INSNS_BASE
-#define PPC_CACHE PPC_INSNS_BASE
-#define PPC_MISC PPC_INSNS_BASE
- /* floating point operations instructions */
- PPC_FLOAT = 0x00000002,
- /* more floating point operations instructions */
- PPC_FLOAT_EXT = 0x00000004,
- /* external control instructions */
- PPC_EXTERN = 0x00000008,
- /* segment register access instructions */
- PPC_SEGMENT = 0x00000010,
- /* Optional cache control instructions */
- PPC_CACHE_OPT = 0x00000020,
- /* Optional floating point op instructions */
- PPC_FLOAT_OPT = 0x00000040,
- /* Optional memory control instructions */
- PPC_MEM_TLBIA = 0x00000080,
- PPC_MEM_TLBIE = 0x00000100,
- PPC_MEM_TLBSYNC = 0x00000200,
- /* eieio & sync */
- PPC_MEM_SYNC = 0x00000400,
- /* PowerPC 6xx TLB management instructions */
- PPC_6xx_TLB = 0x00000800,
- /* Altivec support */
- PPC_ALTIVEC = 0x00001000,
- /* Time base support */
- PPC_TB = 0x00002000,
- /* Embedded PowerPC dedicated instructions */
- PPC_4xx_COMMON = 0x00004000,
- /* PowerPC 40x exception model */
- PPC_40x_EXCP = 0x00008000,
- /* PowerPC 40x specific instructions */
- PPC_40x_SPEC = 0x00010000,
- /* PowerPC 405 Mac instructions */
- PPC_405_MAC = 0x00020000,
- /* PowerPC 440 specific instructions */
- PPC_440_SPEC = 0x00040000,
- /* Specific extensions */
- /* Power-to-PowerPC bridge (601) */
- PPC_POWER_BR = 0x00080000,
- /* PowerPC 602 specific */
- PPC_602_SPEC = 0x00100000,
- /* Deprecated instructions */
- /* Original POWER instruction set */
- PPC_POWER = 0x00200000,
- /* POWER2 instruction set extension */
- PPC_POWER2 = 0x00400000,
- /* Power RTC support */
- PPC_POWER_RTC = 0x00800000,
- /* 64 bits PowerPC instructions */
- /* 64 bits PowerPC instruction set */
- PPC_64B = 0x01000000,
- /* 64 bits hypervisor extensions */
- PPC_64H = 0x02000000,
- /* 64 bits PowerPC "bridge" features */
- PPC_64_BRIDGE = 0x04000000,
-};
-
-/* CPU run-time flags (MMU and exception model) */
-enum {
- /* MMU model */
-#define PPC_FLAGS_MMU_MASK (0x0000000F)
- /* Standard 32 bits PowerPC MMU */
- PPC_FLAGS_MMU_32B = 0x00000000,
- /* Standard 64 bits PowerPC MMU */
- PPC_FLAGS_MMU_64B = 0x00000001,
- /* PowerPC 601 MMU */
- PPC_FLAGS_MMU_601 = 0x00000002,
- /* PowerPC 6xx MMU with software TLB */
- PPC_FLAGS_MMU_SOFT_6xx = 0x00000003,
- /* PowerPC 4xx MMU with software TLB */
- PPC_FLAGS_MMU_SOFT_4xx = 0x00000004,
- /* PowerPC 403 MMU */
- PPC_FLAGS_MMU_403 = 0x00000005,
- /* Exception model */
-#define PPC_FLAGS_EXCP_MASK (0x000000F0)
- /* Standard PowerPC exception model */
- PPC_FLAGS_EXCP_STD = 0x00000000,
- /* PowerPC 40x exception model */
- PPC_FLAGS_EXCP_40x = 0x00000010,
- /* PowerPC 601 exception model */
- PPC_FLAGS_EXCP_601 = 0x00000020,
- /* PowerPC 602 exception model */
- PPC_FLAGS_EXCP_602 = 0x00000030,
- /* PowerPC 603 exception model */
- PPC_FLAGS_EXCP_603 = 0x00000040,
- /* PowerPC 604 exception model */
- PPC_FLAGS_EXCP_604 = 0x00000050,
- /* PowerPC 7x0 exception model */
- PPC_FLAGS_EXCP_7x0 = 0x00000060,
- /* PowerPC 7x5 exception model */
- PPC_FLAGS_EXCP_7x5 = 0x00000070,
- /* PowerPC 74xx exception model */
- PPC_FLAGS_EXCP_74xx = 0x00000080,
- /* PowerPC 970 exception model */
- PPC_FLAGS_EXCP_970 = 0x00000090,
-};
-
-#define PPC_MMU(env) (env->flags & PPC_FLAGS_MMU_MASK)
-#define PPC_EXCP(env) (env->flags & PPC_FLAGS_EXCP_MASK)
-
-/*****************************************************************************/
-/* Supported instruction set definitions */
-/* This generates an empty opcode table... */
-#define PPC_INSNS_TODO (PPC_NONE)
-#define PPC_FLAGS_TODO (0x00000000)
-
-/* PowerPC 40x instruction set */
-#define PPC_INSNS_4xx (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_4xx_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)
-/* 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 | \
- PPC_405_MAC)
-#define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_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)
-/* Non-embedded PowerPC */
-#define PPC_INSNS_COMMON (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC | \
- 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)
-/* 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)
-/* 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)
-/* 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)
-/* 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)
-/* 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)
-/* 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)
-/* 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)
-
-/* 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;
-
-/*****************************************************************************/
-/* Types used to describe some PowerPC registers */
-typedef struct CPUPPCState CPUPPCState;
-typedef struct opc_handler_t opc_handler_t;
-typedef struct ppc_tb_t ppc_tb_t;
-typedef struct ppc_spr_t ppc_spr_t;
-typedef struct ppc_dcr_t ppc_dcr_t;
-typedef struct ppc_avr_t ppc_avr_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);
- void (*oea_read)(void *opaque, int spr_num);
- void (*oea_write)(void *opaque, int spr_num);
- const unsigned char *name;
-};
-
-/* Altivec registers (128 bits) */
-struct ppc_avr_t {
- uint32_t u[4];
-};
-
-/* Software TLB cache */
-typedef struct ppc_tlb_t ppc_tlb_t;
-struct ppc_tlb_t {
- /* Physical page number */
- target_phys_addr_t RPN;
- /* Virtual page number */
- target_ulong VPN;
- /* Page size */
- target_ulong size;
- /* Protection bits */
- int prot;
- int is_user;
- uint32_t private;
- uint32_t flags;
-};
-
-/*****************************************************************************/
-/* Machine state register bits definition */
-#define MSR_SF 63 /* Sixty-four-bit mode */
-#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_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_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_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_DWE 10 /* Debug wait enable on 405 */
-#define MSR_BE 9 /* Branch trace enable */
-#define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC */
-#define MSR_FE1 8 /* Floating point exception mode 1 */
-#define MSR_AL 7 /* AL bit on POWER */
-#define MSR_IP 6 /* Interrupt prefix */
-#define MSR_IR 5 /* Instruction relocate */
-#define MSR_IS 5 /* Instruction address space on embedded PowerPC */
-#define MSR_DR 4 /* Data relocate */
-#define MSR_DS 4 /* Data address space on embedded PowerPC */
-#define MSR_PE 3 /* Protection enable on 403 */
-#define MSR_EP 3 /* Exception prefix on 601 */
-#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_sf env->msr[MSR_SF]
-#define msr_isf env->msr[MSR_ISF]
-#define msr_hv env->msr[MSR_HV]
-#define msr_vr env->msr[MSR_VR]
-#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_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_dwe env->msr[MSR_DWE]
-#define msr_be env->msr[MSR_BE]
-#define msr_de env->msr[MSR_DE]
-#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_is env->msr[MSR_IS]
-#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]
-
-/*****************************************************************************/
-/* The whole PowerPC CPU context */
-struct CPUPPCState {
- /* First are the most commonly used resources
- * during translated code execution
- */
-#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
- /* general purpose registers */
- target_ulong gpr[32];
- /* LR */
- target_ulong lr;
- /* CTR */
- target_ulong ctr;
- /* condition register */
- uint8_t crf[8];
- /* XER */
- /* XXX: We use only 5 fields, but we want to keep the structure aligned */
- uint8_t xer[8];
- /* Reservation address */
- target_ulong reserve;
-
- /* Those ones are used in supervisor mode only */
- /* machine state register */
- uint8_t msr[64];
- /* temporary general purpose registers */
- target_ulong tgpr[4]; /* Used to speed-up TLB assist handlers */
-
- /* Floating point execution context */
- /* temporary float registers */
- float64 ft0;
- float64 ft1;
- float64 ft2;
- float_status fp_status;
- /* floating point registers */
- float64 fpr[32];
- /* floating point status and control register */
- uint8_t fpscr[8];
-
- CPU_COMMON
-
- int halted; /* TRUE if the CPU is in suspend state */
-
- int access_type; /* when a memory exception occurs, the access
- type is stored here */
-
- /* MMU context */
- /* Address space register */
- target_ulong asr;
- /* segment registers */
- target_ulong sdr1;
- target_ulong sr[16];
- /* BATs */
- int nb_BATs;
- target_ulong DBAT[2][8];
- target_ulong IBAT[2][8];
-
- /* Other registers */
- /* Special purpose registers */
- target_ulong spr[1024];
- /* Altivec registers */
- ppc_avr_t avr[32];
- uint32_t vscr;
-
- /* 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);
- /* 403 dedicated access protection registers */
- target_ulong pb[4];
-
- /* Those resources are used during exception processing */
- /* CPU model definition */
- uint64_t msr_mask;
- uint32_t flags;
-
- int exception_index;
- int error_code;
- int interrupt_request;
-
- /* Those resources are used only during code translation */
- /* Next instruction pointer */
- target_ulong nip;
- /* SPR translation callbacks */
- ppc_spr_t spr_cb[1024];
- /* opcode handlers */
- opc_handler_t *opcodes[0x40];
-
- /* Those resources are used only in Qemu core */
- jmp_buf jmp_env;
- int user_mode_only; /* user mode only simulation */
- uint32_t hflags;
-
- /* Power management */
- int power_mode;
-
- /* temporary hack to handle OSI calls (only used if non NULL) */
- int (*osi_call)(struct CPUPPCState *env);
-};
-
-/*****************************************************************************/
-CPUPPCState *cpu_ppc_init(void);
-int cpu_ppc_exec(CPUPPCState *s);
-void cpu_ppc_close(CPUPPCState *s);
-/* you can call this signal handler from your SIGBUS and SIGSEGV
- signal handlers to inform the virtual CPU of exceptions. non zero
- is returned if the signal was handled by the virtual CPU. */
-struct siginfo;
-int cpu_ppc_signal_handler(int host_signum, struct siginfo *info,
- void *puc);
-
-void do_interrupt (CPUPPCState *env);
-void cpu_loop_exit(void);
-
-void dump_stack (CPUPPCState *env);
-
-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);
-void do_store_ibatl (CPUPPCState *env, int nr, target_ulong value);
-target_ulong do_load_dbatu (CPUPPCState *env, int nr);
-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);
-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);
-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 do_compute_hflags (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);
-void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
-int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def);
-
-/* Time-base and decrementer management */
-#ifndef NO_CPU_IO_DEFS
-uint32_t cpu_ppc_load_tbl (CPUPPCState *env);
-uint32_t cpu_ppc_load_tbu (CPUPPCState *env);
-void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value);
-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);
-#endif
-
-#define TARGET_PAGE_BITS 12
-#include "cpu-all.h"
-
-/*****************************************************************************/
-/* Registers definitions */
-#define ugpr(n) (env->gpr[n])
-
-#define XER_SO 31
-#define XER_OV 30
-#define XER_CA 29
-#define XER_CMP 8
-#define XER_BC 0
-#define xer_so env->xer[4]
-#define xer_ov env->xer[6]
-#define xer_ca env->xer[2]
-#define xer_cmp env->xer[1]
-#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 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)
-
-/* Memory access type :
- * may be needed for precise access rights control and precise exceptions.
- */
-enum {
- /* 1 bit to define user level / supervisor access */
- ACCESS_USER = 0x00,
- ACCESS_SUPER = 0x01,
- /* Type of instruction that generated the access */
- ACCESS_CODE = 0x10, /* Code fetch access */
- ACCESS_INT = 0x20, /* Integer load/store access */
- ACCESS_FLOAT = 0x30, /* floating point load/store access */
- ACCESS_RES = 0x40, /* load/store with reservation */
- ACCESS_EXT = 0x50, /* external access */
- ACCESS_CACHE = 0x60, /* Cache manipulation */
-};
-
-/*****************************************************************************/
-/* Exceptions */
-#define EXCP_NONE -1
-/* PowerPC hardware exceptions : exception vectors defined in PowerPC book 3 */
-#define EXCP_RESET 0x0100 /* System reset */
-#define EXCP_MACHINE_CHECK 0x0200 /* Machine check exception */
-#define EXCP_DSI 0x0300 /* Data storage exception */
-#define EXCP_DSEG 0x0380 /* Data segment exception */
-#define EXCP_ISI 0x0400 /* Instruction storage exception */
-#define EXCP_ISEG 0x0480 /* Instruction segment exception */
-#define EXCP_EXTERNAL 0x0500 /* External interruption */
-#define EXCP_ALIGN 0x0600 /* Alignment exception */
-#define EXCP_PROGRAM 0x0700 /* Program exception */
-#define EXCP_NO_FP 0x0800 /* Floating point unavailable exception */
-#define EXCP_DECR 0x0900 /* Decrementer exception */
-#define EXCP_HDECR 0x0980 /* Hypervisor decrementer exception */
-#define EXCP_SYSCALL 0x0C00 /* System call */
-#define EXCP_TRACE 0x0D00 /* Trace exception */
-#define EXCP_PERF 0x0F00 /* Performance monitor exception */
-/* Exceptions defined in PowerPC 32 bits programming environment manual */
-#define EXCP_FP_ASSIST 0x0E00 /* Floating-point assist */
-/* Implementation specific exceptions */
-/* 40x exceptions */
-#define EXCP_40x_PIT 0x1000 /* Programmable interval timer interrupt */
-#define EXCP_40x_FIT 0x1010 /* Fixed interval timer interrupt */
-#define EXCP_40x_WATCHDOG 0x1020 /* Watchdog timer exception */
-#define EXCP_40x_DTLBMISS 0x1100 /* Data TLB miss exception */
-#define EXCP_40x_ITLBMISS 0x1200 /* Instruction TLB miss exception */
-#define EXCP_40x_DEBUG 0x2000 /* Debug exception */
-/* 405 specific exceptions */
-#define EXCP_405_APU 0x0F20 /* APU unavailable exception */
-/* TLB assist exceptions (602/603) */
-#define EXCP_I_TLBMISS 0x1000 /* Instruction TLB miss */
-#define EXCP_DL_TLBMISS 0x1100 /* Data load TLB miss */
-#define EXCP_DS_TLBMISS 0x1200 /* Data store TLB miss */
-/* Breakpoint exceptions (602/603/604/620/740/745/750/755...) */
-#define EXCP_IABR 0x1300 /* Instruction address breakpoint */
-#define EXCP_SMI 0x1400 /* System management interrupt */
-/* Altivec related exceptions */
-#define EXCP_VPU 0x0F20 /* VPU unavailable exception */
-/* 601 specific exceptions */
-#define EXCP_601_IO 0x0600 /* IO error exception */
-#define EXCP_601_RUNM 0x2000 /* Run mode exception */
-/* 602 specific exceptions */
-#define EXCP_602_WATCHDOG 0x1500 /* Watchdog exception */
-#define EXCP_602_EMUL 0x1600 /* Emulation trap exception */
-/* G2 specific exceptions */
-#define EXCP_G2_CRIT 0x0A00 /* Critical interrupt */
-/* MPC740/745/750 & IBM 750 specific exceptions */
-#define EXCP_THRM 0x1700 /* Thermal management interrupt */
-/* 74xx specific exceptions */
-#define EXCP_74xx_VPUA 0x1600 /* VPU assist exception */
-/* 970FX specific exceptions */
-#define EXCP_970_SOFTP 0x1500 /* Soft patch exception */
-#define EXCP_970_MAINT 0x1600 /* Maintenance exception */
-#define EXCP_970_THRM 0x1800 /* Thermal exception */
-#define EXCP_970_VPUA 0x1700 /* VPU assist 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 */
-#define EXCP_BRANCH 0x11001 /* branch instruction */
-#define EXCP_SYSCALL_USER 0x12000 /* System call in user mode only */
-#define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ */
-
-/* Error codes */
-enum {
- /* Exception subtypes for EXCP_ALIGN */
- EXCP_ALIGN_FP = 0x01, /* FP alignment exception */
- EXCP_ALIGN_LST = 0x02, /* Unaligned mult/extern load/store */
- EXCP_ALIGN_LE = 0x03, /* Multiple little-endian access */
- EXCP_ALIGN_PROT = 0x04, /* Access cross protection boundary */
- EXCP_ALIGN_BAT = 0x05, /* Access cross a BAT/seg boundary */
- EXCP_ALIGN_CACHE = 0x06, /* Impossible dcbz access */
- /* Exception subtypes for EXCP_PROGRAM */
- /* FP exceptions */
- EXCP_FP = 0x10,
- EXCP_FP_OX = 0x01, /* FP overflow */
- EXCP_FP_UX = 0x02, /* FP underflow */
- EXCP_FP_ZX = 0x03, /* FP divide by zero */
- EXCP_FP_XX = 0x04, /* FP inexact */
- EXCP_FP_VXNAN = 0x05, /* FP invalid SNaN op */
- EXCP_FP_VXISI = 0x06, /* FP invalid infinite substraction */
- EXCP_FP_VXIDI = 0x07, /* FP invalid infinite divide */
- EXCP_FP_VXZDZ = 0x08, /* FP invalid zero divide */
- EXCP_FP_VXIMZ = 0x09, /* FP invalid infinite * zero */
- EXCP_FP_VXVC = 0x0A, /* FP invalid compare */
- EXCP_FP_VXSOFT = 0x0B, /* FP invalid operation */
- EXCP_FP_VXSQRT = 0x0C, /* FP invalid square root */
- EXCP_FP_VXCVI = 0x0D, /* FP invalid integer conversion */
- /* Invalid instruction */
- EXCP_INVAL = 0x20,
- EXCP_INVAL_INVAL = 0x01, /* Invalid instruction */
- EXCP_INVAL_LSWX = 0x02, /* Invalid lswx instruction */
- EXCP_INVAL_SPR = 0x03, /* Invalid SPR access */
- EXCP_INVAL_FP = 0x04, /* Unimplemented mandatory fp instr */
- /* Privileged instruction */
- EXCP_PRIV = 0x30,
- EXCP_PRIV_OPC = 0x01,
- EXCP_PRIV_REG = 0x02,
- /* Trap */
- EXCP_TRAP = 0x40,
-};
-
-/*****************************************************************************/
-
-#endif /* !defined (__CPU_PPC_H__) */
diff --git a/target-ppc/exec.h b/target-ppc/exec.h
deleted file mode 100644
index 3ef0968..0000000
--- a/target-ppc/exec.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * PowerPC emulation definitions for qemu.
- *
- * Copyright (c) 2003-2005 Jocelyn Mayer
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#if !defined (__PPC_H__)
-#define __PPC_H__
-
-#include "config.h"
-
-#include "dyngen-exec.h"
-
-#define TARGET_LONG_BITS 32
-
-register struct CPUPPCState *env asm(AREG0);
-register uint32_t T0 asm(AREG1);
-register uint32_t T1 asm(AREG2);
-register uint32_t T2 asm(AREG3);
-
-#define PARAM(n) ((uint32_t)PARAM##n)
-#define SPARAM(n) ((int32_t)PARAM##n)
-#define FT0 (env->ft0)
-#define FT1 (env->ft1)
-#define FT2 (env->ft2)
-
-#if defined (DEBUG_OP)
-#define RETURN() __asm__ __volatile__("nop");
-#else
-#define RETURN() __asm__ __volatile__("");
-#endif
-
-#include "cpu.h"
-#include "exec-all.h"
-
-static inline uint32_t rotl (uint32_t i, int n)
-{
- return ((i << n) | (i >> (32 - n)));
-}
-
-#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif /* !defined(CONFIG_USER_ONLY) */
-
-void do_raise_exception_err (uint32_t exception, int error_code);
-void do_raise_exception (uint32_t exception);
-
-void do_sraw(void);
-
-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 do_check_reservation (void);
-void do_icbi (void);
-void do_tlbia (void);
-void do_tlbie (void);
-
-static inline void env_to_regs(void)
-{
-}
-
-static inline void regs_to_env(void)
-{
-}
-
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
- int is_user, int is_softmmu);
-
-#endif /* !defined (__PPC_H__) */
diff --git a/target-ppc/helper.c b/target-ppc/helper.c
deleted file mode 100644
index 3f7a708..0000000
--- a/target-ppc/helper.c
+++ /dev/null
@@ -1,1458 +0,0 @@
-/*
- * PowerPC emulation helpers for qemu.
- *
- * Copyright (c) 2003-2005 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 <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <assert.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-
-//#define DEBUG_MMU
-//#define DEBUG_BATS
-//#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,
- int is_user, int is_softmmu)
-{
- int exception, error_code;
-
- if (rw == 2) {
- exception = EXCP_ISI;
- error_code = 0;
- } else {
- exception = EXCP_DSI;
- error_code = 0;
- if (rw)
- error_code |= 0x02000000;
- env->spr[SPR_DAR] = address;
- env->spr[SPR_DSISR] = error_code;
- }
- env->exception_index = exception;
- env->error_code = error_code;
- return 1;
-}
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
- return addr;
-}
-#else
-/* Perform BAT hit & translation */
-static int get_bat (CPUState *env, uint32_t *real, int *prot,
- uint32_t virtual, int rw, int type)
-{
- uint32_t *BATlt, *BATut, *BATu, *BATl;
- uint32_t 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);
- }
-#endif
- switch (type) {
- case ACCESS_CODE:
- BATlt = env->IBAT[1];
- BATut = env->IBAT[0];
- break;
- default:
- BATlt = env->DBAT[1];
- BATut = env->DBAT[0];
- break;
- }
-#if defined (DEBUG_BATS)
- if (loglevel > 0) {
- fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', virtual);
- }
-#endif
- base = virtual & 0xFFFC0000;
- for (i = 0; i < 4; i++) {
- BATu = &BATut[i];
- BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- 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",
- __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
- *BATu, *BATl);
- }
-#endif
- if ((virtual & 0xF0000000) == BEPIu &&
- ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
- /* BAT matches */
- if ((msr_pr == 0 && (*BATu & 0x00000002)) ||
- (msr_pr == 1 && (*BATu & 0x00000001))) {
- /* Get physical address */
- *real = (*BATl & 0xF0000000) |
- ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
- (virtual & 0x0001F000);
- if (*BATl & 0x00000001)
- *prot = PAGE_READ;
- if (*BATl & 0x00000002)
- *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' : '-');
- }
-#endif
- ret = 0;
- break;
- }
- }
- }
- 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);
- }
-#endif
- }
- /* No hit */
- return ret;
-}
-
-/* PTE table lookup */
-static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va,
- int h, int key, int rw)
-{
- uint32_t pte0, pte1, keep = 0, access = 0;
- int i, good = -1, store = 0;
- int ret = -1; /* No entry found */
-
- 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);
- }
-#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;
- }
- }
- }
- }
- if (good != -1) {
- *RPN = keep & 0xFFFFF000;
-#if defined (DEBUG_MMU)
- if (loglevel > 0) {
- fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n",
- *RPN, *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);
- }
- }
-
- return ret;
-}
-
-static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_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)
-{
- uint32_t pg_addr, sdr, ptem, vsid, pgidx;
- uint32_t hash, mask;
- uint32_t sr;
- int key;
- int ret = -1, ret2;
-
- sr = env->sr[virtual >> 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);
- }
-#endif
- 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);
-#endif
- /* Check if instruction fetch is allowed, if needed */
- if (type != ACCESS_CODE || (sr & 0x10000000) == 0) {
- /* Page address translation */
- vsid = sr & 0x00FFFFFF;
- pgidx = (virtual >> 12) & 0xFFFF;
- 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);
-#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);
- }
-#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);
-#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);
- }
-#endif
- ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw);
- if (ret2 != -1)
- ret = ret2;
- }
- } else {
-#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "No access allowed\n");
-#endif
- ret = -3;
- }
- } else {
-#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "direct store...\n");
-#endif
- /* Direct-store segment : absolutely *BUGGY* for now */
- switch (type) {
- case ACCESS_INT:
- /* Integer load/store : only access allowed */
- break;
- case ACCESS_CODE:
- /* No code fetch is allowed in direct-store areas */
- return -4;
- case ACCESS_FLOAT:
- /* Floating point load/store */
- return -4;
- case ACCESS_RES:
- /* lwarx, ldarx or srwcx. */
- return -4;
- case ACCESS_CACHE:
- /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
- /* Should make the instruction do no-op.
- * As it already do no-op, it's quite easy :-)
- */
- *real = virtual;
- return 0;
- case ACCESS_EXT:
- /* eciwx or ecowx */
- return -4;
- default:
- if (logfile) {
- 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;
- ret = 2;
- } else {
- ret = -2;
- }
- }
-
- return ret;
-}
-
-static int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
- uint32_t address, int rw, int access_type)
-{
- int ret;
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s\n", __func__);
- }
-#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;
- } 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);
- }
- }
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s address %08x => %08x\n",
- __func__, address, *physical);
- }
-#endif
- return ret;
-}
-
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
- uint32_t phys_addr;
- int prot;
-
- if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
- return -1;
- return phys_addr;
-}
-
-/* Perform address translation */
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
- int is_user, int is_softmmu)
-{
- uint32_t physical;
- int prot;
- int exception = 0, error_code = 0;
- int access_type;
- int ret = 0;
-
- if (rw == 2) {
- /* code access */
- rw = 0;
- access_type = ACCESS_CODE;
- } else {
- /* data access */
- /* XXX: put correct access by using cpu_restore_state()
- correctly */
- 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);
- if (ret == 0) {
- ret = tlb_set_page(env, address & ~0xFFF, physical, 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);
-#endif
- if (access_type == ACCESS_CODE) {
- exception = EXCP_ISI;
- switch (ret) {
- case -1:
- /* No matches in page tables */
- error_code = 0x40000000;
- break;
- case -2:
- /* Access rights violation */
- error_code = 0x08000000;
- break;
- case -3:
- /* No execute protection violation */
- error_code = 0x10000000;
- break;
- case -4:
- /* Direct store exception */
- /* No code fetch is allowed in direct-store areas */
- error_code = 0x10000000;
- break;
- case -5:
- /* No match in segment table */
- exception = EXCP_ISEG;
- error_code = 0;
- break;
- }
- } else {
- exception = EXCP_DSI;
- switch (ret) {
- case -1:
- /* No matches in page tables */
- error_code = 0x40000000;
- break;
- case -2:
- /* Access rights violation */
- error_code = 0x08000000;
- break;
- case -4:
- /* Direct store exception */
- switch (access_type) {
- case ACCESS_FLOAT:
- /* Floating point load/store */
- exception = EXCP_ALIGN;
- error_code = EXCP_ALIGN_FP;
- break;
- case ACCESS_RES:
- /* lwarx, ldarx or srwcx. */
- error_code = 0x04000000;
- break;
- case ACCESS_EXT:
- /* eciwx or ecowx */
- error_code = 0x04100000;
- break;
- default:
- printf("DSI: invalid exception (%d)\n", ret);
- exception = EXCP_PROGRAM;
- error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
- break;
- }
- break;
- case -5:
- /* No match in segment table */
- exception = EXCP_DSEG;
- error_code = 0;
- break;
- }
- if (exception == EXCP_DSI && rw == 1)
- error_code |= 0x02000000;
- /* Store fault address */
- env->spr[SPR_DAR] = address;
- env->spr[SPR_DSISR] = error_code;
- }
-#if 0
- printf("%s: set exception to %d %02x\n",
- __func__, exception, error_code);
-#endif
- env->exception_index = exception;
- env->error_code = error_code;
- ret = 1;
- }
- return ret;
-}
-#endif
-
-/*****************************************************************************/
-/* BATs management */
-#if !defined(FLUSH_ALL_TLBS)
-static inline void do_invalidate_BAT (CPUPPCState *env,
- 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);
-#endif
- for (page = base; page != end; page += TARGET_PAGE_SIZE)
- tlb_flush_page(env, page);
-#if defined (DEBUG_BATS)
- if (loglevel != 0)
- fprintf(logfile, "Flush done\n");
-#endif
-}
-#endif
-
-static inline void dump_store_bat (CPUPPCState *env, char ID, int ul, int nr,
- target_ulong value)
-{
-#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);
- }
-#endif
-}
-
-target_ulong do_load_ibatu (CPUPPCState *env, int nr)
-{
- return env->IBAT[0][nr];
-}
-
-target_ulong do_load_ibatl (CPUPPCState *env, int nr)
-{
- return env->IBAT[1][nr];
-}
-
-void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
-{
- target_ulong mask;
-
- dump_store_bat(env, 'I', 0, nr, value);
- if (env->IBAT[0][nr] != value) {
- mask = (value << 15) & 0x0FFE0000UL;
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#endif
- /* When storing valid upper BAT, mask BEPI and BRPN
- * and invalidate all TLBs covered by this BAT
- */
- mask = (value << 15) & 0x0FFE0000UL;
- env->IBAT[0][nr] = (value & 0x00001FFFUL) |
- (value & ~0x0001FFFFUL & ~mask);
- env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
- (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)
- tlb_flush(env, 1);
-#endif
- }
-}
-
-void do_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
-{
- dump_store_bat(env, 'I', 1, nr, value);
- env->IBAT[1][nr] = value;
-}
-
-target_ulong do_load_dbatu (CPUPPCState *env, int nr)
-{
- return env->DBAT[0][nr];
-}
-
-target_ulong do_load_dbatl (CPUPPCState *env, int nr)
-{
- return env->DBAT[1][nr];
-}
-
-void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
-{
- target_ulong mask;
-
- dump_store_bat(env, 'D', 0, nr, value);
- if (env->DBAT[0][nr] != value) {
- /* When storing valid upper BAT, mask BEPI and BRPN
- * and invalidate all TLBs covered by this BAT
- */
- mask = (value << 15) & 0x0FFE0000UL;
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->DBAT[0][nr], mask);
-#endif
- mask = (value << 15) & 0x0FFE0000UL;
- env->DBAT[0][nr] = (value & 0x00001FFFUL) |
- (value & ~0x0001FFFFUL & ~mask);
- env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
- (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->DBAT[0][nr], mask);
-#else
- tlb_flush(env, 1);
-#endif
- }
-}
-
-void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
-{
- dump_store_bat(env, 'D', 1, nr, value);
- env->DBAT[1][nr] = value;
-}
-
-static inline void invalidate_all_tlbs (CPUPPCState *env)
-{
- /* XXX: this needs to be completed for sotware driven TLB support */
- tlb_flush(env, 1);
-}
-
-/*****************************************************************************/
-/* Special registers manipulation */
-target_ulong do_load_nip (CPUPPCState *env)
-{
- return env->nip;
-}
-
-void do_store_nip (CPUPPCState *env, target_ulong value)
-{
- env->nip = value;
-}
-
-target_ulong do_load_sdr1 (CPUPPCState *env)
-{
- return env->sdr1;
-}
-
-void do_store_sdr1 (CPUPPCState *env, target_ulong value)
-{
-#if defined (DEBUG_MMU)
- if (loglevel != 0) {
- fprintf(logfile, "%s: 0x%08lx\n", __func__, (unsigned long)value);
- }
-#endif
- if (env->sdr1 != value) {
- env->sdr1 = value;
- invalidate_all_tlbs(env);
- }
-}
-
-target_ulong do_load_sr (CPUPPCState *env, int srnum)
-{
- return env->sr[srnum];
-}
-
-void do_store_sr (CPUPPCState *env, int srnum, target_ulong value)
-{
-#if defined (DEBUG_MMU)
- if (loglevel != 0) {
- fprintf(logfile, "%s: reg=%d 0x%08lx %08lx\n",
- __func__, srnum, (unsigned long)value, env->sr[srnum]);
- }
-#endif
- if (env->sr[srnum] != value) {
- env->sr[srnum] = value;
-#if !defined(FLUSH_ALL_TLBS) && 0
- {
- target_ulong page, end;
- /* Invalidate 256 MB of virtual memory */
- page = (16 << 20) * srnum;
- end = page + (16 << 20);
- for (; page != end; page += TARGET_PAGE_SIZE)
- tlb_flush_page(env, page);
- }
-#else
- invalidate_all_tlbs(env);
-#endif
- }
-}
-
-uint32_t do_load_cr (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) |
- (xer_bc << XER_BC) |
- (xer_cmp << XER_CMP);
-}
-
-void do_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;
-}
-
-target_ulong do_load_msr (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);
-}
-
-void do_compute_hflags (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);
-}
-
-void do_store_msr (CPUPPCState *env, target_ulong value)
-{
- int enter_pm;
-
- 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
- */
- tlb_flush(env, 1);
- env->interrupt_request |= CPU_INTERRUPT_EXITTB;
- }
-#if 0
- if (loglevel != 0) {
- 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;
- do_compute_hflags(env);
-
- enter_pm = 0;
- switch (PPC_EXCP(env)) {
- case PPC_FLAGS_EXCP_7x0:
- if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0)
- enter_pm = 1;
- break;
- default:
- break;
- }
- if (enter_pm) {
- /* power save: exit cpu loop */
- env->halted = 1;
- env->exception_index = EXCP_HLT;
- cpu_loop_exit();
- }
-}
-
-float64 do_load_fpscr (CPUPPCState *env)
-{
- /* 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
-#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)
-{
- /*
- * 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);
-}
-
-/*****************************************************************************/
-/* Exception processing */
-#if defined (CONFIG_USER_ONLY)
-void do_interrupt (CPUState *env)
-{
- env->exception_index = -1;
-}
-#else
-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",
- 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;
-
- 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];
-#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);
- }
- }
-#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);
- }
- msr_pow = 0;
- /* Generate informations in save/restore registers */
- switch (excp) {
- /* Generic PowerPC exceptions */
- case EXCP_RESET: /* 0x0100 */
- if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) {
- if (msr_ip)
- excp += 0xFFC00;
- excp |= 0xFFC00000;
- } else {
- srr_0 = &env->spr[SPR_40x_SRR2];
- srr_1 = &env->spr[SPR_40x_SRR3];
- }
- 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) {
- srr_0 = &env->spr[SPR_40x_SRR2];
- srr_1 = &env->spr[SPR_40x_SRR3];
- }
- msr_me = 0;
- break;
- case EXCP_DSI: /* 0x0300 */
- /* Store exception cause */
- /* data location address has been stored
- * when the fault has been detected
- */
- 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]);
- }
-#endif
- goto store_next;
- case EXCP_ISI: /* 0x0400 */
- /* Store exception cause */
- 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);
- }
-#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;
- }
- goto store_next;
- case EXCP_ALIGN: /* 0x0600 */
- if (PPC_EXCP(env) != PPC_FLAGS_EXCP_601) {
- /* Store exception cause */
- /* Get rS/rD and rA from faulting opcode */
- env->spr[SPR_DSISR] |=
- (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
- /* data location address has been stored
- * when the fault has been detected
- */
- } else {
- /* IO error exception on PowerPC 601 */
- /* XXX: TODO */
- cpu_abort(env,
- "601 IO error exception is not implemented yet !\n");
- }
- goto store_current;
- case EXCP_PROGRAM: /* 0x0700 */
- 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");
-#endif
- return;
- }
- msr |= 0x00100000;
- /* 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;
- break;
- case EXCP_INVAL:
- // printf("Invalid instruction at 0x%08x\n", env->nip);
- msr |= 0x00080000;
- break;
- case EXCP_PRIV:
- msr |= 0x00040000;
- break;
- case EXCP_TRAP:
- msr |= 0x00020000;
- break;
- default:
- /* Should never occur */
- break;
- }
- msr |= 0x00010000;
- goto store_current;
- case EXCP_NO_FP: /* 0x0800 */
- 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 */
- /* NOTE: this is a temporary hack to support graphics OSI
- calls from the MOL driver */
- if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
- env->osi_call) {
- if (env->osi_call(env) != 0)
- return;
- }
- if (loglevel & CPU_LOG_INT) {
- dump_syscall(env);
- }
- goto store_next;
- case EXCP_TRACE: /* 0x0D00 */
- /* XXX: TODO */
- cpu_abort(env, "Trace exception is not implemented yet !\n");
- goto store_next;
- case EXCP_PERF: /* 0x0F00 */
- /* XXX: TODO */
- cpu_abort(env,
- "Performance counter exception is not implemented yet !\n");
- goto store_next;
- /* 32 bits PowerPC specific exceptions */
- case EXCP_FP_ASSIST: /* 0x0E00 */
- /* XXX: TODO */
- cpu_abort(env, "Floating point assist exception "
- "is not implemented yet !\n");
- goto store_next;
- /* 64 bits PowerPC exceptions */
- case EXCP_DSEG: /* 0x0380 */
- /* XXX: TODO */
- cpu_abort(env, "Data segment exception is not implemented yet !\n");
- goto store_next;
- case EXCP_ISEG: /* 0x0480 */
- /* XXX: TODO */
- cpu_abort(env,
- "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");
- goto store_next;
- /* Implementation specific exceptions */
- case 0x0A00:
- if (PPC_EXCP(env) != PPC_FLAGS_EXCP_602) {
- /* Critical interrupt on G2 */
- /* XXX: TODO */
- cpu_abort(env, "G2 critical interrupt is not implemented yet !\n");
- goto store_next;
- } else {
- cpu_abort(env, "Invalid exception 0x0A00 !\n");
- }
- return;
- case 0x0F20:
- switch (PPC_EXCP(env)) {
- case PPC_FLAGS_EXCP_40x:
- /* APU unavailable on 405 */
- /* XXX: TODO */
- cpu_abort(env,
- "APU unavailable exception is not implemented yet !\n");
- goto store_next;
- case PPC_FLAGS_EXCP_74xx:
- /* Altivec unavailable */
- /* XXX: TODO */
- cpu_abort(env, "Altivec unavailable exception "
- "is not implemented yet !\n");
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x0F20 !\n");
- break;
- }
- return;
- case 0x1000:
- 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");
- 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;
- default:
- cpu_abort(env, "Invalid exception 0x1000 !\n");
- break;
- }
- return;
- case 0x1010:
- 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 */
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x1010 !\n");
- break;
- }
- return;
- case 0x1020:
- 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");
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x1020 !\n");
- break;
- }
- return;
- case 0x1100:
- 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");
- 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;
- default:
- cpu_abort(env, "Invalid exception 0x1100 !\n");
- break;
- }
- return;
- case 0x1200:
- 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");
- goto store_next;
- case PPC_FLAGS_EXCP_602:
- case PPC_FLAGS_EXCP_603:
- /* DSTLBMISS on 602/603 */
- msr &= ~0xF00F0000;
- 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],
- 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;
- 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;
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x1200 !\n");
- break;
- }
- return;
- case 0x1300:
- switch (PPC_EXCP(env)) {
- case PPC_FLAGS_EXCP_601:
- case PPC_FLAGS_EXCP_602:
- case PPC_FLAGS_EXCP_603:
- case PPC_FLAGS_EXCP_604:
- case PPC_FLAGS_EXCP_7x0:
- case PPC_FLAGS_EXCP_7x5:
- /* IABR on 6xx/7xx */
- /* XXX: TODO */
- cpu_abort(env, "IABR exception is not implemented yet !\n");
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x1300 !\n");
- break;
- }
- return;
- case 0x1400:
- switch (PPC_EXCP(env)) {
- case PPC_FLAGS_EXCP_601:
- case PPC_FLAGS_EXCP_602:
- case PPC_FLAGS_EXCP_603:
- case PPC_FLAGS_EXCP_604:
- case PPC_FLAGS_EXCP_7x0:
- case PPC_FLAGS_EXCP_7x5:
- /* SMI on 6xx/7xx */
- /* XXX: TODO */
- cpu_abort(env, "SMI exception is not implemented yet !\n");
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x1400 !\n");
- break;
- }
- return;
- case 0x1500:
- switch (PPC_EXCP(env)) {
- case PPC_FLAGS_EXCP_602:
- /* Watchdog on 602 */
- cpu_abort(env,
- "602 watchdog exception is not implemented yet !\n");
- goto store_next;
- case PPC_FLAGS_EXCP_970:
- /* Soft patch exception on 970 */
- /* XXX: TODO */
- cpu_abort(env,
- "970 soft-patch exception is not implemented yet !\n");
- goto store_next;
- case PPC_FLAGS_EXCP_74xx:
- /* VPU assist on 74xx */
- /* XXX: TODO */
- cpu_abort(env, "VPU assist exception is not implemented yet !\n");
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x1500 !\n");
- break;
- }
- return;
- case 0x1600:
- switch (PPC_EXCP(env)) {
- case PPC_FLAGS_EXCP_602:
- /* Emulation trap on 602 */
- /* XXX: TODO */
- cpu_abort(env, "602 emulation trap exception "
- "is not implemented yet !\n");
- goto store_next;
- case PPC_FLAGS_EXCP_970:
- /* Maintenance exception on 970 */
- /* XXX: TODO */
- cpu_abort(env,
- "970 maintenance exception is not implemented yet !\n");
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x1600 !\n");
- break;
- }
- return;
- case 0x1700:
- switch (PPC_EXCP(env)) {
- case PPC_FLAGS_EXCP_7x0:
- case PPC_FLAGS_EXCP_7x5:
- /* Thermal management interrupt on G3 */
- /* XXX: TODO */
- cpu_abort(env, "G3 thermal management exception "
- "is not implemented yet !\n");
- goto store_next;
- case PPC_FLAGS_EXCP_970:
- /* VPU assist on 970 */
- /* XXX: TODO */
- cpu_abort(env,
- "970 VPU assist exception is not implemented yet !\n");
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x1700 !\n");
- break;
- }
- return;
- case 0x1800:
- switch (PPC_EXCP(env)) {
- case PPC_FLAGS_EXCP_970:
- /* Thermal exception on 970 */
- /* XXX: TODO */
- cpu_abort(env, "970 thermal management exception "
- "is not implemented yet !\n");
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x1800 !\n");
- break;
- }
- return;
- case 0x2000:
- switch (PPC_EXCP(env)) {
- case PPC_FLAGS_EXCP_40x:
- /* DEBUG on 4xx */
- /* XXX: TODO */
- cpu_abort(env, "40x debug exception is not implemented yet !\n");
- goto store_next;
- case PPC_FLAGS_EXCP_601:
- /* Run mode exception on 601 */
- /* XXX: TODO */
- cpu_abort(env,
- "601 run mode exception is not implemented yet !\n");
- goto store_next;
- default:
- cpu_abort(env, "Invalid exception 0x1800 !\n");
- break;
- }
- return;
- /* Other exceptions */
- /* Qemu internal exceptions:
- * we should never come here with those values: abort execution
- */
- default:
- cpu_abort(env, "Invalid exception: code %d (%04x)\n", excp, excp);
- return;
- store_current:
- /* save current instruction location */
- *srr_0 = (env->nip - 4) & 0xFFFFFFFFULL;
- break;
- store_next:
- /* save next instruction location */
- *srr_0 = env->nip & 0xFFFFFFFFULL;
- break;
- }
- /* Save msr */
- *srr_1 = msr;
- /* If we disactivated any translation, flush TLBs */
- if (msr_ir || msr_dr) {
- tlb_flush(env, 1);
- }
- /* reload MSR with correct bits */
- msr_ee = 0;
- msr_pr = 0;
- msr_fp = 0;
- msr_fe0 = 0;
- msr_se = 0;
- msr_be = 0;
- msr_fe1 = 0;
- msr_ir = 0;
- msr_dr = 0;
- msr_ri = 0;
- msr_le = msr_ile;
- msr_sf = msr_isf;
- do_compute_hflags(env);
- /* Jump to handler */
- env->nip = excp;
- env->exception_index = EXCP_NONE;
-}
-#endif /* !CONFIG_USER_ONLY */
diff --git a/target-ppc/op.c b/target-ppc/op.c
deleted file mode 100644
index ca1dbc5..0000000
--- a/target-ppc/op.c
+++ /dev/null
@@ -1,1296 +0,0 @@
-/*
- * PowerPC emulation micro-operations for qemu.
- *
- * Copyright (c) 2003-2005 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"
-
-#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)
-
-#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"
-
-/* 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)
-{
- env->crf[0] = 0x02 | xer_ov;
- RETURN();
-}
-
-/* set_Rc0_1 */
-PPC_OP(set_Rc0_1)
-{
- env->crf[0] = 0x04 | xer_ov;
- RETURN();
-}
-
-/* Set Rc1 (for floating point arithmetic) */
-PPC_OP(set_Rc1)
-{
- env->crf[1] = regs->fpscr[7];
- RETURN();
-}
-
-/* Constants load */
-PPC_OP(set_T0)
-{
- T0 = PARAM(1);
- RETURN();
-}
-
-PPC_OP(set_T1)
-{
- T1 = PARAM(1);
- RETURN();
-}
-
-PPC_OP(set_T2)
-{
- T2 = PARAM(1);
- RETURN();
-}
-
-/* Generate exceptions */
-PPC_OP(raise_exception_err)
-{
- do_raise_exception_err(PARAM(1), PARAM(2));
-}
-
-PPC_OP(raise_exception)
-{
- do_raise_exception(PARAM(1));
-}
-
-PPC_OP(update_nip)
-{
- env->nip = PARAM(1);
-}
-
-PPC_OP(debug)
-{
- do_raise_exception(EXCP_DEBUG);
-}
-
-/* Segment registers load and store with immediate index */
-PPC_OP(load_srin)
-{
- T0 = regs->sr[T1 >> 28];
- RETURN();
-}
-
-PPC_OP(store_srin)
-{
- do_store_sr(env, ((uint32_t)T1 >> 28), T0);
- RETURN();
-}
-
-PPC_OP(load_sdr1)
-{
- T0 = regs->sdr1;
- RETURN();
-}
-
-PPC_OP(store_sdr1)
-{
- do_store_sdr1(env, T0);
- RETURN();
-}
-
-PPC_OP(exit_tb)
-{
- EXIT_TB();
-}
-
-/* Load/store special registers */
-PPC_OP(load_cr)
-{
- T0 = do_load_cr(env);
- RETURN();
-}
-
-PPC_OP(store_cr)
-{
- do_store_cr(env, T0, PARAM(1));
- RETURN();
-}
-
-PPC_OP(load_xer_cr)
-{
- T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1);
- RETURN();
-}
-
-PPC_OP(clear_xer_cr)
-{
- xer_so = 0;
- xer_ov = 0;
- xer_ca = 0;
- RETURN();
-}
-
-PPC_OP(load_xer_bc)
-{
- T1 = xer_bc;
- RETURN();
-}
-
-PPC_OP(load_xer)
-{
- T0 = do_load_xer(env);
- RETURN();
-}
-
-PPC_OP(store_xer)
-{
- do_store_xer(env, T0);
- RETURN();
-}
-
-PPC_OP(load_msr)
-{
- T0 = do_load_msr(env);
- RETURN();
-}
-
-PPC_OP(store_msr)
-{
- do_store_msr(env, T0);
- RETURN();
-}
-
-/* SPR */
-PPC_OP(load_spr)
-{
- T0 = regs->spr[PARAM(1)];
- RETURN();
-}
-
-PPC_OP(store_spr)
-{
- regs->spr[PARAM(1)] = T0;
- RETURN();
-}
-
-PPC_OP(load_lr)
-{
- T0 = regs->lr;
- RETURN();
-}
-
-PPC_OP(store_lr)
-{
- regs->lr = T0;
- RETURN();
-}
-
-PPC_OP(load_ctr)
-{
- T0 = regs->ctr;
- RETURN();
-}
-
-PPC_OP(store_ctr)
-{
- regs->ctr = T0;
- RETURN();
-}
-
-PPC_OP(load_tbl)
-{
- T0 = cpu_ppc_load_tbl(regs);
- RETURN();
-}
-
-PPC_OP(load_tbu)
-{
- T0 = cpu_ppc_load_tbu(regs);
- RETURN();
-}
-
-PPC_OP(store_tbl)
-{
- cpu_ppc_store_tbl(regs, T0);
- RETURN();
-}
-
-PPC_OP(store_tbu)
-{
- cpu_ppc_store_tbu(regs, T0);
- RETURN();
-}
-
-PPC_OP(load_decr)
-{
- T0 = cpu_ppc_load_decr(regs);
- }
-
-PPC_OP(store_decr)
-{
- cpu_ppc_store_decr(regs, T0);
- RETURN();
-}
-
-PPC_OP(load_ibat)
-{
- T0 = regs->IBAT[PARAM(1)][PARAM(2)];
-}
-
-void op_store_ibatu (void)
-{
- do_store_ibatu(env, PARAM1, T0);
- RETURN();
-}
-
-void op_store_ibatl (void)
-{
-#if 1
- env->IBAT[1][PARAM1] = T0;
-#else
- do_store_ibatl(env, PARAM1, T0);
-#endif
- RETURN();
-}
-
-PPC_OP(load_dbat)
-{
- T0 = regs->DBAT[PARAM(1)][PARAM(2)];
-}
-
-void op_store_dbatu (void)
-{
- do_store_dbatu(env, PARAM1, T0);
- RETURN();
-}
-
-void op_store_dbatl (void)
-{
-#if 1
- env->DBAT[1][PARAM1] = T0;
-#else
- do_store_dbatl(env, PARAM1, T0);
-#endif
- RETURN();
-}
-
-/* FPSCR */
-PPC_OP(load_fpscr)
-{
- FT0 = do_load_fpscr(env);
- RETURN();
-}
-
-PPC_OP(store_fpscr)
-{
- do_store_fpscr(env, FT0, PARAM1);
- RETURN();
-}
-
-PPC_OP(reset_scrfx)
-{
- regs->fpscr[7] &= ~0x8;
- RETURN();
-}
-
-/* crf operations */
-PPC_OP(getbit_T0)
-{
- T0 = (T0 >> PARAM(1)) & 1;
- RETURN();
-}
-
-PPC_OP(getbit_T1)
-{
- T1 = (T1 >> PARAM(1)) & 1;
- RETURN();
-}
-
-PPC_OP(setcrfbit)
-{
- T1 = (T1 & PARAM(1)) | (T0 << PARAM(2));
- RETURN();
-}
-
-/* Branch */
-#define EIP regs->nip
-
-PPC_OP(setlr)
-{
- regs->lr = PARAM1;
-}
-
-PPC_OP(goto_tb0)
-{
- GOTO_TB(op_goto_tb0, PARAM1, 0);
-}
-
-PPC_OP(goto_tb1)
-{
- GOTO_TB(op_goto_tb1, PARAM1, 1);
-}
-
-PPC_OP(b_T1)
-{
- regs->nip = T1 & ~3;
-}
-
-PPC_OP(jz_T0)
-{
- if (!T0)
- GOTO_LABEL_PARAM(1);
- RETURN();
-}
-
-PPC_OP(btest_T1)
-{
- if (T0) {
- regs->nip = T1 & ~3;
- } else {
- regs->nip = PARAM1;
- }
- RETURN();
-}
-
-PPC_OP(movl_T1_ctr)
-{
- T1 = regs->ctr;
-}
-
-PPC_OP(movl_T1_lr)
-{
- T1 = regs->lr;
-}
-
-/* tests with result in T0 */
-
-PPC_OP(test_ctr)
-{
- T0 = regs->ctr;
-}
-
-PPC_OP(test_ctr_true)
-{
- T0 = (regs->ctr != 0 && (T0 & PARAM(1)) != 0);
-}
-
-PPC_OP(test_ctr_false)
-{
- T0 = (regs->ctr != 0 && (T0 & PARAM(1)) == 0);
-}
-
-PPC_OP(test_ctrz)
-{
- T0 = (regs->ctr == 0);
-}
-
-PPC_OP(test_ctrz_true)
-{
- T0 = (regs->ctr == 0 && (T0 & PARAM(1)) != 0);
-}
-
-PPC_OP(test_ctrz_false)
-{
- T0 = (regs->ctr == 0 && (T0 & PARAM(1)) == 0);
-}
-
-PPC_OP(test_true)
-{
- T0 = (T0 & PARAM(1));
-}
-
-PPC_OP(test_false)
-{
- T0 = ((T0 & PARAM(1)) == 0);
-}
-
-/* CTR maintenance */
-PPC_OP(dec_ctr)
-{
- regs->ctr--;
- RETURN();
-}
-
-/*** Integer arithmetic ***/
-/* add */
-PPC_OP(add)
-{
- T0 += T1;
- RETURN();
-}
-
-void do_addo (void);
-void op_addo (void)
-{
- do_addo();
- RETURN();
-}
-
-/* add carrying */
-PPC_OP(addc)
-{
- T2 = T0;
- T0 += T1;
- if (T0 < T2) {
- xer_ca = 1;
- } else {
- xer_ca = 0;
- }
- RETURN();
-}
-
-void do_addco (void);
-void op_addco (void)
-{
- do_addco();
- RETURN();
-}
-
-/* add extended */
-void do_adde (void);
-void op_adde (void)
-{
- do_adde();
-}
-
-void do_addeo (void);
-PPC_OP(addeo)
-{
- do_addeo();
- RETURN();
-}
-
-/* add immediate */
-PPC_OP(addi)
-{
- T0 += PARAM(1);
- RETURN();
-}
-
-/* add immediate carrying */
-PPC_OP(addic)
-{
- T1 = T0;
- T0 += PARAM(1);
- if (T0 < T1) {
- xer_ca = 1;
- } else {
- xer_ca = 0;
- }
- RETURN();
-}
-
-/* add to minus one extended */
-PPC_OP(addme)
-{
- T1 = T0;
- T0 += xer_ca + (-1);
- if (T1 != 0)
- xer_ca = 1;
- RETURN();
-}
-
-void do_addmeo (void);
-void op_addmeo (void)
-{
- do_addmeo();
- RETURN();
-}
-
-/* add to zero extended */
-PPC_OP(addze)
-{
- T1 = T0;
- T0 += xer_ca;
- if (T0 < T1) {
- xer_ca = 1;
- } else {
- xer_ca = 0;
- }
- RETURN();
-}
-
-void do_addzeo (void);
-void op_addzeo (void)
-{
- do_addzeo();
- RETURN();
-}
-
-/* divide word */
-PPC_OP(divw)
-{
- if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
- T0 = (int32_t)((-1) * (T0 >> 31));
- } else {
- T0 = (Ts0 / Ts1);
- }
- RETURN();
-}
-
-void do_divwo (void);
-void op_divwo (void)
-{
- do_divwo();
- RETURN();
-}
-
-/* divide word unsigned */
-PPC_OP(divwu)
-{
- if (T1 == 0) {
- T0 = 0;
- } else {
- T0 /= T1;
- }
- RETURN();
-}
-
-void do_divwuo (void);
-void op_divwuo (void)
-{
- do_divwuo();
- RETURN();
-}
-
-/* multiply high word */
-PPC_OP(mulhw)
-{
- T0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32;
- RETURN();
-}
-
-/* multiply high word unsigned */
-PPC_OP(mulhwu)
-{
- T0 = ((uint64_t)T0 * (uint64_t)T1) >> 32;
- RETURN();
-}
-
-/* multiply low immediate */
-PPC_OP(mulli)
-{
- T0 = (Ts0 * SPARAM(1));
- RETURN();
-}
-
-/* multiply low word */
-PPC_OP(mullw)
-{
- T0 *= T1;
- RETURN();
-}
-
-void do_mullwo (void);
-void op_mullwo (void)
-{
- do_mullwo();
- RETURN();
-}
-
-/* negate */
-PPC_OP(neg)
-{
- if (T0 != 0x80000000) {
- T0 = -Ts0;
- }
- RETURN();
-}
-
-void do_nego (void);
-void op_nego (void)
-{
- do_nego();
- RETURN();
-}
-
-/* substract from */
-PPC_OP(subf)
-{
- T0 = T1 - T0;
- RETURN();
-}
-
-void do_subfo (void);
-void op_subfo (void)
-{
- do_subfo();
- RETURN();
-}
-
-/* substract from carrying */
-PPC_OP(subfc)
-{
- T0 = T1 - T0;
- if (T0 <= T1) {
- xer_ca = 1;
- } else {
- xer_ca = 0;
- }
- RETURN();
-}
-
-void do_subfco (void);
-void op_subfco (void)
-{
- do_subfco();
- RETURN();
-}
-
-/* substract from extended */
-void do_subfe (void);
-void op_subfe (void)
-{
- do_subfe();
- RETURN();
-}
-
-void do_subfeo (void);
-PPC_OP(subfeo)
-{
- do_subfeo();
- RETURN();
-}
-
-/* substract from immediate carrying */
-PPC_OP(subfic)
-{
- T0 = PARAM(1) + ~T0 + 1;
- if (T0 <= PARAM(1)) {
- xer_ca = 1;
- } else {
- xer_ca = 0;
- }
- RETURN();
-}
-
-/* substract from minus one extended */
-PPC_OP(subfme)
-{
- T0 = ~T0 + xer_ca - 1;
-
- if (T0 != -1)
- xer_ca = 1;
- RETURN();
-}
-
-void do_subfmeo (void);
-void op_subfmeo (void)
-{
- do_subfmeo();
- RETURN();
-}
-
-/* substract from zero extended */
-PPC_OP(subfze)
-{
- T1 = ~T0;
- T0 = T1 + xer_ca;
- if (T0 < T1) {
- xer_ca = 1;
- } else {
- xer_ca = 0;
- }
- RETURN();
-}
-
-void do_subfzeo (void);
-void op_subfzeo (void)
-{
- do_subfzeo();
- RETURN();
-}
-
-/*** Integer comparison ***/
-/* compare */
-PPC_OP(cmp)
-{
- if (Ts0 < Ts1) {
- T0 = 0x08;
- } else if (Ts0 > Ts1) {
- T0 = 0x04;
- } else {
- T0 = 0x02;
- }
- RETURN();
-}
-
-/* compare immediate */
-PPC_OP(cmpi)
-{
- if (Ts0 < SPARAM(1)) {
- T0 = 0x08;
- } else if (Ts0 > SPARAM(1)) {
- T0 = 0x04;
- } else {
- T0 = 0x02;
- }
- RETURN();
-}
-
-/* compare logical */
-PPC_OP(cmpl)
-{
- if (T0 < T1) {
- T0 = 0x08;
- } else if (T0 > T1) {
- T0 = 0x04;
- } else {
- T0 = 0x02;
- }
- RETURN();
-}
-
-/* compare logical immediate */
-PPC_OP(cmpli)
-{
- if (T0 < PARAM(1)) {
- T0 = 0x08;
- } else if (T0 > PARAM(1)) {
- T0 = 0x04;
- } else {
- T0 = 0x02;
- }
- RETURN();
-}
-
-/*** Integer logical ***/
-/* and */
-PPC_OP(and)
-{
- T0 &= T1;
- RETURN();
-}
-
-/* andc */
-PPC_OP(andc)
-{
- T0 &= ~T1;
- RETURN();
-}
-
-/* andi. */
-PPC_OP(andi_)
-{
- T0 &= PARAM(1);
- RETURN();
-}
-
-/* count leading zero */
-PPC_OP(cntlzw)
-{
- T1 = T0;
- for (T0 = 32; T1 > 0; T0--)
- T1 = T1 >> 1;
- RETURN();
-}
-
-/* eqv */
-PPC_OP(eqv)
-{
- T0 = ~(T0 ^ T1);
- RETURN();
-}
-
-/* extend sign byte */
-PPC_OP(extsb)
-{
- T0 = (int32_t)((int8_t)(Ts0));
- RETURN();
-}
-
-/* extend sign half word */
-PPC_OP(extsh)
-{
- T0 = (int32_t)((int16_t)(Ts0));
- RETURN();
-}
-
-/* nand */
-PPC_OP(nand)
-{
- T0 = ~(T0 & T1);
- RETURN();
-}
-
-/* nor */
-PPC_OP(nor)
-{
- T0 = ~(T0 | T1);
- RETURN();
-}
-
-/* or */
-PPC_OP(or)
-{
- T0 |= T1;
- RETURN();
-}
-
-/* orc */
-PPC_OP(orc)
-{
- T0 |= ~T1;
- RETURN();
-}
-
-/* ori */
-PPC_OP(ori)
-{
- T0 |= PARAM(1);
- RETURN();
-}
-
-/* xor */
-PPC_OP(xor)
-{
- T0 ^= T1;
- RETURN();
-}
-
-/* xori */
-PPC_OP(xori)
-{
- T0 ^= PARAM(1);
- RETURN();
-}
-
-/*** Integer rotate ***/
-/* rotate left word immediate then mask insert */
-PPC_OP(rlwimi)
-{
- T0 = (rotl(T0, PARAM(1)) & PARAM(2)) | (T1 & PARAM(3));
- RETURN();
-}
-
-/* rotate left immediate then and with mask insert */
-PPC_OP(rotlwi)
-{
- T0 = rotl(T0, PARAM(1));
- RETURN();
-}
-
-PPC_OP(slwi)
-{
- T0 = T0 << PARAM(1);
- RETURN();
-}
-
-PPC_OP(srwi)
-{
- T0 = T0 >> PARAM(1);
- RETURN();
-}
-
-/* rotate left word then and with mask insert */
-PPC_OP(rlwinm)
-{
- T0 = rotl(T0, PARAM(1)) & PARAM(2);
- RETURN();
-}
-
-PPC_OP(rotl)
-{
- T0 = rotl(T0, T1);
- RETURN();
-}
-
-PPC_OP(rlwnm)
-{
- T0 = rotl(T0, T1) & PARAM(1);
- RETURN();
-}
-
-/*** Integer shift ***/
-/* shift left word */
-PPC_OP(slw)
-{
- if (T1 & 0x20) {
- T0 = 0;
- } else {
- T0 = T0 << T1;
- }
- RETURN();
-}
-
-/* shift right algebraic word */
-void op_sraw (void)
-{
- do_sraw();
- RETURN();
-}
-
-/* shift right algebraic word immediate */
-PPC_OP(srawi)
-{
- T1 = T0;
- T0 = (Ts0 >> PARAM(1));
- if (Ts1 < 0 && (Ts1 & PARAM(2)) != 0) {
- xer_ca = 1;
- } else {
- xer_ca = 0;
- }
- RETURN();
-}
-
-/* shift right word */
-PPC_OP(srw)
-{
- if (T1 & 0x20) {
- T0 = 0;
- } else {
- T0 = T0 >> T1;
- }
- RETURN();
-}
-
-/*** Floating-Point arithmetic ***/
-/* fadd - fadd. */
-PPC_OP(fadd)
-{
- FT0 += FT1;
- RETURN();
-}
-
-/* fsub - fsub. */
-PPC_OP(fsub)
-{
- FT0 -= FT1;
- RETURN();
-}
-
-/* fmul - fmul. */
-PPC_OP(fmul)
-{
- FT0 *= FT1;
- RETURN();
-}
-
-/* fdiv - fdiv. */
-PPC_OP(fdiv)
-{
- FT0 = float64_div(FT0, FT1, &env->fp_status);
- RETURN();
-}
-
-/* fsqrt - fsqrt. */
-PPC_OP(fsqrt)
-{
- do_fsqrt();
- RETURN();
-}
-
-/* fres - fres. */
-PPC_OP(fres)
-{
- do_fres();
- RETURN();
-}
-
-/* frsqrte - frsqrte. */
-PPC_OP(frsqrte)
-{
- do_frsqrte();
- RETURN();
-}
-
-/* fsel - fsel. */
-PPC_OP(fsel)
-{
- do_fsel();
- RETURN();
-}
-
-/*** Floating-Point multiply-and-add ***/
-/* fmadd - fmadd. */
-PPC_OP(fmadd)
-{
- FT0 = (FT0 * FT1) + FT2;
- RETURN();
-}
-
-/* fmsub - fmsub. */
-PPC_OP(fmsub)
-{
- FT0 = (FT0 * FT1) - FT2;
- RETURN();
-}
-
-/* fnmadd - fnmadd. - fnmadds - fnmadds. */
-PPC_OP(fnmadd)
-{
- do_fnmadd();
- RETURN();
-}
-
-/* fnmsub - fnmsub. */
-PPC_OP(fnmsub)
-{
- do_fnmsub();
- RETURN();
-}
-
-/*** Floating-Point round & convert ***/
-/* frsp - frsp. */
-PPC_OP(frsp)
-{
- FT0 = (float)FT0;
- RETURN();
-}
-
-/* fctiw - fctiw. */
-PPC_OP(fctiw)
-{
- do_fctiw();
- RETURN();
-}
-
-/* fctiwz - fctiwz. */
-PPC_OP(fctiwz)
-{
- do_fctiwz();
- RETURN();
-}
-
-
-/*** Floating-Point compare ***/
-/* fcmpu */
-PPC_OP(fcmpu)
-{
- do_fcmpu();
- RETURN();
-}
-
-/* fcmpo */
-PPC_OP(fcmpo)
-{
- do_fcmpo();
- RETURN();
-}
-
-/*** Floating-point move ***/
-/* fabs */
-PPC_OP(fabs)
-{
- FT0 = float64_abs(FT0);
- RETURN();
-}
-
-/* fnabs */
-PPC_OP(fnabs)
-{
- FT0 = float64_abs(FT0);
- FT0 = float64_chs(FT0);
- RETURN();
-}
-
-/* fneg */
-PPC_OP(fneg)
-{
- FT0 = float64_chs(FT0);
- RETURN();
-}
-
-/* Load and store */
-#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"
-#endif
-
-/* Special op to check and maybe clear reservation */
-PPC_OP(check_reservation)
-{
- if ((uint32_t)env->reserve == (uint32_t)(T0 & ~0x00000003))
- env->reserve = -1;
- RETURN();
-}
-
-/* Return from interrupt */
-void do_rfi (void);
-void op_rfi (void)
-{
- do_rfi();
- RETURN();
-}
-
-/* Trap word */
-void do_tw (uint32_t cmp, int flags);
-void op_tw (void)
-{
- do_tw(T1, PARAM(1));
- RETURN();
-}
-
-void op_twi (void)
-{
- do_tw(PARAM(1), PARAM(2));
- RETURN();
-}
-
-/* Instruction cache block invalidate */
-PPC_OP(icbi)
-{
- do_icbi();
- RETURN();
-}
-
-/* tlbia */
-PPC_OP(tlbia)
-{
- do_tlbia();
- RETURN();
-}
-
-/* tlbie */
-PPC_OP(tlbie)
-{
- do_tlbie();
- RETURN();
-}
-
-void op_store_pir (void)
-{
- env->spr[SPR_PIR] = T0 & 0x0000000FUL;
- RETURN();
-}
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
deleted file mode 100644
index e949eb4..0000000
--- a/target-ppc/op_helper.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * PowerPC emulation helpers for qemu.
- *
- * Copyright (c) 2003-2005 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"
-
-#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"
-#endif
-
-//#define DEBUG_OP
-//#define DEBUG_EXCEPTIONS
-//#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)
-{
- longjmp(env->jmp_env, 1);
-}
-
-void do_raise_exception_err (uint32_t exception, int error_code)
-{
-#if 0
- printf("Raise exception %3x code : %d\n", exception, error_code);
-#endif
- switch (exception) {
- case EXCP_PROGRAM:
- if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
- return;
- break;
- default:
- break;
-}
- env->exception_index = exception;
- env->error_code = error_code;
- cpu_loop_exit();
- }
-
-void do_raise_exception (uint32_t exception)
-{
- do_raise_exception_err(exception, 0);
-}
-
-/*****************************************************************************/
-/* Fixed point operations helpers */
-void do_addo (void)
-{
- T2 = T0;
- T0 += T1;
- if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
- xer_ov = 0;
- } else {
- xer_so = 1;
- xer_ov = 1;
- }
-}
-
-void do_addco (void)
-{
- T2 = T0;
- T0 += T1;
- if (likely(T0 >= 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;
- }
-}
-
-void do_adde (void)
-{
- T2 = T0;
- T0 += T1 + xer_ca;
- if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
- xer_ca = 0;
- } else {
- xer_ca = 1;
- }
-}
-
-void do_addeo (void)
-{
- T2 = T0;
- T0 += T1 + xer_ca;
- if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == 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;
- }
-}
-
-void do_addmeo (void)
-{
- T1 = T0;
- T0 += xer_ca + (-1);
- if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) {
- xer_ov = 0;
- } else {
- xer_so = 1;
- xer_ov = 1;
- }
- if (likely(T1 != 0))
- xer_ca = 1;
-}
-
-void do_addzeo (void)
-{
- T1 = T0;
- T0 += xer_ca;
- if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) {
- xer_ov = 0;
- } else {
- xer_so = 1;
- xer_ov = 1;
- }
- if (likely(T0 >= T1)) {
- xer_ca = 0;
- } else {
- xer_ca = 1;
- }
-}
-
-void do_divwo (void)
-{
- if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) {
- xer_ov = 0;
- T0 = (Ts0 / Ts1);
- } else {
- xer_so = 1;
- xer_ov = 1;
- T0 = (-1) * ((uint32_t)T0 >> 31);
- }
-}
-
-void do_divwuo (void)
-{
- if (likely((uint32_t)T1 != 0)) {
- xer_ov = 0;
- T0 = (uint32_t)T0 / (uint32_t)T1;
- } else {
- xer_so = 1;
- xer_ov = 1;
- T0 = 0;
- }
-}
-
-void do_mullwo (void)
-{
- int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
-
- if (likely((int32_t)res == res)) {
- xer_ov = 0;
- } else {
- xer_ov = 1;
- xer_so = 1;
- }
- T0 = (int32_t)res;
-}
-
-void do_nego (void)
-{
- if (likely(T0 != INT32_MIN)) {
- xer_ov = 0;
- T0 = -Ts0;
- } else {
- xer_ov = 1;
- xer_so = 1;
- }
-}
-
-void do_subfo (void)
-{
- T2 = T0;
- T0 = T1 - T0;
- if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
- xer_ov = 0;
- } else {
- xer_so = 1;
- xer_ov = 1;
- }
- RETURN();
-}
-
-void do_subfco (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)))) {
- xer_ov = 0;
- } else {
- xer_so = 1;
- xer_ov = 1;
- }
-}
-
-void do_subfe (void)
-{
- T0 = T1 + ~T0 + xer_ca;
- if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
- xer_ca = 0;
- } else {
- xer_ca = 1;
- }
-}
-
-void do_subfeo (void)
-{
- T2 = T0;
- T0 = T1 + ~T0 + xer_ca;
- if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) {
- xer_ov = 0;
- } else {
- xer_so = 1;
- xer_ov = 1;
- }
- if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
- xer_ca = 0;
- } else {
- xer_ca = 1;
- }
-}
-
-void do_subfmeo (void)
-{
- T1 = T0;
- T0 = ~T0 + xer_ca - 1;
- if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) {
- xer_ov = 0;
- } else {
- xer_so = 1;
- xer_ov = 1;
- }
- if (likely(T1 != -1))
- xer_ca = 1;
-}
-
-void do_subfzeo (void)
-{
- T1 = T0;
- T0 = ~T0 + xer_ca;
- if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) {
- xer_ov = 0;
- } else {
- xer_ov = 1;
- xer_so = 1;
- }
- if (likely(T0 >= ~T1)) {
- xer_ca = 0;
- } else {
- xer_ca = 1;
- }
-}
-
-/* shift right arithmetic helper */
-void do_sraw (void)
-{
- int32_t ret;
-
- if (likely(!(T1 & 0x20UL))) {
- if (likely(T1 != 0)) {
- ret = (int32_t)T0 >> (T1 & 0x1fUL);
- if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
- xer_ca = 0;
- } else {
- xer_ca = 1;
- }
- } else {
- 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;
-}
-
-/*****************************************************************************/
-/* Floating point operations helpers */
-void do_fctiw (void)
-{
- union {
- double d;
- uint64_t i;
- } p;
-
- /* XXX: higher bits are not supposed to be significant.
- * 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;
- FT0 = p.d;
-}
-
-void do_fctiwz (void)
-{
- union {
- double d;
- uint64_t i;
- } p;
-
- /* XXX: higher bits are not supposed to be significant.
- * 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;
- FT0 = p.d;
-}
-
-void do_fnmadd (void)
-{
- FT0 = float64_mul(FT0, FT1, &env->fp_status);
- FT0 = float64_add(FT0, FT2, &env->fp_status);
- if (likely(!isnan(FT0)))
- FT0 = float64_chs(FT0);
-}
-
-void do_fnmsub (void)
-{
- FT0 = float64_mul(FT0, FT1, &env->fp_status);
- FT0 = float64_sub(FT0, FT2, &env->fp_status);
- if (likely(!isnan(FT0)))
- FT0 = float64_chs(FT0);
-}
-
-void do_fsqrt (void)
-{
- FT0 = float64_sqrt(FT0, &env->fp_status);
-}
-
-void do_fres (void)
-{
- union {
- double d;
- uint64_t i;
- } p;
-
- if (likely(isnormal(FT0))) {
- FT0 = (float)(1.0 / FT0);
- } else {
- p.d = FT0;
- if (p.i == 0x8000000000000000ULL) {
- p.i = 0xFFF0000000000000ULL;
- } else if (p.i == 0x0000000000000000ULL) {
- p.i = 0x7FF0000000000000ULL;
- } else if (isnan(FT0)) {
- p.i = 0x7FF8000000000000ULL;
- } else if (FT0 < 0.0) {
- p.i = 0x8000000000000000ULL;
- } else {
- p.i = 0x0000000000000000ULL;
- }
- FT0 = p.d;
- }
-}
-
-void do_frsqrte (void)
-{
- union {
- double d;
- uint64_t i;
- } p;
-
- if (likely(isnormal(FT0) && FT0 > 0.0)) {
- FT0 = float64_sqrt(FT0, &env->fp_status);
- FT0 = float32_div(1.0, FT0, &env->fp_status);
- } else {
- p.d = FT0;
- if (p.i == 0x8000000000000000ULL) {
- p.i = 0xFFF0000000000000ULL;
- } else if (p.i == 0x0000000000000000ULL) {
- p.i = 0x7FF0000000000000ULL;
- } else if (isnan(FT0)) {
- if (!(p.i & 0x0008000000000000ULL))
- p.i |= 0x000FFFFFFFFFFFFFULL;
- } else if (FT0 < 0) {
- p.i = 0x7FF8000000000000ULL;
- } else {
- p.i = 0x0000000000000000ULL;
- }
- FT0 = p.d;
- }
-}
-
-void do_fsel (void)
-{
- if (FT0 >= 0)
- FT0 = FT1;
- else
- FT0 = FT2;
-}
-
-void do_fcmpu (void)
-{
- if (likely(!isnan(FT0) && !isnan(FT1))) {
- if (float64_lt(FT0, FT1, &env->fp_status)) {
- T0 = 0x08UL;
- } else if (!float64_le(FT0, FT1, &env->fp_status)) {
- T0 = 0x04UL;
- } else {
- T0 = 0x02UL;
- }
- } else {
- T0 = 0x01UL;
- env->fpscr[4] |= 0x1;
- env->fpscr[6] |= 0x1;
- }
- env->fpscr[3] = T0;
-}
-
-void do_fcmpo (void)
-{
- env->fpscr[4] &= ~0x1;
- if (likely(!isnan(FT0) && !isnan(FT1))) {
- if (float64_lt(FT0, FT1, &env->fp_status)) {
- T0 = 0x08UL;
- } else if (!float64_le(FT0, FT1, &env->fp_status)) {
- T0 = 0x04UL;
- } else {
- T0 = 0x02UL;
- }
- } else {
- T0 = 0x01UL;
- env->fpscr[4] |= 0x1;
- /* I don't know how to test "quiet" nan... */
- if (0 /* || ! quiet_nan(...) */) {
- env->fpscr[6] |= 0x1;
- if (!(env->fpscr[1] & 0x8))
- env->fpscr[4] |= 0x8;
- } else {
- env->fpscr[4] |= 0x8;
- }
- }
- env->fpscr[3] = T0;
-}
-
-void do_rfi (void)
-{
- env->nip = env->spr[SPR_SRR0] & ~0x00000003;
- T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
- do_store_msr(env, T0);
-#if defined (DEBUG_OP)
- dump_rfi();
-#endif
- env->interrupt_request |= CPU_INTERRUPT_EXITTB;
-}
-
-void do_tw (uint32_t cmp, int flags)
-{
- 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)))))
- do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
-}
-
-/* Instruction cache invalidation helper */
-void do_icbi (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".
- */
-#if defined(TARGET_PPC64)
- if (!msr_sf)
- T0 &= 0xFFFFFFFFULL;
-#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)
-{
- tlb_flush(env, 1);
-}
-
-void do_tlbie (void)
-{
-#if !defined(FLUSH_ALL_TLBS)
- tlb_flush_page(env, T0);
-#else
- do_tlbia();
-#endif
-}
-
-/*****************************************************************************/
-/* Softmmu support */
-#if !defined (CONFIG_USER_ONLY)
-
-#define MMUSUFFIX _mmu
-#define GETPC() (__builtin_return_address(0))
-
-#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_ppc_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);
-}
- }
- do_raise_exception_err(env->exception_index, env->error_code);
- }
- env = saved_env;
-}
-#endif /* !CONFIG_USER_ONLY */
-
diff --git a/target-ppc/op_helper_mem.h b/target-ppc/op_helper_mem.h
deleted file mode 100644
index fb90691..0000000
--- a/target-ppc/op_helper_mem.h
+++ /dev/null
@@ -1,100 +0,0 @@
-void glue(do_lsw, 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, dst);
- }
-#endif
- for (; T1 > 3; T1 -= 4, T0 += 4) {
- ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0);
- if (dst == 32)
- dst = 0;
- }
- if (T1 > 0) {
- tmp = 0;
- for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) {
- tmp |= glue(ldub, MEMSUFFIX)(T0) << sh;
- }
- ugpr(dst) = tmp;
- }
-}
-
-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);
- }
-#endif
- for (; T1 > 3; T1 -= 4, T0 += 4) {
- glue(stl, MEMSUFFIX)(T0, ugpr(src++));
- if (src == 32)
- src = 0;
- }
- if (T1 > 0) {
- for (sh = 24; T1 > 0; T1--, T0++, sh -= 8)
- glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF);
- }
-}
-
-void glue(do_lsw_le, 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, 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)
- dst = 0;
- }
- if (T1 > 0) {
- tmp = 0;
- for (sh = 0; T1 > 0; T1--, T0++, sh += 8) {
- tmp |= glue(ldub, MEMSUFFIX)(T0) << sh;
- }
- ugpr(dst) = tmp;
- }
-}
-
-void glue(do_stsw_le, MEMSUFFIX) (int src)
-{
- 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);
- }
-#endif
- 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)
- src = 0;
- }
- if (T1 > 0) {
- for (sh = 0; T1 > 0; T1--, T0++, sh += 8)
- glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF);
- }
-}
-
-#undef MEMSUFFIX
diff --git a/target-ppc/op_mem.h b/target-ppc/op_mem.h
deleted file mode 100644
index 9b3f721..0000000
--- a/target-ppc/op_mem.h
+++ /dev/null
@@ -1,371 +0,0 @@
-/* External helpers */
-void glue(do_lsw, MEMSUFFIX) (int dst);
-void glue(do_stsw, MEMSUFFIX) (int src);
-
-static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA)
-{
- uint16_t tmp = glue(lduw, MEMSUFFIX)(EA);
- return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
-}
-
-static inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA)
-{
- int16_t tmp = glue(lduw, MEMSUFFIX)(EA);
- return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
-}
-
-static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA)
-{
- uint32_t tmp = glue(ldl, MEMSUFFIX)(EA);
- return ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) |
- ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24);
-}
-
-static inline void glue(st16r, MEMSUFFIX) (target_ulong EA, uint16_t data)
-{
- uint16_t tmp = ((data & 0xFF00) >> 8) | ((data & 0x00FF) << 8);
- glue(stw, MEMSUFFIX)(EA, tmp);
-}
-
-static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, uint32_t data)
-{
- uint32_t tmp = ((data & 0xFF000000) >> 24) | ((data & 0x00FF0000) >> 8) |
- ((data & 0x0000FF00) << 8) | ((data & 0x000000FF) << 24);
- glue(stl, MEMSUFFIX)(EA, tmp);
-}
-
-/*** Integer load ***/
-#define PPC_LD_OP(name, op) \
-PPC_OP(glue(glue(l, name), MEMSUFFIX)) \
-{ \
- T1 = glue(op, MEMSUFFIX)(T0); \
- RETURN(); \
-}
-
-#define PPC_ST_OP(name, op) \
-PPC_OP(glue(glue(st, name), MEMSUFFIX)) \
-{ \
- glue(op, MEMSUFFIX)(T0, T1); \
- RETURN(); \
-}
-
-PPC_LD_OP(bz, ldub);
-PPC_LD_OP(ha, ldsw);
-PPC_LD_OP(hz, lduw);
-PPC_LD_OP(wz, ldl);
-
-PPC_LD_OP(ha_le, ld16rs);
-PPC_LD_OP(hz_le, ld16r);
-PPC_LD_OP(wz_le, ld32r);
-
-/*** Integer store ***/
-PPC_ST_OP(b, stb);
-PPC_ST_OP(h, stw);
-PPC_ST_OP(w, stl);
-
-PPC_ST_OP(h_le, st16r);
-PPC_ST_OP(w_le, st32r);
-
-/*** 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);
-
-PPC_LD_OP(hbr_le, lduw);
-PPC_LD_OP(wbr_le, ldl);
-PPC_ST_OP(hbr_le, stw);
-PPC_ST_OP(wbr_le, stl);
-
-/*** Integer load and store multiple ***/
-PPC_OP(glue(lmw, MEMSUFFIX))
-{
- int dst = PARAM(1);
-
- for (; dst < 32; dst++, T0 += 4) {
- ugpr(dst) = glue(ldl, MEMSUFFIX)(T0);
- }
- RETURN();
-}
-
-PPC_OP(glue(stmw, MEMSUFFIX))
-{
- int src = PARAM(1);
-
- for (; src < 32; src++, T0 += 4) {
- glue(stl, MEMSUFFIX)(T0, ugpr(src));
- }
- RETURN();
-}
-
-PPC_OP(glue(lmw_le, MEMSUFFIX))
-{
- int dst = PARAM(1);
-
- for (; dst < 32; dst++, T0 += 4) {
- ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0);
- }
- RETURN();
-}
-
-PPC_OP(glue(stmw_le, MEMSUFFIX))
-{
- int src = PARAM(1);
-
- for (; src < 32; src++, T0 += 4) {
- glue(st32r, MEMSUFFIX)(T0, ugpr(src));
- }
- RETURN();
-}
-
-/*** Integer load and store strings ***/
-PPC_OP(glue(lswi, MEMSUFFIX))
-{
- glue(do_lsw, MEMSUFFIX)(PARAM(1));
- RETURN();
-}
-
-void glue(do_lsw_le, MEMSUFFIX) (int dst);
-PPC_OP(glue(lswi_le, MEMSUFFIX))
-{
- glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
- RETURN();
-}
-
-/* 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))
-{
- if (T1 > 0) {
- if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
- (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
- do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
- } else {
- glue(do_lsw, MEMSUFFIX)(PARAM(1));
- }
- }
- RETURN();
-}
-
-PPC_OP(glue(lswx_le, MEMSUFFIX))
-{
- if (T1 > 0) {
- if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
- (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
- do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
- } else {
- glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
- }
- }
- RETURN();
-}
-
-PPC_OP(glue(stsw, MEMSUFFIX))
-{
- glue(do_stsw, MEMSUFFIX)(PARAM(1));
- RETURN();
-}
-
-void glue(do_stsw_le, MEMSUFFIX) (int src);
-PPC_OP(glue(stsw_le, MEMSUFFIX))
-{
- glue(do_stsw_le, MEMSUFFIX)(PARAM(1));
- RETURN();
-}
-
-/*** Floating-point store ***/
-#define PPC_STF_OP(name, op) \
-PPC_OP(glue(glue(st, name), MEMSUFFIX)) \
-{ \
- glue(op, MEMSUFFIX)(T0, FT1); \
- RETURN(); \
-}
-
-PPC_STF_OP(fd, stfq);
-PPC_STF_OP(fs, stfl);
-
-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);
-}
-
-static inline void glue(stflr, MEMSUFFIX) (target_ulong EA, float f)
-{
- union {
- float f;
- uint32_t u;
- } u;
-
- u.f = f;
- u.u = ((u.u & 0xFF000000UL) >> 24) |
- ((u.u & 0x00FF0000ULL) >> 8) |
- ((u.u & 0x0000FF00UL) << 8) |
- ((u.u & 0x000000FFULL) << 24);
- glue(stfl, MEMSUFFIX)(EA, u.f);
-}
-
-PPC_STF_OP(fd_le, stfqr);
-PPC_STF_OP(fs_le, stflr);
-
-/*** Floating-point load ***/
-#define PPC_LDF_OP(name, op) \
-PPC_OP(glue(glue(l, name), MEMSUFFIX)) \
-{ \
- FT1 = glue(op, MEMSUFFIX)(T0); \
- RETURN(); \
-}
-
-PPC_LDF_OP(fd, ldfq);
-PPC_LDF_OP(fs, ldfl);
-
-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;
-}
-
-static inline float glue(ldflr, MEMSUFFIX) (target_ulong EA)
-{
- union {
- float f;
- uint32_t u;
- } u;
-
- u.f = glue(ldfl, MEMSUFFIX)(EA);
- u.u = ((u.u & 0xFF000000UL) >> 24) |
- ((u.u & 0x00FF0000ULL) >> 8) |
- ((u.u & 0x0000FF00UL) << 8) |
- ((u.u & 0x000000FFULL) << 24);
-
- return u.f;
-}
-
-PPC_LDF_OP(fd_le, ldfqr);
-PPC_LDF_OP(fs_le, ldflr);
-
-/* Load and set reservation */
-PPC_OP(glue(lwarx, MEMSUFFIX))
-{
- if (T0 & 0x03) {
- do_raise_exception(EXCP_ALIGN);
- } else {
- T1 = glue(ldl, MEMSUFFIX)(T0);
- regs->reserve = T0;
- }
- RETURN();
-}
-
-PPC_OP(glue(lwarx_le, MEMSUFFIX))
-{
- if (T0 & 0x03) {
- do_raise_exception(EXCP_ALIGN);
- } else {
- T1 = glue(ld32r, MEMSUFFIX)(T0);
- regs->reserve = T0;
- }
- RETURN();
-}
-
-/* Store with reservation */
-PPC_OP(glue(stwcx, MEMSUFFIX))
-{
- if (T0 & 0x03) {
- do_raise_exception(EXCP_ALIGN);
- } else {
- if (regs->reserve != T0) {
- env->crf[0] = xer_ov;
- } else {
- glue(stl, MEMSUFFIX)(T0, T1);
- env->crf[0] = xer_ov | 0x02;
- }
- }
- regs->reserve = 0;
- RETURN();
-}
-
-PPC_OP(glue(stwcx_le, MEMSUFFIX))
-{
- if (T0 & 0x03) {
- do_raise_exception(EXCP_ALIGN);
- } else {
- if (regs->reserve != T0) {
- env->crf[0] = xer_ov;
- } else {
- glue(st32r, MEMSUFFIX)(T0, T1);
- env->crf[0] = xer_ov | 0x02;
- }
- }
- regs->reserve = 0;
- RETURN();
-}
-
-PPC_OP(glue(dcbz, MEMSUFFIX))
-{
- 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);
- RETURN();
-}
-
-/* External access */
-PPC_OP(glue(eciwx, MEMSUFFIX))
-{
- T1 = glue(ldl, MEMSUFFIX)(T0);
- RETURN();
-}
-
-PPC_OP(glue(ecowx, MEMSUFFIX))
-{
- glue(stl, MEMSUFFIX)(T0, T1);
- RETURN();
-}
-
-PPC_OP(glue(eciwx_le, MEMSUFFIX))
-{
- T1 = glue(ld32r, MEMSUFFIX)(T0);
- RETURN();
-}
-
-PPC_OP(glue(ecowx_le, MEMSUFFIX))
-{
- glue(st32r, MEMSUFFIX)(T0, T1);
- RETURN();
-}
-
-#undef MEMSUFFIX
diff --git a/target-ppc/op_template.h b/target-ppc/op_template.h
deleted file mode 100644
index 1be640d..0000000
--- a/target-ppc/op_template.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * PowerPC emulation micro-operations for qemu.
- *
- * Copyright (c) 2003-2005 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
- */
-
-/* General purpose registers moves */
-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)
-{
- T1 = regs->gpr[REG];
- RETURN();
-}
-
-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)
-{
- regs->gpr[REG] = T0;
- RETURN();
-}
-
-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)
-{
- regs->gpr[REG] = T2;
- RETURN();
-}
-
-#if REG <= 7
-/* Condition register moves */
-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)
-{
- T1 = regs->crf[REG];
- RETURN();
-}
-
-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)
-{
- regs->crf[REG] = T1;
- RETURN();
-}
-
-/* Floating point condition and status register moves */
-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)
-{
- regs->fpscr[REG] = (regs->fpscr[REG] & 0x9) | (T0 & ~0x9);
- RETURN();
-}
-
-void OPPROTO glue(op_store_T0_fpscri_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)
-{
- regs->fpscr[REG] = T0;
- RETURN();
-}
-
-void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
-{
- regs->fpscr[REG] = PARAM(1);
- RETURN();
-}
-
-void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
-{
- regs->fpscr[REG] = 0x0;
- RETURN();
-}
-#endif
-
-#endif /* REG <= 7 */
-
-/* floating point registers moves */
-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)
-{
- env->fpr[REG] = FT0;
- RETURN();
-}
-
-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)
-{
- env->fpr[REG] = FT1;
- RETURN();
-}
-
-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)
-{
- 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
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
deleted file mode 100644
index 046f168..0000000
--- a/target-ppc/translate.c
+++ /dev/null
@@ -1,2701 +0,0 @@
-/*
- * PowerPC emulation for qemu: main translation routines.
- *
- * Copyright (c) 2003-2005 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 <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-#include "disas.h"
-
-//#define DO_SINGLE_STEP
-//#define PPC_DEBUG_DISAS
-
-#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"
-
-#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, \
-}; \
-static inline void func(int n) \
-{ \
- NAME ## _table[n](); \
-}
-
-#define GEN16(func, NAME) \
-static GenOpFunc *NAME ## _table [16] = { \
-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, \
-}; \
-static inline void func(int n) \
-{ \
- NAME ## _table[n](); \
-}
-
-#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](); \
-}
-
-/* Condition register moves */
-GEN8(gen_op_load_crf_T0, gen_op_load_crf_T0_crf);
-GEN8(gen_op_load_crf_T1, gen_op_load_crf_T1_crf);
-GEN8(gen_op_store_T0_crf, gen_op_store_T0_crf_crf);
-GEN8(gen_op_store_T1_crf, gen_op_store_T1_crf_crf);
-
-/* Floating point condition and status register moves */
-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);
-}
-
-/* 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);
-GEN32(gen_op_load_gpr_T2, gen_op_load_gpr_T2_gpr);
-
-GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
-GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
-GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr);
-
-/* floating point registers moves */
-GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr);
-GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fpr);
-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);
-GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr);
-
-static uint8_t spr_access[1024 / 2];
-
-/* internal defines */
-typedef struct DisasContext {
- struct TranslationBlock *tb;
- target_ulong nip;
- uint32_t opcode;
- uint32_t exception;
- /* Routine used to access memory */
- int mem_idx;
- /* Translation flags */
-#if !defined(CONFIG_USER_ONLY)
- int supervisor;
-#endif
- int fpu_enabled;
- ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
- int singlestep_enabled;
-} DisasContext;
-
-struct opc_handler_t {
- /* invalid bits */
- uint32_t inval;
- /* instruction type */
- uint32_t type;
- /* handler */
- void (*handler)(DisasContext *ctx);
-};
-
-#define RET_EXCP(ctx, excp, error) \
-do { \
- if ((ctx)->exception == EXCP_NONE) { \
- gen_op_update_nip((ctx)->nip); \
- } \
- gen_op_raise_exception_err((excp), (error)); \
- ctx->exception = (excp); \
-} while (0)
-
-#define RET_INVAL(ctx) \
-RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL)
-
-#define RET_PRIVOPC(ctx) \
-RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC)
-
-#define RET_PRIVREG(ctx) \
-RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG)
-
-/* Stop translation */
-static inline void RET_STOP (DisasContext *ctx)
-{
- gen_op_update_nip((ctx)->nip);
- ctx->exception = EXCP_MTMSR;
-}
-
-/* No need to update nip here, as execution flow will change */
-static inline void RET_CHG_FLOW (DisasContext *ctx)
-{
- ctx->exception = EXCP_MTMSR;
-}
-
-#define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
-static void gen_##name (DisasContext *ctx); \
-GEN_OPCODE(name, opc1, opc2, opc3, inval, type); \
-static void gen_##name (DisasContext *ctx)
-
-typedef struct opcode_t {
- unsigned char opc1, opc2, opc3;
-#if HOST_LONG_BITS == 64 /* Explicitely align to 64 bits */
- unsigned char pad[5];
-#else
- unsigned char pad[1];
-#endif
- opc_handler_t handler;
- const unsigned char *oname;
-} opcode_t;
-
-/*** Instruction decoding ***/
-#define EXTRACT_HELPER(name, shift, nb) \
-static inline uint32_t name (uint32_t opcode) \
-{ \
- return (opcode >> (shift)) & ((1 << (nb)) - 1); \
-}
-
-#define EXTRACT_SHELPER(name, shift, nb) \
-static inline int32_t name (uint32_t opcode) \
-{ \
- return (int16_t)((opcode >> (shift)) & ((1 << (nb)) - 1)); \
-}
-
-/* Opcode part 1 */
-EXTRACT_HELPER(opc1, 26, 6);
-/* Opcode part 2 */
-EXTRACT_HELPER(opc2, 1, 5);
-/* Opcode part 3 */
-EXTRACT_HELPER(opc3, 6, 5);
-/* Update Cr0 flags */
-EXTRACT_HELPER(Rc, 0, 1);
-/* Destination */
-EXTRACT_HELPER(rD, 21, 5);
-/* Source */
-EXTRACT_HELPER(rS, 21, 5);
-/* First operand */
-EXTRACT_HELPER(rA, 16, 5);
-/* Second operand */
-EXTRACT_HELPER(rB, 11, 5);
-/* Third operand */
-EXTRACT_HELPER(rC, 6, 5);
-/*** Get CRn ***/
-EXTRACT_HELPER(crfD, 23, 3);
-EXTRACT_HELPER(crfS, 18, 3);
-EXTRACT_HELPER(crbD, 21, 5);
-EXTRACT_HELPER(crbA, 16, 5);
-EXTRACT_HELPER(crbB, 11, 5);
-/* SPR / TBL */
-EXTRACT_HELPER(_SPR, 11, 10);
-static inline uint32_t SPR (uint32_t opcode)
-{
- uint32_t sprn = _SPR(opcode);
-
- return ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
-}
-/*** Get constants ***/
-EXTRACT_HELPER(IMM, 12, 8);
-/* 16 bits signed immediate value */
-EXTRACT_SHELPER(SIMM, 0, 16);
-/* 16 bits unsigned immediate value */
-EXTRACT_HELPER(UIMM, 0, 16);
-/* Bit count */
-EXTRACT_HELPER(NB, 11, 5);
-/* Shift count */
-EXTRACT_HELPER(SH, 11, 5);
-/* Mask start */
-EXTRACT_HELPER(MB, 6, 5);
-/* Mask end */
-EXTRACT_HELPER(ME, 1, 5);
-/* Trap operand */
-EXTRACT_HELPER(TO, 21, 5);
-
-EXTRACT_HELPER(CRM, 12, 8);
-EXTRACT_HELPER(FM, 17, 8);
-EXTRACT_HELPER(SR, 16, 4);
-EXTRACT_HELPER(FPIMM, 20, 4);
-
-/*** Jump target decoding ***/
-/* Displacement */
-EXTRACT_SHELPER(d, 0, 16);
-/* Immediate address */
-static inline uint32_t LI (uint32_t opcode)
-{
- return (opcode >> 0) & 0x03FFFFFC;
-}
-
-static inline uint32_t BD (uint32_t opcode)
-{
- return (opcode >> 0) & 0xFFFC;
-}
-
-EXTRACT_HELPER(BO, 21, 5);
-EXTRACT_HELPER(BI, 16, 5);
-/* Absolute/relative address */
-EXTRACT_HELPER(AA, 1, 1);
-/* Link */
-EXTRACT_HELPER(LK, 0, 1);
-
-/* Create a mask between <start> and <end> bits */
-static inline uint32_t MASK (uint32_t start, uint32_t end)
-{
- uint32_t ret;
-
- ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1);
- if (start > end)
- return ~ret;
-
- return ret;
-}
-
-#if HOST_LONG_BITS == 64
-#define OPC_ALIGN 8
-#else
-#define OPC_ALIGN 4
-#endif
-#if defined(__APPLE__)
-#define OPCODES_SECTION \
- __attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
-#else
-#define OPCODES_SECTION \
- __attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
-#endif
-
-#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), \
-}
-
-#define GEN_OPCODE_MARK(name) \
-OPCODES_SECTION opcode_t opc_##name = { \
- .opc1 = 0xFF, \
- .opc2 = 0xFF, \
- .opc3 = 0xFF, \
- .pad = { 0, }, \
- .handler = { \
- .inval = 0x00000000, \
- .type = 0x00, \
- .handler = NULL, \
- }, \
- .oname = stringify(name), \
-}
-
-/* Start opcode list */
-GEN_OPCODE_MARK(start);
-
-/* Invalid instruction */
-GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE)
-{
- RET_INVAL(ctx);
-}
-
-static opc_handler_t invalid_handler = {
- .inval = 0xFFFFFFFF,
- .type = PPC_NONE,
- .handler = gen_invalid,
-};
-
-/*** Integer arithmetic ***/
-#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval) \
-GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
-{ \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
- gen_op_store_T0_gpr(rD(ctx->opcode)); \
-}
-
-#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \
-GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
-{ \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
- gen_op_store_T0_gpr(rD(ctx->opcode)); \
-}
-
-#define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \
-GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
-{ \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
- gen_op_store_T0_gpr(rD(ctx->opcode)); \
-}
-#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \
-GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
-{ \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
- gen_op_store_T0_gpr(rD(ctx->opcode)); \
-}
-
-/* Two operands arithmetic functions */
-#define GEN_INT_ARITH2(name, opc1, opc2, opc3) \
-__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000) \
-__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000)
-
-/* Two operands arithmetic functions with no overflow allowed */
-#define GEN_INT_ARITHN(name, opc1, opc2, opc3) \
-__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400)
-
-/* One operand arithmetic functions */
-#define GEN_INT_ARITH1(name, opc1, opc2, opc3) \
-__GEN_INT_ARITH1(name, opc1, opc2, opc3) \
-__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10)
-
-/* add add. addo addo. */
-GEN_INT_ARITH2 (add, 0x1F, 0x0A, 0x08);
-/* addc addc. addco addco. */
-GEN_INT_ARITH2 (addc, 0x1F, 0x0A, 0x00);
-/* adde adde. addeo addeo. */
-GEN_INT_ARITH2 (adde, 0x1F, 0x0A, 0x04);
-/* addme addme. addmeo addmeo. */
-GEN_INT_ARITH1 (addme, 0x1F, 0x0A, 0x07);
-/* addze addze. addzeo addzeo. */
-GEN_INT_ARITH1 (addze, 0x1F, 0x0A, 0x06);
-/* divw divw. divwo divwo. */
-GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F);
-/* divwu divwu. divwuo divwuo. */
-GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E);
-/* mulhw mulhw. */
-GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02);
-/* mulhwu mulhwu. */
-GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00);
-/* mullw mullw. mullwo mullwo. */
-GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07);
-/* neg neg. nego nego. */
-GEN_INT_ARITH1 (neg, 0x1F, 0x08, 0x03);
-/* subf subf. subfo subfo. */
-GEN_INT_ARITH2 (subf, 0x1F, 0x08, 0x01);
-/* subfc subfc. subfco subfco. */
-GEN_INT_ARITH2 (subfc, 0x1F, 0x08, 0x00);
-/* subfe subfe. subfeo subfeo. */
-GEN_INT_ARITH2 (subfe, 0x1F, 0x08, 0x04);
-/* subfme subfme. subfmeo subfmeo. */
-GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07);
-/* subfze subfze. subfzeo subfzeo. */
-GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
-/* addi */
-GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- int32_t simm = SIMM(ctx->opcode);
-
- if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(simm);
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addi(simm);
- }
- gen_op_store_T0_gpr(rD(ctx->opcode));
-}
-/* addic */
-GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addic(SIMM(ctx->opcode));
- gen_op_store_T0_gpr(rD(ctx->opcode));
-}
-/* addic. */
-GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addic(SIMM(ctx->opcode));
- gen_op_set_Rc0();
- gen_op_store_T0_gpr(rD(ctx->opcode));
-}
-/* addis */
-GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- int32_t simm = SIMM(ctx->opcode);
-
- if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(simm << 16);
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addi(simm << 16);
- }
- gen_op_store_T0_gpr(rD(ctx->opcode));
-}
-/* mulli */
-GEN_HANDLER(mulli, 0x07, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_mulli(SIMM(ctx->opcode));
- gen_op_store_T0_gpr(rD(ctx->opcode));
-}
-/* subfic */
-GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_subfic(SIMM(ctx->opcode));
- gen_op_store_T0_gpr(rD(ctx->opcode));
-}
-
-/*** Integer comparison ***/
-#define GEN_CMP(name, opc) \
-GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER) \
-{ \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_##name(); \
- gen_op_store_T0_crf(crfD(ctx->opcode)); \
-}
-
-/* cmp */
-GEN_CMP(cmp, 0x00);
-/* cmpi */
-GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
-{
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_cmpi(SIMM(ctx->opcode));
- gen_op_store_T0_crf(crfD(ctx->opcode));
-}
-/* cmpl */
-GEN_CMP(cmpl, 0x01);
-/* cmpli */
-GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
-{
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_cmpli(UIMM(ctx->opcode));
- gen_op_store_T0_crf(crfD(ctx->opcode));
-}
-
-/*** Integer logical ***/
-#define __GEN_LOGICAL2(name, opc2, opc3) \
-GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \
-{ \
- gen_op_load_gpr_T0(rS(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
- gen_op_store_T0_gpr(rA(ctx->opcode)); \
-}
-#define GEN_LOGICAL2(name, opc) \
-__GEN_LOGICAL2(name, 0x1C, opc)
-
-#define GEN_LOGICAL1(name, opc) \
-GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \
-{ \
- gen_op_load_gpr_T0(rS(ctx->opcode)); \
- gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
- gen_op_store_T0_gpr(rA(ctx->opcode)); \
-}
-
-/* and & and. */
-GEN_LOGICAL2(and, 0x00);
-/* andc & andc. */
-GEN_LOGICAL2(andc, 0x01);
-/* andi. */
-GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_andi_(UIMM(ctx->opcode));
- gen_op_set_Rc0();
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-/* andis. */
-GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_andi_(UIMM(ctx->opcode) << 16);
- gen_op_set_Rc0();
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-
-/* cntlzw */
-GEN_LOGICAL1(cntlzw, 0x00);
-/* eqv & eqv. */
-GEN_LOGICAL2(eqv, 0x08);
-/* extsb & extsb. */
-GEN_LOGICAL1(extsb, 0x1D);
-/* extsh & extsh. */
-GEN_LOGICAL1(extsh, 0x1C);
-/* nand & nand. */
-GEN_LOGICAL2(nand, 0x0E);
-/* nor & nor. */
-GEN_LOGICAL2(nor, 0x03);
-
-/* or & or. */
-GEN_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();
- }
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-
-/* orc & orc. */
-GEN_LOGICAL2(orc, 0x0C);
-/* xor & xor. */
-GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
-{
- gen_op_load_gpr_T0(rS(ctx->opcode));
- /* Optimisation for "set to zero" case */
- if (rS(ctx->opcode) != rB(ctx->opcode)) {
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_xor();
- } else {
- gen_op_set_T0(0);
- }
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-/* ori */
-GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- uint32_t 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_ori(uimm);
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-/* oris */
-GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- uint32_t 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_ori(uimm << 16);
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-/* xori */
-GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- uint32_t 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);
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-
-/* xoris */
-GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- uint32_t 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);
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-
-/*** Integer rotate ***/
-/* rlwimi & rlwimi. */
-GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- uint32_t mb, me;
-
- mb = MB(ctx->opcode);
- me = ME(ctx->opcode);
- gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_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_store_T0_gpr(rA(ctx->opcode));
-}
-/* rlwinm & rlwinm. */
-GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- uint32_t mb, me, sh;
-
- sh = SH(ctx->opcode);
- mb = MB(ctx->opcode);
- me = ME(ctx->opcode);
- gen_op_load_gpr_T0(rS(ctx->opcode));
-#if 1 // TRY
- if (sh == 0) {
- gen_op_andi_(MASK(mb, me));
- goto store;
- }
-#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
- }
- } else if (me == 31) {
-#if 0
- if (sh == (32 - mb)) {
- gen_op_srwi(mb);
- goto store;
- }
-#endif
- }
- gen_op_rlwinm(sh, MASK(mb, me));
-store:
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-/* rlwnm & rlwnm. */
-GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
-{
- uint32_t mb, me;
-
- mb = MB(ctx->opcode);
- me = ME(ctx->opcode);
- gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- if (mb == 0 && me == 31) {
- gen_op_rotl();
- } else
- {
- gen_op_rlwnm(MASK(mb, me));
- }
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-
-/*** Integer shift ***/
-/* slw & slw. */
-__GEN_LOGICAL2(slw, 0x18, 0x00);
-/* sraw & sraw. */
-__GEN_LOGICAL2(sraw, 0x18, 0x18);
-/* srawi & srawi. */
-GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
-{
- gen_op_load_gpr_T0(rS(ctx->opcode));
- 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();
- gen_op_store_T0_gpr(rA(ctx->opcode));
-}
-/* srw & srw. */
-__GEN_LOGICAL2(srw, 0x18, 0x10);
-
-/*** 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) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
- return; \
- } \
- gen_op_reset_scrfx(); \
- gen_op_load_fpr_FT0(rA(ctx->opcode)); \
- gen_op_load_fpr_FT1(rC(ctx->opcode)); \
- gen_op_load_fpr_FT2(rB(ctx->opcode)); \
- gen_op_f##op(); \
- if (isfloat) { \
- gen_op_frsp(); \
- } \
- gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
- gen_op_set_Rc1(); \
-}
-
-#define GEN_FLOAT_ACB(name, op2) \
-_GEN_FLOAT_ACB(name, name, 0x3F, op2, 0); \
-_GEN_FLOAT_ACB(name##s, name, 0x3B, op2, 1);
-
-#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
-GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
-{ \
- if (!ctx->fpu_enabled) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
- return; \
- } \
- gen_op_reset_scrfx(); \
- gen_op_load_fpr_FT0(rA(ctx->opcode)); \
- gen_op_load_fpr_FT1(rB(ctx->opcode)); \
- gen_op_f##op(); \
- if (isfloat) { \
- gen_op_frsp(); \
- } \
- gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
- gen_op_set_Rc1(); \
-}
-#define GEN_FLOAT_AB(name, op2, inval) \
-_GEN_FLOAT_AB(name, name, 0x3F, op2, inval, 0); \
-_GEN_FLOAT_AB(name##s, name, 0x3B, op2, inval, 1);
-
-#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
-GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
-{ \
- if (!ctx->fpu_enabled) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
- return; \
- } \
- gen_op_reset_scrfx(); \
- gen_op_load_fpr_FT0(rA(ctx->opcode)); \
- gen_op_load_fpr_FT1(rC(ctx->opcode)); \
- gen_op_f##op(); \
- if (isfloat) { \
- gen_op_frsp(); \
- } \
- gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
- gen_op_set_Rc1(); \
-}
-#define GEN_FLOAT_AC(name, op2, inval) \
-_GEN_FLOAT_AC(name, name, 0x3F, op2, inval, 0); \
-_GEN_FLOAT_AC(name##s, name, 0x3B, op2, inval, 1);
-
-#define GEN_FLOAT_B(name, op2, op3) \
-GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
-{ \
- if (!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_f##name(); \
- gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
- 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) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
- return; \
- } \
- gen_op_reset_scrfx(); \
- gen_op_load_fpr_FT0(rB(ctx->opcode)); \
- gen_op_f##name(); \
- gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
- gen_op_set_Rc1(); \
-}
-
-/* fadd - fadds */
-GEN_FLOAT_AB(add, 0x15, 0x000007C0);
-/* fdiv - fdivs */
-GEN_FLOAT_AB(div, 0x12, 0x000007C0);
-/* fmul - fmuls */
-GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
-
-/* fres */
-GEN_FLOAT_BS(res, 0x3B, 0x18);
-
-/* frsqrte */
-GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
-
-/* fsel */
-_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
-/* fsub - fsubs */
-GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
-/* Optional: */
-/* fsqrt */
-GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
-{
- if (!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_fsqrt();
- gen_op_store_FT0_fpr(rD(ctx->opcode));
- if (Rc(ctx->opcode))
- gen_op_set_Rc1();
-}
-
-GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
-{
- if (!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_fsqrt();
- gen_op_frsp();
- gen_op_store_FT0_fpr(rD(ctx->opcode));
- if (Rc(ctx->opcode))
- gen_op_set_Rc1();
-}
-
-/*** Floating-Point multiply-and-add ***/
-/* fmadd - fmadds */
-GEN_FLOAT_ACB(madd, 0x1D);
-/* fmsub - fmsubs */
-GEN_FLOAT_ACB(msub, 0x1C);
-/* fnmadd - fnmadds */
-GEN_FLOAT_ACB(nmadd, 0x1F);
-/* fnmsub - fnmsubs */
-GEN_FLOAT_ACB(nmsub, 0x1E);
-
-/*** Floating-Point round & convert ***/
-/* fctiw */
-GEN_FLOAT_B(ctiw, 0x0E, 0x00);
-/* fctiwz */
-GEN_FLOAT_B(ctiwz, 0x0F, 0x00);
-/* frsp */
-GEN_FLOAT_B(rsp, 0x0C, 0x00);
-
-/*** Floating-Point compare ***/
-/* fcmpo */
-GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
-{
- if (!ctx->fpu_enabled) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
- return;
- }
- gen_op_reset_scrfx();
- gen_op_load_fpr_FT0(rA(ctx->opcode));
- gen_op_load_fpr_FT1(rB(ctx->opcode));
- gen_op_fcmpo();
- gen_op_store_T0_crf(crfD(ctx->opcode));
-}
-
-/* fcmpu */
-GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
-{
- if (!ctx->fpu_enabled) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
- return;
- }
- gen_op_reset_scrfx();
- gen_op_load_fpr_FT0(rA(ctx->opcode));
- gen_op_load_fpr_FT1(rB(ctx->opcode));
- gen_op_fcmpu();
- gen_op_store_T0_crf(crfD(ctx->opcode));
-}
-
-/*** Floating-point move ***/
-/* fabs */
-GEN_FLOAT_B(abs, 0x08, 0x08);
-
-/* fmr - fmr. */
-GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
-{
- if (!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))
- gen_op_set_Rc1();
-}
-
-/* fnabs */
-GEN_FLOAT_B(nabs, 0x08, 0x04);
-/* fneg */
-GEN_FLOAT_B(neg, 0x08, 0x01);
-
-/*** Floating-Point status & ctrl register ***/
-/* mcrfs */
-GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
-{
- if (!ctx->fpu_enabled) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
- return;
- }
- gen_op_load_fpscr_T0(crfS(ctx->opcode));
- gen_op_store_T0_crf(crfD(ctx->opcode));
- gen_op_clear_fpscr(crfS(ctx->opcode));
-}
-
-/* mffs */
-GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
-{
- if (!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))
- gen_op_set_Rc1();
-}
-
-/* mtfsb0 */
-GEN_HANDLER(mtfsb0, 0x3F, 0x06, 0x02, 0x001FF800, PPC_FLOAT)
-{
- uint8_t crb;
-
- if (!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_store_T0_fpscr(crb);
- if (Rc(ctx->opcode))
- gen_op_set_Rc1();
-}
-
-/* mtfsb1 */
-GEN_HANDLER(mtfsb1, 0x3F, 0x06, 0x01, 0x001FF800, PPC_FLOAT)
-{
- uint8_t crb;
-
- if (!ctx->fpu_enabled) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
- return;
- }
- crb = crbD(ctx->opcode) >> 2;
- gen_op_load_fpscr_T0(crb);
- gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
- gen_op_store_T0_fpscr(crb);
- if (Rc(ctx->opcode))
- gen_op_set_Rc1();
-}
-
-/* mtfsf */
-GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
-{
- if (!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))
- gen_op_set_Rc1();
-}
-
-/* mtfsfi */
-GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
-{
- if (!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))
- gen_op_set_Rc1();
-}
-
-/*** Integer load ***/
-#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
-#if defined(CONFIG_USER_ONLY)
-#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, \
-};
-/* 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
-#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, \
-};
-/* 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) \
-{ \
- 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); \
- } \
- 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) \
-{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (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); \
- 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) \
-{ \
- if (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(); \
- 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) \
-{ \
- 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(l##width); \
- gen_op_store_T1_gpr(rD(ctx->opcode)); \
-}
-
-#define GEN_LDS(width, op) \
-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)
-
-/* lbz lbzu lbzux lbzx */
-GEN_LDS(bz, 0x02);
-/* lha lhau lhaux lhax */
-GEN_LDS(ha, 0x0A);
-/* lhz lhzu lhzux lhzx */
-GEN_LDS(hz, 0x08);
-/* lwz lwzu lwzux lwzx */
-GEN_LDS(wz, 0x00);
-
-/*** Integer store ***/
-#define GEN_ST(width, opc) \
-GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
-{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (rA(ctx->opcode) == 0) { \
- gen_op_set_T0(simm); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- } \
- 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) \
-{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (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_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) \
-{ \
- if (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_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) \
-{ \
- 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_gpr_T1(rS(ctx->opcode)); \
- op_ldst(st##width); \
-}
-
-#define GEN_STS(width, op) \
-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)
-
-/* stb stbu stbux stbx */
-GEN_STS(b, 0x06);
-/* sth sthu sthux sthx */
-GEN_STS(h, 0x0C);
-/* stw stwu stwux stwx */
-GEN_STS(w, 0x04);
-
-/*** Integer load and store with byte reverse ***/
-/* lhbrx */
-OP_LD_TABLE(hbr);
-GEN_LDX(hbr, 0x16, 0x18);
-/* lwbrx */
-OP_LD_TABLE(wbr);
-GEN_LDX(wbr, 0x16, 0x10);
-/* sthbrx */
-OP_ST_TABLE(hbr);
-GEN_STX(hbr, 0x16, 0x1C);
-/* stwbrx */
-OP_ST_TABLE(wbr);
-GEN_STX(wbr, 0x16, 0x14);
-
-/*** Integer load and store multiple ***/
-#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
-#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,
-};
-#else
-static GenOpFunc1 *gen_op_lmw[] = {
- &gen_op_lmw_user,
- &gen_op_lmw_le_user,
- &gen_op_lmw_kernel,
- &gen_op_lmw_le_kernel,
-};
-static GenOpFunc1 *gen_op_stmw[] = {
- &gen_op_stmw_user,
- &gen_op_stmw_le_user,
- &gen_op_stmw_kernel,
- &gen_op_stmw_le_kernel,
-};
-#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);
- }
- 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);
- }
- 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(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
-
-/* lswi */
-/* PowerPC32 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...
- */
-GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER)
-{
- int nb = NB(ctx->opcode);
- int start = rD(ctx->opcode);
- int ra = rA(ctx->opcode);
- int nr;
-
- 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)) {
- 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);
- }
- 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);
-}
-
-/* lswx */
-GEN_HANDLER(lswx, 0x1F, 0x15, 0x10, 0x00000001, PPC_INTEGER)
-{
- int ra = rA(ctx->opcode);
- int rb = rB(ctx->opcode);
-
- 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);
-}
-
-/* stswi */
-GEN_HANDLER(stswi, 0x1F, 0x15, 0x16, 0x00000001, PPC_INTEGER)
-{
- int nb = NB(ctx->opcode);
-
- if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(0);
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- }
- 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();
- }
- 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)
-{
-}
-
-/* isync */
-GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM)
-{
-}
-
-#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
-#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
-#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
-
-/* lwarx */
-GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 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();
- }
- op_lwarx();
- gen_op_store_T1_gpr(rD(ctx->opcode));
-}
-
-/* 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_op_load_gpr_T1(rS(ctx->opcode));
- op_stwcx();
-}
-
-/* sync */
-GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
-{
-}
-
-/*** Floating-point load ***/
-#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) { \
- 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); \
- } \
- op_ldst(l##width); \
- gen_op_store_FT1_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) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
- return; \
- } \
- if (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); \
- op_ldst(l##width); \
- gen_op_store_FT1_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) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
- return; \
- } \
- if (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(); \
- op_ldst(l##width); \
- gen_op_store_FT1_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) { \
- 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(); \
- } \
- op_ldst(l##width); \
- gen_op_store_FT1_fpr(rD(ctx->opcode)); \
-}
-
-#define GEN_LDFS(width, op) \
-OP_LD_TABLE(width); \
-GEN_LDF(width, op | 0x20); \
-GEN_LDUF(width, op | 0x21); \
-GEN_LDUXF(width, op | 0x01); \
-GEN_LDXF(width, 0x17, op | 0x00)
-
-/* lfd lfdu lfdux lfdx */
-GEN_LDFS(fd, 0x12);
-/* lfs lfsu lfsux lfsx */
-GEN_LDFS(fs, 0x10);
-
-/*** Floating-point store ***/
-#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) { \
- 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)); \
- 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) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
- return; \
- } \
- if (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)); \
- op_ldst(st##width); \
- gen_op_store_T0_gpr(rA(ctx->opcode)); \
-}
-
-#define GEN_STUXF(width, opc) \
-GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
-{ \
- if (!ctx->fpu_enabled) { \
- RET_EXCP(ctx, EXCP_NO_FP, 0); \
- return; \
- } \
- if (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)); \
- op_ldst(st##width); \
- gen_op_store_T0_gpr(rA(ctx->opcode)); \
-}
-
-#define GEN_STXF(width, opc2, opc3) \
-GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
-{ \
- if (!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)); \
- op_ldst(st##width); \
-}
-
-#define GEN_STFS(width, op) \
-OP_ST_TABLE(width); \
-GEN_STF(width, op | 0x20); \
-GEN_STUF(width, op | 0x21); \
-GEN_STUXF(width, op | 0x01); \
-GEN_STXF(width, 0x17, op | 0x00)
-
-/* stfd stfdu stfdux stfdx */
-GEN_STFS(fd, 0x16);
-/* stfs stfsu stfsux stfsx */
-GEN_STFS(fs, 0x14);
-
-/* Optional: */
-/* stfiwx */
-GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
-{
- if (!ctx->fpu_enabled) {
- RET_EXCP(ctx, EXCP_NO_FP, 0);
- return;
- }
- RET_INVAL(ctx);
-}
-
-/*** Branch ***/
-
-static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
-{
- TranslationBlock *tb;
- tb = ctx->tb;
- if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) {
- if (n == 0)
- gen_op_goto_tb0(TBPARAM(tb));
- else
- gen_op_goto_tb1(TBPARAM(tb));
- gen_op_set_T1(dest);
- 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();
- if (ctx->singlestep_enabled)
- gen_op_debug();
- gen_op_set_T0(0);
- gen_op_exit_tb();
- }
-}
-
-/* b ba bl bla */
-GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
-{
- uint32_t li, target;
-
- /* sign extend LI */
- li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
-
- if (AA(ctx->opcode) == 0)
- target = ctx->nip + li - 4;
- else
- target = li;
- if (LK(ctx->opcode)) {
- gen_op_setlr(ctx->nip);
- }
- gen_goto_tb(ctx, 0, target);
- ctx->exception = EXCP_BRANCH;
-}
-
-#define BCOND_IM 0
-#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;
-
- if ((bo & 0x4) == 0)
- gen_op_dec_ctr();
- switch(type) {
- case BCOND_IM:
- li = (int32_t)((int16_t)(BD(ctx->opcode)));
- if (AA(ctx->opcode) == 0) {
- target = ctx->nip + li - 4;
- } else {
- target = li;
- }
- break;
- case BCOND_CTR:
- gen_op_movl_T1_ctr();
- break;
- default:
- case BCOND_LR:
- gen_op_movl_T1_lr();
- break;
- }
- if (LK(ctx->opcode)) {
- gen_op_setlr(ctx->nip);
- }
- if (bo & 0x10) {
- /* No CR condition */
- switch (bo & 0x6) {
- case 0:
- gen_op_test_ctr();
- break;
- case 2:
- gen_op_test_ctrz();
- break;
- default:
- case 4:
- case 6:
- if (type == BCOND_IM) {
- gen_goto_tb(ctx, 0, target);
- } else {
- gen_op_b_T1();
- }
- 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:
- 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;
- default:
- case 4:
- case 6:
- gen_op_test_false(mask);
- break;
- }
- }
- }
- if (type == BCOND_IM) {
- int l1 = gen_new_label();
- gen_op_jz_T0(l1);
- gen_goto_tb(ctx, 0, target);
- gen_set_label(l1);
- gen_goto_tb(ctx, 1, ctx->nip);
- } else {
- gen_op_btest_T1(ctx->nip);
- }
- no_test:
- 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);
-}
-
-/*** Condition register logical ***/
-#define GEN_CRLOGIC(op, opc) \
-GEN_HANDLER(cr##op, 0x13, 0x01, opc, 0x00000001, PPC_INTEGER) \
-{ \
- gen_op_load_crf_T0(crbA(ctx->opcode) >> 2); \
- gen_op_getbit_T0(3 - (crbA(ctx->opcode) & 0x03)); \
- gen_op_load_crf_T1(crbB(ctx->opcode) >> 2); \
- gen_op_getbit_T1(3 - (crbB(ctx->opcode) & 0x03)); \
- gen_op_##op(); \
- gen_op_load_crf_T1(crbD(ctx->opcode) >> 2); \
- gen_op_setcrfbit(~(1 << (3 - (crbD(ctx->opcode) & 0x03))), \
- 3 - (crbD(ctx->opcode) & 0x03)); \
- gen_op_store_T1_crf(crbD(ctx->opcode) >> 2); \
-}
-
-/* crand */
-GEN_CRLOGIC(and, 0x08)
-/* crandc */
-GEN_CRLOGIC(andc, 0x04)
-/* creqv */
-GEN_CRLOGIC(eqv, 0x09)
-/* crnand */
-GEN_CRLOGIC(nand, 0x07)
-/* crnor */
-GEN_CRLOGIC(nor, 0x01)
-/* cror */
-GEN_CRLOGIC(or, 0x0E)
-/* crorc */
-GEN_CRLOGIC(orc, 0x0D)
-/* crxor */
-GEN_CRLOGIC(xor, 0x06)
-/* mcrf */
-GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
-{
- gen_op_load_crf_T0(crfS(ctx->opcode));
- gen_op_store_T0_crf(crfD(ctx->opcode));
-}
-
-/*** System linkage ***/
-/* rfi (supervisor only) */
-GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
-#else
- /* Restore CPU state */
- if (!ctx->supervisor) {
- RET_PRIVOPC(ctx);
- return;
- }
- gen_op_rfi();
- RET_CHG_FLOW(ctx);
-#endif
-}
-
-/* sc */
-GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_EXCP(ctx, EXCP_SYSCALL_USER, 0);
-#else
- RET_EXCP(ctx, EXCP_SYSCALL, 0);
-#endif
-}
-
-/*** Trap ***/
-/* tw */
-GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
-{
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_tw(TO(ctx->opcode));
-}
-
-/* twi */
-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));
-}
-
-/*** Processor control ***/
-static inline int check_spr_access (int spr, int rw, int supervisor)
-{
- uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1));
-
-#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);
- }
- }
-#endif
- if (rights == 0)
- return -1;
- rights = rights >> (2 * supervisor);
- rights = rights >> rw;
-
- return rights & 1;
-}
-
-/* mcrxr */
-GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
-{
- gen_op_load_xer_cr();
- gen_op_store_T0_crf(crfD(ctx->opcode));
- gen_op_clear_xer_cr();
-}
-
-/* mfcr */
-GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC)
-{
- gen_op_load_cr();
- gen_op_store_T0_gpr(rD(ctx->opcode));
-}
-
-/* mfmsr */
-GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
-#else
- if (!ctx->supervisor) {
- RET_PRIVREG(ctx);
- return;
- }
- gen_op_load_msr();
- gen_op_store_T0_gpr(rD(ctx->opcode));
-#endif
-}
-
-#if 0
-#define SPR_NOACCESS ((void *)(-1))
-#else
-static void spr_noaccess (void *opaque, int sprn)
-{
- sprn = ((sprn >> 5) & 0x1F) | ((sprn & 0x1F) << 5);
- printf("ERROR: try to access SPR %d !\n", sprn);
-}
-#define SPR_NOACCESS (&spr_noaccess)
-#endif
-
-/* mfspr */
-static inline void gen_op_mfspr (DisasContext *ctx)
-{
- void (*read_cb)(void *opaque, int sprn);
- uint32_t sprn = SPR(ctx->opcode);
-
-#if !defined(CONFIG_USER_ONLY)
- if (ctx->supervisor)
- read_cb = ctx->spr_cb[sprn].oea_read;
- else
-#endif
- read_cb = ctx->spr_cb[sprn].uea_read;
- if (read_cb != NULL) {
- if (read_cb != SPR_NOACCESS) {
- (*read_cb)(ctx, sprn);
- gen_op_store_T0_gpr(rD(ctx->opcode));
- } else {
- /* Privilege exception */
- if (loglevel) {
- 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);
- }
- } else {
- /* Not defined */
- if (loglevel) {
- fprintf(logfile, "Trying to read invalid spr %d %03x\n",
- sprn, sprn);
- }
- printf("Trying to read invalid spr %d %03x\n", sprn, sprn);
- RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
- }
-}
-
-GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
-{
- gen_op_mfspr(ctx);
- }
-
-/* mftb */
-GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
-{
- gen_op_mfspr(ctx);
-}
-
-/* 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)
-{
- gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_store_cr(CRM(ctx->opcode));
-}
-
-/* mtmsr */
-GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
-#else
- if (!ctx->supervisor) {
- RET_PRIVREG(ctx);
- return;
- }
- gen_op_update_nip((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
-}
-
-/* mtspr */
-GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
-{
- void (*write_cb)(void *opaque, int sprn);
- uint32_t sprn = SPR(ctx->opcode);
-
-#if !defined(CONFIG_USER_ONLY)
- if (ctx->supervisor)
- write_cb = ctx->spr_cb[sprn].oea_write;
- else
-#endif
- write_cb = ctx->spr_cb[sprn].uea_write;
- if (write_cb != NULL) {
- if (write_cb != SPR_NOACCESS) {
- gen_op_load_gpr_T0(rS(ctx->opcode));
- (*write_cb)(ctx, sprn);
- } else {
- /* Privilege exception */
- if (loglevel) {
- 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);
- }
- } else {
- /* Not defined */
- if (loglevel) {
- fprintf(logfile, "Trying to write invalid spr %d %03x\n",
- sprn, sprn);
- }
- printf("Trying to write invalid spr %d %03x\n", sprn, sprn);
- RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR);
- }
-}
-
-/*** Cache management ***/
-/* For now, all those will be implemented as nop:
- * this is valid, regarding the PowerPC specs...
- * We just have to flush tb while invalidating instruction cache lines...
- */
-/* 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();
- }
- op_ldst(lbz);
-}
-
-/* dcbi (Supervisor only) */
-GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
-#else
- if (!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);
- op_ldst(stb);
-#endif
-}
-
-/* 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();
- }
- op_ldst(lbz);
-}
-
-/* dcbt */
-GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE)
-{
-}
-
-/* dcbtst */
-GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
-{
-}
-
-/* dcbz */
-#if defined(CONFIG_USER_ONLY)
-#define op_dcbz() gen_op_dcbz_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,
-};
-#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();
- }
- op_dcbz();
- gen_op_check_reservation();
-}
-
-/* icbi */
-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();
-}
-
-/* Optional: */
-/* dcba */
-GEN_HANDLER(dcba, 0x1F, 0x16, 0x17, 0x03E00001, PPC_CACHE_OPT)
-{
-}
-
-/*** Segment register manipulation ***/
-/* Supervisor only: */
-/* mfsr */
-GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
-#else
- if (!ctx->supervisor) {
- RET_PRIVREG(ctx);
- return;
- }
- gen_op_load_sr(SR(ctx->opcode));
- gen_op_store_T0_gpr(rD(ctx->opcode));
-#endif
-}
-
-/* mfsrin */
-GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
-#else
- if (!ctx->supervisor) {
- RET_PRIVREG(ctx);
- return;
- }
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_load_srin();
- gen_op_store_T0_gpr(rD(ctx->opcode));
-#endif
-}
-
-/* mtsr */
-GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
-#else
- if (!ctx->supervisor) {
- RET_PRIVREG(ctx);
- return;
- }
- gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_store_sr(SR(ctx->opcode));
- RET_STOP(ctx);
-#endif
-}
-
-/* mtsrin */
-GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVREG(ctx);
-#else
- if (!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();
- RET_STOP(ctx);
-#endif
-}
-
-/*** Lookaside buffer management ***/
-/* Optional & supervisor only: */
-/* tlbia */
-GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_TLBIA)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
-#else
- if (!ctx->supervisor) {
- if (loglevel)
- fprintf(logfile, "%s: ! supervisor\n", __func__);
- RET_PRIVOPC(ctx);
- return;
- }
- gen_op_tlbia();
- RET_STOP(ctx);
-#endif
-}
-
-/* tlbie */
-GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
-#else
- if (!ctx->supervisor) {
- RET_PRIVOPC(ctx);
- return;
- }
- gen_op_load_gpr_T0(rB(ctx->opcode));
- gen_op_tlbie();
- RET_STOP(ctx);
-#endif
-}
-
-/* tlbsync */
-GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
-{
-#if defined(CONFIG_USER_ONLY)
- RET_PRIVOPC(ctx);
-#else
- if (!ctx->supervisor) {
- RET_PRIVOPC(ctx);
- return;
- }
- /* This has no effect: it should ensure that all previous
- * tlbie have completed
- */
- RET_STOP(ctx);
-#endif
-}
-
-/*** External control ***/
-/* Optional: */
-#define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
-#define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
-#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
-
-/* 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();
- }
- op_eciwx();
- gen_op_store_T0_gpr(rD(ctx->opcode));
-}
-
-/* ecowx */
-GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 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_op_load_gpr_T2(rS(ctx->opcode));
- op_ecowx();
-}
-
-/* End opcode list */
-GEN_OPCODE_MARK(end);
-
-#include "translate_init.c"
-
-/*****************************************************************************/
-/* Misc PowerPC helpers */
-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",
- 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++) {
- 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++)
- 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';
- 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)
- cpu_fprintf(f, "FPR%02d", i);
- cpu_fprintf(f, " %016" PRIx64, *((uint64_t *)&env->fpr[i]));
- if ((i & (RFPL - 1)) == (RFPL - 1))
- cpu_fprintf(f, "\n");
- }
- cpu_fprintf(f, "SRR0 " REGX " SRR1 " REGX " " FILL FILL FILL
- "SDR1 " REGX "\n",
- env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
-
-#undef REGX
-#undef RGPL
-#undef RFPL
-#undef FILL
-}
-
-/*****************************************************************************/
-int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
- int search_pc)
-{
- DisasContext ctx, *ctxp = &ctx;
- opc_handler_t **table, *handler;
- target_ulong pc_start;
- uint16_t *gen_opc_end;
- int j, lj = -1;
-
- 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.nip = pc_start;
- ctx.tb = tb;
- ctx.exception = EXCP_NONE;
- ctx.spr_cb = env->spr_cb;
-#if defined(CONFIG_USER_ONLY)
- ctx.mem_idx = msr_le;
-#else
- ctx.supervisor = 1 - msr_pr;
- ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
-#endif
- ctx.fpu_enabled = msr_fp;
- ctx.singlestep_enabled = env->singlestep_enabled;
-#if defined (DO_SINGLE_STEP) && 0
- /* Single step trace mode */
- msr_se = 1;
-#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 (env->breakpoints[j] == ctx.nip) {
- gen_op_update_nip(ctx.nip);
- gen_op_debug();
- 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.nip;
- gen_opc_instr_start[lj] = 1;
- }
- }
-#if defined PPC_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "----------------\n");
- fprintf(logfile, "nip=%08x super=%d ir=%d\n",
- ctx.nip, 1 - msr_pr, msr_ir);
- }
-#endif
- ctx.opcode = ldl_code(ctx.nip);
- if (msr_le) {
- ctx.opcode = ((ctx.opcode & 0xFF000000) >> 24) |
- ((ctx.opcode & 0x00FF0000) >> 8) |
- ((ctx.opcode & 0x0000FF00) << 8) |
- ((ctx.opcode & 0x000000FF) << 24);
- }
-#if defined PPC_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "translate opcode %08x (%02x %02x %02x) (%s)\n",
- ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode),
- opc3(ctx.opcode), msr_le ? "little" : "big");
- }
-#endif
- ctx.nip += 4;
- table = env->opcodes;
- handler = table[opc1(ctx.opcode)];
- if (is_indirect_opcode(handler)) {
- table = ind_table(handler);
- handler = table[opc2(ctx.opcode)];
- if (is_indirect_opcode(handler)) {
- table = ind_table(handler);
- handler = table[opc3(ctx.opcode)];
- }
- }
- /* Is opcode *REALLY* valid ? */
- if (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),
- opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
- } else {
- printf("invalid/unsupported opcode: "
- "%02x - %02x - %02x (%08x) 0x%08x %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) {
- fprintf(logfile, "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),
- 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),
- ctx.opcode, ctx.nip - 4);
- }
- RET_INVAL(ctxp);
- break;
- }
- }
- (*(handler->handler))(&ctx);
- /* 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)) {
- RET_EXCP(ctxp, EXCP_TRACE, 0);
- }
-
- /* if we reach a page boundary or are single stepping, stop
- * generation
- */
- if (((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
- (env->singlestep_enabled)) {
- break;
- }
-#if defined (DO_SINGLE_STEP)
- break;
-#endif
- }
- if (ctx.exception == EXCP_NONE) {
- gen_goto_tb(&ctx, 0, ctx.nip);
- } else if (ctx.exception != EXCP_BRANCH) {
- gen_op_set_T0(0);
- }
-#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) {
- 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 (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) {
- fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
- target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le);
- 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);
-}
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
deleted file mode 100644
index ddf0c91..0000000
--- a/target-ppc/translate_init.c
+++ /dev/null
@@ -1,2067 +0,0 @@
-/*
- * PowerPC CPU initialization for qemu.
- *
- * Copyright (c) 2003-2005 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
- */
-
-/* A lot of PowerPC definition have been included here.
- * Most of them are not usable for now but have been kept
- * inside "#if defined(TODO) ... #endif" statements to make tests easier.
- */
-
-//#define PPC_DUMP_CPU
-//#define PPC_DEBUG_SPR
-
-struct ppc_def_t {
- const unsigned char *name;
- uint32_t pvr;
- uint32_t pvr_mask;
- uint32_t insns_flags;
- uint32_t flags;
- uint64_t msr_mask;
-};
-
-/* Generic callbacks:
- * do nothing but store/retrieve spr value
- */
-static void spr_read_generic (void *opaque, int sprn)
-{
- gen_op_load_spr(sprn);
-}
-
-static void spr_write_generic (void *opaque, int sprn)
-{
- gen_op_store_spr(sprn);
-}
-
-/* SPR common to all PPC */
-/* XER */
-static void spr_read_xer (void *opaque, int sprn)
-{
- gen_op_load_xer();
-}
-
-static void spr_write_xer (void *opaque, int sprn)
-{
- gen_op_store_xer();
-}
-
-/* LR */
-static void spr_read_lr (void *opaque, int sprn)
-{
- gen_op_load_lr();
-}
-
-static void spr_write_lr (void *opaque, int sprn)
-{
- gen_op_store_lr();
-}
-
-/* CTR */
-static void spr_read_ctr (void *opaque, int sprn)
-{
- gen_op_load_ctr();
-}
-
-static void spr_write_ctr (void *opaque, int sprn)
-{
- gen_op_store_ctr();
-}
-
-/* User read access to SPR */
-/* USPRx */
-/* UMMCRx */
-/* UPMCx */
-/* USIA */
-/* UDECR */
-static void spr_read_ureg (void *opaque, int sprn)
-{
- gen_op_load_spr(sprn + 0x10);
-}
-
-/* SPR common to all non-embedded PPC (ie not 4xx) */
-/* DECR */
-static void spr_read_decr (void *opaque, int sprn)
-{
- gen_op_load_decr();
-}
-
-static void spr_write_decr (void *opaque, int sprn)
-{
- gen_op_store_decr();
-}
-
-/* SPR common to all non-embedded PPC, 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)
-{
- gen_op_store_tbl();
-}
-
-static void spr_read_tbu (void *opaque, int sprn)
-{
- gen_op_load_tbu();
-}
-
-static void spr_write_tbu (void *opaque, int sprn)
-{
- gen_op_store_tbu();
-}
-
-/* IBAT0U...IBAT0U */
-/* IBAT0L...IBAT7L */
-static void spr_read_ibat (void *opaque, int sprn)
-{
- gen_op_load_ibat(sprn & 1, (sprn - SPR_IBAT0U) / 2);
-}
-
-static void spr_read_ibat_h (void *opaque, int sprn)
-{
- gen_op_load_ibat(sprn & 1, (sprn - SPR_IBAT4U) / 2);
-}
-
-static void spr_write_ibatu (void *opaque, int sprn)
-{
- DisasContext *ctx = opaque;
-
- gen_op_store_ibatu((sprn - SPR_IBAT0U) / 2);
- RET_STOP(ctx);
-}
-
-static void spr_write_ibatu_h (void *opaque, int sprn)
-{
- DisasContext *ctx = opaque;
-
- gen_op_store_ibatu((sprn - SPR_IBAT4U) / 2);
- RET_STOP(ctx);
-}
-
-static void spr_write_ibatl (void *opaque, int sprn)
-{
- DisasContext *ctx = opaque;
-
- gen_op_store_ibatl((sprn - SPR_IBAT0L) / 2);
- RET_STOP(ctx);
-}
-
-static void spr_write_ibatl_h (void *opaque, int sprn)
-{
- DisasContext *ctx = opaque;
-
- gen_op_store_ibatl((sprn - SPR_IBAT4L) / 2);
- RET_STOP(ctx);
-}
-
-/* DBAT0U...DBAT7U */
-/* DBAT0L...DBAT7L */
-static void spr_read_dbat (void *opaque, int sprn)
-{
- gen_op_load_dbat(sprn & 1, (sprn - SPR_DBAT0U) / 2);
-}
-
-static void spr_read_dbat_h (void *opaque, int sprn)
-{
- gen_op_load_dbat(sprn & 1, (sprn - SPR_DBAT4U) / 2);
-}
-
-static void spr_write_dbatu (void *opaque, int sprn)
-{
- DisasContext *ctx = opaque;
-
- gen_op_store_dbatu((sprn - SPR_DBAT0U) / 2);
- RET_STOP(ctx);
-}
-
-static void spr_write_dbatu_h (void *opaque, int sprn)
-{
- DisasContext *ctx = opaque;
-
- gen_op_store_dbatu((sprn - SPR_DBAT4U) / 2);
- RET_STOP(ctx);
-}
-
-static void spr_write_dbatl (void *opaque, int sprn)
-{
- DisasContext *ctx = opaque;
-
- gen_op_store_dbatl((sprn - SPR_DBAT0L) / 2);
- RET_STOP(ctx);
-}
-
-static void spr_write_dbatl_h (void *opaque, int sprn)
-{
- DisasContext *ctx = opaque;
-
- gen_op_store_dbatl((sprn - SPR_DBAT4L) / 2);
- RET_STOP(ctx);
-}
-
-/* SDR1 */
-static void spr_read_sdr1 (void *opaque, int sprn)
-{
- gen_op_load_sdr1();
-}
-
-static void spr_write_sdr1 (void *opaque, int sprn)
-{
- DisasContext *ctx = opaque;
-
- gen_op_store_sdr1();
- RET_STOP(ctx);
-}
-
-static void spr_write_pir (void *opaque, int sprn)
-{
- gen_op_store_pir();
-}
-
-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),
- void (*oea_read)(void *opaque, int sprn),
- void (*oea_write)(void *opaque, int sprn),
- target_ulong initial_value)
-{
- 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) {
- 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);
-#endif
- spr->name = name;
- spr->uea_read = uea_read;
- spr->uea_write = uea_write;
- spr->oea_read = oea_read;
- spr->oea_write = oea_write;
- env->spr[num] = initial_value;
-}
-
-/* Generic PowerPC SPRs */
-static void gen_spr_generic (CPUPPCState *env)
-{
- /* Integer processing */
- spr_register(env, SPR_XER, "XER",
- &spr_read_xer, &spr_write_xer,
- &spr_read_xer, &spr_write_xer,
- 0x00000000);
- /* Branch contol */
- spr_register(env, SPR_LR, "LR",
- &spr_read_lr, &spr_write_lr,
- &spr_read_lr, &spr_write_lr,
- 0x00000000);
- spr_register(env, SPR_CTR, "CTR",
- &spr_read_ctr, &spr_write_ctr,
- &spr_read_ctr, &spr_write_ctr,
- 0x00000000);
- /* Interrupt processing */
- spr_register(env, SPR_SRR0, "SRR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- spr_register(env, SPR_SRR1, "SRR1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Processor control */
- spr_register(env, SPR_SPRG0, "SPRG0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- spr_register(env, SPR_SPRG1, "SPRG1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- spr_register(env, SPR_SPRG2, "SPRG2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- spr_register(env, SPR_SPRG3, "SPRG3",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
-}
-
-/* SPR common to all non-embedded PowerPC, including 601 */
-static void gen_spr_ne_601 (CPUPPCState *env)
-{
- /* Exception processing */
- spr_register(env, SPR_DSISR, "DSISR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- spr_register(env, SPR_DAR, "DAR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Timer */
- spr_register(env, SPR_DECR, "DECR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_decr, &spr_write_decr,
- 0x00000000);
- /* Memory management */
- spr_register(env, SPR_SDR1, "SDR1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_sdr1, &spr_write_sdr1,
- 0x00000000);
-}
-
-/* BATs 0-3 */
-static void gen_low_BATs (CPUPPCState *env)
-{
- spr_register(env, SPR_IBAT0U, "IBAT0U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat, &spr_write_ibatu,
- 0x00000000);
- spr_register(env, SPR_IBAT0L, "IBAT0L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat, &spr_write_ibatl,
- 0x00000000);
- spr_register(env, SPR_IBAT1U, "IBAT1U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat, &spr_write_ibatu,
- 0x00000000);
- spr_register(env, SPR_IBAT1L, "IBAT1L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat, &spr_write_ibatl,
- 0x00000000);
- spr_register(env, SPR_IBAT2U, "IBAT2U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat, &spr_write_ibatu,
- 0x00000000);
- spr_register(env, SPR_IBAT2L, "IBAT2L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat, &spr_write_ibatl,
- 0x00000000);
- spr_register(env, SPR_IBAT3U, "IBAT3U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat, &spr_write_ibatu,
- 0x00000000);
- spr_register(env, SPR_IBAT3L, "IBAT3L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat, &spr_write_ibatl,
- 0x00000000);
- spr_register(env, SPR_DBAT0U, "DBAT0U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat, &spr_write_dbatu,
- 0x00000000);
- spr_register(env, SPR_DBAT0L, "DBAT0L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat, &spr_write_dbatl,
- 0x00000000);
- spr_register(env, SPR_DBAT1U, "DBAT1U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat, &spr_write_dbatu,
- 0x00000000);
- spr_register(env, SPR_DBAT1L, "DBAT1L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat, &spr_write_dbatl,
- 0x00000000);
- spr_register(env, SPR_DBAT2U, "DBAT2U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat, &spr_write_dbatu,
- 0x00000000);
- spr_register(env, SPR_DBAT2L, "DBAT2L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat, &spr_write_dbatl,
- 0x00000000);
- spr_register(env, SPR_DBAT3U, "DBAT3U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat, &spr_write_dbatu,
- 0x00000000);
- spr_register(env, SPR_DBAT3L, "DBAT3L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat, &spr_write_dbatl,
- 0x00000000);
- env->nb_BATs = 4;
-}
-
-/* BATs 4-7 */
-static void gen_high_BATs (CPUPPCState *env)
-{
- spr_register(env, SPR_IBAT4U, "IBAT4U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat_h, &spr_write_ibatu_h,
- 0x00000000);
- spr_register(env, SPR_IBAT4L, "IBAT4L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat_h, &spr_write_ibatl_h,
- 0x00000000);
- spr_register(env, SPR_IBAT5U, "IBAT5U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat_h, &spr_write_ibatu_h,
- 0x00000000);
- spr_register(env, SPR_IBAT5L, "IBAT5L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat_h, &spr_write_ibatl_h,
- 0x00000000);
- spr_register(env, SPR_IBAT6U, "IBAT6U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat_h, &spr_write_ibatu_h,
- 0x00000000);
- spr_register(env, SPR_IBAT6L, "IBAT6L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat_h, &spr_write_ibatl_h,
- 0x00000000);
- spr_register(env, SPR_IBAT7U, "IBAT7U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat_h, &spr_write_ibatu_h,
- 0x00000000);
- spr_register(env, SPR_IBAT7L, "IBAT7L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_ibat_h, &spr_write_ibatl_h,
- 0x00000000);
- spr_register(env, SPR_DBAT4U, "DBAT4U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat_h, &spr_write_dbatu_h,
- 0x00000000);
- spr_register(env, SPR_DBAT4L, "DBAT4L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat_h, &spr_write_dbatl_h,
- 0x00000000);
- spr_register(env, SPR_DBAT5U, "DBAT5U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat_h, &spr_write_dbatu_h,
- 0x00000000);
- spr_register(env, SPR_DBAT5L, "DBAT5L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat_h, &spr_write_dbatl_h,
- 0x00000000);
- spr_register(env, SPR_DBAT6U, "DBAT6U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat_h, &spr_write_dbatu_h,
- 0x00000000);
- spr_register(env, SPR_DBAT6L, "DBAT6L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat_h, &spr_write_dbatl_h,
- 0x00000000);
- spr_register(env, SPR_DBAT7U, "DBAT7U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat_h, &spr_write_dbatu_h,
- 0x00000000);
- spr_register(env, SPR_DBAT7L, "DBAT7L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_dbat_h, &spr_write_dbatl_h,
- 0x00000000);
- env->nb_BATs = 8;
-}
-
-/* Generic PowerPC time base */
-static void gen_tbl (CPUPPCState *env)
-{
- spr_register(env, SPR_VTBL, "TBL",
- &spr_read_tbl, SPR_NOACCESS,
- &spr_read_tbl, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_TBL, "TBL",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, &spr_write_tbl,
- 0x00000000);
- spr_register(env, SPR_VTBU, "TBU",
- &spr_read_tbu, SPR_NOACCESS,
- &spr_read_tbu, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_TBU, "TBU",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, &spr_write_tbu,
- 0x00000000);
-}
-
-/* SPR common to all 7xx PowerPC implementations */
-static void gen_spr_7xx (CPUPPCState *env)
-{
- /* 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_IABR, "IABR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Cache management */
- /* XXX : not implemented */
- spr_register(env, SPR_ICTC, "ICTC",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Performance monitors */
- /* XXX : not implemented */
- spr_register(env, SPR_MMCR0, "MMCR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_MMCR1, "MMCR1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_PMC1, "PMC1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_PMC2, "PMC2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_PMC3, "PMC3",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_PMC4, "PMC4",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_SIA, "SIA",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_UMMCR0, "UMMCR0",
- &spr_read_ureg, SPR_NOACCESS,
- &spr_read_ureg, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_UMMCR1, "UMMCR1",
- &spr_read_ureg, SPR_NOACCESS,
- &spr_read_ureg, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_UPMC1, "UPMC1",
- &spr_read_ureg, SPR_NOACCESS,
- &spr_read_ureg, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_UPMC2, "UPMC2",
- &spr_read_ureg, SPR_NOACCESS,
- &spr_read_ureg, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_UPMC3, "UPMC3",
- &spr_read_ureg, SPR_NOACCESS,
- &spr_read_ureg, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_UPMC4, "UPMC4",
- &spr_read_ureg, SPR_NOACCESS,
- &spr_read_ureg, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_USIA, "USIA",
- &spr_read_ureg, SPR_NOACCESS,
- &spr_read_ureg, SPR_NOACCESS,
- 0x00000000);
- /* Thermal management */
- /* XXX : not implemented */
- spr_register(env, SPR_THRM1, "THRM1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_THRM2, "THRM2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_THRM3, "THRM3",
- 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 specific to PowerPC 604 implementation */
-static void gen_spr_604 (CPUPPCState *env)
-{
- /* Processor identification */
- spr_register(env, SPR_PIR, "PIR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_pir,
- 0x00000000);
- /* Breakpoints */
- /* 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_DABR, "DABR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Performance counters */
- /* XXX : not implemented */
- spr_register(env, SPR_MMCR0, "MMCR0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_MMCR1, "MMCR1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_PMC1, "PMC1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_PMC2, "PMC2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_PMC3, "PMC3",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_PMC4, "PMC4",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_SIA, "SIA",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_SDA, "SDA",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, SPR_NOACCESS,
- 0x00000000);
- /* External access control */
- /* XXX : not implemented */
- spr_register(env, SPR_EAR, "EAR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
-}
-
-// XXX: TODO (64 bits PPC sprs)
-/*
- * ASR => SPR 280 (64 bits)
- * FPECR => SPR 1022 (?)
- * VRSAVE => SPR 256 (Altivec)
- * SCOMC => SPR 276 (64 bits ?)
- * SCOMD => SPR 277 (64 bits ?)
- * HSPRG0 => SPR 304 (hypervisor)
- * HSPRG1 => SPR 305 (hypervisor)
- * HDEC => SPR 310 (hypervisor)
- * HIOR => SPR 311 (hypervisor)
- * RMOR => SPR 312 (970)
- * HRMOR => SPR 313 (hypervisor)
- * HSRR0 => SPR 314 (hypervisor)
- * HSRR1 => SPR 315 (hypervisor)
- * LPCR => SPR 316 (970)
- * LPIDR => SPR 317 (970)
- * ... and more (thermal management, performance counters, ...)
- */
-
-static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
-{
- /* Default MMU definitions */
- env->nb_BATs = -1;
- env->nb_tlb = 0;
- env->nb_ways = 0;
- /* XXX: missing:
- * 32 bits PPC:
- * - MPC5xx(x)
- * - MPC8xx(x)
- * - RCPU (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 */
- 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",
- 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);
- break;
-
- case CPU_PPC_74x: /* PPC 740 / 750 */
- case CPU_PPC_74xP: /* PPC 740P / 750P */
- case CPU_PPC_750CXE: /* IBM PPC 750cxe */
- gen_spr_generic(env);
- gen_spr_ne_601(env);
- /* Memory management */
- gen_low_BATs(env);
- /* Time base */
- gen_tbl(env);
- gen_spr_7xx(env);
- /* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* 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);
- break;
-
- case CPU_PPC_750FX: /* IBM PPC 750 FX */
- case CPU_PPC_750GX: /* IBM PPC 750 GX */
- 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);
- /* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* 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);
- break;
-
- default:
- gen_spr_generic(env);
- break;
- }
- if (env->nb_BATs == -1)
- env->nb_BATs = 4;
-}
-
-#if defined(PPC_DUMP_CPU)
-static void dump_sprs (CPUPPCState *env)
-{
- ppc_spr_t *spr;
- uint32_t pvr = env->spr[SPR_PVR];
- uint32_t sr, sw, ur, uw;
- int i, j, n;
-
- printf("* SPRs for PVR=%08x\n", pvr);
- for (i = 0; i < 32; i++) {
- for (j = 0; j < 32; j++) {
- n = (i << 5) | j;
- spr = &env->spr_cb[n];
- sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS;
- sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS;
- 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) {
- printf("%4d (%03x) %8s s%c%c u%c%c\n",
- (i << 5) | j, (i << 5) | j, spr->name,
- sw ? 'w' : '-', sr ? 'r' : '-',
- uw ? 'w' : '-', ur ? 'r' : '-');
- }
- }
- }
- fflush(stdout);
- fflush(stderr);
-}
-#endif
-
-/*****************************************************************************/
-#include <stdlib.h>
-#include <string.h>
-
-int fflush (FILE *stream);
-
-/* Opcode types */
-enum {
- PPC_DIRECT = 0, /* Opcode routine */
- PPC_INDIRECT = 1, /* Indirect opcode table */
-};
-
-static inline int is_indirect_opcode (void *handler)
-{
- return ((unsigned long)handler & 0x03) == PPC_INDIRECT;
-}
-
-static inline opc_handler_t **ind_table(void *handler)
-{
- return (opc_handler_t **)((unsigned long)handler & ~3);
-}
-
-/* Instruction table creation */
-/* Opcodes tables creation */
-static void fill_new_table (opc_handler_t **table, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- table[i] = &invalid_handler;
-}
-
-static int create_new_table (opc_handler_t **table, unsigned char idx)
-{
- opc_handler_t **tmp;
-
- tmp = malloc(0x20 * sizeof(opc_handler_t));
- if (tmp == NULL)
- return -1;
- fill_new_table(tmp, 0x20);
- table[idx] = (opc_handler_t *)((unsigned long)tmp | PPC_INDIRECT);
-
- return 0;
-}
-
-static int insert_in_table (opc_handler_t **table, unsigned char idx,
- opc_handler_t *handler)
-{
- if (table[idx] != &invalid_handler)
- return -1;
- table[idx] = handler;
-
- return 0;
-}
-
-static int register_direct_insn (opc_handler_t **ppc_opcodes,
- unsigned char idx, opc_handler_t *handler)
-{
- if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
- printf("*** ERROR: opcode %02x already assigned in main "
- "opcode table\n", idx);
- return -1;
- }
-
- return 0;
-}
-
-static int register_ind_in_table (opc_handler_t **table,
- unsigned char idx1, unsigned char idx2,
- opc_handler_t *handler)
-{
- if (table[idx1] == &invalid_handler) {
- if (create_new_table(table, idx1) < 0) {
- printf("*** ERROR: unable to create indirect table "
- "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);
- 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);
- return -1;
- }
-
- return 0;
-}
-
-static int register_ind_insn (opc_handler_t **ppc_opcodes,
- unsigned char idx1, unsigned char idx2,
- opc_handler_t *handler)
-{
- int ret;
-
- ret = register_ind_in_table(ppc_opcodes, idx1, idx2, handler);
-
- return ret;
-}
-
-static int register_dblind_insn (opc_handler_t **ppc_opcodes,
- unsigned char idx1, unsigned char idx2,
- 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);
- 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);
- return -1;
- }
-
- return 0;
-}
-
-static int register_insn (opc_handler_t **ppc_opcodes, opcode_t *insn)
-{
- if (insn->opc2 != 0xFF) {
- if (insn->opc3 != 0xFF) {
- if (register_dblind_insn(ppc_opcodes, insn->opc1, insn->opc2,
- insn->opc3, &insn->handler) < 0)
- return -1;
- } else {
- if (register_ind_insn(ppc_opcodes, insn->opc1,
- insn->opc2, &insn->handler) < 0)
- return -1;
- }
- } else {
- if (register_direct_insn(ppc_opcodes, insn->opc1, &insn->handler) < 0)
- return -1;
- }
-
- return 0;
-}
-
-static int test_opcode_table (opc_handler_t **table, int len)
-{
- int i, count, tmp;
-
- for (i = 0, count = 0; i < len; i++) {
- /* Consistency fixup */
- if (table[i] == NULL)
- table[i] = &invalid_handler;
- if (table[i] != &invalid_handler) {
- if (is_indirect_opcode(table[i])) {
- tmp = test_opcode_table(ind_table(table[i]), 0x20);
- if (tmp == 0) {
- free(table[i]);
- table[i] = &invalid_handler;
- } else {
- count++;
- }
- } else {
- count++;
- }
- }
- }
-
- return count;
-}
-
-static void fix_opcode_tables (opc_handler_t **ppc_opcodes)
-{
- if (test_opcode_table(ppc_opcodes, 0x40) == 0)
- printf("*** WARNING: no opcode defined !\n");
-}
-
-/*****************************************************************************/
-static int create_ppc_opcodes (CPUPPCState *env, ppc_def_t *def)
-{
- opcode_t *opc, *start, *end;
-
- fill_new_table(env->opcodes, 0x40);
-#if defined(PPC_DUMP_CPU)
- printf("* PPC instructions for PVR %08x: %s\n", def->pvr, def->name);
-#endif
- if (&opc_start < &opc_end) {
- start = &opc_start;
- end = &opc_end;
- } else {
- 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);
- return -1;
- }
-#if defined(PPC_DUMP_CPU)
- if (opc1 != 0x00) {
- if (opc->opc3 == 0xFF) {
- if (opc->opc2 == 0xFF) {
- printf(" %02x -- -- (%2d ----) : %s\n",
- opc->opc1, opc->opc1, opc->oname);
- } else {
- printf(" %02x %02x -- (%2d %4d) : %s\n",
- opc->opc1, opc->opc2, opc->opc1, opc->opc2,
- opc->oname);
- }
- } else {
- printf(" %02x %02x %02x (%2d %4d) : %s\n",
- opc->opc1, opc->opc2, opc->opc3,
- opc->opc1, (opc->opc3 << 5) | opc->opc2,
- opc->oname);
- }
- }
-#endif
- }
- }
- fix_opcode_tables(env->opcodes);
- fflush(stdout);
- fflush(stderr);
-
- return 0;
-}
-
-int cpu_ppc_register (CPUPPCState *env, ppc_def_t *def)
-{
- 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);
- return -1;
- }
- init_ppc_proc(env, def);
-#if defined(PPC_DUMP_CPU)
- dump_sprs(env);
-#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 */
-#if defined (TODO)
- /* PPC 401 */
- {
- .name = "401",
- .pvr = CPU_PPC_401,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_401,
- .flags = PPC_FLAGS_401,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* IOP480 (401 microcontroler) */
- {
- .name = "iop480",
- .pvr = CPU_PPC_IOP480,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_401,
- .flags = PPC_FLAGS_401,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* PPC 403 GA */
- {
- .name = "403ga",
- .pvr = CPU_PPC_403GA,
- .pvr_mask = 0xFFFFFF00,
- .insns_flags = PPC_INSNS_403,
- .flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
- },
-#endif
-#if defined (TODO)
- /* PPC 403 GB */
- {
- .name = "403gb",
- .pvr = CPU_PPC_403GB,
- .pvr_mask = 0xFFFFFF00,
- .insns_flags = PPC_INSNS_403,
- .flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
- },
-#endif
-#if defined (TODO)
- /* PPC 403 GC */
- {
- .name = "403gc",
- .pvr = CPU_PPC_403GC,
- .pvr_mask = 0xFFFFFF00,
- .insns_flags = PPC_INSNS_403,
- .flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
- },
-#endif
-#if defined (TODO)
- /* PPC 403 GCX */
- {
- .name = "403gcx",
- .pvr = CPU_PPC_403GCX,
- .pvr_mask = 0xFFFFFF00,
- .insns_flags = PPC_INSNS_403,
- .flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
- },
-#endif
-#if defined (TODO)
- /* PPC 405 CR */
- {
- .name = "405cr",
- .pvr = CPU_PPC_405,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* PPC 405 GP */
- {
- .name = "405gp",
- .pvr = CPU_PPC_405,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* PPC 405 EP */
- {
- .name = "405ep",
- .pvr = CPU_PPC_405EP,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* PPC 405 GPR */
- {
- .name = "405gpr",
- .pvr = CPU_PPC_405GPR,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* PPC 405 D2 */
- {
- .name = "405d2",
- .pvr = CPU_PPC_405D2,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* PPC 405 D4 */
- {
- .name = "405d4",
- .pvr = CPU_PPC_405D4,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* Npe405 H */
- {
- .name = "Npe405H",
- .pvr = CPU_PPC_NPE405H,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* Npe405 L */
- {
- .name = "Npe405L",
- .pvr = CPU_PPC_NPE405L,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* STB03xx */
- {
- .name = "STB03",
- .pvr = CPU_PPC_STB03,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* STB04xx */
- {
- .name = "STB04",
- .pvr = CPU_PPC_STB04,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* STB25xx */
- {
- .name = "STB25",
- .pvr = CPU_PPC_STB25,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
- },
-#endif
-#if defined (TODO)
- /* PPC 440 EP */
- {
- .name = "440ep",
- .pvr = CPU_PPC_440EP,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_440,
- .flags = PPC_FLAGS_440,
- .msr_mask = 0x000000000006D630,
- },
-#endif
-#if defined (TODO)
- /* PPC 440 GP */
- {
- .name = "440gp",
- .pvr = CPU_PPC_440GP,
- .pvr_mask = 0xFFFFFF00,
- .insns_flags = PPC_INSNS_440,
- .flags = PPC_FLAGS_440,
- .msr_mask = 0x000000000006D630,
- },
-#endif
-#if defined (TODO)
- /* PPC 440 GX */
- {
- .name = "440gx",
- .pvr = CPU_PPC_440GX,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
- .flags = PPC_FLAGS_440,
- .msr_mask = 0x000000000006D630,
- },
-#endif
-
- /* 32 bits "classic" powerpc */
-#if defined (TODO)
- /* PPC 601 */
- {
- .name = "601",
- .pvr = CPU_PPC_601,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_601,
- .flags = PPC_FLAGS_601,
- .msr_mask = 0x000000000000FD70,
- },
-#endif
-#if defined (TODO)
- /* PPC 602 */
- {
- .name = "602",
- .pvr = CPU_PPC_602,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_602,
- .flags = PPC_FLAGS_602,
- .msr_mask = 0x0000000000C7FF73,
- },
-#endif
-#if defined (TODO)
- /* PPC 603 */
- {
- .name = "603",
- .pvr = CPU_PPC_603,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
-#endif
-#if defined (TODO)
- /* PPC 603e */
- {
- .name = "603e",
- .pvr = CPU_PPC_603E,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
- {
- .name = "Stretch",
- .pvr = CPU_PPC_603E,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
-#endif
-#if defined (TODO)
- /* PPC 603ev */
- {
- .name = "603ev",
- .pvr = CPU_PPC_603EV,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
-#endif
-#if defined (TODO)
- /* PPC 603r */
- {
- .name = "603r",
- .pvr = CPU_PPC_603R,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
- {
- .name = "Goldeneye",
- .pvr = CPU_PPC_603R,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_603,
- .flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
- },
-#endif
-#if defined (TODO)
- /* XXX: TODO: according to Motorola UM, this is a derivative to 603e */
- {
- .name = "G2",
- .pvr = CPU_PPC_G2,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_G2,
- .flags = PPC_FLAGS_G2,
- .msr_mask = 0x000000000006FFF2,
- },
- { /* 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,
- },
-#endif
- /* PPC 604 */
- {
- .name = "604",
- .pvr = CPU_PPC_604,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_604,
- .flags = PPC_FLAGS_604,
- .msr_mask = 0x000000000005FF77,
- },
- /* PPC 604e */
- {
- .name = "604e",
- .pvr = CPU_PPC_604E,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_604,
- .flags = PPC_FLAGS_604,
- .msr_mask = 0x000000000005FF77,
- },
- /* PPC 604r */
- {
- .name = "604r",
- .pvr = CPU_PPC_604R,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_604,
- .flags = PPC_FLAGS_604,
- .msr_mask = 0x000000000005FF77,
- },
- /* generic G3 */
- {
- .name = "G3",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
-#if defined (TODO)
- /* MPC740 (G3) */
- {
- .name = "740",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
- {
- .name = "Arthur",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
-#endif
-#if defined (TODO)
- /* MPC745 (G3) */
- {
- .name = "745",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x5,
- .flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
- },
- {
- .name = "Goldfinger",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x5,
- .flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
- },
-#endif
- /* MPC750 (G3) */
- {
- .name = "750",
- .pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
-#if defined (TODO)
- /* MPC755 (G3) */
- {
- .name = "755",
- .pvr = CPU_PPC_755,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x5,
- .flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
- },
-#endif
-#if defined (TODO)
- /* MPC740P (G3) */
- {
- .name = "740p",
- .pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
- {
- .name = "Conan/Doyle",
- .pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
-#endif
-#if defined (TODO)
- /* MPC745P (G3) */
- {
- .name = "745p",
- .pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x5,
- .flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
- },
-#endif
- /* MPC750P (G3) */
- {
- .name = "750p",
- .pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
-#if defined (TODO)
- /* MPC755P (G3) */
- {
- .name = "755p",
- .pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x5,
- .flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
- },
-#endif
- /* IBM 750CXe (G3 embedded) */
- {
- .name = "750cxe",
- .pvr = CPU_PPC_750CXE,
- .pvr_mask = 0xFFFFF000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
- /* IBM 750FX (G3 embedded) */
- {
- .name = "750fx",
- .pvr = CPU_PPC_750FX,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
- /* IBM 750GX (G3 embedded) */
- {
- .name = "750gx",
- .pvr = CPU_PPC_750GX,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_7x0,
- .flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
- },
-#if defined (TODO)
- /* generic G4 */
- {
- .name = "G4",
- .pvr = CPU_PPC_7400,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
-#endif
-#if defined (TODO)
- /* PPC 7400 (G4) */
- {
- .name = "7400",
- .pvr = CPU_PPC_7400,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Max",
- .pvr = CPU_PPC_7400,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
-#endif
-#if defined (TODO)
- /* PPC 7410 (G4) */
- {
- .name = "7410",
- .pvr = CPU_PPC_7410,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Nitro",
- .pvr = CPU_PPC_7410,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
-#endif
- /* XXX: 7441 */
- /* XXX: 7445 */
- /* XXX: 7447 */
- /* XXX: 7447A */
-#if defined (TODO)
- /* PPC 7450 (G4) */
- {
- .name = "7450",
- .pvr = CPU_PPC_7450,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Vger",
- .pvr = CPU_PPC_7450,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
-#endif
- /* XXX: 7451 */
-#if defined (TODO)
- /* PPC 7455 (G4) */
- {
- .name = "7455",
- .pvr = CPU_PPC_7455,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Apollo 6",
- .pvr = CPU_PPC_7455,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
-#endif
-#if defined (TODO)
- /* PPC 7457 (G4) */
- {
- .name = "7457",
- .pvr = CPU_PPC_7457,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Apollo 7",
- .pvr = CPU_PPC_7457,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
-#endif
-#if defined (TODO)
- /* PPC 7457A (G4) */
- {
- .name = "7457A",
- .pvr = CPU_PPC_7457A,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
- {
- .name = "Apollo 7 PM",
- .pvr = CPU_PPC_7457A,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_74xx,
- .flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
- },
-#endif
- /* 64 bits PPC */
-#if defined (TODO)
- /* PPC 620 */
- {
- .name = "620",
- .pvr = CPU_PPC_620,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_620,
- .flags = PPC_FLAGS_620,
- .msr_mask = 0x800000000005FF73,
- },
-#endif
-#if defined (TODO)
- /* PPC 630 (POWER3) */
- {
- .name = "630",
- .pvr = CPU_PPC_630,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_630,
- .flags = PPC_FLAGS_630,
- .msr_mask = xxx,
- }
- {
- .name = "POWER3",
- .pvr = CPU_PPC_630,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_630,
- .flags = PPC_FLAGS_630,
- .msr_mask = xxx,
- }
-#endif
-#if defined (TODO)
- /* PPC 631 (Power 3+)*/
- {
- .name = "631",
- .pvr = CPU_PPC_631,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_631,
- .flags = PPC_FLAGS_631,
- .msr_mask = xxx,
- },
- {
- .name = "POWER3+",
- .pvr = CPU_PPC_631,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_631,
- .flags = PPC_FLAGS_631,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* POWER4 */
- {
- .name = "POWER4",
- .pvr = CPU_PPC_POWER4,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER4,
- .flags = PPC_FLAGS_POWER4,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* POWER4p */
- {
- .name = "POWER4+",
- .pvr = CPU_PPC_POWER4P,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER4,
- .flags = PPC_FLAGS_POWER4,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* POWER5 */
- {
- .name = "POWER5",
- .pvr = CPU_PPC_POWER5,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER5,
- .flags = PPC_FLAGS_POWER5,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* POWER5+ */
- {
- .name = "POWER5+",
- .pvr = CPU_PPC_POWER5P,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER5,
- .flags = PPC_FLAGS_POWER5,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* PPC 970 */
- {
- .name = "970",
- .pvr = CPU_PPC_970,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_970,
- .flags = PPC_FLAGS_970,
- .msr_mask = 0x900000000204FF36,
- },
-#endif
-#if defined (TODO)
- /* PPC 970FX (G5) */
- {
- .name = "970fx",
- .pvr = CPU_PPC_970FX,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_970FX,
- .flags = PPC_FLAGS_970FX,
- .msr_mask = 0x800000000204FF36,
- },
-#endif
-#if defined (TODO)
- /* RS64 (Apache/A35) */
- /* This one seems to support the whole POWER2 instruction set
- * and the PowerPC 64 one.
- */
- {
- .name = "RS64",
- .pvr = CPU_PPC_RS64,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "Apache",
- .pvr = CPU_PPC_RS64,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "A35",
- .pvr = CPU_PPC_RS64,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* RS64-II (NorthStar/A50) */
- {
- .name = "RS64-II",
- .pvr = CPU_PPC_RS64II,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "NortStar",
- .pvr = CPU_PPC_RS64II,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "A50",
- .pvr = CPU_PPC_RS64II,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* RS64-III (Pulsar) */
- {
- .name = "RS64-III",
- .pvr = CPU_PPC_RS64III,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "Pulsar",
- .pvr = CPU_PPC_RS64III,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* RS64-IV (IceStar/IStar/SStar) */
- {
- .name = "RS64-IV",
- .pvr = CPU_PPC_RS64IV,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "IceStar",
- .pvr = CPU_PPC_RS64IV,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "IStar",
- .pvr = CPU_PPC_RS64IV,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
- {
- .name = "SStar",
- .pvr = CPU_PPC_RS64IV,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_RS64,
- .flags = PPC_FLAGS_RS64,
- .msr_mask = xxx,
- },
-#endif
- /* POWER */
-#if defined (TODO)
- /* Original POWER */
- {
- .name = "POWER",
- .pvr = CPU_POWER,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER,
- .flags = PPC_FLAGS_POWER,
- .msr_mask = xxx,
- },
-#endif
-#if defined (TODO)
- /* POWER2 */
- {
- .name = "POWER2",
- .pvr = CPU_POWER2,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_POWER,
- .flags = PPC_FLAGS_POWER,
- .msr_mask = xxx,
- },
-#endif
- /* Generic PowerPCs */
-#if defined (TODO)
- {
- .name = "ppc64",
- .pvr = CPU_PPC_970,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_PPC64,
- .flags = PPC_FLAGS_PPC64,
- .msr_mask = 0xA00000000204FF36,
- },
-#endif
- {
- .name = "ppc32",
- .pvr = CPU_PPC_604,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_PPC32,
- .flags = PPC_FLAGS_PPC32,
- .msr_mask = 0x000000000005FF77,
- },
- /* Fallback */
- {
- .name = "ppc",
- .pvr = CPU_PPC_604,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_PPC32,
- .flags = PPC_FLAGS_PPC32,
- .msr_mask = 0x000000000005FF77,
- },
-};
-
-int ppc_find_by_name (const unsigned char *name, ppc_def_t **def)
-{
- int i, ret;
-
- ret = -1;
- *def = NULL;
- for (i = 0; strcmp(ppc_defs[i].name, "ppc") != 0; i++) {
- if (strcasecmp(name, ppc_defs[i].name) == 0) {
- *def = &ppc_defs[i];
- ret = 0;
- break;
- }
- }
-
- return ret;
-}
-
-int ppc_find_by_pvr (uint32_t pvr, ppc_def_t **def)
-{
- int i, ret;
-
- ret = -1;
- *def = NULL;
- for (i = 0; ppc_defs[i].name != NULL; i++) {
- if ((pvr & ppc_defs[i].pvr_mask) ==
- (ppc_defs[i].pvr & ppc_defs[i].pvr_mask)) {
- *def = &ppc_defs[i];
- ret = 0;
- break;
- }
- }
-
- return ret;
-}
-
-void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
-{
- int i;
-
- for (i = 0; ; i++) {
- (*cpu_fprintf)(f, "PowerPC '%s' 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)
- break;
- }
-}
diff --git a/target-sh4/README.sh4 b/target-sh4/README.sh4
deleted file mode 100644
index b887175..0000000
--- a/target-sh4/README.sh4
+++ /dev/null
@@ -1,150 +0,0 @@
-qemu target: sh4
-author: Samuel Tardieu <sam@rfc1149.net>
-last modified: Tue Dec 6 07:22:44 CET 2005
-
-The sh4 target is not ready at all yet for integration in qemu. This
-file describes the current state of implementation.
-
-Most places requiring attention and/or modification can be detected by
-looking for "XXXXX" or "assert (0)".
-
-The sh4 core is located in target-sh4/*, while the 7750 peripheral
-features (IO ports for example) are located in hw/sh7750.[ch]. The
-main board description is in hw/shix.c, and the NAND flash in
-hw/tc58128.[ch].
-
-All the shortcomings indicated here will eventually be resolved. This
-is a work in progress. Features are added in a semi-random order: if a
-point is blocking to progress on booting the Linux kernel for the shix
-board, it is addressed first; if feedback is necessary and no progress
-can be made on blocking points until it is received, a random feature
-is worked on.
-
-Goals
------
-
-The primary model being worked on is the soft MMU target to be able to
-emulate the Shix 2.0 board by Alexis Polti, described at
-http://perso.enst.fr/~polti/realisations/shix20/
-
-Ultimately, qemu will be coupled with a system C or a verilog
-simulator to simulate the whole board functionalities.
-
-A sh4 user-mode has also somewhat started but will be worked on
-afterwards. The goal is to automate tests for GNAT (GNU Ada) compiler
-that I ported recently to the sh4-linux target.
-
-Registers
----------
-
-16 general purpose registers are available at any time. The first 8
-registers are banked and the non-directly visible ones can be accessed
-by privileged instructions. In qemu, we define 24 general purpose
-registers and the code generation use either [0-7]+[8-15] or
-[16-23]+[8-15] depending on the MD and RB flags in the sr
-configuration register.
-
-Instructions
-------------
-
-Most sh4 instructions have been implemented. The missing ones at this
-time are:
- - FPU related instructions
- - LDTLB to load a new MMU entry
- - SLEEP to put the processor in sleep mode
-
-Most instructions could be optimized a lot. This will be worked on
-after the current model is fully functional unless debugging
-convenience requires that it is done early.
-
-Many instructions did not have a chance to be tested yet. The plan is
-to implement unit and regression testing of those in the future.
-
-MMU
----
-
-The MMU is implemented in the sh4 core. MMU management has not been
-tested at all yet. In the sh7750, it can be manipulated through memory
-mapped registers and this part has not yet been implemented.
-
-Exceptions
-----------
-
-Exceptions are implemented as described in the sh4 reference manual
-but have not been tested yet. They do not use qemu EXCP_ features
-yet.
-
-IRQ
----
-
-IRQ are not implemented yet.
-
-Peripheral features
--------------------
-
- + Serial ports
-
-Configuration and use of the first serial port (SCI) without
-interrupts is supported. Input has not yet been tested.
-
-Configuration of the second serial port (SCIF) is supported. FIFO
-handling infrastructure has been started but is not completed yet.
-
- + GPIO ports
-
-GPIO ports have been implemented. A registration function allows
-external modules to register interest in some port changes (see
-hw/tc58128.[ch] for an example) and will be called back. Interrupt
-generation is not yet supported but some infrastructure is in place
-for this purpose. Note that in the current model a peripheral module
-cannot directly simulate a H->L->H input port transition and have an
-interrupt generated on the low level.
-
- + TC58128 NAND flash
-
-TC58128 NAND flash is partially implemented through GPIO ports. It
-supports reading from flash.
-
-GDB
----
-
-GDB remote target support has been implemented and lightly tested.
-
-Files
------
-
-File names are harcoded at this time. The bootloader must be stored in
-shix_bios.bin in the current directory. The initial Linux image must
-be stored in shix_linux_nand.bin in the current directory in NAND
-format. Test files can be obtained from
-http://perso.enst.fr/~polti/robot/ as well as the various datasheets I
-use.
-
-qemu disk parameter on the command line is unused. You can supply any
-existing image and it will be ignored. As the goal is to simulate an
-embedded target, it is not clear how this parameter will be handled in
-the future.
-
-To build an ELF kernel image from the NAND image, 16 bytes have to be
-stripped off the end of every 528 bytes, keeping only 512 of them. The
-following Python code snippet does it:
-
-#! /usr/bin/python
-
-def denand (infd, outfd):
- while True:
- d = infd.read (528)
- if not d: return
- outfd.write (d[:512])
-
-if __name__ == '__main__':
- import sys
- denand (open (sys.argv[1], 'rb'),
- open (sys.argv[2], 'wb'))
-
-Style isssues
--------------
-
-There is currently a mix between my style (space before opening
-parenthesis) and qemu style. This will be resolved before final
-integration is proposed.
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
deleted file mode 100644
index ef818fd..0000000
--- a/target-sh4/cpu.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * SH4 emulation
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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
- */
-#ifndef _CPU_SH4_H
-#define _CPU_SH4_H
-
-#include "config.h"
-
-#define TARGET_LONG_BITS 32
-#define TARGET_HAS_ICE 1
-
-#include "cpu-defs.h"
-
-#include "softfloat.h"
-
-#define TARGET_PAGE_BITS 12 /* 4k XXXXX */
-
-#define SR_MD (1 << 30)
-#define SR_RB (1 << 29)
-#define SR_BL (1 << 28)
-#define SR_FD (1 << 15)
-#define SR_M (1 << 9)
-#define SR_Q (1 << 8)
-#define SR_S (1 << 1)
-#define SR_T (1 << 0)
-
-#define FPSCR_FR (1 << 21)
-#define FPSCR_SZ (1 << 20)
-#define FPSCR_PR (1 << 19)
-#define FPSCR_DN (1 << 18)
-
-#define DELAY_SLOT (1 << 0) /* Must be the same as SR_T. */
-/* This flag is set if the next insn is a delay slot for a conditional jump.
- The dynamic value of the DELAY_SLOT determines whether the jup is taken. */
-#define DELAY_SLOT_CONDITIONAL (1 << 1)
-/* Those are used in contexts only */
-#define BRANCH (1 << 2)
-#define BRANCH_CONDITIONAL (1 << 3)
-#define MODE_CHANGE (1 << 4) /* Potential MD|RB change */
-#define BRANCH_EXCEPTION (1 << 5) /* Branch after exception */
-
-/* XXXXX The structure could be made more compact */
-typedef struct tlb_t {
- uint8_t asid; /* address space identifier */
- uint32_t vpn; /* virtual page number */
- uint8_t v; /* validity */
- uint32_t ppn; /* physical page number */
- uint8_t sz; /* page size */
- uint32_t size; /* cached page size in bytes */
- uint8_t sh; /* share status */
- uint8_t c; /* cacheability */
- uint8_t pr; /* protection key */
- uint8_t d; /* dirty */
- uint8_t wt; /* write through */
- uint8_t sa; /* space attribute (PCMCIA) */
- uint8_t tc; /* timing control */
-} tlb_t;
-
-#define UTLB_SIZE 64
-#define ITLB_SIZE 4
-
-typedef struct CPUSH4State {
- uint32_t flags; /* general execution flags */
- uint32_t gregs[24]; /* general registers */
- uint32_t fregs[32]; /* floating point registers */
- uint32_t sr; /* status register */
- uint32_t ssr; /* saved status register */
- uint32_t spc; /* saved program counter */
- uint32_t gbr; /* global base register */
- uint32_t vbr; /* vector base register */
- uint32_t sgr; /* saved global register 15 */
- uint32_t dbr; /* debug base register */
- uint32_t pc; /* program counter */
- uint32_t delayed_pc; /* target of delayed jump */
- uint32_t mach; /* multiply and accumulate high */
- uint32_t macl; /* multiply and accumulate low */
- uint32_t pr; /* procedure register */
- uint32_t fpscr; /* floating point status/control register */
- uint32_t fpul; /* floating point communication register */
-
- /* temporary float registers */
- float32 ft0, ft1;
- float64 dt0, dt1;
-
- /* Those belong to the specific unit (SH7750) but are handled here */
- uint32_t mmucr; /* MMU control register */
- uint32_t pteh; /* page table entry high register */
- uint32_t ptel; /* page table entry low register */
- uint32_t ptea; /* page table entry assistance register */
- uint32_t ttb; /* tranlation table base register */
- uint32_t tea; /* TLB exception address register */
- uint32_t tra; /* TRAPA exception register */
- uint32_t expevt; /* exception event register */
- uint32_t intevt; /* interrupt event register */
-
- jmp_buf jmp_env;
- int user_mode_only;
- int interrupt_request;
- int exception_index;
- CPU_COMMON tlb_t utlb[UTLB_SIZE]; /* unified translation table */
- tlb_t itlb[ITLB_SIZE]; /* instruction translation table */
-} CPUSH4State;
-
-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);
-
-#include "softfloat.h"
-
-#include "cpu-all.h"
-
-/* Memory access type */
-enum {
- /* Privilege */
- ACCESS_PRIV = 0x01,
- /* Direction */
- ACCESS_WRITE = 0x02,
- /* Type of instruction */
- ACCESS_CODE = 0x10,
- ACCESS_INT = 0x20
-};
-
-/* MMU control register */
-#define MMUCR 0x1F000010
-#define MMUCR_AT (1<<0)
-#define MMUCR_SV (1<<8)
-
-#endif /* _CPU_SH4_H */
diff --git a/target-sh4/exec.h b/target-sh4/exec.h
deleted file mode 100644
index 3563300..0000000
--- a/target-sh4/exec.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * SH4 emulation
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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
- */
-#ifndef _EXEC_SH4_H
-#define _EXEC_SH4_H
-
-#include "config.h"
-#include "dyngen-exec.h"
-
-register struct CPUSH4State *env asm(AREG0);
-register uint32_t T0 asm(AREG1);
-register uint32_t T1 asm(AREG2);
-//register uint32_t T2 asm(AREG3);
-
-#define FT0 (env->ft0)
-#define FT1 (env->ft1)
-#define DT0 (env->dt0)
-#define DT1 (env->dt1)
-
-#include "cpu.h"
-#include "exec-all.h"
-
-#ifndef CONFIG_USER_ONLY
-#include "softmmu_exec.h"
-#endif
-
-#define RETURN() __asm__ __volatile__("")
-
-static inline void regs_to_env(void)
-{
- /* XXXXX */
-}
-
-static inline void env_to_regs(void)
-{
- /* XXXXX */
-}
-
-int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
- int is_user, int is_softmmu);
-
-int find_itlb_entry(CPUState * env, target_ulong address,
- int use_asid, int update);
-int find_utlb_entry(CPUState * env, target_ulong address, int use_asid);
-
-void helper_addc_T0_T1(void);
-void helper_addv_T0_T1(void);
-void helper_div1_T0_T1(void);
-void helper_dmulsl_T0_T1(void);
-void helper_dmulul_T0_T1(void);
-void helper_macl_T0_T1(void);
-void helper_macw_T0_T1(void);
-void helper_negc_T0(void);
-void helper_subc_T0_T1(void);
-void helper_subv_T0_T1(void);
-void helper_rotcl(uint32_t * addr);
-void helper_rotcr(uint32_t * addr);
-
-void do_interrupt(CPUState * env);
-
-void cpu_loop_exit(void);
-void do_raise_exception(void);
-
-#endif /* _EXEC_SH4_H */
diff --git a/target-sh4/helper.c b/target-sh4/helper.c
deleted file mode 100644
index 1839c96..0000000
--- a/target-sh4/helper.c
+++ /dev/null
@@ -1,441 +0,0 @@
-/*
- * SH4 emulation
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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 <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <assert.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-
-#if defined(CONFIG_USER_ONLY)
-
-void do_interrupt (CPUState *env)
-{
- env->exception_index = -1;
-}
-
-int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
- int is_user, int is_softmmu)
-{
- env->tea = address;
- switch (rw) {
- case 0:
- env->exception_index = 0x0a0;
- break;
- case 1:
- env->exception_index = 0x0c0;
- break;
- case 2:
- env->exception_index = 0x0a0;
- break;
- }
- return 1;
-}
-
-target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
-{
- return addr;
-}
-
-#else /* !CONFIG_USER_ONLY */
-
-#define MMU_OK 0
-#define MMU_ITLB_MISS (-1)
-#define MMU_ITLB_MULTIPLE (-2)
-#define MMU_ITLB_VIOLATION (-3)
-#define MMU_DTLB_MISS_READ (-4)
-#define MMU_DTLB_MISS_WRITE (-5)
-#define MMU_DTLB_INITIAL_WRITE (-6)
-#define MMU_DTLB_VIOLATION_READ (-7)
-#define MMU_DTLB_VIOLATION_WRITE (-8)
-#define MMU_DTLB_MULTIPLE (-9)
-#define MMU_DTLB_MISS (-10)
-
-void do_interrupt(CPUState * env)
-{
- if (loglevel & CPU_LOG_INT) {
- const char *expname;
- switch (env->exception_index) {
- case 0x0e0:
- expname = "addr_error";
- break;
- case 0x040:
- expname = "tlb_miss";
- break;
- case 0x0a0:
- expname = "tlb_violation";
- break;
- case 0x180:
- expname = "illegal_instruction";
- break;
- case 0x1a0:
- expname = "slot_illegal_instruction";
- break;
- case 0x800:
- expname = "fpu_disable";
- break;
- case 0x820:
- expname = "slot_fpu";
- break;
- case 0x100:
- expname = "data_write";
- break;
- case 0x060:
- expname = "dtlb_miss_write";
- break;
- case 0x0c0:
- expname = "dtlb_violation_write";
- break;
- case 0x120:
- expname = "fpu_exception";
- break;
- case 0x080:
- expname = "initial_page_write";
- break;
- case 0x160:
- expname = "trapa";
- break;
- default:
- expname = "???";
- break;
- }
- fprintf(logfile, "exception 0x%03x [%s] raised\n",
- env->exception_index, expname);
- cpu_dump_state(env, logfile, fprintf, 0);
- }
-
- env->ssr = env->sr;
- env->spc = env->spc;
- env->sgr = env->gregs[15];
- env->sr |= SR_BL | SR_MD | SR_RB;
-
- env->expevt = env->exception_index & 0x7ff;
- switch (env->exception_index) {
- case 0x040:
- case 0x060:
- case 0x080:
- env->pc = env->vbr + 0x400;
- break;
- case 0x140:
- env->pc = 0xa0000000;
- break;
- default:
- env->pc = env->vbr + 0x100;
- break;
- }
-}
-
-static void update_itlb_use(CPUState * env, int itlbnb)
-{
- uint8_t or_mask = 0, and_mask = (uint8_t) - 1;
-
- switch (itlbnb) {
- case 0:
- and_mask = 0x7f;
- break;
- case 1:
- and_mask = 0xe7;
- or_mask = 0x80;
- break;
- case 2:
- and_mask = 0xfb;
- or_mask = 0x50;
- break;
- case 3:
- or_mask = 0x2c;
- break;
- }
-
- env->mmucr &= (and_mask << 24);
- env->mmucr |= (or_mask << 24);
-}
-
-static int itlb_replacement(CPUState * env)
-{
- if ((env->mmucr & 0xe0000000) == 0xe0000000)
- return 0;
- if ((env->mmucr & 0x98000000) == 0x08000000)
- return 1;
- if ((env->mmucr & 0x54000000) == 0x04000000)
- return 2;
- if ((env->mmucr & 0x2c000000) == 0x00000000)
- return 3;
- assert(0);
-}
-
-/* Find the corresponding entry in the right TLB
- Return entry, MMU_DTLB_MISS or MMU_DTLB_MULTIPLE
-*/
-static int find_tlb_entry(CPUState * env, target_ulong address,
- tlb_t * entries, uint8_t nbtlb, int use_asid)
-{
- int match = MMU_DTLB_MISS;
- uint32_t start, end;
- uint8_t asid;
- int i;
-
- asid = env->pteh & 0xff;
-
- for (i = 0; i < nbtlb; i++) {
- if (!entries[i].v)
- continue; /* Invalid entry */
- if (use_asid && entries[i].asid != asid && !entries[i].sh)
- continue; /* Bad ASID */
-#if 0
- switch (entries[i].sz) {
- case 0:
- size = 1024; /* 1kB */
- break;
- case 1:
- size = 4 * 1024; /* 4kB */
- break;
- case 2:
- size = 64 * 1024; /* 64kB */
- break;
- case 3:
- size = 1024 * 1024; /* 1MB */
- break;
- default:
- assert(0);
- }
-#endif
- start = (entries[i].vpn << 10) & ~(entries[i].size - 1);
- end = start + entries[i].size - 1;
- if (address >= start && address <= end) { /* Match */
- if (match != -1)
- return MMU_DTLB_MULTIPLE; /* Multiple match */
- match = i;
- }
- }
- return match;
-}
-
-/* Find itlb entry - update itlb from utlb if necessary and asked for
- Return entry, MMU_ITLB_MISS, MMU_ITLB_MULTIPLE or MMU_DTLB_MULTIPLE
- Update the itlb from utlb if update is not 0
-*/
-int find_itlb_entry(CPUState * env, target_ulong address,
- int use_asid, int update)
-{
- int e, n;
-
- e = find_tlb_entry(env, address, env->itlb, ITLB_SIZE, use_asid);
- if (e == MMU_DTLB_MULTIPLE)
- e = MMU_ITLB_MULTIPLE;
- else if (e == MMU_DTLB_MISS && update) {
- e = find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
- if (e >= 0) {
- n = itlb_replacement(env);
- env->itlb[n] = env->utlb[e];
- e = n;
- }
- }
- if (e >= 0)
- update_itlb_use(env, e);
- return e;
-}
-
-/* Find utlb entry
- Return entry, MMU_DTLB_MISS, MMU_DTLB_MULTIPLE */
-int find_utlb_entry(CPUState * env, target_ulong address, int use_asid)
-{
- uint8_t urb, urc;
-
- /* Increment URC */
- urb = ((env->mmucr) >> 18) & 0x3f;
- urc = ((env->mmucr) >> 10) & 0x3f;
- urc++;
- if (urc == urb || urc == UTLB_SIZE - 1)
- urc = 0;
- env->mmucr = (env->mmucr & 0xffff03ff) | (urc << 10);
-
- /* Return entry */
- return find_tlb_entry(env, address, env->utlb, UTLB_SIZE, use_asid);
-}
-
-/* Match address against MMU
- Return MMU_OK, MMU_DTLB_MISS_READ, MMU_DTLB_MISS_WRITE,
- MMU_DTLB_INITIAL_WRITE, MMU_DTLB_VIOLATION_READ,
- MMU_DTLB_VIOLATION_WRITE, MMU_ITLB_MISS,
- MMU_ITLB_MULTIPLE, MMU_ITLB_VIOLATION
-*/
-static int get_mmu_address(CPUState * env, target_ulong * physical,
- int *prot, target_ulong address,
- int rw, int access_type)
-{
- int use_asid, is_code, n;
- tlb_t *matching = NULL;
-
- use_asid = (env->mmucr & MMUCR_SV) == 0 && (env->sr & SR_MD) == 0;
- is_code = env->pc == address; /* Hack */
-
- /* Use a hack to find if this is an instruction or data access */
- if (env->pc == address && !(rw & PAGE_WRITE)) {
- n = find_itlb_entry(env, address, use_asid, 1);
- if (n >= 0) {
- matching = &env->itlb[n];
- if ((env->sr & SR_MD) & !(matching->pr & 2))
- n = MMU_ITLB_VIOLATION;
- else
- *prot = PAGE_READ;
- }
- } else {
- n = find_utlb_entry(env, address, use_asid);
- if (n >= 0) {
- matching = &env->utlb[n];
- switch ((matching->pr << 1) | ((env->sr & SR_MD) ? 1 : 0)) {
- case 0: /* 000 */
- case 2: /* 010 */
- n = (rw & PAGE_WRITE) ? MMU_DTLB_VIOLATION_WRITE :
- MMU_DTLB_VIOLATION_READ;
- break;
- case 1: /* 001 */
- case 4: /* 100 */
- case 5: /* 101 */
- if (rw & PAGE_WRITE)
- n = MMU_DTLB_VIOLATION_WRITE;
- else
- *prot = PAGE_READ;
- break;
- case 3: /* 011 */
- case 6: /* 110 */
- case 7: /* 111 */
- *prot = rw & (PAGE_READ | PAGE_WRITE);
- break;
- }
- } else if (n == MMU_DTLB_MISS) {
- n = (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE :
- MMU_DTLB_MISS_READ;
- }
- }
- if (n >= 0) {
- *physical = ((matching->ppn << 10) & ~(matching->size - 1)) |
- (address & (matching->size - 1));
- if ((rw & PAGE_WRITE) & !matching->d)
- n = MMU_DTLB_INITIAL_WRITE;
- else
- n = MMU_OK;
- }
- return n;
-}
-
-int get_physical_address(CPUState * env, target_ulong * physical,
- int *prot, target_ulong address,
- int rw, int access_type)
-{
- /* P1, P2 and P4 areas do not use translation */
- if ((address >= 0x80000000 && address < 0xc0000000) ||
- address >= 0xe0000000) {
- if (!(env->sr & SR_MD)
- && (address < 0xe0000000 || address > 0xe4000000)) {
- /* Unauthorized access in user mode (only store queues are available) */
- fprintf(stderr, "Unauthorized access\n");
- return (rw & PAGE_WRITE) ? MMU_DTLB_MISS_WRITE :
- MMU_DTLB_MISS_READ;
- }
- /* Mask upper 3 bits */
- *physical = address & 0x1FFFFFFF;
- *prot = PAGE_READ | PAGE_WRITE;
- return MMU_OK;
- }
-
- /* If MMU is disabled, return the corresponding physical page */
- if (!env->mmucr & MMUCR_AT) {
- *physical = address & 0x1FFFFFFF;
- *prot = PAGE_READ | PAGE_WRITE;
- return MMU_OK;
- }
-
- /* We need to resort to the MMU */
- return get_mmu_address(env, physical, prot, address, rw, access_type);
-}
-
-int cpu_sh4_handle_mmu_fault(CPUState * env, target_ulong address, int rw,
- int is_user, int is_softmmu)
-{
- target_ulong physical, page_offset, page_size;
- int prot, ret, access_type;
-
- /* XXXXX */
-#if 0
- fprintf(stderr, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
- __func__, env->pc, address, rw, is_user, is_softmmu);
-#endif
-
- access_type = ACCESS_INT;
- ret =
- get_physical_address(env, &physical, &prot, address, rw,
- access_type);
-
- if (ret != MMU_OK) {
- env->tea = address;
- switch (ret) {
- case MMU_ITLB_MISS:
- case MMU_DTLB_MISS_READ:
- env->exception_index = 0x040;
- break;
- case MMU_DTLB_MULTIPLE:
- case MMU_ITLB_MULTIPLE:
- env->exception_index = 0x140;
- break;
- case MMU_ITLB_VIOLATION:
- env->exception_index = 0x0a0;
- break;
- case MMU_DTLB_MISS_WRITE:
- env->exception_index = 0x060;
- break;
- case MMU_DTLB_INITIAL_WRITE:
- env->exception_index = 0x080;
- break;
- case MMU_DTLB_VIOLATION_READ:
- env->exception_index = 0x0a0;
- break;
- case MMU_DTLB_VIOLATION_WRITE:
- env->exception_index = 0x0c0;
- break;
- default:
- assert(0);
- }
- return 1;
- }
-
- page_size = TARGET_PAGE_SIZE;
- page_offset =
- (address - (address & TARGET_PAGE_MASK)) & ~(page_size - 1);
- address = (address & TARGET_PAGE_MASK) + page_offset;
- physical = (physical & TARGET_PAGE_MASK) + page_offset;
-
- 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_ulong physical;
- int prot;
-
- get_physical_address(env, &physical, &prot, addr, PAGE_READ, 0);
- return physical;
-}
-
-#endif
diff --git a/target-sh4/op.c b/target-sh4/op.c
deleted file mode 100644
index d3b68bc..0000000
--- a/target-sh4/op.c
+++ /dev/null
@@ -1,967 +0,0 @@
-/*
- * SH4 emulation
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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"
-
-static inline void set_flag(uint32_t flag)
-{
- env->flags |= flag;
-}
-
-static inline void clr_flag(uint32_t flag)
-{
- env->flags &= ~flag;
-}
-
-static inline void set_t(void)
-{
- env->sr |= SR_T;
-}
-
-static inline void clr_t(void)
-{
- env->sr &= ~SR_T;
-}
-
-static inline void cond_t(int cond)
-{
- if (cond)
- set_t();
- else
- clr_t();
-}
-
-void OPPROTO op_movl_imm_T0(void)
-{
- T0 = (uint32_t) PARAM1;
- RETURN();
-}
-
-void OPPROTO op_movl_imm_T1(void)
-{
- T0 = (uint32_t) PARAM1;
- RETURN();
-}
-
-void OPPROTO op_movl_imm_T2(void)
-{
- T0 = (uint32_t) PARAM1;
- RETURN();
-}
-
-void OPPROTO op_cmp_eq_imm_T0(void)
-{
- cond_t((int32_t) T0 == (int32_t) PARAM1);
- RETURN();
-}
-
-void OPPROTO op_cmd_eq_T0_T1(void)
-{
- cond_t(T0 == T1);
- RETURN();
-}
-
-void OPPROTO op_cmd_hs_T0_T1(void)
-{
- cond_t((uint32_t) T0 <= (uint32_t) T1);
- RETURN();
-}
-
-void OPPROTO op_cmd_ge_T0_T1(void)
-{
- cond_t((int32_t) T0 <= (int32_t) T1);
- RETURN();
-}
-
-void OPPROTO op_cmd_hi_T0_T1(void)
-{
- cond_t((uint32_t) T0 < (uint32_t) T1);
- RETURN();
-}
-
-void OPPROTO op_cmd_gt_T0_T1(void)
-{
- cond_t((int32_t) T0 < (int32_t) T1);
- RETURN();
-}
-
-void OPPROTO op_not_T0(void)
-{
- T0 = ~T0;
- RETURN();
-}
-
-void OPPROTO op_bf_s(void)
-{
- env->delayed_pc = PARAM1;
- set_flag(DELAY_SLOT_CONDITIONAL | ((~env->sr) & SR_T));
- RETURN();
-}
-
-void OPPROTO op_bt_s(void)
-{
- env->delayed_pc = PARAM1;
- set_flag(DELAY_SLOT_CONDITIONAL | (env->sr & SR_T));
- RETURN();
-}
-
-void OPPROTO op_bra(void)
-{
- env->delayed_pc = PARAM1;
- set_flag(DELAY_SLOT);
- RETURN();
-}
-
-void OPPROTO op_braf_T0(void)
-{
- env->delayed_pc = PARAM1 + T0;
- set_flag(DELAY_SLOT);
- RETURN();
-}
-
-void OPPROTO op_bsr(void)
-{
- env->pr = PARAM1;
- env->delayed_pc = PARAM2;
- set_flag(DELAY_SLOT);
- RETURN();
-}
-
-void OPPROTO op_bsrf_T0(void)
-{
- env->pr = PARAM1;
- env->delayed_pc = PARAM1 + T0;
- set_flag(DELAY_SLOT);
- RETURN();
-}
-
-void OPPROTO op_jsr_T0(void)
-{
- env->pr = PARAM1;
- env->delayed_pc = T0;
- set_flag(DELAY_SLOT);
- RETURN();
-}
-
-void OPPROTO op_rts(void)
-{
- env->delayed_pc = env->pr;
- set_flag(DELAY_SLOT);
- RETURN();
-}
-
-void OPPROTO op_clr_delay_slot(void)
-{
- clr_flag(DELAY_SLOT);
- RETURN();
-}
-
-void OPPROTO op_clr_delay_slot_conditional(void)
-{
- clr_flag(DELAY_SLOT_CONDITIONAL);
- RETURN();
-}
-
-void OPPROTO op_exit_tb(void)
-{
- EXIT_TB();
- RETURN();
-}
-
-void OPPROTO op_addl_imm_T0(void)
-{
- T0 += PARAM1;
- RETURN();
-}
-
-void OPPROTO op_addl_imm_T1(void)
-{
- T1 += PARAM1;
- RETURN();
-}
-
-void OPPROTO op_clrmac(void)
-{
- env->mach = env->macl = 0;
- RETURN();
-}
-
-void OPPROTO op_clrs(void)
-{
- env->sr &= ~SR_S;
- RETURN();
-}
-
-void OPPROTO op_clrt(void)
-{
- env->sr &= ~SR_T;
- RETURN();
-}
-
-void OPPROTO op_sets(void)
-{
- env->sr |= SR_S;
- RETURN();
-}
-
-void OPPROTO op_sett(void)
-{
- env->sr |= SR_T;
- RETURN();
-}
-
-void OPPROTO op_frchg(void)
-{
- env->fpscr ^= FPSCR_FR;
- RETURN();
-}
-
-void OPPROTO op_fschg(void)
-{
- env->fpscr ^= FPSCR_SZ;
- RETURN();
-}
-
-void OPPROTO op_rte(void)
-{
- env->sr = env->ssr;
- env->delayed_pc = env->spc;
- set_flag(DELAY_SLOT);
- RETURN();
-}
-
-void OPPROTO op_swapb_T0(void)
-{
- T0 = (T0 & 0xffff0000) | ((T0 & 0xff) << 8) | ((T0 >> 8) & 0xff);
- RETURN();
-}
-
-void OPPROTO op_swapw_T0(void)
-{
- T0 = ((T0 & 0xffff) << 16) | ((T0 >> 16) & 0xffff);
- RETURN();
-}
-
-void OPPROTO op_xtrct_T0_T1(void)
-{
- T1 = ((T0 & 0xffff) << 16) | ((T1 >> 16) & 0xffff);
- RETURN();
-}
-
-void OPPROTO op_addc_T0_T1(void)
-{
- helper_addc_T0_T1();
- RETURN();
-}
-
-void OPPROTO op_addv_T0_T1(void)
-{
- helper_addv_T0_T1();
- RETURN();
-}
-
-void OPPROTO op_cmp_eq_T0_T1(void)
-{
- cond_t(T1 == T0);
- RETURN();
-}
-
-void OPPROTO op_cmp_ge_T0_T1(void)
-{
- cond_t((int32_t) T1 >= (int32_t) T0);
- RETURN();
-}
-
-void OPPROTO op_cmp_gt_T0_T1(void)
-{
- cond_t((int32_t) T1 > (int32_t) T0);
- RETURN();
-}
-
-void OPPROTO op_cmp_hi_T0_T1(void)
-{
- cond_t((uint32_t) T1 > (uint32_t) T0);
- RETURN();
-}
-
-void OPPROTO op_cmp_hs_T0_T1(void)
-{
- cond_t((uint32_t) T1 >= (uint32_t) T0);
- RETURN();
-}
-
-void OPPROTO op_cmp_str_T0_T1(void)
-{
- cond_t((T0 & 0x000000ff) == (T1 & 0x000000ff) ||
- (T0 & 0x0000ff00) == (T1 & 0x0000ff00) ||
- (T0 & 0x00ff0000) == (T1 & 0x00ff0000) ||
- (T0 & 0xff000000) == (T1 & 0xff000000));
- RETURN();
-}
-
-void OPPROTO op_tst_T0_T1(void)
-{
- cond_t((T1 & T0) == 0);
- RETURN();
-}
-
-void OPPROTO op_div0s_T0_T1(void)
-{
- if (T1 & 0x80000000)
- env->sr |= SR_Q;
- else
- env->sr &= ~SR_Q;
- if (T0 & 0x80000000)
- env->sr |= SR_M;
- else
- env->sr &= ~SR_M;
- cond_t((T1 ^ T0) & 0x80000000);
- RETURN();
-}
-
-void OPPROTO op_div0u(void)
-{
- env->sr &= ~(SR_M | SR_Q | SR_T);
- RETURN();
-}
-
-void OPPROTO op_div1_T0_T1(void)
-{
- helper_div1_T0_T1();
- RETURN();
-}
-
-void OPPROTO op_dmulsl_T0_T1(void)
-{
- helper_dmulsl_T0_T1();
- RETURN();
-}
-
-void OPPROTO op_dmulul_T0_T1(void)
-{
- helper_dmulul_T0_T1();
- RETURN();
-}
-
-void OPPROTO op_macl_T0_T1(void)
-{
- helper_macl_T0_T1();
- RETURN();
-}
-
-void OPPROTO op_macw_T0_T1(void)
-{
- helper_macw_T0_T1();
- RETURN();
-}
-
-void OPPROTO op_mull_T0_T1(void)
-{
- env->macl = (T0 * T1) & 0xffffffff;
- RETURN();
-}
-
-void OPPROTO op_mulsw_T0_T1(void)
-{
- env->macl = (int32_t) T0 *(int32_t) T1;
- RETURN();
-}
-
-void OPPROTO op_muluw_T0_T1(void)
-{
- env->macl = (uint32_t) T0 *(uint32_t) T1;
- RETURN();
-}
-
-void OPPROTO op_neg_T0(void)
-{
- T0 = -T0;
- RETURN();
-}
-
-void OPPROTO op_negc_T0(void)
-{
- helper_negc_T0();
- RETURN();
-}
-
-void OPPROTO op_shad_T0_T1(void)
-{
- if ((T0 & 0x80000000) == 0)
- T1 <<= (T0 & 0x1f);
- else if ((T0 & 0x1f) == 0)
- T1 = 0;
- else
- T1 = ((int32_t) T1) >> ((~T0 & 0x1f) + 1);
- RETURN();
-}
-
-void OPPROTO op_shld_T0_T1(void)
-{
- if ((T0 & 0x80000000) == 0)
- T1 <<= (T0 & 0x1f);
- else if ((T0 & 0x1f) == 0)
- T1 = 0;
- else
- T1 = ((uint32_t) T1) >> ((~T0 & 0x1f) + 1);
- RETURN();
-}
-
-void OPPROTO op_subc_T0_T1(void)
-{
- helper_subc_T0_T1();
- RETURN();
-}
-
-void OPPROTO op_subv_T0_T1(void)
-{
- helper_subv_T0_T1();
- RETURN();
-}
-
-void OPPROTO op_trapa(void)
-{
- env->tra = PARAM1 * 2;
- env->exception_index = 0x160;
- do_raise_exception();
- RETURN();
-}
-
-void OPPROTO op_cmp_pl_T0(void)
-{
- cond_t((int32_t) T0 > 0);
- RETURN();
-}
-
-void OPPROTO op_cmp_pz_T0(void)
-{
- cond_t((int32_t) T0 >= 0);
- RETURN();
-}
-
-void OPPROTO op_jmp_T0(void)
-{
- env->delayed_pc = T0;
- set_flag(DELAY_SLOT);
- RETURN();
-}
-
-void OPPROTO op_movl_rN_rN(void)
-{
- env->gregs[PARAM2] = env->gregs[PARAM1];
- RETURN();
-}
-
-void OPPROTO op_ldcl_rMplus_rN_bank(void)
-{
- env->gregs[PARAM2] = env->gregs[PARAM1];
- env->gregs[PARAM1] += 4;
- RETURN();
-}
-
-void OPPROTO op_ldc_T0_sr(void)
-{
- env->sr = T0 & 0x700083f3;
- RETURN();
-}
-
-void OPPROTO op_stc_sr_T0(void)
-{
- T0 = env->sr;
- RETURN();
-}
-
-#define LDSTOPS(target,load,store) \
-void OPPROTO op_##load##_T0_##target (void) \
-{ env ->target = T0; RETURN(); \
-} \
-void OPPROTO op_##store##_##target##_T0 (void) \
-{ T0 = env->target; RETURN(); \
-} \
-
- LDSTOPS(gbr, ldc, stc)
- LDSTOPS(vbr, ldc, stc)
- LDSTOPS(ssr, ldc, stc)
- LDSTOPS(spc, ldc, stc)
- LDSTOPS(sgr, ldc, stc)
- LDSTOPS(dbr, ldc, stc)
- LDSTOPS(mach, lds, sts)
- LDSTOPS(macl, lds, sts)
- LDSTOPS(pr, lds, sts)
- LDSTOPS(fpul, lds, sts)
-
-void OPPROTO op_lds_T0_fpscr(void)
-{
- env->fpscr = T0 & 0x003fffff;
- RETURN();
-}
-
-void OPPROTO op_sts_fpscr_T0(void)
-{
- T0 = env->fpscr & 0x003fffff;
- RETURN();
-}
-
-void OPPROTO op_movt_rN(void)
-{
- env->gregs[PARAM1] = env->sr & SR_T;
- RETURN();
-}
-
-void OPPROTO op_rotcl_Rn(void)
-{
- helper_rotcl(&env->gregs[PARAM1]);
- RETURN();
-}
-
-void OPPROTO op_rotcr_Rn(void)
-{
- helper_rotcr(&env->gregs[PARAM1]);
- RETURN();
-}
-
-void OPPROTO op_rotl_Rn(void)
-{
- cond_t(env->gregs[PARAM1] & 0x80000000);
- env->gregs[PARAM1] = (env->gregs[PARAM1] << 1) | (env->sr & SR_T);
- RETURN();
-}
-
-void OPPROTO op_rotr_Rn(void)
-{
- cond_t(env->gregs[PARAM1] & 1);
- env->gregs[PARAM1] = (env->gregs[PARAM1] >> 1) |
- ((env->sr & SR_T) ? 0x80000000 : 0);
- RETURN();
-}
-
-void OPPROTO op_shal_Rn(void)
-{
- cond_t(env->gregs[PARAM1] & 0x80000000);
- env->gregs[PARAM1] <<= 1;
- RETURN();
-}
-
-void OPPROTO op_shar_Rn(void)
-{
- cond_t(env->gregs[PARAM1] & 1);
- *(int32_t *) & env->gregs[PARAM1] >>= 1;
- RETURN();
-}
-
-void OPPROTO op_shlr_Rn(void)
-{
- cond_t(env->gregs[PARAM1] & 1);
- *(uint32_t *) & env->gregs[PARAM1] >>= 1;
- RETURN();
-}
-
-void OPPROTO op_shll2_Rn(void)
-{
- env->gregs[PARAM1] <<= 2;
- RETURN();
-}
-
-void OPPROTO op_shll8_Rn(void)
-{
- env->gregs[PARAM1] <<= 8;
- RETURN();
-}
-
-void OPPROTO op_shll16_Rn(void)
-{
- env->gregs[PARAM1] <<= 16;
- RETURN();
-}
-
-void OPPROTO op_shlr2_Rn(void)
-{
- *(uint32_t *) & env->gregs[PARAM1] >>= 2;
- RETURN();
-}
-
-void OPPROTO op_shlr8_Rn(void)
-{
- *(uint32_t *) & env->gregs[PARAM1] >>= 8;
- RETURN();
-}
-
-void OPPROTO op_shlr16_Rn(void)
-{
- *(uint32_t *) & env->gregs[PARAM1] >>= 16;
- RETURN();
-}
-
-void OPPROTO op_tasb_rN(void)
-{
- cond_t(*(int8_t *) env->gregs[PARAM1] == 0);
- *(int8_t *) env->gregs[PARAM1] |= 0x80;
- RETURN();
-}
-
-void OPPROTO op_movl_T0_rN(void)
-{
- env->gregs[PARAM1] = T0;
- RETURN();
-}
-
-void OPPROTO op_movl_T1_rN(void)
-{
- env->gregs[PARAM1] = T1;
- RETURN();
-}
-
-void OPPROTO op_movb_rN_T0(void)
-{
- T0 = (int32_t) (int8_t) (env->gregs[PARAM1] & 0xff);
- RETURN();
-}
-
-void OPPROTO op_movub_rN_T0(void)
-{
- T0 = env->gregs[PARAM1] & 0xff;
- RETURN();
-}
-
-void OPPROTO op_movw_rN_T0(void)
-{
- T0 = (int32_t) (int16_t) (env->gregs[PARAM1] & 0xffff);
- RETURN();
-}
-
-void OPPROTO op_movuw_rN_T0(void)
-{
- T0 = env->gregs[PARAM1] & 0xffff;
- RETURN();
-}
-
-void OPPROTO op_movl_rN_T0(void)
-{
- T0 = env->gregs[PARAM1];
- RETURN();
-}
-
-void OPPROTO op_movb_rN_T1(void)
-{
- T1 = (int32_t) (int8_t) (env->gregs[PARAM1] & 0xff);
- RETURN();
-}
-
-void OPPROTO op_movub_rN_T1(void)
-{
- T1 = env->gregs[PARAM1] & 0xff;
- RETURN();
-}
-
-void OPPROTO op_movw_rN_T1(void)
-{
- T1 = (int32_t) (int16_t) (env->gregs[PARAM1] & 0xffff);
- RETURN();
-}
-
-void OPPROTO op_movuw_rN_T1(void)
-{
- T1 = env->gregs[PARAM1] & 0xffff;
- RETURN();
-}
-
-void OPPROTO op_movl_rN_T1(void)
-{
- T1 = env->gregs[PARAM1];
- RETURN();
-}
-
-void OPPROTO op_movl_imm_rN(void)
-{
- env->gregs[PARAM2] = PARAM1;
- RETURN();
-}
-
-void OPPROTO op_fmov_frN_FT0(void)
-{
- FT0 = *(float32 *)&env->fregs[PARAM1];
- RETURN();
-}
-
-void OPPROTO op_fmov_drN_DT0(void)
-{
- DT0 = *(float64 *)&env->fregs[PARAM1];
- RETURN();
-}
-
-void OPPROTO op_fmov_FT0_frN(void)
-{
- *(float32 *)&env->fregs[PARAM1] = FT0;
- RETURN();
-}
-
-void OPPROTO op_fmov_DT0_drN(void)
-{
- *(float64 *)&env->fregs[PARAM1] = DT0;
- RETURN();
-}
-
-void OPPROTO op_dec1_rN(void)
-{
- env->gregs[PARAM1] -= 1;
- RETURN();
-}
-
-void OPPROTO op_dec2_rN(void)
-{
- env->gregs[PARAM1] -= 2;
- RETURN();
-}
-
-void OPPROTO op_dec4_rN(void)
-{
- env->gregs[PARAM1] -= 4;
- RETURN();
-}
-
-void OPPROTO op_dec8_rN(void)
-{
- env->gregs[PARAM1] -= 4;
- RETURN();
-}
-
-void OPPROTO op_inc1_rN(void)
-{
- env->gregs[PARAM1] += 1;
- RETURN();
-}
-
-void OPPROTO op_inc2_rN(void)
-{
- env->gregs[PARAM1] += 2;
- RETURN();
-}
-
-void OPPROTO op_inc4_rN(void)
-{
- env->gregs[PARAM1] += 4;
- RETURN();
-}
-
-void OPPROTO op_inc8_rN(void)
-{
- env->gregs[PARAM1] += 4;
- RETURN();
-}
-
-void OPPROTO op_add_T0_rN(void)
-{
- env->gregs[PARAM1] += T0;
- RETURN();
-}
-
-void OPPROTO op_sub_T0_rN(void)
-{
- env->gregs[PARAM1] -= T0;
- RETURN();
-}
-
-void OPPROTO op_and_T0_rN(void)
-{
- env->gregs[PARAM1] &= T0;
- RETURN();
-}
-
-void OPPROTO op_or_T0_rN(void)
-{
- env->gregs[PARAM1] |= T0;
- RETURN();
-}
-
-void OPPROTO op_xor_T0_rN(void)
-{
- env->gregs[PARAM1] ^= T0;
- RETURN();
-}
-
-void OPPROTO op_add_rN_T0(void)
-{
- T0 += env->gregs[PARAM1];
- RETURN();
-}
-
-void OPPROTO op_add_rN_T1(void)
-{
- T1 += env->gregs[PARAM1];
- RETURN();
-}
-
-void OPPROTO op_add_imm_rN(void)
-{
- env->gregs[PARAM2] += PARAM1;
- RETURN();
-}
-
-void OPPROTO op_and_imm_rN(void)
-{
- env->gregs[PARAM2] &= PARAM1;
- RETURN();
-}
-
-void OPPROTO op_or_imm_rN(void)
-{
- env->gregs[PARAM2] |= PARAM1;
- RETURN();
-}
-
-void OPPROTO op_xor_imm_rN(void)
-{
- env->gregs[PARAM2] ^= PARAM1;
- RETURN();
-}
-
-void OPPROTO op_dt_rN(void)
-{
- cond_t((--env->gregs[PARAM1]) == 0);
- RETURN();
-}
-
-void OPPROTO op_tst_imm_rN(void)
-{
- cond_t((env->gregs[PARAM2] & PARAM1) == 0);
- RETURN();
-}
-
-void OPPROTO op_movl_T0_T1(void)
-{
- T1 = T0;
- RETURN();
-}
-
-void OPPROTO op_movl_fpul_FT0(void)
-{
- FT0 = *(float32 *)&env->fpul;
- RETURN();
-}
-
-void OPPROTO op_movl_FT0_fpul(void)
-{
- *(float32 *)&env->fpul = FT0;
- RETURN();
-}
-
-void OPPROTO op_goto_tb0(void)
-{
- GOTO_TB(op_goto_tb0, PARAM1, 0);
- RETURN();
-}
-
-void OPPROTO op_goto_tb1(void)
-{
- GOTO_TB(op_goto_tb1, PARAM1, 1);
- RETURN();
-}
-
-void OPPROTO op_movl_imm_PC(void)
-{
- env->pc = PARAM1;
- RETURN();
-}
-
-void OPPROTO op_jT(void)
-{
- if (env->sr & SR_T)
- GOTO_LABEL_PARAM(1);
- RETURN();
-}
-
-void OPPROTO op_jdelayed(void)
-{
- uint32_t flags;
- flags = env->flags;
- env->flags &= ~(DELAY_SLOT | DELAY_SLOT_CONDITIONAL);
- if (flags & DELAY_SLOT)
- GOTO_LABEL_PARAM(1);
- RETURN();
-}
-
-void OPPROTO op_movl_delayed_pc_PC(void)
-{
- env->pc = env->delayed_pc;
- RETURN();
-}
-
-void OPPROTO op_addl_GBR_T0(void)
-{
- T0 += env->gbr;
- RETURN();
-}
-
-void OPPROTO op_and_imm_T0(void)
-{
- T0 &= PARAM1;
- RETURN();
-}
-
-void OPPROTO op_or_imm_T0(void)
-{
- T0 |= PARAM1;
- RETURN();
-}
-
-void OPPROTO op_xor_imm_T0(void)
-{
- T0 ^= PARAM1;
- RETURN();
-}
-
-void OPPROTO op_tst_imm_T0(void)
-{
- cond_t((T0 & PARAM1) == 0);
- RETURN();
-}
-
-void OPPROTO op_raise_illegal_instruction(void)
-{
- env->exception_index = 0x180;
- do_raise_exception();
- RETURN();
-}
-
-void OPPROTO op_raise_slot_illegal_instruction(void)
-{
- env->exception_index = 0x1a0;
- do_raise_exception();
- RETURN();
-}
-
-void OPPROTO op_debug(void)
-{
- env->exception_index = EXCP_DEBUG;
- cpu_loop_exit();
-}
-
-/* Load and store */
-#define MEMSUFFIX _raw
-#include "op_mem.c"
-#undef MEMSUFFIX
-#if !defined(CONFIG_USER_ONLY)
-#define MEMSUFFIX _user
-#include "op_mem.c"
-#undef MEMSUFFIX
-
-#define MEMSUFFIX _kernel
-#include "op_mem.c"
-#undef MEMSUFFIX
-#endif
diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c
deleted file mode 100644
index f02fa58..0000000
--- a/target-sh4/op_helper.c
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * SH4 emulation
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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 <assert.h>
-#include "exec.h"
-
-void cpu_loop_exit(void)
-{
- longjmp(env->jmp_env, 1);
-}
-
-void do_raise_exception(void)
-{
- cpu_loop_exit();
-}
-
-#ifndef CONFIG_USER_ONLY
-
-#define MMUSUFFIX _mmu
-#define GETPC() (__builtin_return_address(0))
-
-#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"
-
-void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
-{
- TranslationBlock *tb;
- CPUState *saved_env;
- unsigned long pc;
- int ret;
-
- /* XXX: hack to restore env in all cases, even if not called from
- generated code */
- saved_env = env;
- env = cpu_single_env;
- ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, is_user, 1);
- if (ret) {
- if (retaddr) {
- /* now we have a real cpu fault */
- pc = (unsigned long) retaddr;
- tb = tb_find_pc(pc);
- if (tb) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, pc, NULL);
- }
- }
- do_raise_exception();
- }
- env = saved_env;
-}
-
-#endif
-
-void helper_addc_T0_T1(void)
-{
- uint32_t tmp0, tmp1;
-
- tmp1 = T0 + T1;
- tmp0 = T1;
- T1 = tmp1 + (env->sr & 1);
- if (tmp0 > tmp1)
- env->sr |= SR_T;
- else
- env->sr &= ~SR_T;
- if (tmp1 > T1)
- env->sr |= SR_T;
-}
-
-void helper_addv_T0_T1(void)
-{
- uint32_t dest, src, ans;
-
- if ((int32_t) T1 >= 0)
- dest = 0;
- else
- dest = 1;
- if ((int32_t) T0 >= 0)
- src = 0;
- else
- src = 1;
- src += dest;
- T1 += T0;
- if ((int32_t) T1 >= 0)
- ans = 0;
- else
- ans = 1;
- ans += dest;
- if (src == 0 || src == 2) {
- if (ans == 1)
- env->sr |= SR_T;
- else
- env->sr &= ~SR_T;
- } else
- env->sr &= ~SR_T;
-}
-
-#define T (env->sr & SR_T)
-#define Q (env->sr & SR_Q ? 1 : 0)
-#define M (env->sr & SR_M ? 1 : 0)
-#define SETT env->sr |= SR_T
-#define CLRT env->sr &= ~SR_T
-#define SETQ env->sr |= SR_Q
-#define CLRQ env->sr &= ~SR_Q
-#define SETM env->sr |= SR_M
-#define CLRM env->sr &= ~SR_M
-
-void helper_div1_T0_T1(void)
-{
- uint32_t tmp0, tmp2;
- uint8_t old_q, tmp1 = 0xff;
-
- //printf("div1 T0=0x%08x T1=0x%08x M=%d Q=%d T=%d\n", T0, T1, M, Q, T);
- old_q = Q;
- if ((0x80000000 & T1) != 0)
- SETQ;
- else
- CLRQ;
- tmp2 = T0;
- T1 <<= 1;
- T1 |= T;
- switch (old_q) {
- case 0:
- switch (M) {
- case 0:
- tmp0 = T1;
- T1 -= tmp2;
- tmp1 = T1 > tmp0;
- switch (Q) {
- case 0:
- if (tmp1)
- SETQ;
- else
- CLRQ;
- break;
- case 1:
- if (tmp1 == 0)
- SETQ;
- else
- CLRQ;
- break;
- }
- break;
- case 1:
- tmp0 = T1;
- T1 += tmp2;
- tmp1 = T1 < tmp0;
- switch (Q) {
- case 0:
- if (tmp1 == 0)
- SETQ;
- else
- CLRQ;
- break;
- case 1:
- if (tmp1)
- SETQ;
- else
- CLRQ;
- break;
- }
- break;
- }
- break;
- case 1:
- switch (M) {
- case 0:
- tmp0 = T1;
- T1 += tmp2;
- tmp1 = T1 < tmp0;
- switch (Q) {
- case 0:
- if (tmp1)
- SETQ;
- else
- CLRQ;
- break;
- case 1:
- if (tmp1 == 0)
- SETQ;
- else
- CLRQ;
- break;
- }
- break;
- case 1:
- tmp0 = T1;
- T1 -= tmp2;
- tmp1 = T1 > tmp0;
- switch (Q) {
- case 0:
- if (tmp1 == 0)
- SETQ;
- else
- CLRQ;
- break;
- case 1:
- if (tmp1)
- SETQ;
- else
- CLRQ;
- break;
- }
- break;
- }
- break;
- }
- if (Q == M)
- SETT;
- else
- CLRT;
- //printf("Output: T1=0x%08x M=%d Q=%d T=%d\n", T1, M, Q, T);
-}
-
-void helper_dmulsl_T0_T1()
-{
- int64_t res;
-
- res = (int64_t) (int32_t) T0 *(int64_t) (int32_t) T1;
- env->mach = (res >> 32) & 0xffffffff;
- env->macl = res & 0xffffffff;
-}
-
-void helper_dmulul_T0_T1()
-{
- uint64_t res;
-
- res = (uint64_t) (uint32_t) T0 *(uint64_t) (uint32_t) T1;
- env->mach = (res >> 32) & 0xffffffff;
- env->macl = res & 0xffffffff;
-}
-
-void helper_macl_T0_T1()
-{
- int64_t res;
-
- res = ((uint64_t) env->mach << 32) | env->macl;
- res += (int64_t) (int32_t) T0 *(int64_t) (int32_t) T1;
- env->mach = (res >> 32) & 0xffffffff;
- env->macl = res & 0xffffffff;
- if (env->sr & SR_S) {
- if (res < 0)
- env->mach |= 0xffff0000;
- else
- env->mach &= 0x00007fff;
- }
-}
-
-void helper_macw_T0_T1()
-{
- int64_t res;
-
- res = ((uint64_t) env->mach << 32) | env->macl;
- res += (int64_t) (int16_t) T0 *(int64_t) (int16_t) T1;
- env->mach = (res >> 32) & 0xffffffff;
- env->macl = res & 0xffffffff;
- if (env->sr & SR_S) {
- if (res < -0x80000000) {
- env->mach = 1;
- env->macl = 0x80000000;
- } else if (res > 0x000000007fffffff) {
- env->mach = 1;
- env->macl = 0x7fffffff;
- }
- }
-}
-
-void helper_negc_T0()
-{
- uint32_t temp;
-
- temp = -T0;
- T0 = temp - (env->sr & SR_T);
- if (0 < temp)
- env->sr |= SR_T;
- else
- env->sr &= ~SR_T;
- if (temp < T0)
- env->sr |= SR_T;
-}
-
-void helper_subc_T0_T1()
-{
- uint32_t tmp0, tmp1;
-
- tmp1 = T1 - T0;
- tmp0 = T1;
- T1 = tmp1 - (env->sr & SR_T);
- if (tmp0 < tmp1)
- env->sr |= SR_T;
- else
- env->sr &= ~SR_T;
- if (tmp1 < T1)
- env->sr |= SR_T;
-}
-
-void helper_subv_T0_T1()
-{
- int32_t dest, src, ans;
-
- if ((int32_t) T1 >= 0)
- dest = 0;
- else
- dest = 1;
- if ((int32_t) T0 >= 0)
- src = 0;
- else
- src = 1;
- src += dest;
- T1 -= T0;
- if ((int32_t) T1 >= 0)
- ans = 0;
- else
- ans = 1;
- ans += dest;
- if (src == 1) {
- if (ans == 1)
- env->sr |= SR_T;
- else
- env->sr &= ~SR_T;
- } else
- env->sr &= ~SR_T;
-}
-
-void helper_rotcl(uint32_t * addr)
-{
- uint32_t new;
-
- new = (*addr << 1) | (env->sr & SR_T);
- if (*addr & 0x80000000)
- env->sr |= SR_T;
- else
- env->sr &= ~SR_T;
- *addr = new;
-}
-
-void helper_rotcr(uint32_t * addr)
-{
- uint32_t new;
-
- new = (*addr >> 1) | ((env->sr & SR_T) ? 0x80000000 : 0);
- if (*addr & 1)
- env->sr |= SR_T;
- else
- env->sr &= ~SR_T;
- *addr = new;
-}
diff --git a/target-sh4/op_mem.c b/target-sh4/op_mem.c
deleted file mode 100644
index ca39abf..0000000
--- a/target-sh4/op_mem.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * SH4 emulation
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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 glue(op_ldb_T0_T0, MEMSUFFIX) (void) {
- T0 = glue(ldsb, MEMSUFFIX) (T0);
- RETURN();
-}
-
-void glue(op_ldub_T0_T0, MEMSUFFIX) (void) {
- T0 = glue(ldub, MEMSUFFIX) (T0);
- RETURN();
-}
-
-void glue(op_stb_T0_T1, MEMSUFFIX) (void) {
- glue(stb, MEMSUFFIX) (T1, T0);
- RETURN();
-}
-
-void glue(op_ldw_T0_T0, MEMSUFFIX) (void) {
- T0 = glue(ldsw, MEMSUFFIX) (T0);
- RETURN();
-}
-
-void glue(op_lduw_T0_T0, MEMSUFFIX) (void) {
- T0 = glue(lduw, MEMSUFFIX) (T0);
- RETURN();
-}
-
-void glue(op_stw_T0_T1, MEMSUFFIX) (void) {
- glue(stw, MEMSUFFIX) (T1, T0);
- RETURN();
-}
-
-void glue(op_ldl_T0_T0, MEMSUFFIX) (void) {
- T0 = glue(ldl, MEMSUFFIX) (T0);
- RETURN();
-}
-
-void glue(op_stl_T0_T1, MEMSUFFIX) (void) {
- glue(stl, MEMSUFFIX) (T1, T0);
- RETURN();
-}
-
-void glue(op_ldfl_T0_FT0, MEMSUFFIX) (void) {
- FT0 = glue(ldfl, MEMSUFFIX) (T0);
- RETURN();
-}
-
-void glue(op_stfl_FT0_T1, MEMSUFFIX) (void) {
- glue(stfl, MEMSUFFIX) (T1, FT0);
- RETURN();
-}
-
-void glue(op_ldfq_T0_DT0, MEMSUFFIX) (void) {
- DT0 = glue(ldfq, MEMSUFFIX) (T0);
- RETURN();
-}
-
-void glue(op_stfq_DT0_T1, MEMSUFFIX) (void) {
- glue(stfq, MEMSUFFIX) (T1, DT0);
- RETURN();
-}
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
deleted file mode 100644
index 358f975..0000000
--- a/target-sh4/translate.c
+++ /dev/null
@@ -1,1219 +0,0 @@
-/*
- * SH4 translation
- *
- * Copyright (c) 2005 Samuel Tardieu
- *
- * 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 <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <assert.h>
-
-#define DEBUG_DISAS
-#define SH4_DEBUG_DISAS
-//#define SH4_SINGLE_STEP
-
-#include "cpu.h"
-#include "exec-all.h"
-#include "disas.h"
-
-enum {
-#define DEF(s, n, copy_size) INDEX_op_ ## s,
-#include "opc.h"
-#undef DEF
- NB_OPS,
-};
-
-#ifdef USE_DIRECT_JUMP
-#define TBPARAM(x)
-#else
-#define TBPARAM(x) ((long)(x))
-#endif
-
-static uint16_t *gen_opc_ptr;
-static uint32_t *gen_opparam_ptr;
-
-#include "gen-op.h"
-
-typedef struct DisasContext {
- struct TranslationBlock *tb;
- target_ulong pc;
- uint32_t sr;
- uint32_t fpscr;
- uint16_t opcode;
- uint32_t flags;
- int memidx;
- uint32_t delayed_pc;
- int singlestep_enabled;
-} DisasContext;
-
-#ifdef CONFIG_USER_ONLY
-
-#define GEN_OP_LD(width, reg) \
- void gen_op_ld##width##_T0_##reg (DisasContext *ctx) { \
- gen_op_ld##width##_T0_##reg##_raw(); \
- }
-#define GEN_OP_ST(width, reg) \
- void gen_op_st##width##_##reg##_T1 (DisasContext *ctx) { \
- gen_op_st##width##_##reg##_T1_raw(); \
- }
-
-#else
-
-#define GEN_OP_LD(width, reg) \
- void gen_op_ld##width##_T0_##reg (DisasContext *ctx) { \
- if (ctx->memidx) gen_op_ld##width##_T0_##reg##_kernel(); \
- else gen_op_ld##width##_T0_##reg##_user();\
- }
-#define GEN_OP_ST(width, reg) \
- void gen_op_st##width##_##reg##_T1 (DisasContext *ctx) { \
- if (ctx->memidx) gen_op_st##width##_##reg##_T1_kernel(); \
- else gen_op_st##width##_##reg##_T1_user();\
- }
-
-#endif
-
-GEN_OP_LD(ub, T0)
-GEN_OP_LD(b, T0)
-GEN_OP_ST(b, T0)
-GEN_OP_LD(uw, T0)
-GEN_OP_LD(w, T0)
-GEN_OP_ST(w, T0)
-GEN_OP_LD(l, T0)
-GEN_OP_ST(l, T0)
-GEN_OP_LD(fl, FT0)
-GEN_OP_ST(fl, FT0)
-GEN_OP_LD(fq, DT0)
-GEN_OP_ST(fq, DT0)
-
-void cpu_dump_state(CPUState * env, FILE * f,
- int (*cpu_fprintf) (FILE * f, const char *fmt, ...),
- int flags)
-{
- int i;
- cpu_fprintf(f, "pc=0x%08x sr=0x%08x pr=0x%08x fpscr=0x%08x\n",
- env->pc, env->sr, env->pr, env->fpscr);
- for (i = 0; i < 24; i += 4) {
- cpu_fprintf(f, "r%d=0x%08x r%d=0x%08x r%d=0x%08x r%d=0x%08x\n",
- i, env->gregs[i], i + 1, env->gregs[i + 1],
- i + 2, env->gregs[i + 2], i + 3, env->gregs[i + 3]);
- }
- if (env->flags & DELAY_SLOT) {
- cpu_fprintf(f, "in delay slot (delayed_pc=0x%08x)\n",
- env->delayed_pc);
- } else if (env->flags & DELAY_SLOT_CONDITIONAL) {
- cpu_fprintf(f, "in conditional delay slot (delayed_pc=0x%08x)\n",
- env->delayed_pc);
- }
-}
-
-void cpu_sh4_reset(CPUSH4State * env)
-{
-#if defined(CONFIG_USER_ONLY)
- env->sr = 0x00000000;
-#else
- env->sr = 0x700000F0; /* MD, RB, BL, I3-I0 */
-#endif
- env->vbr = 0;
- env->pc = 0xA0000000;
- env->fpscr = 0x00040001;
- env->mmucr = 0;
-}
-
-CPUSH4State *cpu_sh4_init(void)
-{
- CPUSH4State *env;
-
- env = qemu_mallocz(sizeof(CPUSH4State));
- if (!env)
- return NULL;
- cpu_exec_init(env);
- cpu_sh4_reset(env);
- tlb_flush(env, 1);
- return env;
-}
-
-static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest)
-{
- TranslationBlock *tb;
- tb = ctx->tb;
-
- if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK) &&
- !ctx->singlestep_enabled) {
- /* Use a direct jump if in same page and singlestep not enabled */
- if (n == 0)
- gen_op_goto_tb0(TBPARAM(tb));
- else
- gen_op_goto_tb1(TBPARAM(tb));
- gen_op_movl_imm_T0((long) tb + n);
- } else {
- gen_op_movl_imm_T0(0);
- }
- gen_op_movl_imm_PC(dest);
- if (ctx->singlestep_enabled)
- gen_op_debug();
- gen_op_exit_tb();
-}
-
-/* Jump to pc after an exception */
-static void gen_jump_exception(DisasContext * ctx)
-{
- gen_op_movl_imm_T0(0);
- if (ctx->singlestep_enabled)
- gen_op_debug();
- gen_op_exit_tb();
-}
-
-static void gen_jump(DisasContext * ctx)
-{
- if (ctx->delayed_pc == (uint32_t) - 1) {
- /* Target is not statically known, it comes necessarily from a
- delayed jump as immediate jump are conditinal jumps */
- gen_op_movl_delayed_pc_PC();
- gen_op_movl_imm_T0(0);
- if (ctx->singlestep_enabled)
- gen_op_debug();
- gen_op_exit_tb();
- } else {
- gen_goto_tb(ctx, 0, ctx->delayed_pc);
- }
-}
-
-/* Immediate conditional jump (bt or bf) */
-static void gen_conditional_jump(DisasContext * ctx,
- target_ulong ift, target_ulong ifnott)
-{
- int l1;
-
- l1 = gen_new_label();
- gen_op_jT(l1);
- gen_goto_tb(ctx, 0, ifnott);
- gen_set_label(l1);
- gen_goto_tb(ctx, 1, ift);
-}
-
-/* Delayed conditional jump (bt or bf) */
-static void gen_delayed_conditional_jump(DisasContext * ctx)
-{
- int l1;
-
- l1 = gen_new_label();
- gen_op_jdelayed(l1);
- gen_goto_tb(ctx, 1, ctx->pc);
- gen_set_label(l1);
- gen_jump(ctx);
-}
-
-#define B3_0 (ctx->opcode & 0xf)
-#define B6_4 ((ctx->opcode >> 4) & 0x7)
-#define B7_4 ((ctx->opcode >> 4) & 0xf)
-#define B7_0 (ctx->opcode & 0xff)
-#define B7_0s ((int32_t) (int8_t) (ctx->opcode & 0xff))
-#define B11_0s (ctx->opcode & 0x800 ? 0xfffff000 | (ctx->opcode & 0xfff) : \
- (ctx->opcode & 0xfff))
-#define B11_8 ((ctx->opcode >> 8) & 0xf)
-#define B15_12 ((ctx->opcode >> 12) & 0xf)
-
-#define REG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB) ? \
- (x) + 16 : (x))
-
-#define ALTREG(x) ((x) < 8 && (ctx->sr & (SR_MD | SR_RB)) != (SR_MD | SR_RB) \
- ? (x) + 16 : (x))
-
-#define FREG(x) (ctx->fpscr & FPSCR_FR ? (x) ^ 0x10 : (x))
-#define XHACK(x) (((x) & 1 ) << 4 | ((x) & 0xe ) << 1)
-#define XREG(x) (ctx->fpscr & FPSCR_FR ? XHACK(x) ^ 0x10 : XHACK(x))
-
-#define CHECK_NOT_DELAY_SLOT \
- if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \
- {gen_op_raise_slot_illegal_instruction (); ctx->flags |= BRANCH_EXCEPTION; \
- return;}
-
-void decode_opc(DisasContext * ctx)
-{
-#if 0
- fprintf(stderr, "Translating opcode 0x%04x\n", ctx->opcode);
-#endif
- switch (ctx->opcode) {
- case 0x0019: /* div0u */
- gen_op_div0u();
- return;
- case 0x000b: /* rts */
- CHECK_NOT_DELAY_SLOT gen_op_rts();
- ctx->flags |= DELAY_SLOT;
- ctx->delayed_pc = (uint32_t) - 1;
- return;
- case 0x0028: /* clrmac */
- gen_op_clrmac();
- return;
- case 0x0048: /* clrs */
- gen_op_clrs();
- return;
- case 0x0008: /* clrt */
- gen_op_clrt();
- return;
- case 0x0038: /* ldtlb */
- assert(0); /* XXXXX */
- return;
- case 0x004b: /* rte */
- CHECK_NOT_DELAY_SLOT gen_op_rte();
- ctx->flags |= DELAY_SLOT;
- ctx->delayed_pc = (uint32_t) - 1;
- return;
- case 0x0058: /* sets */
- gen_op_sets();
- return;
- case 0x0018: /* sett */
- gen_op_sett();
- return;
- case 0xfbfb: /* frchg */
- gen_op_frchg();
- ctx->flags |= MODE_CHANGE;
- return;
- case 0xf3fb: /* fschg */
- gen_op_fschg();
- ctx->flags |= MODE_CHANGE;
- return;
- case 0x0009: /* nop */
- return;
- case 0x001b: /* sleep */
- assert(0); /* XXXXX */
- return;
- }
-
- switch (ctx->opcode & 0xf000) {
- case 0x1000: /* mov.l Rm,@(disp,Rn) */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_addl_imm_T1(B3_0 * 4);
- gen_op_stl_T0_T1(ctx);
- return;
- case 0x5000: /* mov.l @(disp,Rm),Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_addl_imm_T0(B3_0 * 4);
- gen_op_ldl_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0xe000: /* mov.l #imm,Rn */
- gen_op_movl_imm_rN(B7_0s, REG(B11_8));
- return;
- case 0x9000: /* mov.w @(disp,PC),Rn */
- gen_op_movl_imm_T0(ctx->pc + 4 + B7_0 * 2);
- gen_op_ldw_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0xd000: /* mov.l @(disp,PC),Rn */
- gen_op_movl_imm_T0((ctx->pc + 4 + B7_0 * 4) & ~3);
- gen_op_ldl_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x7000: /* add.l #imm,Rn */
- gen_op_add_imm_rN(B7_0s, REG(B11_8));
- return;
- case 0xa000: /* bra disp */
- CHECK_NOT_DELAY_SLOT
- gen_op_bra(ctx->delayed_pc = ctx->pc + 4 + B11_0s * 2);
- ctx->flags |= DELAY_SLOT;
- return;
- case 0xb000: /* bsr disp */
- CHECK_NOT_DELAY_SLOT
- gen_op_bsr(ctx->pc + 4, ctx->delayed_pc =
- ctx->pc + 4 + B11_0s * 2);
- ctx->flags |= DELAY_SLOT;
- return;
- }
-
- switch (ctx->opcode & 0xf00f) {
- case 0x6003: /* mov Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x2000: /* mov.b Rm,@Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stb_T0_T1(ctx);
- return;
- case 0x2001: /* mov.w Rm,@Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stw_T0_T1(ctx);
- return;
- case 0x2002: /* mov.l Rm,@Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stl_T0_T1(ctx);
- return;
- case 0x6000: /* mov.b @Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldb_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x6001: /* mov.w @Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldw_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x6002: /* mov.l @Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldl_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x2004: /* mov.b Rm,@-Rn */
- gen_op_dec1_rN(REG(B11_8));
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stb_T0_T1(ctx);
- return;
- case 0x2005: /* mov.w Rm,@-Rn */
- gen_op_dec2_rN(REG(B11_8));
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stw_T0_T1(ctx);
- return;
- case 0x2006: /* mov.l Rm,@-Rn */
- gen_op_dec4_rN(REG(B11_8));
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stl_T0_T1(ctx);
- return;
- case 0x6004: /* mov.b @Rm+,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldb_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- gen_op_inc1_rN(REG(B7_4));
- return;
- case 0x6005: /* mov.w @Rm+,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldw_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- gen_op_inc2_rN(REG(B7_4));
- return;
- case 0x6006: /* mov.l @Rm+,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldl_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- gen_op_inc4_rN(REG(B7_4));
- return;
- case 0x0004: /* mov.b Rm,@(R0,Rn) */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_add_rN_T1(REG(0));
- gen_op_stb_T0_T1(ctx);
- return;
- case 0x0005: /* mov.w Rm,@(R0,Rn) */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_add_rN_T1(REG(0));
- gen_op_stw_T0_T1(ctx);
- return;
- case 0x0006: /* mov.l Rm,@(R0,Rn) */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_add_rN_T1(REG(0));
- gen_op_stl_T0_T1(ctx);
- return;
- case 0x000c: /* mov.b @(R0,Rm),Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_add_rN_T0(REG(0));
- gen_op_ldb_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x000d: /* mov.w @(R0,Rm),Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_add_rN_T0(REG(0));
- gen_op_ldw_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x000e: /* mov.l @(R0,Rm),Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_add_rN_T0(REG(0));
- gen_op_ldl_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x6008: /* swap.b Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_swapb_T0();
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x6009: /* swap.w Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_swapw_T0();
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x200d: /* xtrct Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_xtrct_T0_T1();
- gen_op_movl_T1_rN(REG(B11_8));
- return;
- case 0x300c: /* add Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_add_T0_rN(REG(B11_8));
- return;
- case 0x300e: /* addc Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_addc_T0_T1();
- gen_op_movl_T1_rN(REG(B11_8));
- return;
- case 0x300f: /* addv Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_addv_T0_T1();
- gen_op_movl_T1_rN(REG(B11_8));
- return;
- case 0x2009: /* and Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_and_T0_rN(REG(B11_8));
- return;
- case 0x3000: /* cmp/eq Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_cmp_eq_T0_T1();
- return;
- case 0x3003: /* cmp/ge Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_cmp_ge_T0_T1();
- return;
- case 0x3007: /* cmp/gt Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_cmp_gt_T0_T1();
- return;
- case 0x3006: /* cmp/hi Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_cmp_hi_T0_T1();
- return;
- case 0x3002: /* cmp/hs Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_cmp_hs_T0_T1();
- return;
- case 0x200c: /* cmp/str Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_cmp_str_T0_T1();
- return;
- case 0x2007: /* div0s Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_div0s_T0_T1();
- gen_op_movl_T1_rN(REG(B11_8));
- return;
- case 0x3004: /* div1 Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_div1_T0_T1();
- gen_op_movl_T1_rN(REG(B11_8));
- return;
- case 0x300d: /* dmuls.l Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_dmulsl_T0_T1();
- return;
- case 0x3005: /* dmulu.l Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_dmulul_T0_T1();
- return;
- case 0x600e: /* exts.b Rm,Rn */
- gen_op_movb_rN_T0(REG(B7_4));
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x600f: /* exts.w Rm,Rn */
- gen_op_movw_rN_T0(REG(B7_4));
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x600c: /* extu.b Rm,Rn */
- gen_op_movub_rN_T0(REG(B7_4));
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x600d: /* extu.w Rm,Rn */
- gen_op_movuw_rN_T0(REG(B7_4));
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x000f: /* mac.l @Rm+,@Rn- */
- gen_op_movl_rN_T0(REG(B11_8));
- gen_op_ldl_T0_T0(ctx);
- gen_op_movl_T0_T1();
- gen_op_movl_rN_T1(REG(B7_4));
- gen_op_ldl_T0_T0(ctx);
- gen_op_macl_T0_T1();
- gen_op_inc4_rN(REG(B7_4));
- gen_op_inc4_rN(REG(B11_8));
- return;
- case 0x400f: /* mac.w @Rm+,@Rn+ */
- gen_op_movl_rN_T0(REG(B11_8));
- gen_op_ldl_T0_T0(ctx);
- gen_op_movl_T0_T1();
- gen_op_movl_rN_T1(REG(B7_4));
- gen_op_ldl_T0_T0(ctx);
- gen_op_macw_T0_T1();
- gen_op_inc2_rN(REG(B7_4));
- gen_op_inc2_rN(REG(B11_8));
- return;
- case 0x0007: /* mul.l Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_mull_T0_T1();
- return;
- case 0x200f: /* muls.w Rm,Rn */
- gen_op_movw_rN_T0(REG(B7_4));
- gen_op_movw_rN_T1(REG(B11_8));
- gen_op_mulsw_T0_T1();
- return;
- case 0x200e: /* mulu.w Rm,Rn */
- gen_op_movuw_rN_T0(REG(B7_4));
- gen_op_movuw_rN_T1(REG(B11_8));
- gen_op_muluw_T0_T1();
- return;
- case 0x600b: /* neg Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_neg_T0();
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x600a: /* negc Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_negc_T0();
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x6007: /* not Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_not_T0();
- gen_op_movl_T0_rN(REG(B11_8));
- return;
- case 0x200b: /* or Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_or_T0_rN(REG(B11_8));
- return;
- case 0x400c: /* shad Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_shad_T0_T1();
- gen_op_movl_T1_rN(REG(B11_8));
- return;
- case 0x400d: /* shld Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_shld_T0_T1();
- gen_op_movl_T1_rN(REG(B11_8));
- return;
- case 0x3008: /* sub Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_sub_T0_rN(REG(B11_8));
- return;
- case 0x300a: /* subc Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_subc_T0_T1();
- gen_op_movl_T1_rN(REG(B11_8));
- return;
- case 0x300b: /* subv Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_subv_T0_T1();
- gen_op_movl_T1_rN(REG(B11_8));
- return;
- case 0x2008: /* tst Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_tst_T0_T1();
- return;
- case 0x200a: /* xor Rm,Rn */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_xor_T0_rN(REG(B11_8));
- return;
- case 0xf00c: /* fmov {F,D,X}Rm,{F,D,X}Rn */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_fmov_DT0_drN(XREG(B11_8));
- } else if (ctx->fpscr & FPSCR_SZ) {
- if (ctx->opcode & 0x0110)
- break; /* illegal instruction */
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_fmov_DT0_drN(XREG(B11_8));
- } else {
- gen_op_fmov_frN_FT0(FREG(B7_4));
- gen_op_fmov_FT0_frN(FREG(B11_8));
- }
- return;
- case 0xf00a: /* fmov {F,D,X}Rm,@Rn */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stfq_DT0_T1(ctx);
- } else if (ctx->fpscr & FPSCR_SZ) {
- if (ctx->opcode & 0x0010)
- break; /* illegal instruction */
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stfq_DT0_T1(ctx);
- } else {
- gen_op_fmov_frN_FT0(FREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stfl_FT0_T1(ctx);
- }
- return;
- case 0xf008: /* fmov @Rm,{F,D,X}Rn */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
- } else if (ctx->fpscr & FPSCR_SZ) {
- if (ctx->opcode & 0x0100)
- break; /* illegal instruction */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
- } else {
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldfl_T0_FT0(ctx);
- gen_op_fmov_FT0_frN(XREG(B11_8));
- }
- return;
- case 0xf009: /* fmov @Rm+,{F,D,X}Rn */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
- gen_op_inc8_rN(REG(B7_4));
- } else if (ctx->fpscr & FPSCR_SZ) {
- if (ctx->opcode & 0x0100)
- break; /* illegal instruction */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
- gen_op_inc8_rN(REG(B7_4));
- } else {
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_ldfl_T0_FT0(ctx);
- gen_op_fmov_FT0_frN(XREG(B11_8));
- gen_op_inc4_rN(REG(B7_4));
- }
- return;
- case 0xf00b: /* fmov {F,D,X}Rm,@-Rn */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_dec8_rN(REG(B11_8));
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stfq_DT0_T1(ctx);
- } else if (ctx->fpscr & FPSCR_SZ) {
- if (ctx->opcode & 0x0100)
- break; /* illegal instruction */
- gen_op_dec8_rN(REG(B11_8));
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stfq_DT0_T1(ctx);
- } else {
- gen_op_dec4_rN(REG(B11_8));
- gen_op_fmov_frN_FT0(FREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stfl_FT0_T1(ctx);
- }
- return;
- case 0xf006: /* fmov @(R0,Rm),{F,D,X}Rm */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_add_rN_T0(REG(0));
- gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
- } else if (ctx->fpscr & FPSCR_SZ) {
- if (ctx->opcode & 0x0100)
- break; /* illegal instruction */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_add_rN_T0(REG(0));
- gen_op_ldfq_T0_DT0(ctx);
- gen_op_fmov_DT0_drN(XREG(B11_8));
- } else {
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_add_rN_T0(REG(0));
- gen_op_ldfl_T0_FT0(ctx);
- gen_op_fmov_FT0_frN(XREG(B11_8));
- }
- return;
- case 0xf007: /* fmov {F,D,X}Rn,@(R0,Rn) */
- if (ctx->fpscr & FPSCR_PR) {
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_add_rN_T1(REG(0));
- gen_op_stfq_DT0_T1(ctx);
- } else if (ctx->fpscr & FPSCR_SZ) {
- if (ctx->opcode & 0x0010)
- break; /* illegal instruction */
- gen_op_fmov_drN_DT0(XREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_add_rN_T1(REG(0));
- gen_op_stfq_DT0_T1(ctx);
- } else {
- gen_op_fmov_frN_FT0(FREG(B7_4));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_add_rN_T1(REG(0));
- gen_op_stfl_FT0_T1(ctx);
- }
- return;
- }
-
- switch (ctx->opcode & 0xff00) {
- case 0xc900: /* and #imm,R0 */
- gen_op_and_imm_rN(B7_0, REG(0));
- return;
- case 0xcd00: /* and.b #imm,@(R0+GBR) */
- gen_op_movl_rN_T0(REG(0));
- gen_op_addl_GBR_T0();
- gen_op_movl_T0_T1();
- gen_op_ldb_T0_T0(ctx);
- gen_op_and_imm_T0(B7_0);
- gen_op_stb_T0_T1(ctx);
- return;
- case 0x8b00: /* bf label */
- CHECK_NOT_DELAY_SLOT
- gen_conditional_jump(ctx, ctx->pc + 2,
- ctx->pc + 4 + B7_0s * 2);
- ctx->flags |= BRANCH_CONDITIONAL;
- return;
- case 0x8f00: /* bf/s label */
- CHECK_NOT_DELAY_SLOT
- gen_op_bf_s(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2);
- ctx->flags |= DELAY_SLOT_CONDITIONAL;
- return;
- case 0x8900: /* bt label */
- CHECK_NOT_DELAY_SLOT
- gen_conditional_jump(ctx, ctx->pc + 4 + B7_0s * 2,
- ctx->pc + 2);
- ctx->flags |= BRANCH_CONDITIONAL;
- return;
- case 0x8d00: /* bt/s label */
- CHECK_NOT_DELAY_SLOT
- gen_op_bt_s(ctx->delayed_pc = ctx->pc + 4 + B7_0s * 2);
- ctx->flags |= DELAY_SLOT_CONDITIONAL;
- return;
- case 0x8800: /* cmp/eq #imm,R0 */
- gen_op_movl_rN_T0(REG(0));
- gen_op_cmp_eq_imm_T0(B7_0s);
- return;
- case 0xc400: /* mov.b @(disp,GBR),R0 */
- gen_op_stc_gbr_T0();
- gen_op_addl_imm_T0(B7_0);
- gen_op_ldb_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(0));
- return;
- case 0xc500: /* mov.w @(disp,GBR),R0 */
- gen_op_stc_gbr_T0();
- gen_op_addl_imm_T0(B7_0);
- gen_op_ldw_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(0));
- return;
- case 0xc600: /* mov.l @(disp,GBR),R0 */
- gen_op_stc_gbr_T0();
- gen_op_addl_imm_T0(B7_0);
- gen_op_ldl_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(0));
- return;
- case 0xc000: /* mov.b R0,@(disp,GBR) */
- gen_op_stc_gbr_T0();
- gen_op_addl_imm_T0(B7_0);
- gen_op_movl_T0_T1();
- gen_op_movl_rN_T0(REG(0));
- gen_op_stb_T0_T1(ctx);
- return;
- case 0xc100: /* mov.w R0,@(disp,GBR) */
- gen_op_stc_gbr_T0();
- gen_op_addl_imm_T0(B7_0);
- gen_op_movl_T0_T1();
- gen_op_movl_rN_T0(REG(0));
- gen_op_stw_T0_T1(ctx);
- return;
- case 0xc200: /* mov.l R0,@(disp,GBR) */
- gen_op_stc_gbr_T0();
- gen_op_addl_imm_T0(B7_0);
- gen_op_movl_T0_T1();
- gen_op_movl_rN_T0(REG(0));
- gen_op_stl_T0_T1(ctx);
- return;
- case 0x8000: /* mov.b R0,@(disp,Rn) */
- gen_op_movl_rN_T0(REG(0));
- gen_op_movl_rN_T1(REG(B7_4));
- gen_op_addl_imm_T1(B3_0);
- gen_op_stb_T0_T1(ctx);
- return;
- case 0x8100: /* mov.w R0,@(disp,Rn) */
- gen_op_movl_rN_T0(REG(0));
- gen_op_movl_rN_T1(REG(B7_4));
- gen_op_addl_imm_T1(B3_0 * 2);
- gen_op_stw_T0_T1(ctx);
- return;
- case 0x8400: /* mov.b @(disp,Rn),R0 */
- gen_op_movl_rN_T0(REG(0));
- gen_op_movl_rN_T1(REG(B7_4));
- gen_op_addl_imm_T1(B3_0);
- gen_op_stb_T0_T1(ctx);
- return;
- case 0x8500: /* mov.w @(disp,Rn),R0 */
- gen_op_movl_rN_T0(REG(B7_4));
- gen_op_addl_imm_T0(B3_0 * 2);
- gen_op_ldw_T0_T0(ctx);
- gen_op_movl_T0_rN(REG(0));
- return;
- case 0xc700: /* mova @(disp,PC),R0 */
- gen_op_movl_imm_rN(((ctx->pc & 0xfffffffc) + 4 + B7_0 * 4) & ~3,
- REG(0));
- return;
- case 0xcb00: /* or #imm,R0 */
- gen_op_or_imm_rN(B7_0, REG(0));
- return;
- case 0xcf00: /* or.b #imm,@(R0+GBR) */
- gen_op_movl_rN_T0(REG(0));
- gen_op_addl_GBR_T0();
- gen_op_movl_T0_T1();
- gen_op_ldb_T0_T0(ctx);
- gen_op_or_imm_T0(B7_0);
- gen_op_stb_T0_T1(ctx);
- return;
- case 0xc300: /* trapa #imm */
- CHECK_NOT_DELAY_SLOT gen_op_movl_imm_PC(ctx->pc);
- gen_op_trapa(B7_0);
- ctx->flags |= BRANCH;
- return;
- case 0xc800: /* tst #imm,R0 */
- gen_op_tst_imm_rN(B7_0, REG(0));
- return;
- case 0xcc00: /* tst #imm,@(R0+GBR) */
- gen_op_movl_rN_T0(REG(0));
- gen_op_addl_GBR_T0();
- gen_op_ldb_T0_T0(ctx);
- gen_op_tst_imm_T0(B7_0);
- return;
- case 0xca00: /* xor #imm,R0 */
- gen_op_xor_imm_rN(B7_0, REG(0));
- return;
- case 0xce00: /* xor.b #imm,@(R0+GBR) */
- gen_op_movl_rN_T0(REG(0));
- gen_op_addl_GBR_T0();
- gen_op_movl_T0_T1();
- gen_op_ldb_T0_T0(ctx);
- gen_op_xor_imm_T0(B7_0);
- gen_op_stb_T0_T1(ctx);
- return;
- }
-
- switch (ctx->opcode & 0xf08f) {
- case 0x408e: /* ldc Rm,Rn_BANK */
- gen_op_movl_rN_rN(REG(B11_8), ALTREG(B6_4));
- return;
- case 0x4087: /* ldc.l @Rm+,Rn_BANK */
- gen_op_movl_rN_T0(REG(B11_8));
- gen_op_ldl_T0_T0(ctx);
- gen_op_movl_T0_rN(ALTREG(B6_4));
- gen_op_inc4_rN(REG(B11_8));
- return;
- case 0x0082: /* stc Rm_BANK,Rn */
- gen_op_movl_rN_rN(ALTREG(B6_4), REG(B11_8));
- return;
- case 0x4083: /* stc.l Rm_BANK,@-Rn */
- gen_op_dec4_rN(REG(B11_8));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_movl_rN_T0(ALTREG(B6_4));
- gen_op_stl_T0_T1(ctx);
- return;
- }
-
- switch (ctx->opcode & 0xf0ff) {
- case 0x0023: /* braf Rn */
- CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8));
- gen_op_braf_T0(ctx->pc + 4);
- ctx->flags |= DELAY_SLOT;
- ctx->delayed_pc = (uint32_t) - 1;
- return;
- case 0x0003: /* bsrf Rn */
- CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8));
- gen_op_bsrf_T0(ctx->pc + 4);
- ctx->flags |= DELAY_SLOT;
- ctx->delayed_pc = (uint32_t) - 1;
- return;
- case 0x4015: /* cmp/pl Rn */
- gen_op_movl_rN_T0(REG(B11_8));
- gen_op_cmp_pl_T0();
- return;
- case 0x4011: /* cmp/pz Rn */
- gen_op_movl_rN_T0(REG(B11_8));
- gen_op_cmp_pz_T0();
- return;
- case 0x4010: /* dt Rn */
- gen_op_dt_rN(REG(B11_8));
- return;
- case 0x402b: /* jmp @Rn */
- CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8));
- gen_op_jmp_T0();
- ctx->flags |= DELAY_SLOT;
- ctx->delayed_pc = (uint32_t) - 1;
- return;
- case 0x400b: /* jsr @Rn */
- CHECK_NOT_DELAY_SLOT gen_op_movl_rN_T0(REG(B11_8));
- gen_op_jsr_T0(ctx->pc + 4);
- ctx->flags |= DELAY_SLOT;
- ctx->delayed_pc = (uint32_t) - 1;
- return;
-#define LDST(reg,ldnum,ldpnum,ldop,stnum,stpnum,stop,extrald) \
- case ldnum: \
- gen_op_movl_rN_T0 (REG(B11_8)); \
- gen_op_##ldop##_T0_##reg (); \
- extrald \
- return; \
- case ldpnum: \
- gen_op_movl_rN_T0 (REG(B11_8)); \
- gen_op_ldl_T0_T0 (ctx); \
- gen_op_inc4_rN (REG(B11_8)); \
- gen_op_##ldop##_T0_##reg (); \
- extrald \
- return; \
- case stnum: \
- gen_op_##stop##_##reg##_T0 (); \
- gen_op_movl_T0_rN (REG(B11_8)); \
- return; \
- case stpnum: \
- gen_op_##stop##_##reg##_T0 (); \
- gen_op_dec4_rN (REG(B11_8)); \
- gen_op_movl_rN_T1 (REG(B11_8)); \
- gen_op_stl_T0_T1 (ctx); \
- return;
- LDST(sr, 0x400e, 0x4007, ldc, 0x0002, 0x4003, stc, ctx->flags |=
- MODE_CHANGE;)
- LDST(gbr, 0x401e, 0x4017, ldc, 0x0012, 0x4013, stc,)
- LDST(vbr, 0x402e, 0x4027, ldc, 0x0022, 0x4023, stc,)
- LDST(ssr, 0x403e, 0x4037, ldc, 0x0032, 0x4033, stc,)
- LDST(spc, 0x404e, 0x4047, ldc, 0x0042, 0x4043, stc,)
- LDST(dbr, 0x40fa, 0x40f6, ldc, 0x00fa, 0x40f2, stc,)
- 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 |=
- MODE_CHANGE;)
- case 0x00c3: /* movca.l R0,@Rm */
- gen_op_movl_rN_T0(REG(0));
- gen_op_movl_rN_T1(REG(B11_8));
- gen_op_stl_T0_T1(ctx);
- return;
- case 0x0029: /* movt Rn */
- gen_op_movt_rN(REG(B11_8));
- return;
- case 0x0093: /* ocbi @Rn */
- gen_op_movl_rN_T0(REG(B11_8));
- gen_op_ldl_T0_T0(ctx);
- return;
- case 0x00a2: /* ocbp @Rn */
- gen_op_movl_rN_T0(REG(B11_8));
- gen_op_ldl_T0_T0(ctx);
- return;
- case 0x00b3: /* ocbwb @Rn */
- gen_op_movl_rN_T0(REG(B11_8));
- gen_op_ldl_T0_T0(ctx);
- return;
- case 0x0083: /* pref @Rn */
- return;
- case 0x4024: /* rotcl Rn */
- gen_op_rotcl_Rn(REG(B11_8));
- return;
- case 0x4025: /* rotcr Rn */
- gen_op_rotcr_Rn(REG(B11_8));
- return;
- case 0x4004: /* rotl Rn */
- gen_op_rotl_Rn(REG(B11_8));
- return;
- case 0x4005: /* rotr Rn */
- gen_op_rotr_Rn(REG(B11_8));
- return;
- case 0x4000: /* shll Rn */
- case 0x4020: /* shal Rn */
- gen_op_shal_Rn(REG(B11_8));
- return;
- case 0x4021: /* shar Rn */
- gen_op_shar_Rn(REG(B11_8));
- return;
- case 0x4001: /* shlr Rn */
- gen_op_shlr_Rn(REG(B11_8));
- return;
- case 0x4008: /* shll2 Rn */
- gen_op_shll2_Rn(REG(B11_8));
- return;
- case 0x4018: /* shll8 Rn */
- gen_op_shll8_Rn(REG(B11_8));
- return;
- case 0x4028: /* shll16 Rn */
- gen_op_shll16_Rn(REG(B11_8));
- return;
- case 0x4009: /* shlr2 Rn */
- gen_op_shlr2_Rn(REG(B11_8));
- return;
- case 0x4019: /* shlr8 Rn */
- gen_op_shlr8_Rn(REG(B11_8));
- return;
- case 0x4029: /* shlr16 Rn */
- gen_op_shlr16_Rn(REG(B11_8));
- return;
- case 0x401b: /* tas.b @Rn */
- gen_op_tasb_rN(REG(B11_8));
- return;
- case 0xf00d: /* fsts FPUL,FRn */
- gen_op_movl_fpul_FT0();
- gen_op_fmov_FT0_frN(FREG(B11_8));
- return;
- case 0xf01d: /* flds FRm.FPUL */
- gen_op_fmov_frN_FT0(FREG(B11_8));
- gen_op_movl_FT0_fpul();
- return;
- }
-
- fprintf(stderr, "unknown instruction 0x%04x at pc 0x%08x\n",
- ctx->opcode, ctx->pc);
- gen_op_raise_illegal_instruction();
- ctx->flags |= BRANCH_EXCEPTION;
-}
-
-int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
- int search_pc)
-{
- DisasContext ctx;
- target_ulong pc_start;
- static uint16_t *gen_opc_end;
- uint32_t old_flags;
- int i, ii;
-
- pc_start = tb->pc;
- gen_opc_ptr = gen_opc_buf;
- gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
- gen_opparam_ptr = gen_opparam_buf;
- ctx.pc = pc_start;
- ctx.flags = env->flags;
- old_flags = 0;
- ctx.sr = env->sr;
- ctx.fpscr = env->fpscr;
- ctx.memidx = (env->sr & SR_MD) ? 1 : 0;
- /* We don't know if the delayed pc came from a dynamic or static branch,
- so assume it is a dynamic branch. */
- ctx.delayed_pc = -1;
- ctx.tb = tb;
- ctx.singlestep_enabled = env->singlestep_enabled;
- nb_gen_labels = 0;
-
-#ifdef DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_CPU) {
- fprintf(logfile,
- "------------------------------------------------\n");
- cpu_dump_state(env, logfile, fprintf, 0);
- }
-#endif
-
- ii = -1;
- while ((old_flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) == 0 &&
- (ctx.flags & (BRANCH | BRANCH_CONDITIONAL | MODE_CHANGE |
- BRANCH_EXCEPTION)) == 0 &&
- gen_opc_ptr < gen_opc_end && ctx.sr == env->sr) {
- old_flags = ctx.flags;
- if (env->nb_breakpoints > 0) {
- for (i = 0; i < env->nb_breakpoints; i++) {
- if (ctx.pc == env->breakpoints[i]) {
- /* We have hit a breakpoint - make sure PC is up-to-date */
- gen_op_movl_imm_PC(ctx.pc);
- gen_op_debug();
- ctx.flags |= BRANCH_EXCEPTION;
- break;
- }
- }
- }
- if (search_pc) {
- i = gen_opc_ptr - gen_opc_buf;
- if (ii < i) {
- ii++;
- while (ii < i)
- gen_opc_instr_start[ii++] = 0;
- }
- gen_opc_pc[ii] = ctx.pc;
- gen_opc_instr_start[ii] = 1;
- }
-#if 0
- fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc);
- fflush(stderr);
-#endif
- ctx.opcode = lduw_code(ctx.pc);
- decode_opc(&ctx);
- ctx.pc += 2;
- if ((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0)
- break;
- if (env->singlestep_enabled)
- break;
-#ifdef SH4_SINGLE_STEP
- break;
-#endif
- }
-
- if (old_flags & DELAY_SLOT_CONDITIONAL) {
- gen_delayed_conditional_jump(&ctx);
- } else if (old_flags & DELAY_SLOT) {
- gen_op_clr_delay_slot();
- gen_jump(&ctx);
- } else if (ctx.flags & BRANCH_EXCEPTION) {
- gen_jump_exception(&ctx);
- } else if ((ctx.flags & (BRANCH | BRANCH_CONDITIONAL)) == 0) {
- gen_goto_tb(&ctx, 0, ctx.pc);
- }
-
- if (env->singlestep_enabled) {
- gen_op_debug();
- }
- *gen_opc_ptr = INDEX_op_end;
- if (search_pc) {
- i = gen_opc_ptr - gen_opc_buf;
- ii++;
- while (ii <= i)
- gen_opc_instr_start[ii++] = 0;
- tb->size = 0;
- } else {
- tb->size = ctx.pc - pc_start;
- }
-
-#ifdef DEBUG_DISAS
-#ifdef SH4_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM)
- fprintf(logfile, "\n");
-#endif
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "IN:\n"); /* , lookup_symbol(pc_start)); */
- target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
- 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);
-}
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
deleted file mode 100644
index 8cbf0b2..0000000
--- a/target-sparc/cpu.h
+++ /dev/null
@@ -1,277 +0,0 @@
-#ifndef CPU_SPARC_H
-#define CPU_SPARC_H
-
-#include "config.h"
-
-#if !defined(TARGET_SPARC64)
-#define TARGET_LONG_BITS 32
-#define TARGET_FPREGS 32
-#define TARGET_PAGE_BITS 12 /* 4k */
-#else
-#define TARGET_LONG_BITS 64
-#define TARGET_FPREGS 64
-#define TARGET_PAGE_BITS 12 /* XXX */
-#endif
-
-#include "cpu-defs.h"
-
-#include "softfloat.h"
-
-#define TARGET_HAS_ICE 1
-
-/*#define EXCP_INTERRUPT 0x100*/
-
-/* trap definitions */
-#ifndef TARGET_SPARC64
-#define TT_TFAULT 0x01
-#define TT_ILL_INSN 0x02
-#define TT_PRIV_INSN 0x03
-#define TT_NFPU_INSN 0x04
-#define TT_WIN_OVF 0x05
-#define TT_WIN_UNF 0x06
-#define TT_FP_EXCP 0x08
-#define TT_DFAULT 0x09
-#define TT_EXTINT 0x10
-#define TT_DIV_ZERO 0x2a
-#define TT_TRAP 0x80
-#else
-#define TT_TFAULT 0x08
-#define TT_TMISS 0x09
-#define TT_ILL_INSN 0x10
-#define TT_PRIV_INSN 0x11
-#define TT_NFPU_INSN 0x20
-#define TT_FP_EXCP 0x21
-#define TT_CLRWIN 0x24
-#define TT_DIV_ZERO 0x28
-#define TT_DFAULT 0x30
-#define TT_DMISS 0x31
-#define TT_DPROT 0x32
-#define TT_PRIV_ACT 0x37
-#define TT_EXTINT 0x40
-#define TT_SPILL 0x80
-#define TT_FILL 0xc0
-#define TT_WOTHER 0x10
-#define TT_TRAP 0x100
-#endif
-
-#define PSR_NEG (1<<23)
-#define PSR_ZERO (1<<22)
-#define PSR_OVF (1<<21)
-#define PSR_CARRY (1<<20)
-#define PSR_ICC (PSR_NEG|PSR_ZERO|PSR_OVF|PSR_CARRY)
-#define PSR_EF (1<<12)
-#define PSR_PIL 0xf00
-#define PSR_S (1<<7)
-#define PSR_PS (1<<6)
-#define PSR_ET (1<<5)
-#define PSR_CWP 0x1f
-
-/* Trap base register */
-#define TBR_BASE_MASK 0xfffff000
-
-#if defined(TARGET_SPARC64)
-#define PS_IG (1<<11)
-#define PS_MG (1<<10)
-#define PS_RED (1<<5)
-#define PS_PEF (1<<4)
-#define PS_AM (1<<3)
-#define PS_PRIV (1<<2)
-#define PS_IE (1<<1)
-#define PS_AG (1<<0)
-
-#define FPRS_FEF (1<<2)
-#endif
-
-/* Fcc */
-#define FSR_RD1 (1<<31)
-#define FSR_RD0 (1<<30)
-#define FSR_RD_MASK (FSR_RD1 | FSR_RD0)
-#define FSR_RD_NEAREST 0
-#define FSR_RD_ZERO FSR_RD0
-#define FSR_RD_POS FSR_RD1
-#define FSR_RD_NEG (FSR_RD1 | FSR_RD0)
-
-#define FSR_NVM (1<<27)
-#define FSR_OFM (1<<26)
-#define FSR_UFM (1<<25)
-#define FSR_DZM (1<<24)
-#define FSR_NXM (1<<23)
-#define FSR_TEM_MASK (FSR_NVM | FSR_OFM | FSR_UFM | FSR_DZM | FSR_NXM)
-
-#define FSR_NVA (1<<9)
-#define FSR_OFA (1<<8)
-#define FSR_UFA (1<<7)
-#define FSR_DZA (1<<6)
-#define FSR_NXA (1<<5)
-#define FSR_AEXC_MASK (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA)
-
-#define FSR_NVC (1<<4)
-#define FSR_OFC (1<<3)
-#define FSR_UFC (1<<2)
-#define FSR_DZC (1<<1)
-#define FSR_NXC (1<<0)
-#define FSR_CEXC_MASK (FSR_NVC | FSR_OFC | FSR_UFC | FSR_DZC | FSR_NXC)
-
-#define FSR_FTT2 (1<<16)
-#define FSR_FTT1 (1<<15)
-#define FSR_FTT0 (1<<14)
-#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_INVAL_FPR (6 << 14)
-
-#define FSR_FCC1 (1<<11)
-#define FSR_FCC0 (1<<10)
-
-/* MMU */
-#define MMU_E (1<<0)
-#define MMU_NF (1<<1)
-
-#define PTE_ENTRYTYPE_MASK 3
-#define PTE_ACCESS_MASK 0x1c
-#define PTE_ACCESS_SHIFT 2
-#define PTE_PPN_SHIFT 7
-#define PTE_ADDR_MASK 0xffffff00
-
-#define PG_ACCESSED_BIT 5
-#define PG_MODIFIED_BIT 6
-#define PG_CACHE_BIT 7
-
-#define PG_ACCESSED_MASK (1 << PG_ACCESSED_BIT)
-#define PG_MODIFIED_MASK (1 << PG_MODIFIED_BIT)
-#define PG_CACHE_MASK (1 << PG_CACHE_BIT)
-
-/* 2 <= NWINDOWS <= 32. In QEMU it must also be a power of two. */
-#define NWINDOWS 8
-
-typedef struct CPUSPARCState {
- target_ulong gregs[8]; /* general registers */
- target_ulong *regwptr; /* pointer to current register window */
- float32 fpr[TARGET_FPREGS]; /* floating point registers */
- target_ulong pc; /* program counter */
- target_ulong npc; /* next program counter */
- target_ulong y; /* multiply/divide register */
- uint32_t psr; /* processor state register */
- target_ulong fsr; /* FPU state register */
- uint32_t cwp; /* index of current register window (extracted
- from PSR) */
- uint32_t wim; /* window invalid mask */
- target_ulong tbr; /* trap base register */
- int psrs; /* supervisor mode (extracted from PSR) */
- int psrps; /* previous supervisor mode */
- int psret; /* enable traps */
- uint32_t psrpil; /* interrupt level */
- int psref; /* enable fpu */
- jmp_buf jmp_env;
- int user_mode_only;
- int exception_index;
- int interrupt_index;
- int interrupt_request;
- int halted;
- /* NOTE: we allow 8 more registers to handle wrapping */
- target_ulong regbase[NWINDOWS * 16 + 8];
-
- CPU_COMMON
-
- /* MMU regs */
-#if defined(TARGET_SPARC64)
- uint64_t lsu;
-#define DMMU_E 0x8
-#define IMMU_E 0x4
- uint64_t immuregs[16];
- uint64_t dmmuregs[16];
- uint64_t itlb_tag[64];
- uint64_t itlb_tte[64];
- uint64_t dtlb_tag[64];
- uint64_t dtlb_tte[64];
-#else
- uint32_t mmuregs[16];
-#endif
- /* temporary float registers */
- float32 ft0, ft1;
- float64 dt0, dt1;
- float_status fp_status;
-#if defined(TARGET_SPARC64)
-#define MAXTL 4
- uint64_t t0, t1, t2;
- uint64_t tpc[MAXTL];
- uint64_t tnpc[MAXTL];
- uint64_t tstate[MAXTL];
- uint32_t tt[MAXTL];
- uint32_t xcc; /* Extended integer condition codes */
- uint32_t asi;
- uint32_t pstate;
- uint32_t tl;
- uint32_t cansave, canrestore, otherwin, wstate, cleanwin;
- uint64_t agregs[8]; /* alternate general registers */
- 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;
-#endif
-#if !defined(TARGET_SPARC64) && !defined(reg_T2)
- target_ulong t2;
-#endif
-} CPUSPARCState;
-#if defined(TARGET_SPARC64)
-#define GET_FSR32(env) (env->fsr & 0xcfc1ffff)
-#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \
- env->fsr = (_tmp & 0xcfc1c3ff) | (env->fsr & 0x3f00000000ULL); \
- } while (0)
-#define GET_FSR64(env) (env->fsr & 0x3fcfc1ffffULL)
-#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; \
- } while (0)
-#endif
-
-CPUSPARCState *cpu_sparc_init(void);
-int cpu_sparc_exec(CPUSPARCState *s);
-int cpu_sparc_close(CPUSPARCState *s);
-
-/* Fake impl 0, version 4 */
-#define GET_PSR(env) ((0 << 28) | (4 << 24) | (env->psr & PSR_ICC) | \
- (env->psref? PSR_EF : 0) | \
- (env->psrpil << 8) | \
- (env->psrs? PSR_S : 0) | \
- (env->psrps? PSR_PS : 0) | \
- (env->psret? PSR_ET : 0) | env->cwp)
-
-#ifndef NO_CPU_IO_DEFS
-void cpu_set_cwp(CPUSPARCState *env1, int new_cwp);
-#endif
-
-#define PUT_PSR(env, val) do { int _tmp = val; \
- env->psr = _tmp & PSR_ICC; \
- env->psref = (_tmp & PSR_EF)? 1 : 0; \
- env->psrpil = (_tmp & PSR_PIL) >> 8; \
- 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)); \
- } while (0)
-
-#ifdef TARGET_SPARC64
-#define GET_CCR(env) ((env->xcc << 4) | (env->psr & PSR_ICC))
-#define PUT_CCR(env, val) do { int _tmp = val; \
- env->xcc = _tmp >> 4; \
- env->psr = (_tmp & 0xf) << 20; \
- } while (0)
-#endif
-
-struct siginfo;
-int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
-
-#include "cpu-all.h"
-
-#endif
diff --git a/target-sparc/exec.h b/target-sparc/exec.h
deleted file mode 100644
index 1b67ef4..0000000
--- a/target-sparc/exec.h
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef EXEC_SPARC_H
-#define EXEC_SPARC_H 1
-#include "dyngen-exec.h"
-#include "config.h"
-
-register struct CPUSPARCState *env asm(AREG0);
-#ifdef TARGET_SPARC64
-#define T0 (env->t0)
-#define T1 (env->t1)
-#define T2 (env->t2)
-#define REGWPTR env->regwptr
-#else
-register uint32_t T0 asm(AREG1);
-register uint32_t T1 asm(AREG2);
-
-#undef REG_REGWPTR // Broken
-#ifdef REG_REGWPTR
-register uint32_t *REGWPTR asm(AREG3);
-#define reg_REGWPTR
-
-#ifdef AREG4
-register uint32_t T2 asm(AREG4);
-#define reg_T2
-#else
-#define T2 (env->t2)
-#endif
-
-#else
-#define REGWPTR env->regwptr
-register uint32_t T2 asm(AREG3);
-#define reg_T2
-#endif
-#endif
-
-#define FT0 (env->ft0)
-#define FT1 (env->ft1)
-#define DT0 (env->dt0)
-#define DT1 (env->dt1)
-
-#include "cpu.h"
-#include "exec-all.h"
-
-void cpu_lock(void);
-void cpu_unlock(void);
-void cpu_loop_exit(void);
-void helper_flush(target_ulong addr);
-void helper_ld_asi(int asi, int size, int sign);
-void helper_st_asi(int asi, int size, int sign);
-void helper_rett(void);
-void helper_ldfsr(void);
-void set_cwp(int new_cwp);
-void do_fitos(void);
-void do_fitod(void);
-void do_fabss(void);
-void do_fsqrts(void);
-void do_fsqrtd(void);
-void do_fcmps(void);
-void do_fcmpd(void);
-#ifdef TARGET_SPARC64
-void do_fabsd(void);
-void do_fcmps_fcc1(void);
-void do_fcmpd_fcc1(void);
-void do_fcmps_fcc2(void);
-void do_fcmpd_fcc2(void);
-void do_fcmps_fcc3(void);
-void do_fcmpd_fcc3(void);
-void do_popc();
-void do_wrpstate();
-void do_done();
-void do_retry();
-#endif
-void do_ldd_kernel(target_ulong addr);
-void do_ldd_user(target_ulong addr);
-void do_ldd_raw(target_ulong addr);
-void do_interrupt(int intno);
-void raise_exception(int tt);
-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);
-void helper_debug();
-void do_wrpsr();
-void do_rdpsr();
-
-/* XXX: move that to a generic header */
-#if !defined(CONFIG_USER_ONLY)
-#include "softmmu_exec.h"
-#endif /* !defined(CONFIG_USER_ONLY) */
-
-static inline void env_to_regs(void)
-{
-#if defined(reg_REGWPTR)
- REGWPTR = env->regbase + (env->cwp * 16);
- env->regwptr = REGWPTR;
-#endif
-}
-
-static inline void regs_to_env(void)
-{
-}
-
-int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
- int is_user, int is_softmmu);
-
-#endif
diff --git a/target-sparc/fbranch_template.h b/target-sparc/fbranch_template.h
deleted file mode 100644
index e6bf9a2..0000000
--- a/target-sparc/fbranch_template.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* FCC1:FCC0: 0 =, 1 <, 2 >, 3 u */
-
-void OPPROTO glue(op_eval_fbne, FCC)(void)
-{
-// !0
- T2 = FFLAG_SET(FSR_FCC0) | FFLAG_SET(FSR_FCC1); /* L or G or U */
-}
-
-void OPPROTO glue(op_eval_fblg, FCC)(void)
-{
-// 1 or 2
- T2 = FFLAG_SET(FSR_FCC0) ^ FFLAG_SET(FSR_FCC1);
-}
-
-void OPPROTO glue(op_eval_fbul, FCC)(void)
-{
-// 1 or 3
- T2 = FFLAG_SET(FSR_FCC0);
-}
-
-void OPPROTO glue(op_eval_fbl, FCC)(void)
-{
-// 1
- T2 = FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1);
-}
-
-void OPPROTO glue(op_eval_fbug, FCC)(void)
-{
-// 2 or 3
- T2 = FFLAG_SET(FSR_FCC1);
-}
-
-void OPPROTO glue(op_eval_fbg, FCC)(void)
-{
-// 2
- T2 = !FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1);
-}
-
-void OPPROTO glue(op_eval_fbu, FCC)(void)
-{
-// 3
- T2 = FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1);
-}
-
-void OPPROTO glue(op_eval_fbe, FCC)(void)
-{
-// 0
- T2 = !FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1);
-}
-
-void OPPROTO glue(op_eval_fbue, FCC)(void)
-{
-// 0 or 3
- T2 = !(FFLAG_SET(FSR_FCC1) ^ FFLAG_SET(FSR_FCC0));
- FORCE_RET();
-}
-
-void OPPROTO glue(op_eval_fbge, FCC)(void)
-{
-// 0 or 2
- T2 = !FFLAG_SET(FSR_FCC0);
-}
-
-void OPPROTO glue(op_eval_fbuge, FCC)(void)
-{
-// !1
- T2 = !(FFLAG_SET(FSR_FCC0) & !FFLAG_SET(FSR_FCC1));
-}
-
-void OPPROTO glue(op_eval_fble, FCC)(void)
-{
-// 0 or 1
- T2 = !FFLAG_SET(FSR_FCC1);
-}
-
-void OPPROTO glue(op_eval_fbule, FCC)(void)
-{
-// !2
- T2 = !(!FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1));
-}
-
-void OPPROTO glue(op_eval_fbo, FCC)(void)
-{
-// !3
- T2 = !(FFLAG_SET(FSR_FCC0) & FFLAG_SET(FSR_FCC1));
-}
-
-#undef FCC
-#undef FFLAG_SET
diff --git a/target-sparc/fop_template.h b/target-sparc/fop_template.h
deleted file mode 100644
index 74988f7..0000000
--- a/target-sparc/fop_template.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * SPARC micro operations (templates for various register related
- * operations)
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/* floating point registers moves */
-void OPPROTO glue(op_load_fpr_FT0_fpr, REGNAME)(void)
-{
- FT0 = REG;
-}
-
-void OPPROTO glue(op_store_FT0_fpr_fpr, REGNAME)(void)
-{
- REG = FT0;
-}
-
-void OPPROTO glue(op_load_fpr_FT1_fpr, REGNAME)(void)
-{
- FT1 = REG;
-}
-
-void OPPROTO glue(op_store_FT1_fpr_fpr, REGNAME)(void)
-{
- REG = FT1;
-}
-
-/* double floating point registers moves */
-void OPPROTO glue(op_load_fpr_DT0_fpr, REGNAME)(void)
-{
- CPU_DoubleU u;
- uint32_t *p = (uint32_t *)&REG;
- u.l.lower = *(p +1);
- u.l.upper = *p;
- DT0 = u.d;
-}
-
-void OPPROTO glue(op_store_DT0_fpr_fpr, REGNAME)(void)
-{
- CPU_DoubleU u;
- uint32_t *p = (uint32_t *)&REG;
- u.d = DT0;
- *(p +1) = u.l.lower;
- *p = u.l.upper;
-}
-
-void OPPROTO glue(op_load_fpr_DT1_fpr, REGNAME)(void)
-{
- CPU_DoubleU u;
- uint32_t *p = (uint32_t *)&REG;
- u.l.lower = *(p +1);
- u.l.upper = *p;
- DT1 = u.d;
-}
-
-void OPPROTO glue(op_store_DT1_fpr_fpr, REGNAME)(void)
-{
- CPU_DoubleU u;
- uint32_t *p = (uint32_t *)&REG;
- u.d = DT1;
- *(p +1) = u.l.lower;
- *p = u.l.upper;
-}
-
-#undef REG
-#undef REGNAME
diff --git a/target-sparc/helper.c b/target-sparc/helper.c
deleted file mode 100644
index 8f12667..0000000
--- a/target-sparc/helper.c
+++ /dev/null
@@ -1,589 +0,0 @@
-/*
- * sparc helpers
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <stdarg.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include <signal.h>
-#include <assert.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-
-//#define DEBUG_MMU
-
-/* Sparc MMU emulation */
-
-/* thread support */
-
-spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
-
-void cpu_lock(void)
-{
- spin_lock(&global_cpu_lock);
-}
-
-void cpu_unlock(void)
-{
- spin_unlock(&global_cpu_lock);
-}
-
-#if defined(CONFIG_USER_ONLY)
-
-int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
- int is_user, int is_softmmu)
-{
- if (rw & 2)
- env->exception_index = TT_TFAULT;
- else
- env->exception_index = TT_DFAULT;
- return 1;
-}
-
-#else
-
-#ifndef TARGET_SPARC64
-/*
- * Sparc V8 Reference MMU (SRMMU)
- */
-static const int access_table[8][8] = {
- { 0, 0, 0, 0, 2, 0, 3, 3 },
- { 0, 0, 0, 0, 2, 0, 0, 0 },
- { 2, 2, 0, 0, 0, 2, 3, 3 },
- { 2, 2, 0, 0, 0, 2, 0, 0 },
- { 2, 0, 2, 0, 2, 2, 3, 3 },
- { 2, 0, 2, 0, 2, 0, 2, 0 },
- { 2, 2, 2, 0, 2, 2, 3, 3 },
- { 2, 2, 2, 0, 2, 2, 2, 0 }
-};
-
-static const int perm_table[2][8] = {
- {
- PAGE_READ,
- PAGE_READ | PAGE_WRITE,
- PAGE_READ | PAGE_EXEC,
- PAGE_READ | PAGE_WRITE | PAGE_EXEC,
- PAGE_EXEC,
- PAGE_READ | PAGE_WRITE,
- PAGE_READ | PAGE_EXEC,
- PAGE_READ | PAGE_WRITE | PAGE_EXEC
- },
- {
- PAGE_READ,
- PAGE_READ | PAGE_WRITE,
- PAGE_READ | PAGE_EXEC,
- PAGE_READ | PAGE_WRITE | PAGE_EXEC,
- PAGE_EXEC,
- PAGE_READ,
- 0,
- 0,
- }
-};
-
-int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot,
- int *access_index, target_ulong address, int rw,
- int is_user)
-{
- int access_perms = 0;
- target_phys_addr_t pde_ptr;
- uint32_t pde;
- target_ulong virt_addr;
- int error_code = 0, is_dirty;
- unsigned long page_offset;
-
- virt_addr = address & TARGET_PAGE_MASK;
- if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
- *physical = address;
- *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return 0;
- }
-
- *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
- *physical = 0xfffff000;
-
- /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
- /* Context base + context number */
- pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
- pde = ldl_phys(pde_ptr);
-
- /* Ctx pde */
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- return 1 << 2;
- case 2: /* L0 PTE, maybe should not happen? */
- case 3: /* Reserved */
- return 4 << 2;
- case 1: /* L0 PDE */
- pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- return (1 << 8) | (1 << 2);
- case 3: /* Reserved */
- return (1 << 8) | (4 << 2);
- case 1: /* L1 PDE */
- pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- return (2 << 8) | (1 << 2);
- case 3: /* Reserved */
- return (2 << 8) | (4 << 2);
- case 1: /* L2 PDE */
- pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- return (3 << 8) | (1 << 2);
- case 1: /* PDE, should not happen */
- case 3: /* Reserved */
- return (3 << 8) | (4 << 2);
- case 2: /* L3 PTE */
- virt_addr = address & TARGET_PAGE_MASK;
- page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
- }
- break;
- case 2: /* L2 PTE */
- virt_addr = address & ~0x3ffff;
- page_offset = address & 0x3ffff;
- }
- break;
- case 2: /* L1 PTE */
- virt_addr = address & ~0xffffff;
- page_offset = address & 0xffffff;
- }
- }
-
- /* update page modified and dirty bits */
- is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
- if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
- pde |= PG_ACCESSED_MASK;
- if (is_dirty)
- pde |= PG_MODIFIED_MASK;
- stl_phys_notdirty(pde_ptr, pde);
- }
- /* check access */
- access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
- error_code = access_table[*access_index][access_perms];
- if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
- return error_code;
-
- /* the page can be put in the TLB */
- *prot = perm_table[is_user][access_perms];
- if (!(pde & PG_MODIFIED_MASK)) {
- /* only set write access if already dirty... otherwise wait
- for dirty access */
- *prot &= ~PAGE_WRITE;
- }
-
- /* Even if large ptes, we map only one 4KB page in the cache to
- avoid filling it too fast */
- *physical = ((pde & PTE_ADDR_MASK) << 4) + page_offset;
- return error_code;
-}
-
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int is_user, int is_softmmu)
-{
- target_phys_addr_t paddr;
- unsigned long vaddr;
- int error_code = 0, prot, ret = 0, access_index;
-
- error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
- if (error_code == 0) {
- vaddr = address & TARGET_PAGE_MASK;
- paddr &= TARGET_PAGE_MASK;
-#ifdef DEBUG_MMU
- printf("Translate at 0x%lx -> 0x%lx, vaddr 0x%lx\n", (long)address, (long)paddr, (long)vaddr);
-#endif
- ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
- return ret;
- }
-
- if (env->mmuregs[3]) /* Fault status register */
- env->mmuregs[3] = 1; /* overflow (not read before another fault) */
- env->mmuregs[3] |= (access_index << 5) | error_code | 2;
- env->mmuregs[4] = address; /* Fault address register */
-
- if ((env->mmuregs[0] & MMU_NF) || env->psret == 0) {
- // No fault mode: if a mapping is available, just override
- // permissions. If no mapping is available, redirect accesses to
- // neverland. Fake/overridden mappings will be flushed when
- // switching to normal mode.
- vaddr = address & TARGET_PAGE_MASK;
- prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
- return ret;
- } else {
- if (rw & 2)
- env->exception_index = TT_TFAULT;
- else
- env->exception_index = TT_DFAULT;
- return 1;
- }
-}
-
-target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
-{
- target_phys_addr_t pde_ptr;
- uint32_t pde;
-
- /* Context base + context number */
- pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- case 2: /* PTE, maybe should not happen? */
- case 3: /* Reserved */
- return 0;
- case 1: /* L1 PDE */
- if (mmulev == 3)
- return pde;
- pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- case 3: /* Reserved */
- return 0;
- case 2: /* L1 PTE */
- return pde;
- case 1: /* L2 PDE */
- if (mmulev == 2)
- return pde;
- pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- case 3: /* Reserved */
- return 0;
- case 2: /* L2 PTE */
- return pde;
- case 1: /* L3 PDE */
- if (mmulev == 1)
- return pde;
- pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
- pde = ldl_phys(pde_ptr);
-
- switch (pde & PTE_ENTRYTYPE_MASK) {
- default:
- case 0: /* Invalid */
- case 1: /* PDE, should not happen */
- case 3: /* Reserved */
- return 0;
- case 2: /* L3 PTE */
- return pde;
- }
- }
- }
- }
- return 0;
-}
-
-#ifdef DEBUG_MMU
-void dump_mmu(CPUState *env)
-{
- target_ulong va, va1, va2;
- unsigned int n, m, o;
- target_phys_addr_t pde_ptr, pa;
- uint32_t pde;
-
- printf("MMU dump:\n");
- pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
- pde = ldl_phys(pde_ptr);
- printf("Root ptr: " TARGET_FMT_lx ", ctx: %d\n", env->mmuregs[1] << 4, env->mmuregs[2]);
- for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
- pde_ptr = mmu_probe(env, va, 2);
- if (pde_ptr) {
- pa = cpu_get_phys_page_debug(env, va);
- printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va, pa, pde_ptr);
- for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
- pde_ptr = mmu_probe(env, va1, 1);
- if (pde_ptr) {
- pa = cpu_get_phys_page_debug(env, va1);
- printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PDE: " TARGET_FMT_lx "\n", va1, pa, pde_ptr);
- for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
- pde_ptr = mmu_probe(env, va2, 0);
- if (pde_ptr) {
- pa = cpu_get_phys_page_debug(env, va2);
- printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx " PTE: " TARGET_FMT_lx "\n", va2, pa, pde_ptr);
- }
- }
- }
- }
- }
- }
- printf("MMU dump ends\n");
-}
-#endif /* DEBUG_MMU */
-
-#else /* !TARGET_SPARC64 */
-/*
- * UltraSparc IIi I/DMMUs
- */
-static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot,
- int *access_index, target_ulong address, int rw,
- int is_user)
-{
- target_ulong mask;
- unsigned int i;
-
- if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
- *physical = address;
- *prot = PAGE_READ | PAGE_WRITE;
- return 0;
- }
-
- for (i = 0; i < 64; i++) {
- switch ((env->dtlb_tte[i] >> 61) & 3) {
- default:
- case 0x0: // 8k
- mask = 0xffffffffffffe000ULL;
- break;
- case 0x1: // 64k
- mask = 0xffffffffffff0000ULL;
- break;
- case 0x2: // 512k
- mask = 0xfffffffffff80000ULL;
- break;
- case 0x3: // 4M
- mask = 0xffffffffffc00000ULL;
- break;
- }
- // ctx match, vaddr match?
- if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
- (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
- // valid, access ok?
- if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 ||
- ((env->dtlb_tte[i] & 0x4) && is_user) ||
- (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
- if (env->dmmuregs[3]) /* Fault status register */
- env->dmmuregs[3] = 2; /* overflow (not read before another fault) */
- env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
- env->dmmuregs[4] = address; /* Fault address register */
- env->exception_index = TT_DFAULT;
-#ifdef DEBUG_MMU
- printf("DFAULT at 0x%" PRIx64 "\n", address);
-#endif
- return 1;
- }
- *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
- *prot = PAGE_READ;
- if (env->dtlb_tte[i] & 0x2)
- *prot |= PAGE_WRITE;
- return 0;
- }
- }
-#ifdef DEBUG_MMU
- printf("DMISS at 0x%" PRIx64 "\n", address);
-#endif
- env->exception_index = TT_DMISS;
- return 1;
-}
-
-static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot,
- int *access_index, target_ulong address, int rw,
- int is_user)
-{
- target_ulong mask;
- unsigned int i;
-
- if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
- *physical = address;
- *prot = PAGE_EXEC;
- return 0;
- }
-
- for (i = 0; i < 64; i++) {
- switch ((env->itlb_tte[i] >> 61) & 3) {
- default:
- case 0x0: // 8k
- mask = 0xffffffffffffe000ULL;
- break;
- case 0x1: // 64k
- mask = 0xffffffffffff0000ULL;
- break;
- case 0x2: // 512k
- mask = 0xfffffffffff80000ULL;
- break;
- case 0x3: // 4M
- mask = 0xffffffffffc00000ULL;
- break;
- }
- // ctx match, vaddr match?
- if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
- (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
- // valid, access ok?
- if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 ||
- ((env->itlb_tte[i] & 0x4) && is_user)) {
- if (env->immuregs[3]) /* Fault status register */
- env->immuregs[3] = 2; /* overflow (not read before another fault) */
- env->immuregs[3] |= (is_user << 3) | 1;
- env->exception_index = TT_TFAULT;
-#ifdef DEBUG_MMU
- printf("TFAULT at 0x%" PRIx64 "\n", address);
-#endif
- return 1;
- }
- *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
- *prot = PAGE_EXEC;
- return 0;
- }
- }
-#ifdef DEBUG_MMU
- printf("TMISS at 0x%" PRIx64 "\n", address);
-#endif
- env->exception_index = TT_TMISS;
- return 1;
-}
-
-int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot,
- int *access_index, target_ulong address, int rw,
- int is_user)
-{
- if (rw == 2)
- return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user);
- else
- return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user);
-}
-
-/* Perform address translation */
-int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
- int is_user, int is_softmmu)
-{
- target_ulong virt_addr, vaddr;
- target_phys_addr_t paddr;
- int error_code = 0, prot, ret = 0, access_index;
-
- error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
- if (error_code == 0) {
- virt_addr = address & TARGET_PAGE_MASK;
- vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
-#ifdef DEBUG_MMU
- printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr);
-#endif
- ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
- return ret;
- }
- // XXX
- return 1;
-}
-
-#ifdef DEBUG_MMU
-void dump_mmu(CPUState *env)
-{
- unsigned int i;
- const char *mask;
-
- printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n", env->dmmuregs[1], env->dmmuregs[2]);
- if ((env->lsu & DMMU_E) == 0) {
- printf("DMMU disabled\n");
- } else {
- printf("DMMU dump:\n");
- for (i = 0; i < 64; i++) {
- switch ((env->dtlb_tte[i] >> 61) & 3) {
- default:
- case 0x0:
- mask = " 8k";
- break;
- case 0x1:
- mask = " 64k";
- break;
- case 0x2:
- mask = "512k";
- break;
- case 0x3:
- mask = " 4M";
- break;
- }
- if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
- printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %" PRId64 "\n",
- env->dtlb_tag[i] & ~0x1fffULL,
- env->dtlb_tte[i] & 0x1ffffffe000ULL,
- mask,
- env->dtlb_tte[i] & 0x4? "priv": "user",
- env->dtlb_tte[i] & 0x2? "RW": "RO",
- env->dtlb_tte[i] & 0x40? "locked": "unlocked",
- env->dtlb_tag[i] & 0x1fffULL);
- }
- }
- }
- if ((env->lsu & IMMU_E) == 0) {
- printf("IMMU disabled\n");
- } else {
- printf("IMMU dump:\n");
- for (i = 0; i < 64; i++) {
- switch ((env->itlb_tte[i] >> 61) & 3) {
- default:
- case 0x0:
- mask = " 8k";
- break;
- case 0x1:
- mask = " 64k";
- break;
- case 0x2:
- mask = "512k";
- break;
- case 0x3:
- mask = " 4M";
- break;
- }
- if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
- printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %" PRId64 "\n",
- env->itlb_tag[i] & ~0x1fffULL,
- env->itlb_tte[i] & 0x1ffffffe000ULL,
- mask,
- env->itlb_tte[i] & 0x4? "priv": "user",
- env->itlb_tte[i] & 0x40? "locked": "unlocked",
- env->itlb_tag[i] & 0x1fffULL);
- }
- }
- }
-}
-#endif /* DEBUG_MMU */
-
-#endif /* TARGET_SPARC64 */
-#endif /* !CONFIG_USER_ONLY */
-
-void memcpy32(target_ulong *dst, const target_ulong *src)
-{
- dst[0] = src[0];
- dst[1] = src[1];
- dst[2] = src[2];
- dst[3] = src[3];
- dst[4] = src[4];
- dst[5] = src[5];
- dst[6] = src[6];
- dst[7] = src[7];
-}
diff --git a/target-sparc/op.c b/target-sparc/op.c
deleted file mode 100644
index 7ea209e..0000000
--- a/target-sparc/op.c
+++ /dev/null
@@ -1,1597 +0,0 @@
-/*
- SPARC micro operations
-
- Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at>
-
- 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"
-
- /*XXX*/
-#define REGNAME g0
-#define REG (env->gregs[0])
-#include "op_template.h"
-#define REGNAME g1
-#define REG (env->gregs[1])
-#include "op_template.h"
-#define REGNAME g2
-#define REG (env->gregs[2])
-#include "op_template.h"
-#define REGNAME g3
-#define REG (env->gregs[3])
-#include "op_template.h"
-#define REGNAME g4
-#define REG (env->gregs[4])
-#include "op_template.h"
-#define REGNAME g5
-#define REG (env->gregs[5])
-#include "op_template.h"
-#define REGNAME g6
-#define REG (env->gregs[6])
-#include "op_template.h"
-#define REGNAME g7
-#define REG (env->gregs[7])
-#include "op_template.h"
-#define REGNAME i0
-#define REG (REGWPTR[16])
-#include "op_template.h"
-#define REGNAME i1
-#define REG (REGWPTR[17])
-#include "op_template.h"
-#define REGNAME i2
-#define REG (REGWPTR[18])
-#include "op_template.h"
-#define REGNAME i3
-#define REG (REGWPTR[19])
-#include "op_template.h"
-#define REGNAME i4
-#define REG (REGWPTR[20])
-#include "op_template.h"
-#define REGNAME i5
-#define REG (REGWPTR[21])
-#include "op_template.h"
-#define REGNAME i6
-#define REG (REGWPTR[22])
-#include "op_template.h"
-#define REGNAME i7
-#define REG (REGWPTR[23])
-#include "op_template.h"
-#define REGNAME l0
-#define REG (REGWPTR[8])
-#include "op_template.h"
-#define REGNAME l1
-#define REG (REGWPTR[9])
-#include "op_template.h"
-#define REGNAME l2
-#define REG (REGWPTR[10])
-#include "op_template.h"
-#define REGNAME l3
-#define REG (REGWPTR[11])
-#include "op_template.h"
-#define REGNAME l4
-#define REG (REGWPTR[12])
-#include "op_template.h"
-#define REGNAME l5
-#define REG (REGWPTR[13])
-#include "op_template.h"
-#define REGNAME l6
-#define REG (REGWPTR[14])
-#include "op_template.h"
-#define REGNAME l7
-#define REG (REGWPTR[15])
-#include "op_template.h"
-#define REGNAME o0
-#define REG (REGWPTR[0])
-#include "op_template.h"
-#define REGNAME o1
-#define REG (REGWPTR[1])
-#include "op_template.h"
-#define REGNAME o2
-#define REG (REGWPTR[2])
-#include "op_template.h"
-#define REGNAME o3
-#define REG (REGWPTR[3])
-#include "op_template.h"
-#define REGNAME o4
-#define REG (REGWPTR[4])
-#include "op_template.h"
-#define REGNAME o5
-#define REG (REGWPTR[5])
-#include "op_template.h"
-#define REGNAME o6
-#define REG (REGWPTR[6])
-#include "op_template.h"
-#define REGNAME o7
-#define REG (REGWPTR[7])
-#include "op_template.h"
-
-#define REGNAME f0
-#define REG (env->fpr[0])
-#include "fop_template.h"
-#define REGNAME f1
-#define REG (env->fpr[1])
-#include "fop_template.h"
-#define REGNAME f2
-#define REG (env->fpr[2])
-#include "fop_template.h"
-#define REGNAME f3
-#define REG (env->fpr[3])
-#include "fop_template.h"
-#define REGNAME f4
-#define REG (env->fpr[4])
-#include "fop_template.h"
-#define REGNAME f5
-#define REG (env->fpr[5])
-#include "fop_template.h"
-#define REGNAME f6
-#define REG (env->fpr[6])
-#include "fop_template.h"
-#define REGNAME f7
-#define REG (env->fpr[7])
-#include "fop_template.h"
-#define REGNAME f8
-#define REG (env->fpr[8])
-#include "fop_template.h"
-#define REGNAME f9
-#define REG (env->fpr[9])
-#include "fop_template.h"
-#define REGNAME f10
-#define REG (env->fpr[10])
-#include "fop_template.h"
-#define REGNAME f11
-#define REG (env->fpr[11])
-#include "fop_template.h"
-#define REGNAME f12
-#define REG (env->fpr[12])
-#include "fop_template.h"
-#define REGNAME f13
-#define REG (env->fpr[13])
-#include "fop_template.h"
-#define REGNAME f14
-#define REG (env->fpr[14])
-#include "fop_template.h"
-#define REGNAME f15
-#define REG (env->fpr[15])
-#include "fop_template.h"
-#define REGNAME f16
-#define REG (env->fpr[16])
-#include "fop_template.h"
-#define REGNAME f17
-#define REG (env->fpr[17])
-#include "fop_template.h"
-#define REGNAME f18
-#define REG (env->fpr[18])
-#include "fop_template.h"
-#define REGNAME f19
-#define REG (env->fpr[19])
-#include "fop_template.h"
-#define REGNAME f20
-#define REG (env->fpr[20])
-#include "fop_template.h"
-#define REGNAME f21
-#define REG (env->fpr[21])
-#include "fop_template.h"
-#define REGNAME f22
-#define REG (env->fpr[22])
-#include "fop_template.h"
-#define REGNAME f23
-#define REG (env->fpr[23])
-#include "fop_template.h"
-#define REGNAME f24
-#define REG (env->fpr[24])
-#include "fop_template.h"
-#define REGNAME f25
-#define REG (env->fpr[25])
-#include "fop_template.h"
-#define REGNAME f26
-#define REG (env->fpr[26])
-#include "fop_template.h"
-#define REGNAME f27
-#define REG (env->fpr[27])
-#include "fop_template.h"
-#define REGNAME f28
-#define REG (env->fpr[28])
-#include "fop_template.h"
-#define REGNAME f29
-#define REG (env->fpr[29])
-#include "fop_template.h"
-#define REGNAME f30
-#define REG (env->fpr[30])
-#include "fop_template.h"
-#define REGNAME f31
-#define REG (env->fpr[31])
-#include "fop_template.h"
-
-#ifdef TARGET_SPARC64
-#define REGNAME f32
-#define REG (env->fpr[32])
-#include "fop_template.h"
-#define REGNAME f34
-#define REG (env->fpr[34])
-#include "fop_template.h"
-#define REGNAME f36
-#define REG (env->fpr[36])
-#include "fop_template.h"
-#define REGNAME f38
-#define REG (env->fpr[38])
-#include "fop_template.h"
-#define REGNAME f40
-#define REG (env->fpr[40])
-#include "fop_template.h"
-#define REGNAME f42
-#define REG (env->fpr[42])
-#include "fop_template.h"
-#define REGNAME f44
-#define REG (env->fpr[44])
-#include "fop_template.h"
-#define REGNAME f46
-#define REG (env->fpr[46])
-#include "fop_template.h"
-#define REGNAME f48
-#define REG (env->fpr[47])
-#include "fop_template.h"
-#define REGNAME f50
-#define REG (env->fpr[50])
-#include "fop_template.h"
-#define REGNAME f52
-#define REG (env->fpr[52])
-#include "fop_template.h"
-#define REGNAME f54
-#define REG (env->fpr[54])
-#include "fop_template.h"
-#define REGNAME f56
-#define REG (env->fpr[56])
-#include "fop_template.h"
-#define REGNAME f58
-#define REG (env->fpr[58])
-#include "fop_template.h"
-#define REGNAME f60
-#define REG (env->fpr[60])
-#include "fop_template.h"
-#define REGNAME f62
-#define REG (env->fpr[62])
-#include "fop_template.h"
-#endif
-
-#ifdef TARGET_SPARC64
-#ifdef WORDS_BIGENDIAN
-typedef union UREG64 {
- struct { uint16_t v3, v2, v1, v0; } w;
- struct { uint32_t v1, v0; } l;
- uint64_t q;
-} UREG64;
-#else
-typedef union UREG64 {
- struct { uint16_t v0, v1, v2, v3; } w;
- struct { uint32_t v0, v1; } l;
- uint64_t q;
-} UREG64;
-#endif
-
-#define PARAMQ1 \
-({\
- UREG64 __p;\
- __p.l.v1 = PARAM1;\
- __p.l.v0 = PARAM2;\
- __p.q;\
-})
-
-void OPPROTO op_movq_T0_im64(void)
-{
- T0 = PARAMQ1;
-}
-
-void OPPROTO op_movq_T1_im64(void)
-{
- T1 = PARAMQ1;
-}
-
-#define XFLAG_SET(x) ((env->xcc&x)?1:0)
-
-#else
-#define EIP (env->pc)
-#endif
-
-#define FLAG_SET(x) ((env->psr&x)?1:0)
-
-void OPPROTO op_movl_T0_0(void)
-{
- T0 = 0;
-}
-
-void OPPROTO op_movl_T0_im(void)
-{
- T0 = (uint32_t)PARAM1;
-}
-
-void OPPROTO op_movl_T1_im(void)
-{
- T1 = (uint32_t)PARAM1;
-}
-
-void OPPROTO op_movl_T2_im(void)
-{
- T2 = (uint32_t)PARAM1;
-}
-
-void OPPROTO op_movl_T0_sim(void)
-{
- T0 = (int32_t)PARAM1;
-}
-
-void OPPROTO op_movl_T1_sim(void)
-{
- T1 = (int32_t)PARAM1;
-}
-
-void OPPROTO op_movl_T2_sim(void)
-{
- T2 = (int32_t)PARAM1;
-}
-
-void OPPROTO op_movl_T0_env(void)
-{
- T0 = *(uint32_t *)((char *)env + PARAM1);
-}
-
-void OPPROTO op_movl_env_T0(void)
-{
- *(uint32_t *)((char *)env + PARAM1) = T0;
-}
-
-void OPPROTO op_movtl_T0_env(void)
-{
- T0 = *(target_ulong *)((char *)env + PARAM1);
-}
-
-void OPPROTO op_movtl_env_T0(void)
-{
- *(target_ulong *)((char *)env + PARAM1) = T0;
-}
-
-void OPPROTO op_add_T1_T0(void)
-{
- T0 += T1;
-}
-
-void OPPROTO op_add_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;
-
- 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;
-#endif
- FORCE_RET();
-}
-
-void OPPROTO op_addx_T1_T0(void)
-{
- T0 += T1 + FLAG_SET(PSR_CARRY);
-}
-
-void OPPROTO op_addx_T1_T0_cc(void)
-{
- target_ulong src1;
- src1 = T0;
- if (FLAG_SET(PSR_CARRY))
- {
- T0 += T1 + 1;
- env->psr = 0;
-#ifdef TARGET_SPARC64
- if ((T0 & 0xffffffff) <= (src1 & 0xffffffff))
- env->psr |= PSR_CARRY;
- env->xcc = 0;
- if (T0 <= src1)
- env->xcc |= PSR_CARRY;
-#else
- if (T0 <= src1)
- env->psr |= PSR_CARRY;
-#endif
- }
- else
- {
- T0 += T1;
- env->psr = 0;
-#ifdef TARGET_SPARC64
- if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
- env->psr |= PSR_CARRY;
- env->xcc = 0;
- if (T0 < src1)
- env->xcc |= PSR_CARRY;
-#else
- if (T0 < src1)
- env->psr |= PSR_CARRY;
-#endif
- }
-#ifdef TARGET_SPARC64
- if (!(T0 & 0xffffffff))
- env->psr |= PSR_ZERO;
- if ((int32_t) T0 < 0)
- env->psr |= PSR_NEG;
- if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
- ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
- env->psr |= PSR_OVF;
-
- if (!T0)
- env->xcc |= PSR_ZERO;
- if ((int64_t) T0 < 0)
- env->xcc |= PSR_NEG;
- 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 (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
- env->psr |= PSR_OVF;
-#endif
- FORCE_RET();
-}
-
-void OPPROTO op_sub_T1_T0(void)
-{
- T0 -= T1;
-}
-
-void OPPROTO op_sub_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;
-
- 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;
-#endif
- FORCE_RET();
-}
-
-void OPPROTO op_subx_T1_T0(void)
-{
- T0 -= T1 + FLAG_SET(PSR_CARRY);
-}
-
-void OPPROTO op_subx_T1_T0_cc(void)
-{
- target_ulong src1;
- src1 = T0;
- if (FLAG_SET(PSR_CARRY))
- {
- T0 -= T1 + 1;
- env->psr = 0;
-#ifdef TARGET_SPARC64
- if ((src1 & 0xffffffff) <= (T1 & 0xffffffff))
- env->psr |= PSR_CARRY;
- env->xcc = 0;
- if (src1 <= T1)
- env->xcc |= PSR_CARRY;
-#else
- if (src1 <= T1)
- env->psr |= PSR_CARRY;
-#endif
- }
- else
- {
- T0 -= T1;
- env->psr = 0;
-#ifdef TARGET_SPARC64
- if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
- env->psr |= PSR_CARRY;
- env->xcc = 0;
- if (src1 < T1)
- env->xcc |= PSR_CARRY;
-#else
- if (src1 < T1)
- env->psr |= PSR_CARRY;
-#endif
- }
-#ifdef TARGET_SPARC64
- if (!(T0 & 0xffffffff))
- env->psr |= PSR_ZERO;
- if ((int32_t) T0 < 0)
- env->psr |= PSR_NEG;
- if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
- ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
- env->psr |= PSR_OVF;
-
- if (!T0)
- env->xcc |= PSR_ZERO;
- if ((int64_t) T0 < 0)
- env->xcc |= PSR_NEG;
- 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) & (src1 ^ T0)) & (1 << 31))
- env->psr |= PSR_OVF;
-#endif
- FORCE_RET();
-}
-
-void OPPROTO op_and_T1_T0(void)
-{
- T0 &= T1;
-}
-
-void OPPROTO op_or_T1_T0(void)
-{
- T0 |= T1;
-}
-
-void OPPROTO op_xor_T1_T0(void)
-{
- T0 ^= T1;
-}
-
-void OPPROTO op_andn_T1_T0(void)
-{
- T0 &= ~T1;
-}
-
-void OPPROTO op_orn_T1_T0(void)
-{
- T0 |= ~T1;
-}
-
-void OPPROTO op_xnor_T1_T0(void)
-{
- T0 ^= ~T1;
-}
-
-void OPPROTO op_umul_T1_T0(void)
-{
- uint64_t res;
- res = (uint64_t) T0 * (uint64_t) T1;
-#ifdef TARGET_SPARC64
- T0 = res;
-#else
- T0 = res & 0xffffffff;
-#endif
- env->y = res >> 32;
-}
-
-void OPPROTO op_smul_T1_T0(void)
-{
- uint64_t res;
- res = (int64_t) ((int32_t) T0) * (int64_t) ((int32_t) T1);
-#ifdef TARGET_SPARC64
- T0 = res;
-#else
- T0 = res & 0xffffffff;
-#endif
- env->y = res >> 32;
-}
-
-void OPPROTO op_mulscc_T1_T0(void)
-{
- unsigned int b1, N, V, b2;
- target_ulong src1;
-
- N = FLAG_SET(PSR_NEG);
- V = FLAG_SET(PSR_OVF);
- b1 = N ^ V;
- b2 = T0 & 1;
- T0 = (b1 << 31) | (T0 >> 1);
- if (!(env->y & 1))
- T1 = 0;
- /* do addition and update flags */
- src1 = T0;
- T0 += T1;
- env->psr = 0;
- 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;
- env->y = (b2 << 31) | (env->y >> 1);
- FORCE_RET();
-}
-
-void OPPROTO op_udiv_T1_T0(void)
-{
- uint64_t x0;
- uint32_t x1;
-
- x0 = T0 | ((uint64_t) (env->y) << 32);
- x1 = T1;
- x0 = x0 / x1;
- if (x0 > 0xffffffff) {
- T0 = 0xffffffff;
- T1 = 1;
- } else {
- T0 = x0;
- T1 = 0;
- }
- FORCE_RET();
-}
-
-void OPPROTO op_sdiv_T1_T0(void)
-{
- int64_t x0;
- int32_t x1;
-
- x0 = T0 | ((int64_t) (env->y) << 32);
- x1 = T1;
- x0 = x0 / x1;
- if ((int32_t) x0 != x0) {
- T0 = x0 < 0? 0x80000000: 0x7fffffff;
- T1 = 1;
- } else {
- T0 = x0;
- T1 = 0;
- }
- FORCE_RET();
-}
-
-void OPPROTO op_div_cc(void)
-{
- env->psr = 0;
-#ifdef TARGET_SPARC64
- if (!T0)
- env->psr |= PSR_ZERO;
- if ((int32_t) T0 < 0)
- env->psr |= PSR_NEG;
- if (T1)
- env->psr |= PSR_OVF;
-
- env->xcc = 0;
- if (!T0)
- env->xcc |= PSR_ZERO;
- if ((int64_t) T0 < 0)
- env->xcc |= PSR_NEG;
-#else
- if (!T0)
- env->psr |= PSR_ZERO;
- if ((int32_t) T0 < 0)
- env->psr |= PSR_NEG;
- if (T1)
- env->psr |= PSR_OVF;
-#endif
- FORCE_RET();
-}
-
-#ifdef TARGET_SPARC64
-void OPPROTO op_mulx_T1_T0(void)
-{
- T0 *= T1;
- FORCE_RET();
-}
-
-void OPPROTO op_udivx_T1_T0(void)
-{
- T0 /= T1;
- FORCE_RET();
-}
-
-void OPPROTO op_sdivx_T1_T0(void)
-{
- if (T0 == INT64_MIN && T1 == -1)
- T0 = INT64_MIN;
- else
- T0 /= (target_long) T1;
- FORCE_RET();
-}
-#endif
-
-void OPPROTO op_logic_T0_cc(void)
-{
- env->psr = 0;
-#ifdef TARGET_SPARC64
- if (!(T0 & 0xffffffff))
- env->psr |= PSR_ZERO;
- if ((int32_t) T0 < 0)
- env->psr |= PSR_NEG;
-
- env->xcc = 0;
- if (!T0)
- env->xcc |= PSR_ZERO;
- if ((int64_t) T0 < 0)
- env->xcc |= PSR_NEG;
-#else
- if (!T0)
- env->psr |= PSR_ZERO;
- if ((int32_t) T0 < 0)
- env->psr |= PSR_NEG;
-#endif
- FORCE_RET();
-}
-
-void OPPROTO op_sll(void)
-{
- T0 <<= T1;
-}
-
-#ifdef TARGET_SPARC64
-void OPPROTO op_srl(void)
-{
- T0 = (T0 & 0xffffffff) >> T1;
-}
-
-void OPPROTO op_srlx(void)
-{
- T0 >>= T1;
-}
-
-void OPPROTO op_sra(void)
-{
- T0 = ((int32_t) (T0 & 0xffffffff)) >> T1;
-}
-
-void OPPROTO op_srax(void)
-{
- T0 = ((int64_t) T0) >> T1;
-}
-#else
-void OPPROTO op_srl(void)
-{
- T0 >>= T1;
-}
-
-void OPPROTO op_sra(void)
-{
- T0 = ((int32_t) T0) >> T1;
-}
-#endif
-
-/* Load and store */
-#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"
-#endif
-
-void OPPROTO op_ldfsr(void)
-{
- PUT_FSR32(env, *((uint32_t *) &FT0));
- helper_ldfsr();
-}
-
-void OPPROTO op_stfsr(void)
-{
- *((uint32_t *) &FT0) = GET_FSR32(env);
-}
-
-#ifndef TARGET_SPARC64
-void OPPROTO op_rdpsr(void)
-{
- do_rdpsr();
-}
-
-void OPPROTO op_wrpsr(void)
-{
- do_wrpsr();
- FORCE_RET();
-}
-
-void OPPROTO op_rett(void)
-{
- helper_rett();
- FORCE_RET();
-}
-
-/* XXX: use another pointer for %iN registers to avoid slow wrapping
- handling ? */
-void OPPROTO op_save(void)
-{
- uint32_t cwp;
- cwp = (env->cwp - 1) & (NWINDOWS - 1);
- if (env->wim & (1 << cwp)) {
- raise_exception(TT_WIN_OVF);
- }
- set_cwp(cwp);
- FORCE_RET();
-}
-
-void OPPROTO op_restore(void)
-{
- uint32_t cwp;
- cwp = (env->cwp + 1) & (NWINDOWS - 1);
- if (env->wim & (1 << cwp)) {
- raise_exception(TT_WIN_UNF);
- }
- set_cwp(cwp);
- FORCE_RET();
-}
-#else
-void OPPROTO op_rdccr(void)
-{
- T0 = GET_CCR(env);
-}
-
-void OPPROTO op_wrccr(void)
-{
- PUT_CCR(env, T0);
-}
-
-void OPPROTO op_rdtick(void)
-{
- T0 = 0; // XXX read cycle counter and bit 31
-}
-
-void OPPROTO op_wrtick(void)
-{
- // XXX write cycle counter and bit 31
-}
-
-void OPPROTO op_rdtpc(void)
-{
- T0 = env->tpc[env->tl];
-}
-
-void OPPROTO op_wrtpc(void)
-{
- env->tpc[env->tl] = T0;
-}
-
-void OPPROTO op_rdtnpc(void)
-{
- T0 = env->tnpc[env->tl];
-}
-
-void OPPROTO op_wrtnpc(void)
-{
- env->tnpc[env->tl] = T0;
-}
-
-void OPPROTO op_rdtstate(void)
-{
- T0 = env->tstate[env->tl];
-}
-
-void OPPROTO op_wrtstate(void)
-{
- env->tstate[env->tl] = T0;
-}
-
-void OPPROTO op_rdtt(void)
-{
- T0 = env->tt[env->tl];
-}
-
-void OPPROTO op_wrtt(void)
-{
- env->tt[env->tl] = T0;
-}
-
-void OPPROTO op_rdpstate(void)
-{
- T0 = env->pstate;
-}
-
-void OPPROTO op_wrpstate(void)
-{
- do_wrpstate();
-}
-
-// CWP handling is reversed in V9, but we still use the V8 register
-// order.
-void OPPROTO op_rdcwp(void)
-{
- T0 = NWINDOWS - 1 - env->cwp;
-}
-
-void OPPROTO op_wrcwp(void)
-{
- env->cwp = NWINDOWS - 1 - T0;
-}
-
-/* XXX: use another pointer for %iN registers to avoid slow wrapping
- handling ? */
-void OPPROTO op_save(void)
-{
- uint32_t cwp;
- cwp = (env->cwp - 1) & (NWINDOWS - 1);
- if (env->cansave == 0) {
- raise_exception(TT_SPILL | (env->otherwin != 0 ?
- (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
- ((env->wstate & 0x7) << 2)));
- } else {
- if (env->cleanwin - env->canrestore == 0) {
- // XXX Clean windows without trap
- raise_exception(TT_CLRWIN);
- } else {
- env->cansave--;
- env->canrestore++;
- set_cwp(cwp);
- }
- }
- FORCE_RET();
-}
-
-void OPPROTO op_restore(void)
-{
- uint32_t cwp;
- cwp = (env->cwp + 1) & (NWINDOWS - 1);
- if (env->canrestore == 0) {
- raise_exception(TT_FILL | (env->otherwin != 0 ?
- (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
- ((env->wstate & 0x7) << 2)));
- } else {
- env->cansave++;
- env->canrestore--;
- set_cwp(cwp);
- }
- FORCE_RET();
-}
-#endif
-
-void OPPROTO op_exception(void)
-{
- env->exception_index = PARAM1;
- cpu_loop_exit();
-}
-
-void OPPROTO op_trap_T0(void)
-{
- env->exception_index = TT_TRAP + (T0 & 0x7f);
- cpu_loop_exit();
-}
-
-void OPPROTO op_trapcc_T0(void)
-{
- if (T2) {
- env->exception_index = TT_TRAP + (T0 & 0x7f);
- cpu_loop_exit();
- }
- FORCE_RET();
-}
-
-void OPPROTO op_fpexception_im(void)
-{
- env->exception_index = TT_FP_EXCP;
- env->fsr &= ~FSR_FTT_MASK;
- env->fsr |= PARAM1;
- cpu_loop_exit();
- FORCE_RET();
-}
-
-void OPPROTO op_debug(void)
-{
- helper_debug();
-}
-
-void OPPROTO op_exit_tb(void)
-{
- EXIT_TB();
-}
-
-void OPPROTO op_eval_ba(void)
-{
- T2 = 1;
-}
-
-void OPPROTO op_eval_be(void)
-{
- T2 = FLAG_SET(PSR_ZERO);
-}
-
-void OPPROTO op_eval_ble(void)
-{
- target_ulong Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF);
-
- T2 = Z | (N ^ V);
-}
-
-void OPPROTO op_eval_bl(void)
-{
- target_ulong N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF);
-
- T2 = N ^ V;
-}
-
-void OPPROTO op_eval_bleu(void)
-{
- target_ulong Z = FLAG_SET(PSR_ZERO), C = FLAG_SET(PSR_CARRY);
-
- T2 = C | Z;
-}
-
-void OPPROTO op_eval_bcs(void)
-{
- T2 = FLAG_SET(PSR_CARRY);
-}
-
-void OPPROTO op_eval_bvs(void)
-{
- T2 = FLAG_SET(PSR_OVF);
-}
-
-void OPPROTO op_eval_bn(void)
-{
- T2 = 0;
-}
-
-void OPPROTO op_eval_bneg(void)
-{
- T2 = FLAG_SET(PSR_NEG);
-}
-
-void OPPROTO op_eval_bne(void)
-{
- T2 = !FLAG_SET(PSR_ZERO);
-}
-
-void OPPROTO op_eval_bg(void)
-{
- target_ulong Z = FLAG_SET(PSR_ZERO), N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF);
-
- T2 = !(Z | (N ^ V));
-}
-
-void OPPROTO op_eval_bge(void)
-{
- target_ulong N = FLAG_SET(PSR_NEG), V = FLAG_SET(PSR_OVF);
-
- T2 = !(N ^ V);
-}
-
-void OPPROTO op_eval_bgu(void)
-{
- target_ulong Z = FLAG_SET(PSR_ZERO), C = FLAG_SET(PSR_CARRY);
-
- T2 = !(C | Z);
-}
-
-void OPPROTO op_eval_bcc(void)
-{
- T2 = !FLAG_SET(PSR_CARRY);
-}
-
-void OPPROTO op_eval_bpos(void)
-{
- T2 = !FLAG_SET(PSR_NEG);
-}
-
-void OPPROTO op_eval_bvc(void)
-{
- T2 = !FLAG_SET(PSR_OVF);
-}
-
-#ifdef TARGET_SPARC64
-void OPPROTO op_eval_xbe(void)
-{
- T2 = XFLAG_SET(PSR_ZERO);
-}
-
-void OPPROTO op_eval_xble(void)
-{
- target_ulong Z = XFLAG_SET(PSR_ZERO), N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF);
-
- T2 = Z | (N ^ V);
-}
-
-void OPPROTO op_eval_xbl(void)
-{
- target_ulong N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF);
-
- T2 = N ^ V;
-}
-
-void OPPROTO op_eval_xbleu(void)
-{
- target_ulong Z = XFLAG_SET(PSR_ZERO), C = XFLAG_SET(PSR_CARRY);
-
- T2 = C | Z;
-}
-
-void OPPROTO op_eval_xbcs(void)
-{
- T2 = XFLAG_SET(PSR_CARRY);
-}
-
-void OPPROTO op_eval_xbvs(void)
-{
- T2 = XFLAG_SET(PSR_OVF);
-}
-
-void OPPROTO op_eval_xbneg(void)
-{
- T2 = XFLAG_SET(PSR_NEG);
-}
-
-void OPPROTO op_eval_xbne(void)
-{
- T2 = !XFLAG_SET(PSR_ZERO);
-}
-
-void OPPROTO op_eval_xbg(void)
-{
- target_ulong Z = XFLAG_SET(PSR_ZERO), N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF);
-
- T2 = !(Z | (N ^ V));
-}
-
-void OPPROTO op_eval_xbge(void)
-{
- target_ulong N = XFLAG_SET(PSR_NEG), V = XFLAG_SET(PSR_OVF);
-
- T2 = !(N ^ V);
-}
-
-void OPPROTO op_eval_xbgu(void)
-{
- target_ulong Z = XFLAG_SET(PSR_ZERO), C = XFLAG_SET(PSR_CARRY);
-
- T2 = !(C | Z);
-}
-
-void OPPROTO op_eval_xbcc(void)
-{
- T2 = !XFLAG_SET(PSR_CARRY);
-}
-
-void OPPROTO op_eval_xbpos(void)
-{
- T2 = !XFLAG_SET(PSR_NEG);
-}
-
-void OPPROTO op_eval_xbvc(void)
-{
- T2 = !XFLAG_SET(PSR_OVF);
-}
-#endif
-
-#define FCC
-#define FFLAG_SET(x) (env->fsr & x? 1: 0)
-#include "fbranch_template.h"
-
-#ifdef TARGET_SPARC64
-#define FCC _fcc1
-#define FFLAG_SET(x) ((env->fsr & ((uint64_t)x >> 32))? 1: 0)
-#include "fbranch_template.h"
-#define FCC _fcc2
-#define FFLAG_SET(x) ((env->fsr & ((uint64_t)x >> 34))? 1: 0)
-#include "fbranch_template.h"
-#define FCC _fcc3
-#define FFLAG_SET(x) ((env->fsr & ((uint64_t)x >> 36))? 1: 0)
-#include "fbranch_template.h"
-#endif
-
-#ifdef TARGET_SPARC64
-void OPPROTO op_eval_brz(void)
-{
- T2 = (T0 == 0);
-}
-
-void OPPROTO op_eval_brnz(void)
-{
- T2 = (T0 != 0);
-}
-
-void OPPROTO op_eval_brlz(void)
-{
- T2 = ((int64_t)T0 < 0);
-}
-
-void OPPROTO op_eval_brlez(void)
-{
- T2 = ((int64_t)T0 <= 0);
-}
-
-void OPPROTO op_eval_brgz(void)
-{
- T2 = ((int64_t)T0 > 0);
-}
-
-void OPPROTO op_eval_brgez(void)
-{
- T2 = ((int64_t)T0 >= 0);
-}
-
-void OPPROTO op_jmp_im64(void)
-{
- env->pc = PARAMQ1;
-}
-
-void OPPROTO op_movq_npc_im64(void)
-{
- env->npc = PARAMQ1;
-}
-#endif
-
-void OPPROTO op_jmp_im(void)
-{
- env->pc = (uint32_t)PARAM1;
-}
-
-void OPPROTO op_movl_npc_im(void)
-{
- env->npc = (uint32_t)PARAM1;
-}
-
-void OPPROTO op_movl_npc_T0(void)
-{
- env->npc = T0;
-}
-
-void OPPROTO op_mov_pc_npc(void)
-{
- env->pc = env->npc;
-}
-
-void OPPROTO op_next_insn(void)
-{
- env->pc = env->npc;
- env->npc = env->npc + 4;
-}
-
-void OPPROTO op_goto_tb0(void)
-{
- GOTO_TB(op_goto_tb0, PARAM1, 0);
-}
-
-void OPPROTO op_goto_tb1(void)
-{
- GOTO_TB(op_goto_tb1, PARAM1, 1);
-}
-
-void OPPROTO op_jmp_label(void)
-{
- GOTO_LABEL_PARAM(1);
-}
-
-void OPPROTO op_jnz_T2_label(void)
-{
- if (T2)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO op_jz_T2_label(void)
-{
- if (!T2)
- GOTO_LABEL_PARAM(1);
- FORCE_RET();
-}
-
-void OPPROTO op_flush_T0(void)
-{
- helper_flush(T0);
-}
-
-#define F_OP(name, p) void OPPROTO op_f##name##p(void)
-
-#define F_BINOP(name) \
- F_OP(name, s) \
- { \
- FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \
- } \
- F_OP(name, d) \
- { \
- DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
- }
-
-F_BINOP(add);
-F_BINOP(sub);
-F_BINOP(mul);
-F_BINOP(div);
-#undef F_BINOP
-
-void OPPROTO op_fsmuld(void)
-{
- DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status),
- float32_to_float64(FT1, &env->fp_status),
- &env->fp_status);
-}
-
-#define F_HELPER(name) \
- F_OP(name, s) \
- { \
- do_f##name##s(); \
- } \
- F_OP(name, d) \
- { \
- do_f##name##d(); \
- }
-
-F_HELPER(sqrt);
-
-F_OP(neg, s)
-{
- FT0 = float32_chs(FT1);
-}
-
-F_OP(abs, s)
-{
- do_fabss();
-}
-
-F_HELPER(cmp);
-
-#ifdef TARGET_SPARC64
-F_OP(neg, d)
-{
- DT0 = float64_chs(DT1);
-}
-
-F_OP(abs, d)
-{
- do_fabsd();
-}
-
-void OPPROTO op_fcmps_fcc1(void)
-{
- do_fcmps_fcc1();
-}
-
-void OPPROTO op_fcmpd_fcc1(void)
-{
- do_fcmpd_fcc1();
-}
-
-void OPPROTO op_fcmps_fcc2(void)
-{
- do_fcmps_fcc2();
-}
-
-void OPPROTO op_fcmpd_fcc2(void)
-{
- do_fcmpd_fcc2();
-}
-
-void OPPROTO op_fcmps_fcc3(void)
-{
- do_fcmps_fcc3();
-}
-
-void OPPROTO op_fcmpd_fcc3(void)
-{
- do_fcmpd_fcc3();
-}
-#endif
-
-/* Integer to float conversion. */
-#ifdef USE_INT_TO_FLOAT_HELPERS
-F_HELPER(ito);
-#else
-F_OP(ito, s)
-{
- FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
-}
-
-F_OP(ito, d)
-{
- DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
-}
-
-#ifdef TARGET_SPARC64
-F_OP(xto, s)
-{
- FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
-}
-
-F_OP(xto, d)
-{
- DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
-}
-#endif
-#endif
-#undef F_HELPER
-
-/* floating point conversion */
-void OPPROTO op_fdtos(void)
-{
- FT0 = float64_to_float32(DT1, &env->fp_status);
-}
-
-void OPPROTO op_fstod(void)
-{
- DT0 = float32_to_float64(FT1, &env->fp_status);
-}
-
-/* Float to integer conversion. */
-void OPPROTO op_fstoi(void)
-{
- *((int32_t *)&FT0) = float32_to_int32(FT1, &env->fp_status);
-}
-
-void OPPROTO op_fdtoi(void)
-{
- *((int32_t *)&FT0) = float64_to_int32(DT1, &env->fp_status);
-}
-
-#ifdef TARGET_SPARC64
-void OPPROTO op_fstox(void)
-{
- *((int64_t *)&DT0) = float32_to_int64(FT1, &env->fp_status);
-}
-
-void OPPROTO op_fdtox(void)
-{
- *((int64_t *)&DT0) = float64_to_int64(DT1, &env->fp_status);
-}
-
-void OPPROTO op_fmovs_cc(void)
-{
- if (T2)
- FT0 = FT1;
-}
-
-void OPPROTO op_fmovd_cc(void)
-{
- if (T2)
- DT0 = DT1;
-}
-
-void OPPROTO op_mov_cc(void)
-{
- if (T2)
- T0 = T1;
-}
-
-void OPPROTO op_flushw(void)
-{
- if (env->cansave != NWINDOWS - 2) {
- raise_exception(TT_SPILL | (env->otherwin != 0 ?
- (TT_WOTHER | ((env->wstate & 0x38) >> 1)):
- ((env->wstate & 0x7) << 2)));
- }
-}
-
-void OPPROTO op_saved(void)
-{
- env->cansave++;
- if (env->otherwin == 0)
- env->canrestore--;
- else
- env->otherwin--;
- FORCE_RET();
-}
-
-void OPPROTO op_restored(void)
-{
- env->canrestore++;
- if (env->cleanwin < NWINDOWS - 1)
- env->cleanwin++;
- if (env->otherwin == 0)
- env->cansave--;
- else
- env->otherwin--;
- FORCE_RET();
-}
-
-void OPPROTO op_popc(void)
-{
- do_popc();
-}
-
-void OPPROTO op_done(void)
-{
- do_done();
-}
-
-void OPPROTO op_retry(void)
-{
- do_retry();
-}
-
-void OPPROTO op_sir(void)
-{
- // XXX
-
-}
-
-void OPPROTO op_ld_asi_reg()
-{
- T0 += PARAM1;
- helper_ld_asi(env->asi, PARAM2, PARAM3);
-}
-
-void OPPROTO op_st_asi_reg()
-{
- T0 += PARAM1;
- helper_st_asi(env->asi, PARAM2, PARAM3);
-}
-#endif
-
-void OPPROTO op_ld_asi()
-{
- helper_ld_asi(PARAM1, PARAM2, PARAM3);
-}
-
-void OPPROTO op_st_asi()
-{
- helper_st_asi(PARAM1, PARAM2, PARAM3);
-}
-
-#ifdef TARGET_SPARC64
-void OPPROTO op_alignaddr()
-{
- uint64_t tmp;
-
- tmp = T0 + T1;
- env->gsr &= ~7ULL;
- env->gsr |= tmp & 7ULL;
- T0 = tmp & ~7ULL;
-}
-
-void OPPROTO op_faligndata()
-{
- uint64_t tmp;
-
- tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
- tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
- (*((uint64_t *)&DT0)) = tmp;
-}
-#endif
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
deleted file mode 100644
index f4f725d..0000000
--- a/target-sparc/op_helper.c
+++ /dev/null
@@ -1,918 +0,0 @@
-#include "exec.h"
-
-//#define DEBUG_PCALL
-//#define DEBUG_MMU
-
-void raise_exception(int tt)
-{
- env->exception_index = tt;
- cpu_loop_exit();
-}
-
-#ifdef USE_INT_TO_FLOAT_HELPERS
-void do_fitos(void)
-{
- FT0 = int32_to_float32(*((int32_t *)&FT1));
-}
-
-void do_fitod(void)
-{
- DT0 = int32_to_float64(*((int32_t *)&FT1));
-}
-#endif
-
-void do_fabss(void)
-{
- FT0 = float32_abs(FT1);
-}
-
-#ifdef TARGET_SPARC64
-void do_fabsd(void)
-{
- DT0 = float64_abs(DT1);
-}
-#endif
-
-void do_fsqrts(void)
-{
- FT0 = float32_sqrt(FT1, &env->fp_status);
-}
-
-void do_fsqrtd(void)
-{
- DT0 = float64_sqrt(DT1, &env->fp_status);
-}
-
-#define GEN_FCMP(name, size, reg1, reg2, FS) \
- 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) { \
- env->fsr |= T0; \
- raise_exception(TT_FP_EXCP); \
- } else { \
- env->fsr |= FSR_NVA; \
- } \
- break; \
- case float_relation_less: \
- T0 = FSR_FCC0 << FS; \
- break; \
- case float_relation_greater: \
- T0 = FSR_FCC1 << FS; \
- break; \
- default: \
- T0 = 0; \
- break; \
- } \
- env->fsr |= T0; \
- }
-
-GEN_FCMP(fcmps, float32, FT0, FT1, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0);
-
-#ifdef TARGET_SPARC64
-GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22);
-
-GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24);
-
-GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26);
-#endif
-
-#if defined(CONFIG_USER_ONLY)
-void helper_ld_asi(int asi, int size, int sign)
-{
-}
-
-void helper_st_asi(int asi, int size, int sign)
-{
-}
-#else
-#ifndef TARGET_SPARC64
-void helper_ld_asi(int asi, int size, int sign)
-{
- uint32_t ret = 0;
-
- switch (asi) {
- case 3: /* MMU probe */
- {
- int mmulev;
-
- mmulev = (T0 >> 8) & 15;
- if (mmulev > 4)
- ret = 0;
- else {
- ret = mmu_probe(env, T0, mmulev);
- //bswap32s(&ret);
- }
-#ifdef DEBUG_MMU
- printf("mmu_probe: 0x%08x (lev %d) -> 0x%08x\n", T0, mmulev, ret);
-#endif
- }
- break;
- case 4: /* read MMU regs */
- {
- int reg = (T0 >> 8) & 0xf;
-
- ret = env->mmuregs[reg];
- if (reg == 3) /* Fault status cleared on read */
- env->mmuregs[reg] = 0;
-#ifdef DEBUG_MMU
- printf("mmu_read: reg[%d] = 0x%08x\n", reg, ret);
-#endif
- }
- break;
- case 0x20 ... 0x2f: /* MMU passthrough */
- switch(size) {
- case 1:
- ret = ldub_phys(T0);
- break;
- case 2:
- ret = lduw_phys(T0 & ~1);
- break;
- default:
- case 4:
- ret = ldl_phys(T0 & ~3);
- break;
- case 8:
- ret = ldl_phys(T0 & ~3);
- T0 = ldl_phys((T0 + 4) & ~3);
- break;
- }
- break;
- default:
- ret = 0;
- break;
- }
- T1 = ret;
-}
-
-void helper_st_asi(int asi, int size, int sign)
-{
- switch(asi) {
- case 3: /* MMU flush */
- {
- int mmulev;
-
- mmulev = (T0 >> 8) & 15;
-#ifdef DEBUG_MMU
- printf("mmu flush level %d\n", mmulev);
-#endif
- switch (mmulev) {
- case 0: // flush page
- tlb_flush_page(env, T0 & 0xfffff000);
- break;
- case 1: // flush segment (256k)
- case 2: // flush region (16M)
- case 3: // flush context (4G)
- case 4: // flush entire
- tlb_flush(env, 1);
- break;
- default:
- break;
- }
-#ifdef DEBUG_MMU
- dump_mmu(env);
-#endif
- return;
- }
- case 4: /* write MMU regs */
- {
- int reg = (T0 >> 8) & 0xf;
- uint32_t oldreg;
-
- oldreg = env->mmuregs[reg];
- switch(reg) {
- case 0:
- env->mmuregs[reg] &= ~(MMU_E | MMU_NF);
- env->mmuregs[reg] |= T1 & (MMU_E | MMU_NF);
- // Mappings generated during no-fault mode or MMU
- // disabled mode are invalid in normal mode
- if (oldreg != env->mmuregs[reg])
- tlb_flush(env, 1);
- break;
- case 2:
- env->mmuregs[reg] = T1;
- if (oldreg != env->mmuregs[reg]) {
- /* we flush when the MMU context changes because
- QEMU has no MMU context support */
- tlb_flush(env, 1);
- }
- break;
- case 3:
- case 4:
- break;
- default:
- env->mmuregs[reg] = T1;
- break;
- }
-#ifdef DEBUG_MMU
- if (oldreg != env->mmuregs[reg]) {
- printf("mmu change reg[%d]: 0x%08x -> 0x%08x\n", reg, oldreg, env->mmuregs[reg]);
- }
- dump_mmu(env);
-#endif
- return;
- }
- case 0x17: /* Block copy, sta access */
- {
- // value (T1) = src
- // address (T0) = dst
- // copy 32 bytes
- uint32_t src = T1, dst = T0;
- uint8_t temp[32];
-
- tswap32s(&src);
-
- cpu_physical_memory_read(src, (void *) &temp, 32);
- cpu_physical_memory_write(dst, (void *) &temp, 32);
- }
- return;
- case 0x1f: /* Block fill, stda access */
- {
- // value (T1, T2)
- // address (T0) = dst
- // fill 32 bytes
- int i;
- uint32_t dst = T0;
- uint64_t val;
-
- val = (((uint64_t)T1) << 32) | T2;
- tswap64s(&val);
-
- for (i = 0; i < 32; i += 8, dst += 8) {
- cpu_physical_memory_write(dst, (void *) &val, 8);
- }
- }
- return;
- case 0x20 ... 0x2f: /* MMU passthrough */
- {
- switch(size) {
- case 1:
- stb_phys(T0, T1);
- break;
- case 2:
- stw_phys(T0 & ~1, T1);
- break;
- case 4:
- default:
- stl_phys(T0 & ~3, T1);
- break;
- case 8:
- stl_phys(T0 & ~3, T1);
- stl_phys((T0 + 4) & ~3, T2);
- break;
- }
- }
- return;
- default:
- return;
- }
-}
-
-#else
-
-void helper_ld_asi(int asi, int size, int sign)
-{
- uint64_t ret = 0;
-
- if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
- raise_exception(TT_PRIV_ACT);
-
- switch (asi) {
- case 0x14: // Bypass
- case 0x15: // Bypass, non-cacheable
- {
- switch(size) {
- case 1:
- ret = ldub_phys(T0);
- break;
- case 2:
- ret = lduw_phys(T0 & ~1);
- break;
- case 4:
- ret = ldl_phys(T0 & ~3);
- break;
- default:
- case 8:
- ret = ldq_phys(T0 & ~7);
- break;
- }
- break;
- }
- case 0x04: // Nucleus
- case 0x0c: // Nucleus Little Endian (LE)
- case 0x10: // As if user primary
- case 0x11: // As if user secondary
- case 0x18: // As if user primary LE
- case 0x19: // As if user secondary LE
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
- case 0x24: // Nucleus quad LDD 128 bit atomic
- case 0x2c: // Nucleus quad LDD 128 bit atomic
- case 0x4a: // UPA config
- case 0x82: // Primary no-fault
- case 0x83: // Secondary no-fault
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- case 0x8a: // Primary no-fault LE
- case 0x8b: // Secondary no-fault LE
- // XXX
- break;
- case 0x45: // LSU
- ret = env->lsu;
- break;
- case 0x50: // I-MMU regs
- {
- int reg = (T0 >> 3) & 0xf;
-
- ret = env->immuregs[reg];
- break;
- }
- case 0x51: // I-MMU 8k TSB pointer
- case 0x52: // I-MMU 64k TSB pointer
- case 0x55: // I-MMU data access
- // XXX
- break;
- case 0x56: // I-MMU tag read
- {
- unsigned int i;
-
- for (i = 0; i < 64; i++) {
- // Valid, ctx match, vaddr match
- if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0 &&
- env->itlb_tag[i] == T0) {
- ret = env->itlb_tag[i];
- break;
- }
- }
- break;
- }
- case 0x58: // D-MMU regs
- {
- int reg = (T0 >> 3) & 0xf;
-
- ret = env->dmmuregs[reg];
- break;
- }
- case 0x5e: // D-MMU tag read
- {
- unsigned int i;
-
- for (i = 0; i < 64; i++) {
- // Valid, ctx match, vaddr match
- if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0 &&
- env->dtlb_tag[i] == T0) {
- ret = env->dtlb_tag[i];
- break;
- }
- }
- break;
- }
- case 0x59: // D-MMU 8k TSB pointer
- case 0x5a: // D-MMU 64k TSB pointer
- case 0x5b: // D-MMU data pointer
- case 0x5d: // D-MMU data access
- case 0x48: // Interrupt dispatch, RO
- case 0x49: // Interrupt data receive
- case 0x7f: // Incoming interrupt vector, RO
- // XXX
- break;
- case 0x54: // I-MMU data in, WO
- case 0x57: // I-MMU demap, WO
- case 0x5c: // D-MMU data in, WO
- case 0x5f: // D-MMU demap, WO
- case 0x77: // Interrupt vector, WO
- default:
- ret = 0;
- break;
- }
- T1 = ret;
-}
-
-void helper_st_asi(int asi, int size, int sign)
-{
- if (asi < 0x80 && (env->pstate & PS_PRIV) == 0)
- raise_exception(TT_PRIV_ACT);
-
- switch(asi) {
- case 0x14: // Bypass
- case 0x15: // Bypass, non-cacheable
- {
- switch(size) {
- case 1:
- stb_phys(T0, T1);
- break;
- case 2:
- stw_phys(T0 & ~1, T1);
- break;
- case 4:
- stl_phys(T0 & ~3, T1);
- break;
- case 8:
- default:
- stq_phys(T0 & ~7, T1);
- break;
- }
- }
- return;
- case 0x04: // Nucleus
- case 0x0c: // Nucleus Little Endian (LE)
- case 0x10: // As if user primary
- case 0x11: // As if user secondary
- case 0x18: // As if user primary LE
- case 0x19: // As if user secondary LE
- case 0x1c: // Bypass LE
- case 0x1d: // Bypass, non-cacheable LE
- case 0x24: // Nucleus quad LDD 128 bit atomic
- case 0x2c: // Nucleus quad LDD 128 bit atomic
- case 0x4a: // UPA config
- case 0x88: // Primary LE
- case 0x89: // Secondary LE
- // XXX
- return;
- case 0x45: // LSU
- {
- uint64_t oldreg;
-
- oldreg = env->lsu;
- env->lsu = T1 & (DMMU_E | IMMU_E);
- // Mappings generated during D/I MMU disabled mode are
- // invalid in normal mode
- if (oldreg != env->lsu) {
-#ifdef DEBUG_MMU
- printf("LSU change: 0x%" PRIx64 " -> 0x%" PRIx64 "\n", oldreg, env->lsu);
- dump_mmu(env);
-#endif
- tlb_flush(env, 1);
- }
- return;
- }
- case 0x50: // I-MMU regs
- {
- int reg = (T0 >> 3) & 0xf;
- uint64_t oldreg;
-
- oldreg = env->immuregs[reg];
- switch(reg) {
- case 0: // RO
- case 4:
- return;
- case 1: // Not in I-MMU
- case 2:
- case 7:
- case 8:
- return;
- case 3: // SFSR
- if ((T1 & 1) == 0)
- T1 = 0; // Clear SFSR
- break;
- case 5: // TSB access
- case 6: // Tag access
- default:
- break;
- }
- env->immuregs[reg] = T1;
-#ifdef DEBUG_MMU
- if (oldreg != env->immuregs[reg]) {
- printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->immuregs[reg]);
- }
- dump_mmu(env);
-#endif
- return;
- }
- case 0x54: // I-MMU data in
- {
- unsigned int i;
-
- // Try finding an invalid entry
- for (i = 0; i < 64; i++) {
- if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0) {
- env->itlb_tag[i] = env->immuregs[6];
- env->itlb_tte[i] = T1;
- return;
- }
- }
- // Try finding an unlocked entry
- for (i = 0; i < 64; i++) {
- if ((env->itlb_tte[i] & 0x40) == 0) {
- env->itlb_tag[i] = env->immuregs[6];
- env->itlb_tte[i] = T1;
- return;
- }
- }
- // error state?
- return;
- }
- case 0x55: // I-MMU data access
- {
- unsigned int i = (T0 >> 3) & 0x3f;
-
- env->itlb_tag[i] = env->immuregs[6];
- env->itlb_tte[i] = T1;
- return;
- }
- case 0x57: // I-MMU demap
- // XXX
- return;
- case 0x58: // D-MMU regs
- {
- int reg = (T0 >> 3) & 0xf;
- uint64_t oldreg;
-
- oldreg = env->dmmuregs[reg];
- switch(reg) {
- case 0: // RO
- case 4:
- return;
- case 3: // SFSR
- if ((T1 & 1) == 0) {
- T1 = 0; // Clear SFSR, Fault address
- env->dmmuregs[4] = 0;
- }
- env->dmmuregs[reg] = T1;
- break;
- case 1: // Primary context
- case 2: // Secondary context
- case 5: // TSB access
- case 6: // Tag access
- case 7: // Virtual Watchpoint
- case 8: // Physical Watchpoint
- default:
- break;
- }
- env->dmmuregs[reg] = T1;
-#ifdef DEBUG_MMU
- if (oldreg != env->dmmuregs[reg]) {
- printf("mmu change reg[%d]: 0x%08" PRIx64 " -> 0x%08" PRIx64 "\n", reg, oldreg, env->dmmuregs[reg]);
- }
- dump_mmu(env);
-#endif
- return;
- }
- case 0x5c: // D-MMU data in
- {
- unsigned int i;
-
- // Try finding an invalid entry
- for (i = 0; i < 64; i++) {
- if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0) {
- env->dtlb_tag[i] = env->dmmuregs[6];
- env->dtlb_tte[i] = T1;
- return;
- }
- }
- // Try finding an unlocked entry
- for (i = 0; i < 64; i++) {
- if ((env->dtlb_tte[i] & 0x40) == 0) {
- env->dtlb_tag[i] = env->dmmuregs[6];
- env->dtlb_tte[i] = T1;
- return;
- }
- }
- // error state?
- return;
- }
- case 0x5d: // D-MMU data access
- {
- unsigned int i = (T0 >> 3) & 0x3f;
-
- env->dtlb_tag[i] = env->dmmuregs[6];
- env->dtlb_tte[i] = T1;
- return;
- }
- case 0x5f: // D-MMU demap
- case 0x49: // Interrupt data receive
- // XXX
- return;
- case 0x51: // I-MMU 8k TSB pointer, RO
- case 0x52: // I-MMU 64k TSB pointer, RO
- case 0x56: // I-MMU tag read, RO
- case 0x59: // D-MMU 8k TSB pointer, RO
- case 0x5a: // D-MMU 64k TSB pointer, RO
- case 0x5b: // D-MMU data pointer, RO
- case 0x5e: // D-MMU tag read, RO
- case 0x48: // Interrupt dispatch, RO
- case 0x7f: // Incoming interrupt vector, RO
- case 0x82: // Primary no-fault, RO
- case 0x83: // Secondary no-fault, RO
- case 0x8a: // Primary no-fault LE, RO
- case 0x8b: // Secondary no-fault LE, RO
- default:
- return;
- }
-}
-#endif
-#endif /* !CONFIG_USER_ONLY */
-
-#ifndef TARGET_SPARC64
-void helper_rett()
-{
- unsigned int cwp;
-
- env->psret = 1;
- cwp = (env->cwp + 1) & (NWINDOWS - 1);
- if (env->wim & (1 << cwp)) {
- raise_exception(TT_WIN_UNF);
- }
- set_cwp(cwp);
- env->psrs = env->psrps;
-}
-#endif
-
-void helper_ldfsr(void)
-{
- int rnd_mode;
- switch (env->fsr & FSR_RD_MASK) {
- case FSR_RD_NEAREST:
- rnd_mode = float_round_nearest_even;
- break;
- default:
- case FSR_RD_ZERO:
- rnd_mode = float_round_to_zero;
- break;
- case FSR_RD_POS:
- rnd_mode = float_round_up;
- break;
- case FSR_RD_NEG:
- rnd_mode = float_round_down;
- break;
- }
- set_float_rounding_mode(rnd_mode, &env->fp_status);
-}
-
-void helper_debug()
-{
- env->exception_index = EXCP_DEBUG;
- cpu_loop_exit();
-}
-
-#ifndef TARGET_SPARC64
-void do_wrpsr()
-{
- PUT_PSR(env, T0);
-}
-
-void do_rdpsr()
-{
- T0 = GET_PSR(env);
-}
-
-#else
-
-void do_popc()
-{
- T0 = (T1 & 0x5555555555555555ULL) + ((T1 >> 1) & 0x5555555555555555ULL);
- T0 = (T0 & 0x3333333333333333ULL) + ((T0 >> 2) & 0x3333333333333333ULL);
- T0 = (T0 & 0x0f0f0f0f0f0f0f0fULL) + ((T0 >> 4) & 0x0f0f0f0f0f0f0f0fULL);
- T0 = (T0 & 0x00ff00ff00ff00ffULL) + ((T0 >> 8) & 0x00ff00ff00ff00ffULL);
- T0 = (T0 & 0x0000ffff0000ffffULL) + ((T0 >> 16) & 0x0000ffff0000ffffULL);
- T0 = (T0 & 0x00000000ffffffffULL) + ((T0 >> 32) & 0x00000000ffffffffULL);
-}
-
-static inline uint64_t *get_gregset(uint64_t pstate)
-{
- switch (pstate) {
- default:
- case 0:
- return env->bgregs;
- case PS_AG:
- return env->agregs;
- case PS_MG:
- return env->mgregs;
- case PS_IG:
- return env->igregs;
- }
-}
-
-void do_wrpstate()
-{
- uint64_t new_pstate, pstate_regs, new_pstate_regs;
- uint64_t *src, *dst;
-
- new_pstate = T0 & 0xf3f;
- pstate_regs = env->pstate & 0xc01;
- new_pstate_regs = new_pstate & 0xc01;
- if (new_pstate_regs != pstate_regs) {
- // Switch global register bank
- src = get_gregset(new_pstate_regs);
- dst = get_gregset(pstate_regs);
- memcpy32(dst, env->gregs);
- memcpy32(env->gregs, src);
- }
- env->pstate = new_pstate;
-}
-
-void do_done(void)
-{
- env->tl--;
- env->pc = env->tnpc[env->tl];
- env->npc = env->tnpc[env->tl] + 4;
- PUT_CCR(env, env->tstate[env->tl] >> 32);
- env->asi = (env->tstate[env->tl] >> 24) & 0xff;
- env->pstate = (env->tstate[env->tl] >> 8) & 0xfff;
- set_cwp(env->tstate[env->tl] & 0xff);
-}
-
-void do_retry(void)
-{
- env->tl--;
- env->pc = env->tpc[env->tl];
- env->npc = env->tnpc[env->tl];
- PUT_CCR(env, env->tstate[env->tl] >> 32);
- env->asi = (env->tstate[env->tl] >> 24) & 0xff;
- env->pstate = (env->tstate[env->tl] >> 8) & 0xfff;
- set_cwp(env->tstate[env->tl] & 0xff);
-}
-#endif
-
-void set_cwp(int new_cwp)
-{
- /* put the modified wrap registers at their proper location */
- if (env->cwp == (NWINDOWS - 1))
- memcpy32(env->regbase, env->regbase + NWINDOWS * 16);
- env->cwp = new_cwp;
- /* put the wrap registers at their temporary location */
- if (new_cwp == (NWINDOWS - 1))
- memcpy32(env->regbase + NWINDOWS * 16, env->regbase);
- env->regwptr = env->regbase + (new_cwp * 16);
- REGWPTR = env->regwptr;
-}
-
-void cpu_set_cwp(CPUState *env1, int new_cwp)
-{
- CPUState *saved_env;
-#ifdef reg_REGWPTR
- target_ulong *saved_regwptr;
-#endif
-
- saved_env = env;
-#ifdef reg_REGWPTR
- saved_regwptr = REGWPTR;
-#endif
- env = env1;
- set_cwp(new_cwp);
- env = saved_env;
-#ifdef reg_REGWPTR
- REGWPTR = saved_regwptr;
-#endif
-}
-
-#ifdef TARGET_SPARC64
-void do_interrupt(int intno)
-{
-#ifdef DEBUG_PCALL
- if (loglevel & CPU_LOG_INT) {
- static int count;
- fprintf(logfile, "%6d: v=%04x pc=%016" PRIx64 " npc=%016" PRIx64 " SP=%016" PRIx64 "\n",
- count, intno,
- env->pc,
- env->npc, env->regwptr[6]);
- cpu_dump_state(env, logfile, fprintf, 0);
-#if 0
- {
- int i;
- uint8_t *ptr;
-
- fprintf(logfile, " code=");
- ptr = (uint8_t *)env->pc;
- for(i = 0; i < 16; i++) {
- fprintf(logfile, " %02x", ldub(ptr + i));
- }
- fprintf(logfile, "\n");
- }
-#endif
- count++;
- }
-#endif
-#if !defined(CONFIG_USER_ONLY)
- if (env->tl == MAXTL) {
- cpu_abort(env, "Trap 0x%04x while trap level is MAXTL, Error state", env->exception_index);
- return;
- }
-#endif
- env->tstate[env->tl] = ((uint64_t)GET_CCR(env) << 32) | ((env->asi & 0xff) << 24) |
- ((env->pstate & 0xfff) << 8) | (env->cwp & 0xff);
- env->tpc[env->tl] = env->pc;
- env->tnpc[env->tl] = env->npc;
- env->tt[env->tl] = intno;
- env->pstate = PS_PEF | PS_PRIV | PS_AG;
- env->tbr &= ~0x7fffULL;
- env->tbr |= ((env->tl > 1) ? 1 << 14 : 0) | (intno << 5);
- if (env->tl < MAXTL - 1) {
- env->tl++;
- } else {
- env->pstate |= PS_RED;
- if (env->tl != MAXTL)
- env->tl++;
- }
- env->pc = env->tbr;
- env->npc = env->pc + 4;
- env->exception_index = 0;
-}
-#else
-void do_interrupt(int intno)
-{
- int cwp;
-
-#ifdef DEBUG_PCALL
- if (loglevel & CPU_LOG_INT) {
- static int count;
- fprintf(logfile, "%6d: v=%02x pc=%08x npc=%08x SP=%08x\n",
- count, intno,
- env->pc,
- env->npc, env->regwptr[6]);
- cpu_dump_state(env, logfile, fprintf, 0);
-#if 0
- {
- int i;
- uint8_t *ptr;
-
- fprintf(logfile, " code=");
- ptr = (uint8_t *)env->pc;
- for(i = 0; i < 16; i++) {
- fprintf(logfile, " %02x", ldub(ptr + i));
- }
- fprintf(logfile, "\n");
- }
-#endif
- count++;
- }
-#endif
-#if !defined(CONFIG_USER_ONLY)
- if (env->psret == 0) {
- cpu_abort(env, "Trap 0x%02x while interrupts disabled, Error state", env->exception_index);
- return;
- }
-#endif
- env->psret = 0;
- cwp = (env->cwp - 1) & (NWINDOWS - 1);
- set_cwp(cwp);
- env->regwptr[9] = env->pc;
- env->regwptr[10] = env->npc;
- env->psrps = env->psrs;
- env->psrs = 1;
- env->tbr = (env->tbr & TBR_BASE_MASK) | (intno << 4);
- env->pc = env->tbr;
- env->npc = env->pc + 4;
- env->exception_index = 0;
-}
-#endif
-
-#if !defined(CONFIG_USER_ONLY)
-
-#define MMUSUFFIX _mmu
-#define GETPC() (__builtin_return_address(0))
-
-#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;
- int ret;
- unsigned long pc;
- CPUState *saved_env;
-
- /* XXX: hack to restore env in all cases, even if not called from
- generated code */
- saved_env = env;
- env = cpu_single_env;
-
- ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, is_user, 1);
- if (ret) {
- if (retaddr) {
- /* now we have a real cpu fault */
- pc = (unsigned long)retaddr;
- tb = tb_find_pc(pc);
- if (tb) {
- /* the PC is inside the translated code. It means that we have
- a virtual CPU fault */
- cpu_restore_state(tb, env, pc, (void *)T2);
- }
- }
- cpu_loop_exit();
- }
- env = saved_env;
-}
-
-#endif
diff --git a/target-sparc/op_mem.h b/target-sparc/op_mem.h
deleted file mode 100644
index f5dbd26..0000000
--- a/target-sparc/op_mem.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/*** Integer load ***/
-#define SPARC_LD_OP(name, qp) \
-void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \
-{ \
- T1 = (target_ulong)glue(qp, MEMSUFFIX)(T0); \
-}
-
-#define SPARC_LD_OP_S(name, qp) \
- void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \
- { \
- T1 = (target_long)glue(qp, MEMSUFFIX)(T0); \
- }
-
-#define SPARC_ST_OP(name, op) \
-void OPPROTO glue(glue(op_, name), MEMSUFFIX)(void) \
-{ \
- glue(op, MEMSUFFIX)(T0, T1); \
-}
-
-SPARC_LD_OP(ld, ldl);
-SPARC_LD_OP(ldub, ldub);
-SPARC_LD_OP(lduh, lduw);
-SPARC_LD_OP_S(ldsb, ldsb);
-SPARC_LD_OP_S(ldsh, ldsw);
-
-/*** Integer store ***/
-SPARC_ST_OP(st, stl);
-SPARC_ST_OP(stb, stb);
-SPARC_ST_OP(sth, stw);
-
-void OPPROTO glue(op_std, MEMSUFFIX)(void)
-{
- glue(stl, MEMSUFFIX)(T0, T1);
- glue(stl, MEMSUFFIX)((T0 + 4), T2);
-}
-
-void OPPROTO glue(op_ldstub, MEMSUFFIX)(void)
-{
- T1 = glue(ldub, MEMSUFFIX)(T0);
- glue(stb, MEMSUFFIX)(T0, 0xff); /* XXX: Should be Atomically */
-}
-
-void OPPROTO glue(op_swap, MEMSUFFIX)(void)
-{
- target_ulong tmp = glue(ldl, MEMSUFFIX)(T0);
- glue(stl, MEMSUFFIX)(T0, T1); /* XXX: Should be Atomically */
- T1 = tmp;
-}
-
-void OPPROTO glue(op_ldd, MEMSUFFIX)(void)
-{
- T1 = glue(ldl, MEMSUFFIX)(T0);
- T0 = glue(ldl, MEMSUFFIX)((T0 + 4));
-}
-
-/*** Floating-point store ***/
-void OPPROTO glue(op_stf, MEMSUFFIX) (void)
-{
- glue(stfl, MEMSUFFIX)(T0, FT0);
-}
-
-void OPPROTO glue(op_stdf, MEMSUFFIX) (void)
-{
- glue(stfq, MEMSUFFIX)(T0, DT0);
-}
-
-/*** Floating-point load ***/
-void OPPROTO glue(op_ldf, MEMSUFFIX) (void)
-{
- FT0 = glue(ldfl, MEMSUFFIX)(T0);
-}
-
-void OPPROTO glue(op_lddf, MEMSUFFIX) (void)
-{
- DT0 = glue(ldfq, MEMSUFFIX)(T0);
-}
-
-#ifdef TARGET_SPARC64
-/* XXX: Should be Atomically */
-/* XXX: There are no cas[x] instructions, only cas[x]a */
-void OPPROTO glue(op_cas, MEMSUFFIX)(void)
-{
- uint32_t tmp;
-
- tmp = glue(ldl, MEMSUFFIX)(T0);
- T2 &= 0xffffffffULL;
- if (tmp == (T1 & 0xffffffffULL)) {
- glue(stl, MEMSUFFIX)(T0, T2);
- }
- T2 = tmp;
-}
-
-void OPPROTO glue(op_casx, MEMSUFFIX)(void)
-{
- uint64_t tmp;
-
- // XXX
- tmp = (uint64_t)glue(ldl, MEMSUFFIX)(T0) << 32;
- tmp |= glue(ldl, MEMSUFFIX)(T0);
- if (tmp == T1) {
- glue(stq, MEMSUFFIX)(T0, T2);
- }
- T2 = tmp;
-}
-
-void OPPROTO glue(op_ldsw, MEMSUFFIX)(void)
-{
- T1 = (int64_t)(glue(ldl, MEMSUFFIX)(T0) & 0xffffffff);
-}
-
-SPARC_LD_OP(ldx, ldq);
-SPARC_ST_OP(stx, stq);
-#endif
-#undef MEMSUFFIX
diff --git a/target-sparc/op_template.h b/target-sparc/op_template.h
deleted file mode 100644
index ecf65fd..0000000
--- a/target-sparc/op_template.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * SPARC micro operations (templates for various register related
- * operations)
- *
- * Copyright (c) 2003 Fabrice Bellard
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-void OPPROTO glue(op_movl_T0_, REGNAME)(void)
-{
- T0 = REG;
-}
-
-void OPPROTO glue(op_movl_T1_, REGNAME)(void)
-{
- T1 = REG;
-}
-
-void OPPROTO glue(op_movl_T2_, REGNAME)(void)
-{
- T2 = REG;
-}
-
-void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void)
-{
- REG = T0;
-}
-
-void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void)
-{
- REG = T1;
-}
-
-#undef REG
-#undef REGNAME
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
deleted file mode 100644
index a522d77..0000000
--- a/target-sparc/translate.c
+++ /dev/null
@@ -1,2845 +0,0 @@
-/*
- SPARC translation
-
- Copyright (C) 2003 Thomas M. Ogrisegg <tom@fnord.at>
- Copyright (C) 2003-2005 Fabrice Bellard
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/*
- TODO-list:
-
- 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>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-
-#include "cpu.h"
-#include "exec-all.h"
-#include "disas.h"
-
-#define DEBUG_DISAS
-
-#define DYNAMIC_PC 1 /* dynamic pc value */
-#define JUMP_PC 2 /* dynamic pc value which takes only two values
- according to jump_pc[T2] */
-
-typedef struct DisasContext {
- target_ulong pc; /* current Program Counter: integer or DYNAMIC_PC */
- target_ulong npc; /* next PC: integer or DYNAMIC_PC or JUMP_PC */
- target_ulong jump_pc[2]; /* used when JUMP_PC pc value is used */
- int is_br;
- int mem_idx;
- int fpu_enabled;
- struct TranslationBlock *tb;
-} DisasContext;
-
-static uint16_t *gen_opc_ptr;
-static uint32_t *gen_opparam_ptr;
-extern FILE *logfile;
-extern int loglevel;
-
-enum {
-#define DEF(s,n,copy_size) INDEX_op_ ## s,
-#include "opc.h"
-#undef DEF
- NB_OPS
-};
-
-#include "gen-op.h"
-
-// This function uses non-native bit order
-#define GET_FIELD(X, FROM, TO) \
- ((X) >> (31 - (TO)) & ((1 << ((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, 31 - (TO), 31 - (FROM))
-
-#define GET_FIELDs(x,a,b) sign_extend (GET_FIELD(x,a,b), (b) - (a) + 1)
-#define GET_FIELD_SPs(x,a,b) sign_extend (GET_FIELD_SP(x,a,b), 32 - ((b) - (a) + 1))
-
-#ifdef TARGET_SPARC64
-#define DFPREG(r) (((r & 1) << 6) | (r & 0x1e))
-#else
-#define DFPREG(r) (r)
-#endif
-
-#ifdef USE_DIRECT_JUMP
-#define TBPARAM(x)
-#else
-#define TBPARAM(x) (long)(x)
-#endif
-
-static int sign_extend(int x, int len)
-{
- len = 32 - len;
- return (x << len) >> len;
-}
-
-#define IS_IMM (insn & (1<<13))
-
-static void disas_sparc_insn(DisasContext * dc);
-
-static GenOpFunc *gen_op_movl_TN_reg[2][32] = {
- {
- gen_op_movl_g0_T0,
- gen_op_movl_g1_T0,
- gen_op_movl_g2_T0,
- gen_op_movl_g3_T0,
- gen_op_movl_g4_T0,
- gen_op_movl_g5_T0,
- gen_op_movl_g6_T0,
- gen_op_movl_g7_T0,
- gen_op_movl_o0_T0,
- gen_op_movl_o1_T0,
- gen_op_movl_o2_T0,
- gen_op_movl_o3_T0,
- gen_op_movl_o4_T0,
- gen_op_movl_o5_T0,
- gen_op_movl_o6_T0,
- gen_op_movl_o7_T0,
- gen_op_movl_l0_T0,
- gen_op_movl_l1_T0,
- gen_op_movl_l2_T0,
- gen_op_movl_l3_T0,
- gen_op_movl_l4_T0,
- gen_op_movl_l5_T0,
- gen_op_movl_l6_T0,
- gen_op_movl_l7_T0,
- gen_op_movl_i0_T0,
- gen_op_movl_i1_T0,
- gen_op_movl_i2_T0,
- gen_op_movl_i3_T0,
- gen_op_movl_i4_T0,
- gen_op_movl_i5_T0,
- gen_op_movl_i6_T0,
- gen_op_movl_i7_T0,
- },
- {
- gen_op_movl_g0_T1,
- gen_op_movl_g1_T1,
- gen_op_movl_g2_T1,
- gen_op_movl_g3_T1,
- gen_op_movl_g4_T1,
- gen_op_movl_g5_T1,
- gen_op_movl_g6_T1,
- gen_op_movl_g7_T1,
- gen_op_movl_o0_T1,
- gen_op_movl_o1_T1,
- gen_op_movl_o2_T1,
- gen_op_movl_o3_T1,
- gen_op_movl_o4_T1,
- gen_op_movl_o5_T1,
- gen_op_movl_o6_T1,
- gen_op_movl_o7_T1,
- gen_op_movl_l0_T1,
- gen_op_movl_l1_T1,
- gen_op_movl_l2_T1,
- gen_op_movl_l3_T1,
- gen_op_movl_l4_T1,
- gen_op_movl_l5_T1,
- gen_op_movl_l6_T1,
- gen_op_movl_l7_T1,
- gen_op_movl_i0_T1,
- gen_op_movl_i1_T1,
- gen_op_movl_i2_T1,
- gen_op_movl_i3_T1,
- gen_op_movl_i4_T1,
- gen_op_movl_i5_T1,
- gen_op_movl_i6_T1,
- gen_op_movl_i7_T1,
- }
-};
-
-static GenOpFunc *gen_op_movl_reg_TN[3][32] = {
- {
- gen_op_movl_T0_g0,
- gen_op_movl_T0_g1,
- gen_op_movl_T0_g2,
- gen_op_movl_T0_g3,
- gen_op_movl_T0_g4,
- gen_op_movl_T0_g5,
- gen_op_movl_T0_g6,
- gen_op_movl_T0_g7,
- gen_op_movl_T0_o0,
- gen_op_movl_T0_o1,
- gen_op_movl_T0_o2,
- gen_op_movl_T0_o3,
- gen_op_movl_T0_o4,
- gen_op_movl_T0_o5,
- gen_op_movl_T0_o6,
- gen_op_movl_T0_o7,
- gen_op_movl_T0_l0,
- gen_op_movl_T0_l1,
- gen_op_movl_T0_l2,
- gen_op_movl_T0_l3,
- gen_op_movl_T0_l4,
- gen_op_movl_T0_l5,
- gen_op_movl_T0_l6,
- gen_op_movl_T0_l7,
- gen_op_movl_T0_i0,
- gen_op_movl_T0_i1,
- gen_op_movl_T0_i2,
- gen_op_movl_T0_i3,
- gen_op_movl_T0_i4,
- gen_op_movl_T0_i5,
- gen_op_movl_T0_i6,
- gen_op_movl_T0_i7,
- },
- {
- gen_op_movl_T1_g0,
- gen_op_movl_T1_g1,
- gen_op_movl_T1_g2,
- gen_op_movl_T1_g3,
- gen_op_movl_T1_g4,
- gen_op_movl_T1_g5,
- gen_op_movl_T1_g6,
- gen_op_movl_T1_g7,
- gen_op_movl_T1_o0,
- gen_op_movl_T1_o1,
- gen_op_movl_T1_o2,
- gen_op_movl_T1_o3,
- gen_op_movl_T1_o4,
- gen_op_movl_T1_o5,
- gen_op_movl_T1_o6,
- gen_op_movl_T1_o7,
- gen_op_movl_T1_l0,
- gen_op_movl_T1_l1,
- gen_op_movl_T1_l2,
- gen_op_movl_T1_l3,
- gen_op_movl_T1_l4,
- gen_op_movl_T1_l5,
- gen_op_movl_T1_l6,
- gen_op_movl_T1_l7,
- gen_op_movl_T1_i0,
- gen_op_movl_T1_i1,
- gen_op_movl_T1_i2,
- gen_op_movl_T1_i3,
- gen_op_movl_T1_i4,
- gen_op_movl_T1_i5,
- gen_op_movl_T1_i6,
- gen_op_movl_T1_i7,
- },
- {
- gen_op_movl_T2_g0,
- gen_op_movl_T2_g1,
- gen_op_movl_T2_g2,
- gen_op_movl_T2_g3,
- gen_op_movl_T2_g4,
- gen_op_movl_T2_g5,
- gen_op_movl_T2_g6,
- gen_op_movl_T2_g7,
- gen_op_movl_T2_o0,
- gen_op_movl_T2_o1,
- gen_op_movl_T2_o2,
- gen_op_movl_T2_o3,
- gen_op_movl_T2_o4,
- gen_op_movl_T2_o5,
- gen_op_movl_T2_o6,
- gen_op_movl_T2_o7,
- gen_op_movl_T2_l0,
- gen_op_movl_T2_l1,
- gen_op_movl_T2_l2,
- gen_op_movl_T2_l3,
- gen_op_movl_T2_l4,
- gen_op_movl_T2_l5,
- gen_op_movl_T2_l6,
- gen_op_movl_T2_l7,
- gen_op_movl_T2_i0,
- gen_op_movl_T2_i1,
- gen_op_movl_T2_i2,
- gen_op_movl_T2_i3,
- gen_op_movl_T2_i4,
- gen_op_movl_T2_i5,
- gen_op_movl_T2_i6,
- gen_op_movl_T2_i7,
- }
-};
-
-static GenOpFunc1 *gen_op_movl_TN_im[3] = {
- gen_op_movl_T0_im,
- gen_op_movl_T1_im,
- gen_op_movl_T2_im
-};
-
-// Sign extending version
-static GenOpFunc1 * const gen_op_movl_TN_sim[3] = {
- gen_op_movl_T0_sim,
- gen_op_movl_T1_sim,
- gen_op_movl_T2_sim
-};
-
-#ifdef TARGET_SPARC64
-#define GEN32(func, NAME) \
-static GenOpFunc *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, \
-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, \
-NAME ## 32, 0, NAME ## 34, 0, NAME ## 36, 0, NAME ## 38, 0, \
-NAME ## 40, 0, NAME ## 42, 0, NAME ## 44, 0, NAME ## 46, 0, \
-NAME ## 48, 0, NAME ## 50, 0, NAME ## 52, 0, NAME ## 54, 0, \
-NAME ## 56, 0, NAME ## 58, 0, NAME ## 60, 0, NAME ## 62, 0, \
-}; \
-static inline void func(int n) \
-{ \
- NAME ## _table[n](); \
-}
-#else
-#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](); \
-}
-#endif
-
-/* floating point registers moves */
-GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fprf);
-GEN32(gen_op_load_fpr_FT1, gen_op_load_fpr_FT1_fprf);
-GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fprf);
-GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fprf);
-
-GEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fprf);
-GEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fprf);
-GEN32(gen_op_store_DT0_fpr, gen_op_store_DT0_fpr_fprf);
-GEN32(gen_op_store_DT1_fpr, gen_op_store_DT1_fpr_fprf);
-
-#ifdef TARGET_SPARC64
-// 'a' versions allowed to user depending on asi
-#if defined(CONFIG_USER_ONLY)
-#define supervisor(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) \
- { \
- int asi, offset; \
- \
- if (IS_IMM) { \
- offset = GET_FIELD(insn, 25, 31); \
- if (is_ld) \
- gen_op_ld_asi_reg(offset, size, sign); \
- else \
- gen_op_st_asi_reg(offset, size, sign); \
- return; \
- } \
- asi = GET_FIELD(insn, 19, 26); \
- switch (asi) { \
- case 0x80: /* Primary address space */ \
- gen_op_##width##_raw(); \
- break; \
- case 0x82: /* Primary address space, non-faulting load */ \
- gen_op_##width##_raw(); \
- break; \
- default: \
- break; \
- } \
- }
-
-#else
-#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])()
-#define OP_LD_TABLE(width) \
- static GenOpFunc *gen_op_##width[] = { \
- &gen_op_##width##_user, \
- &gen_op_##width##_kernel, \
- }; \
- \
- static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \
- { \
- int asi, offset; \
- \
- if (IS_IMM) { \
- offset = GET_FIELD(insn, 25, 31); \
- if (is_ld) \
- gen_op_ld_asi_reg(offset, size, sign); \
- else \
- gen_op_st_asi_reg(offset, size, sign); \
- return; \
- } \
- asi = GET_FIELD(insn, 19, 26); \
- if (is_ld) \
- gen_op_ld_asi(asi, size, sign); \
- else \
- gen_op_st_asi(asi, size, sign); \
- }
-
-#define supervisor(dc) (dc->mem_idx == 1)
-#endif
-#else
-#if defined(CONFIG_USER_ONLY)
-#define gen_op_ldst(name) gen_op_##name##_raw()
-#define OP_LD_TABLE(width)
-#define supervisor(dc) 0
-#else
-#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])()
-#define OP_LD_TABLE(width) \
-static GenOpFunc *gen_op_##width[] = { \
- &gen_op_##width##_user, \
- &gen_op_##width##_kernel, \
-}; \
- \
-static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \
-{ \
- int asi; \
- \
- asi = GET_FIELD(insn, 19, 26); \
- switch (asi) { \
- case 10: /* User data access */ \
- gen_op_##width##_user(); \
- break; \
- case 11: /* Supervisor data access */ \
- gen_op_##width##_kernel(); \
- break; \
- case 0x20 ... 0x2f: /* MMU passthrough */ \
- if (is_ld) \
- gen_op_ld_asi(asi, size, sign); \
- else \
- gen_op_st_asi(asi, size, sign); \
- break; \
- default: \
- if (is_ld) \
- gen_op_ld_asi(asi, size, sign); \
- else \
- gen_op_st_asi(asi, size, sign); \
- break; \
- } \
-}
-
-#define supervisor(dc) (dc->mem_idx == 1)
-#endif
-#endif
-
-OP_LD_TABLE(ld);
-OP_LD_TABLE(st);
-OP_LD_TABLE(ldub);
-OP_LD_TABLE(lduh);
-OP_LD_TABLE(ldsb);
-OP_LD_TABLE(ldsh);
-OP_LD_TABLE(stb);
-OP_LD_TABLE(sth);
-OP_LD_TABLE(std);
-OP_LD_TABLE(ldstub);
-OP_LD_TABLE(swap);
-OP_LD_TABLE(ldd);
-OP_LD_TABLE(stf);
-OP_LD_TABLE(stdf);
-OP_LD_TABLE(ldf);
-OP_LD_TABLE(lddf);
-
-#ifdef TARGET_SPARC64
-OP_LD_TABLE(ldsw);
-OP_LD_TABLE(ldx);
-OP_LD_TABLE(stx);
-OP_LD_TABLE(cas);
-OP_LD_TABLE(casx);
-#endif
-
-static inline void gen_movl_imm_TN(int reg, uint32_t imm)
-{
- gen_op_movl_TN_im[reg](imm);
-}
-
-static inline void gen_movl_imm_T1(uint32_t val)
-{
- gen_movl_imm_TN(1, val);
-}
-
-static inline void gen_movl_imm_T0(uint32_t val)
-{
- gen_movl_imm_TN(0, val);
-}
-
-static inline void gen_movl_simm_TN(int reg, int32_t imm)
-{
- gen_op_movl_TN_sim[reg](imm);
-}
-
-static inline void gen_movl_simm_T1(int32_t val)
-{
- gen_movl_simm_TN(1, val);
-}
-
-static inline void gen_movl_simm_T0(int32_t val)
-{
- gen_movl_simm_TN(0, val);
-}
-
-static inline void gen_movl_reg_TN(int reg, int t)
-{
- if (reg)
- gen_op_movl_reg_TN[t][reg] ();
- else
- gen_movl_imm_TN(t, 0);
-}
-
-static inline void gen_movl_reg_T0(int reg)
-{
- gen_movl_reg_TN(reg, 0);
-}
-
-static inline void gen_movl_reg_T1(int reg)
-{
- gen_movl_reg_TN(reg, 1);
-}
-
-static inline void gen_movl_reg_T2(int reg)
-{
- gen_movl_reg_TN(reg, 2);
-}
-
-static inline void gen_movl_TN_reg(int reg, int t)
-{
- if (reg)
- gen_op_movl_TN_reg[t][reg] ();
-}
-
-static inline void gen_movl_T0_reg(int reg)
-{
- gen_movl_TN_reg(reg, 0);
-}
-
-static inline void gen_movl_T1_reg(int reg)
-{
- gen_movl_TN_reg(reg, 1);
-}
-
-static inline void gen_jmp_im(target_ulong pc)
-{
-#ifdef TARGET_SPARC64
- if (pc == (uint32_t)pc) {
- gen_op_jmp_im(pc);
- } else {
- gen_op_jmp_im64(pc >> 32, pc);
- }
-#else
- gen_op_jmp_im(pc);
-#endif
-}
-
-static inline void gen_movl_npc_im(target_ulong npc)
-{
-#ifdef TARGET_SPARC64
- if (npc == (uint32_t)npc) {
- gen_op_movl_npc_im(npc);
- } else {
- gen_op_movq_npc_im64(npc >> 32, npc);
- }
-#else
- gen_op_movl_npc_im(npc);
-#endif
-}
-
-static inline void gen_goto_tb(DisasContext *s, int tb_num,
- target_ulong pc, target_ulong npc)
-{
- TranslationBlock *tb;
-
- tb = s->tb;
- if ((pc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK) &&
- (npc & TARGET_PAGE_MASK) == (tb->pc & TARGET_PAGE_MASK)) {
- /* jump to same page: we can use a direct jump */
- if (tb_num == 0)
- gen_op_goto_tb0(TBPARAM(tb));
- else
- gen_op_goto_tb1(TBPARAM(tb));
- gen_jmp_im(pc);
- gen_movl_npc_im(npc);
- gen_op_movl_T0_im((long)tb + tb_num);
- gen_op_exit_tb();
- } else {
- /* jump to another page: currently not optimized */
- gen_jmp_im(pc);
- gen_movl_npc_im(npc);
- gen_op_movl_T0_0();
- gen_op_exit_tb();
- }
-}
-
-static inline void gen_branch2(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2)
-{
- int l1;
-
- l1 = gen_new_label();
-
- gen_op_jz_T2_label(l1);
-
- gen_goto_tb(dc, 0, pc1, pc1 + 4);
-
- gen_set_label(l1);
- gen_goto_tb(dc, 1, pc2, pc2 + 4);
-}
-
-static inline void gen_branch_a(DisasContext *dc, long tb, target_ulong pc1, target_ulong pc2)
-{
- int l1;
-
- l1 = gen_new_label();
-
- gen_op_jz_T2_label(l1);
-
- gen_goto_tb(dc, 0, pc2, pc1);
-
- gen_set_label(l1);
- gen_goto_tb(dc, 1, pc2 + 4, pc2 + 8);
-}
-
-static inline void gen_branch(DisasContext *dc, long tb, target_ulong pc, target_ulong npc)
-{
- gen_goto_tb(dc, 0, pc, npc);
-}
-
-static inline void gen_generic_branch(DisasContext *dc, target_ulong npc1, target_ulong npc2)
-{
- int l1, l2;
-
- l1 = gen_new_label();
- l2 = gen_new_label();
- gen_op_jz_T2_label(l1);
-
- gen_movl_npc_im(npc1);
- gen_op_jmp_label(l2);
-
- gen_set_label(l1);
- gen_movl_npc_im(npc2);
- gen_set_label(l2);
-}
-
-/* call this function before using T2 as it may have been set for a jump */
-static inline void flush_T2(DisasContext * dc)
-{
- if (dc->npc == JUMP_PC) {
- gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
- dc->npc = DYNAMIC_PC;
- }
-}
-
-static inline void save_npc(DisasContext * dc)
-{
- if (dc->npc == JUMP_PC) {
- gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
- dc->npc = DYNAMIC_PC;
- } else if (dc->npc != DYNAMIC_PC) {
- gen_movl_npc_im(dc->npc);
- }
-}
-
-static inline void save_state(DisasContext * dc)
-{
- gen_jmp_im(dc->pc);
- save_npc(dc);
-}
-
-static inline void gen_mov_pc_npc(DisasContext * dc)
-{
- if (dc->npc == JUMP_PC) {
- gen_generic_branch(dc, dc->jump_pc[0], dc->jump_pc[1]);
- gen_op_mov_pc_npc();
- dc->pc = DYNAMIC_PC;
- } else if (dc->npc == DYNAMIC_PC) {
- gen_op_mov_pc_npc();
- dc->pc = DYNAMIC_PC;
- } else {
- dc->pc = dc->npc;
- }
-}
-
-static GenOpFunc * const gen_cond[2][16] = {
- {
- gen_op_eval_ba,
- gen_op_eval_be,
- gen_op_eval_ble,
- gen_op_eval_bl,
- gen_op_eval_bleu,
- gen_op_eval_bcs,
- gen_op_eval_bneg,
- gen_op_eval_bvs,
- gen_op_eval_bn,
- gen_op_eval_bne,
- gen_op_eval_bg,
- gen_op_eval_bge,
- gen_op_eval_bgu,
- gen_op_eval_bcc,
- gen_op_eval_bpos,
- gen_op_eval_bvc,
- },
- {
-#ifdef TARGET_SPARC64
- gen_op_eval_ba,
- gen_op_eval_xbe,
- gen_op_eval_xble,
- gen_op_eval_xbl,
- gen_op_eval_xbleu,
- gen_op_eval_xbcs,
- gen_op_eval_xbneg,
- gen_op_eval_xbvs,
- gen_op_eval_bn,
- gen_op_eval_xbne,
- gen_op_eval_xbg,
- gen_op_eval_xbge,
- gen_op_eval_xbgu,
- gen_op_eval_xbcc,
- gen_op_eval_xbpos,
- gen_op_eval_xbvc,
-#endif
- },
-};
-
-static GenOpFunc * const gen_fcond[4][16] = {
- {
- gen_op_eval_ba,
- gen_op_eval_fbne,
- gen_op_eval_fblg,
- gen_op_eval_fbul,
- gen_op_eval_fbl,
- gen_op_eval_fbug,
- gen_op_eval_fbg,
- gen_op_eval_fbu,
- gen_op_eval_bn,
- gen_op_eval_fbe,
- gen_op_eval_fbue,
- gen_op_eval_fbge,
- gen_op_eval_fbuge,
- gen_op_eval_fble,
- gen_op_eval_fbule,
- gen_op_eval_fbo,
- },
-#ifdef TARGET_SPARC64
- {
- gen_op_eval_ba,
- gen_op_eval_fbne_fcc1,
- gen_op_eval_fblg_fcc1,
- gen_op_eval_fbul_fcc1,
- gen_op_eval_fbl_fcc1,
- gen_op_eval_fbug_fcc1,
- gen_op_eval_fbg_fcc1,
- gen_op_eval_fbu_fcc1,
- gen_op_eval_bn,
- gen_op_eval_fbe_fcc1,
- gen_op_eval_fbue_fcc1,
- gen_op_eval_fbge_fcc1,
- gen_op_eval_fbuge_fcc1,
- gen_op_eval_fble_fcc1,
- gen_op_eval_fbule_fcc1,
- gen_op_eval_fbo_fcc1,
- },
- {
- gen_op_eval_ba,
- gen_op_eval_fbne_fcc2,
- gen_op_eval_fblg_fcc2,
- gen_op_eval_fbul_fcc2,
- gen_op_eval_fbl_fcc2,
- gen_op_eval_fbug_fcc2,
- gen_op_eval_fbg_fcc2,
- gen_op_eval_fbu_fcc2,
- gen_op_eval_bn,
- gen_op_eval_fbe_fcc2,
- gen_op_eval_fbue_fcc2,
- gen_op_eval_fbge_fcc2,
- gen_op_eval_fbuge_fcc2,
- gen_op_eval_fble_fcc2,
- gen_op_eval_fbule_fcc2,
- gen_op_eval_fbo_fcc2,
- },
- {
- gen_op_eval_ba,
- gen_op_eval_fbne_fcc3,
- gen_op_eval_fblg_fcc3,
- gen_op_eval_fbul_fcc3,
- gen_op_eval_fbl_fcc3,
- gen_op_eval_fbug_fcc3,
- gen_op_eval_fbg_fcc3,
- gen_op_eval_fbu_fcc3,
- gen_op_eval_bn,
- gen_op_eval_fbe_fcc3,
- gen_op_eval_fbue_fcc3,
- gen_op_eval_fbge_fcc3,
- gen_op_eval_fbuge_fcc3,
- gen_op_eval_fble_fcc3,
- gen_op_eval_fbule_fcc3,
- gen_op_eval_fbo_fcc3,
- },
-#else
- {}, {}, {},
-#endif
-};
-
-#ifdef TARGET_SPARC64
-static void gen_cond_reg(int cond)
-{
- switch (cond) {
- case 0x1:
- gen_op_eval_brz();
- break;
- case 0x2:
- gen_op_eval_brlez();
- break;
- case 0x3:
- gen_op_eval_brlz();
- break;
- case 0x5:
- gen_op_eval_brnz();
- break;
- case 0x6:
- gen_op_eval_brgz();
- break;
- default:
- case 0x7:
- gen_op_eval_brgez();
- break;
- }
-}
-#endif
-
-/* XXX: potentially incorrect if dynamic npc */
-static void do_branch(DisasContext * dc, int32_t offset, uint32_t insn, int cc)
-{
- unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29));
- target_ulong target = dc->pc + offset;
-
- if (cond == 0x0) {
- /* unconditional not taken */
- if (a) {
- dc->pc = dc->npc + 4;
- dc->npc = dc->pc + 4;
- } else {
- dc->pc = dc->npc;
- dc->npc = dc->pc + 4;
- }
- } else if (cond == 0x8) {
- /* unconditional taken */
- if (a) {
- dc->pc = target;
- dc->npc = dc->pc + 4;
- } else {
- dc->pc = dc->npc;
- dc->npc = target;
- }
- } else {
- flush_T2(dc);
- gen_cond[cc][cond]();
- if (a) {
- gen_branch_a(dc, (long)dc->tb, target, dc->npc);
- dc->is_br = 1;
- } else {
- dc->pc = dc->npc;
- dc->jump_pc[0] = target;
- dc->jump_pc[1] = dc->npc + 4;
- dc->npc = JUMP_PC;
- }
- }
-}
-
-/* XXX: potentially incorrect if dynamic npc */
-static void do_fbranch(DisasContext * dc, int32_t offset, uint32_t insn, int cc)
-{
- unsigned int cond = GET_FIELD(insn, 3, 6), a = (insn & (1 << 29));
- target_ulong target = dc->pc + offset;
-
- if (cond == 0x0) {
- /* unconditional not taken */
- if (a) {
- dc->pc = dc->npc + 4;
- dc->npc = dc->pc + 4;
- } else {
- dc->pc = dc->npc;
- dc->npc = dc->pc + 4;
- }
- } else if (cond == 0x8) {
- /* unconditional taken */
- if (a) {
- dc->pc = target;
- dc->npc = dc->pc + 4;
- } else {
- dc->pc = dc->npc;
- dc->npc = target;
- }
- } else {
- flush_T2(dc);
- gen_fcond[cc][cond]();
- if (a) {
- gen_branch_a(dc, (long)dc->tb, target, dc->npc);
- dc->is_br = 1;
- } else {
- dc->pc = dc->npc;
- dc->jump_pc[0] = target;
- dc->jump_pc[1] = dc->npc + 4;
- dc->npc = JUMP_PC;
- }
- }
-}
-
-#ifdef TARGET_SPARC64
-/* XXX: potentially incorrect if dynamic npc */
-static void do_branch_reg(DisasContext * dc, int32_t offset, uint32_t insn)
-{
- unsigned int cond = GET_FIELD_SP(insn, 25, 27), a = (insn & (1 << 29));
- target_ulong target = dc->pc + offset;
-
- flush_T2(dc);
- gen_cond_reg(cond);
- if (a) {
- gen_branch_a(dc, (long)dc->tb, target, dc->npc);
- dc->is_br = 1;
- } else {
- dc->pc = dc->npc;
- dc->jump_pc[0] = target;
- dc->jump_pc[1] = dc->npc + 4;
- dc->npc = JUMP_PC;
- }
-}
-
-static GenOpFunc * const gen_fcmps[4] = {
- gen_op_fcmps,
- gen_op_fcmps_fcc1,
- gen_op_fcmps_fcc2,
- gen_op_fcmps_fcc3,
-};
-
-static GenOpFunc * const gen_fcmpd[4] = {
- gen_op_fcmpd,
- gen_op_fcmpd_fcc1,
- gen_op_fcmpd_fcc2,
- gen_op_fcmpd_fcc3,
-};
-#endif
-
-static int gen_trap_ifnofpu(DisasContext * dc)
-{
-#if !defined(CONFIG_USER_ONLY)
- if (!dc->fpu_enabled) {
- save_state(dc);
- gen_op_exception(TT_NFPU_INSN);
- dc->is_br = 1;
- return 1;
- }
-#endif
- return 0;
-}
-
-/* before an instruction, dc->pc must be static */
-static void disas_sparc_insn(DisasContext * dc)
-{
- unsigned int insn, opc, rs1, rs2, rd;
-
- insn = ldl_code(dc->pc);
- opc = GET_FIELD(insn, 0, 1);
-
- rd = GET_FIELD(insn, 2, 6);
- switch (opc) {
- case 0: /* branches/sethi */
- {
- unsigned int xop = GET_FIELD(insn, 7, 9);
- int32_t target;
- switch (xop) {
-#ifdef TARGET_SPARC64
- case 0x1: /* V9 BPcc */
- {
- int cc;
-
- target = GET_FIELD_SP(insn, 0, 18);
- target = sign_extend(target, 18);
- target <<= 2;
- cc = GET_FIELD_SP(insn, 20, 21);
- if (cc == 0)
- do_branch(dc, target, insn, 0);
- else if (cc == 2)
- do_branch(dc, target, insn, 1);
- else
- goto illegal_insn;
- goto jmp_insn;
- }
- case 0x3: /* V9 BPr */
- {
- target = GET_FIELD_SP(insn, 0, 13) |
- (GET_FIELD_SP(insn, 20, 21) << 14);
- target = sign_extend(target, 16);
- target <<= 2;
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- do_branch_reg(dc, target, insn);
- goto jmp_insn;
- }
- case 0x5: /* V9 FBPcc */
- {
- int cc = GET_FIELD_SP(insn, 20, 21);
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- target = GET_FIELD_SP(insn, 0, 18);
- target = sign_extend(target, 19);
- target <<= 2;
- do_fbranch(dc, target, insn, cc);
- goto jmp_insn;
- }
-#endif
- case 0x2: /* BN+x */
- {
- target = GET_FIELD(insn, 10, 31);
- target = sign_extend(target, 22);
- target <<= 2;
- do_branch(dc, target, insn, 0);
- goto jmp_insn;
- }
- case 0x6: /* FBN+x */
- {
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- target = GET_FIELD(insn, 10, 31);
- target = sign_extend(target, 22);
- target <<= 2;
- do_fbranch(dc, target, insn, 0);
- goto jmp_insn;
- }
- case 0x4: /* SETHI */
-#define OPTIM
-#if defined(OPTIM)
- if (rd) { // nop
-#endif
- uint32_t value = GET_FIELD(insn, 10, 31);
- gen_movl_imm_T0(value << 10);
- gen_movl_T0_reg(rd);
-#if defined(OPTIM)
- }
-#endif
- break;
- case 0x0: /* UNIMPL */
- default:
- goto illegal_insn;
- }
- break;
- }
- break;
- case 1:
- /*CALL*/ {
- target_long target = GET_FIELDs(insn, 2, 31) << 2;
-
-#ifdef TARGET_SPARC64
- if (dc->pc == (uint32_t)dc->pc) {
- gen_op_movl_T0_im(dc->pc);
- } else {
- gen_op_movq_T0_im64(dc->pc >> 32, dc->pc);
- }
-#else
- gen_op_movl_T0_im(dc->pc);
-#endif
- gen_movl_T0_reg(15);
- target += dc->pc;
- gen_mov_pc_npc(dc);
- dc->npc = target;
- }
- goto jmp_insn;
- case 2: /* FPU & Logical Operations */
- {
- unsigned int xop = GET_FIELD(insn, 7, 12);
- if (xop == 0x3a) { /* generate trap */
- int cond;
-
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- if (IS_IMM) {
- rs2 = GET_FIELD(insn, 25, 31);
-#if defined(OPTIM)
- if (rs2 != 0) {
-#endif
- gen_movl_simm_T1(rs2);
- gen_op_add_T1_T0();
-#if defined(OPTIM)
- }
-#endif
- } else {
- rs2 = GET_FIELD(insn, 27, 31);
-#if defined(OPTIM)
- if (rs2 != 0) {
-#endif
- gen_movl_reg_T1(rs2);
- gen_op_add_T1_T0();
-#if defined(OPTIM)
- }
-#endif
- }
- cond = GET_FIELD(insn, 3, 6);
- if (cond == 0x8) {
- save_state(dc);
- gen_op_trap_T0();
- } else if (cond != 0) {
-#ifdef TARGET_SPARC64
- /* V9 icc/xcc */
- int cc = GET_FIELD_SP(insn, 11, 12);
- flush_T2(dc);
- save_state(dc);
- if (cc == 0)
- gen_cond[0][cond]();
- else if (cc == 2)
- gen_cond[1][cond]();
- else
- goto illegal_insn;
-#else
- flush_T2(dc);
- save_state(dc);
- gen_cond[0][cond]();
-#endif
- gen_op_trapcc_T0();
- }
- gen_op_next_insn();
- gen_op_movl_T0_0();
- gen_op_exit_tb();
- dc->is_br = 1;
- goto jmp_insn;
- } else if (xop == 0x28) {
- rs1 = GET_FIELD(insn, 13, 17);
- switch(rs1) {
- case 0: /* rdy */
- 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();
- gen_movl_T0_reg(rd);
- break;
- case 0x3: /* V9 rdasi */
- gen_op_movl_T0_env(offsetof(CPUSPARCState, asi));
- gen_movl_T0_reg(rd);
- break;
- case 0x4: /* V9 rdtick */
- gen_op_rdtick();
- gen_movl_T0_reg(rd);
- break;
- case 0x5: /* V9 rdpc */
- if (dc->pc == (uint32_t)dc->pc) {
- gen_op_movl_T0_im(dc->pc);
- } else {
- gen_op_movq_T0_im64(dc->pc >> 32, dc->pc);
- }
- gen_movl_T0_reg(rd);
- break;
- case 0x6: /* V9 rdfprs */
- gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs));
- gen_movl_T0_reg(rd);
- break;
- case 0x13: /* Graphics Status */
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- gen_op_movtl_T0_env(offsetof(CPUSPARCState, gsr));
- gen_movl_T0_reg(rd);
- break;
- case 0x17: /* Tick compare */
- gen_op_movtl_T0_env(offsetof(CPUSPARCState, tick_cmpr));
- gen_movl_T0_reg(rd);
- break;
- case 0x18: /* System tick */
- gen_op_rdtick(); // XXX
- gen_movl_T0_reg(rd);
- break;
- case 0x19: /* System tick compare */
- gen_op_movtl_T0_env(offsetof(CPUSPARCState, stick_cmpr));
- gen_movl_T0_reg(rd);
- break;
- case 0x10: /* Performance Control */
- case 0x11: /* Performance Instrumentation Counter */
- case 0x12: /* Dispatch Control */
- case 0x14: /* Softint set, WO */
- case 0x15: /* Softint clear, WO */
- case 0x16: /* Softint write */
-#endif
- default:
- goto illegal_insn;
- }
-#if !defined(CONFIG_USER_ONLY)
-#ifndef TARGET_SPARC64
- } else if (xop == 0x29) { /* rdpsr / V9 unimp */
- if (!supervisor(dc))
- goto priv_insn;
- gen_op_rdpsr();
- gen_movl_T0_reg(rd);
- break;
-#endif
- } else if (xop == 0x2a) { /* rdwim / V9 rdpr */
- if (!supervisor(dc))
- goto priv_insn;
-#ifdef TARGET_SPARC64
- rs1 = GET_FIELD(insn, 13, 17);
- switch (rs1) {
- case 0: // tpc
- gen_op_rdtpc();
- break;
- case 1: // tnpc
- gen_op_rdtnpc();
- break;
- case 2: // tstate
- gen_op_rdtstate();
- break;
- case 3: // tt
- gen_op_rdtt();
- break;
- case 4: // tick
- gen_op_rdtick();
- break;
- case 5: // tba
- gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr));
- break;
- case 6: // pstate
- gen_op_rdpstate();
- break;
- case 7: // tl
- gen_op_movl_T0_env(offsetof(CPUSPARCState, tl));
- break;
- case 8: // pil
- gen_op_movl_T0_env(offsetof(CPUSPARCState, psrpil));
- break;
- case 9: // cwp
- gen_op_rdcwp();
- break;
- case 10: // cansave
- gen_op_movl_T0_env(offsetof(CPUSPARCState, cansave));
- break;
- case 11: // canrestore
- gen_op_movl_T0_env(offsetof(CPUSPARCState, canrestore));
- break;
- case 12: // cleanwin
- gen_op_movl_T0_env(offsetof(CPUSPARCState, cleanwin));
- break;
- case 13: // otherwin
- gen_op_movl_T0_env(offsetof(CPUSPARCState, otherwin));
- break;
- case 14: // wstate
- gen_op_movl_T0_env(offsetof(CPUSPARCState, wstate));
- break;
- case 31: // ver
- gen_op_movtl_T0_env(offsetof(CPUSPARCState, version));
- break;
- case 15: // fq
- default:
- goto illegal_insn;
- }
-#else
- gen_op_movl_T0_env(offsetof(CPUSPARCState, wim));
-#endif
- gen_movl_T0_reg(rd);
- break;
- } else if (xop == 0x2b) { /* rdtbr / V9 flushw */
-#ifdef TARGET_SPARC64
- gen_op_flushw();
-#else
- if (!supervisor(dc))
- goto priv_insn;
- gen_op_movtl_T0_env(offsetof(CPUSPARCState, tbr));
- gen_movl_T0_reg(rd);
-#endif
- break;
-#endif
- } else if (xop == 0x34) { /* FPU Operations */
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- rs1 = GET_FIELD(insn, 13, 17);
- rs2 = GET_FIELD(insn, 27, 31);
- xop = GET_FIELD(insn, 18, 26);
- switch (xop) {
- case 0x1: /* fmovs */
- gen_op_load_fpr_FT0(rs2);
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x5: /* fnegs */
- gen_op_load_fpr_FT1(rs2);
- gen_op_fnegs();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x9: /* fabss */
- gen_op_load_fpr_FT1(rs2);
- gen_op_fabss();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x29: /* fsqrts */
- gen_op_load_fpr_FT1(rs2);
- gen_op_fsqrts();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x2a: /* fsqrtd */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_fsqrtd();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x2b: /* fsqrtq */
- goto nfpu_insn;
- case 0x41:
- gen_op_load_fpr_FT0(rs1);
- gen_op_load_fpr_FT1(rs2);
- gen_op_fadds();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x42:
- gen_op_load_fpr_DT0(DFPREG(rs1));
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_faddd();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x43: /* faddq */
- goto nfpu_insn;
- case 0x45:
- gen_op_load_fpr_FT0(rs1);
- gen_op_load_fpr_FT1(rs2);
- gen_op_fsubs();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x46:
- gen_op_load_fpr_DT0(DFPREG(rs1));
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_fsubd();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x47: /* fsubq */
- goto nfpu_insn;
- case 0x49:
- gen_op_load_fpr_FT0(rs1);
- gen_op_load_fpr_FT1(rs2);
- gen_op_fmuls();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x4a:
- gen_op_load_fpr_DT0(DFPREG(rs1));
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_fmuld();
- gen_op_store_DT0_fpr(rd);
- break;
- case 0x4b: /* fmulq */
- goto nfpu_insn;
- case 0x4d:
- gen_op_load_fpr_FT0(rs1);
- gen_op_load_fpr_FT1(rs2);
- gen_op_fdivs();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x4e:
- gen_op_load_fpr_DT0(DFPREG(rs1));
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_fdivd();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x4f: /* fdivq */
- goto nfpu_insn;
- case 0x69:
- gen_op_load_fpr_FT0(rs1);
- gen_op_load_fpr_FT1(rs2);
- gen_op_fsmuld();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x6e: /* fdmulq */
- goto nfpu_insn;
- case 0xc4:
- gen_op_load_fpr_FT1(rs2);
- gen_op_fitos();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0xc6:
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_fdtos();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0xc7: /* fqtos */
- goto nfpu_insn;
- case 0xc8:
- gen_op_load_fpr_FT1(rs2);
- gen_op_fitod();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0xc9:
- gen_op_load_fpr_FT1(rs2);
- gen_op_fstod();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0xcb: /* fqtod */
- goto nfpu_insn;
- case 0xcc: /* fitoq */
- goto nfpu_insn;
- case 0xcd: /* fstoq */
- goto nfpu_insn;
- case 0xce: /* fdtoq */
- goto nfpu_insn;
- case 0xd1:
- gen_op_load_fpr_FT1(rs2);
- gen_op_fstoi();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0xd2:
- gen_op_load_fpr_DT1(rs2);
- gen_op_fdtoi();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0xd3: /* fqtoi */
- goto nfpu_insn;
-#ifdef TARGET_SPARC64
- case 0x2: /* V9 fmovd */
- gen_op_load_fpr_DT0(DFPREG(rs2));
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x6: /* V9 fnegd */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_fnegd();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0xa: /* V9 fabsd */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_fabsd();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x81: /* V9 fstox */
- gen_op_load_fpr_FT1(rs2);
- gen_op_fstox();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x82: /* V9 fdtox */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_fdtox();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x84: /* V9 fxtos */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_fxtos();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x88: /* V9 fxtod */
- gen_op_load_fpr_DT1(DFPREG(rs2));
- gen_op_fxtod();
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- case 0x3: /* V9 fmovq */
- case 0x7: /* V9 fnegq */
- case 0xb: /* V9 fabsq */
- case 0x83: /* V9 fqtox */
- case 0x8c: /* V9 fxtoq */
- goto nfpu_insn;
-#endif
- default:
- goto illegal_insn;
- }
- } else if (xop == 0x35) { /* FPU Operations */
-#ifdef TARGET_SPARC64
- int cond;
-#endif
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- rs1 = GET_FIELD(insn, 13, 17);
- rs2 = GET_FIELD(insn, 27, 31);
- xop = GET_FIELD(insn, 18, 26);
-#ifdef TARGET_SPARC64
- if ((xop & 0x11f) == 0x005) { // V9 fmovsr
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_FT0(rd);
- gen_op_load_fpr_FT1(rs2);
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- flush_T2(dc);
- gen_cond_reg(cond);
- gen_op_fmovs_cc();
- gen_op_store_FT0_fpr(rd);
- break;
- } else if ((xop & 0x11f) == 0x006) { // V9 fmovdr
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_DT0(rd);
- gen_op_load_fpr_DT1(rs2);
- flush_T2(dc);
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- gen_cond_reg(cond);
- gen_op_fmovs_cc();
- gen_op_store_DT0_fpr(rd);
- break;
- } else if ((xop & 0x11f) == 0x007) { // V9 fmovqr
- goto nfpu_insn;
- }
-#endif
- switch (xop) {
-#ifdef TARGET_SPARC64
- case 0x001: /* V9 fmovscc %fcc0 */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_FT0(rd);
- gen_op_load_fpr_FT1(rs2);
- flush_T2(dc);
- gen_fcond[0][cond]();
- gen_op_fmovs_cc();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x002: /* V9 fmovdcc %fcc0 */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_DT0(rd);
- gen_op_load_fpr_DT1(rs2);
- flush_T2(dc);
- gen_fcond[0][cond]();
- gen_op_fmovd_cc();
- gen_op_store_DT0_fpr(rd);
- break;
- case 0x003: /* V9 fmovqcc %fcc0 */
- goto nfpu_insn;
- case 0x041: /* V9 fmovscc %fcc1 */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_FT0(rd);
- gen_op_load_fpr_FT1(rs2);
- flush_T2(dc);
- gen_fcond[1][cond]();
- gen_op_fmovs_cc();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x042: /* V9 fmovdcc %fcc1 */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_DT0(rd);
- gen_op_load_fpr_DT1(rs2);
- flush_T2(dc);
- gen_fcond[1][cond]();
- gen_op_fmovd_cc();
- gen_op_store_DT0_fpr(rd);
- break;
- case 0x043: /* V9 fmovqcc %fcc1 */
- goto nfpu_insn;
- case 0x081: /* V9 fmovscc %fcc2 */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_FT0(rd);
- gen_op_load_fpr_FT1(rs2);
- flush_T2(dc);
- gen_fcond[2][cond]();
- gen_op_fmovs_cc();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x082: /* V9 fmovdcc %fcc2 */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_DT0(rd);
- gen_op_load_fpr_DT1(rs2);
- flush_T2(dc);
- gen_fcond[2][cond]();
- gen_op_fmovd_cc();
- gen_op_store_DT0_fpr(rd);
- break;
- case 0x083: /* V9 fmovqcc %fcc2 */
- goto nfpu_insn;
- case 0x0c1: /* V9 fmovscc %fcc3 */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_FT0(rd);
- gen_op_load_fpr_FT1(rs2);
- flush_T2(dc);
- gen_fcond[3][cond]();
- gen_op_fmovs_cc();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x0c2: /* V9 fmovdcc %fcc3 */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_DT0(rd);
- gen_op_load_fpr_DT1(rs2);
- flush_T2(dc);
- gen_fcond[3][cond]();
- gen_op_fmovd_cc();
- gen_op_store_DT0_fpr(rd);
- break;
- case 0x0c3: /* V9 fmovqcc %fcc3 */
- goto nfpu_insn;
- case 0x101: /* V9 fmovscc %icc */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_FT0(rd);
- gen_op_load_fpr_FT1(rs2);
- flush_T2(dc);
- gen_cond[0][cond]();
- gen_op_fmovs_cc();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x102: /* V9 fmovdcc %icc */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_DT0(rd);
- gen_op_load_fpr_DT1(rs2);
- flush_T2(dc);
- gen_cond[0][cond]();
- gen_op_fmovd_cc();
- gen_op_store_DT0_fpr(rd);
- break;
- case 0x103: /* V9 fmovqcc %icc */
- goto nfpu_insn;
- case 0x181: /* V9 fmovscc %xcc */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_FT0(rd);
- gen_op_load_fpr_FT1(rs2);
- flush_T2(dc);
- gen_cond[1][cond]();
- gen_op_fmovs_cc();
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x182: /* V9 fmovdcc %xcc */
- cond = GET_FIELD_SP(insn, 14, 17);
- gen_op_load_fpr_DT0(rd);
- gen_op_load_fpr_DT1(rs2);
- flush_T2(dc);
- gen_cond[1][cond]();
- gen_op_fmovd_cc();
- gen_op_store_DT0_fpr(rd);
- break;
- case 0x183: /* V9 fmovqcc %xcc */
- goto nfpu_insn;
-#endif
- case 0x51: /* V9 %fcc */
- gen_op_load_fpr_FT0(rs1);
- gen_op_load_fpr_FT1(rs2);
-#ifdef TARGET_SPARC64
- gen_fcmps[rd & 3]();
-#else
- gen_op_fcmps();
-#endif
- break;
- case 0x52: /* V9 %fcc */
- gen_op_load_fpr_DT0(DFPREG(rs1));
- gen_op_load_fpr_DT1(DFPREG(rs2));
-#ifdef TARGET_SPARC64
- gen_fcmpd[rd & 3]();
-#else
- gen_op_fcmpd();
-#endif
- break;
- case 0x53: /* fcmpq */
- goto nfpu_insn;
- case 0x55: /* fcmpes, V9 %fcc */
- gen_op_load_fpr_FT0(rs1);
- gen_op_load_fpr_FT1(rs2);
-#ifdef TARGET_SPARC64
- gen_fcmps[rd & 3]();
-#else
- gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */
-#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]();
-#else
- gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */
-#endif
- break;
- case 0x57: /* fcmpeq */
- goto nfpu_insn;
- default:
- goto illegal_insn;
- }
-#if defined(OPTIM)
- } else if (xop == 0x2) {
- // clr/mov shortcut
-
- rs1 = GET_FIELD(insn, 13, 17);
- if (rs1 == 0) {
- // or %g0, x, y -> mov T1, x; mov y, T1
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 19, 31);
- gen_movl_simm_T1(rs2);
- } else { /* register */
- rs2 = GET_FIELD(insn, 27, 31);
- gen_movl_reg_T1(rs2);
- }
- gen_movl_T1_reg(rd);
- } else {
- gen_movl_reg_T0(rs1);
- if (IS_IMM) { /* immediate */
- // or x, #0, y -> mov T1, x; mov y, T1
- rs2 = GET_FIELDs(insn, 19, 31);
- if (rs2 != 0) {
- gen_movl_simm_T1(rs2);
- gen_op_or_T1_T0();
- }
- } else { /* register */
- // or x, %g0, y -> mov T1, x; mov y, T1
- rs2 = GET_FIELD(insn, 27, 31);
- if (rs2 != 0) {
- gen_movl_reg_T1(rs2);
- gen_op_or_T1_T0();
- }
- }
- gen_movl_T0_reg(rd);
- }
-#endif
-#ifdef TARGET_SPARC64
- } else if (xop == 0x25) { /* sll, V9 sllx ( == sll) */
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 20, 31);
- gen_movl_simm_T1(rs2);
- } else { /* register */
- rs2 = GET_FIELD(insn, 27, 31);
- gen_movl_reg_T1(rs2);
- }
- gen_op_sll();
- gen_movl_T0_reg(rd);
- } else if (xop == 0x26) { /* srl, V9 srlx */
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 20, 31);
- gen_movl_simm_T1(rs2);
- } else { /* register */
- rs2 = GET_FIELD(insn, 27, 31);
- gen_movl_reg_T1(rs2);
- }
- if (insn & (1 << 12))
- gen_op_srlx();
- else
- gen_op_srl();
- gen_movl_T0_reg(rd);
- } else if (xop == 0x27) { /* sra, V9 srax */
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 20, 31);
- gen_movl_simm_T1(rs2);
- } else { /* register */
- rs2 = GET_FIELD(insn, 27, 31);
- gen_movl_reg_T1(rs2);
- }
- if (insn & (1 << 12))
- gen_op_srax();
- else
- gen_op_sra();
- gen_movl_T0_reg(rd);
-#endif
- } else if (xop < 0x38) {
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 19, 31);
- gen_movl_simm_T1(rs2);
- } else { /* register */
- rs2 = GET_FIELD(insn, 27, 31);
- gen_movl_reg_T1(rs2);
- }
- if (xop < 0x20) {
- switch (xop & ~0x10) {
- case 0x0:
- if (xop & 0x10)
- gen_op_add_T1_T0_cc();
- else
- gen_op_add_T1_T0();
- break;
- case 0x1:
- gen_op_and_T1_T0();
- if (xop & 0x10)
- gen_op_logic_T0_cc();
- break;
- case 0x2:
- gen_op_or_T1_T0();
- if (xop & 0x10)
- gen_op_logic_T0_cc();
- break;
- case 0x3:
- gen_op_xor_T1_T0();
- if (xop & 0x10)
- gen_op_logic_T0_cc();
- break;
- case 0x4:
- if (xop & 0x10)
- gen_op_sub_T1_T0_cc();
- else
- gen_op_sub_T1_T0();
- break;
- case 0x5:
- gen_op_andn_T1_T0();
- if (xop & 0x10)
- gen_op_logic_T0_cc();
- break;
- case 0x6:
- gen_op_orn_T1_T0();
- if (xop & 0x10)
- gen_op_logic_T0_cc();
- break;
- case 0x7:
- gen_op_xnor_T1_T0();
- if (xop & 0x10)
- gen_op_logic_T0_cc();
- break;
- case 0x8:
- if (xop & 0x10)
- gen_op_addx_T1_T0_cc();
- else
- gen_op_addx_T1_T0();
- break;
-#ifdef TARGET_SPARC64
- case 0x9: /* V9 mulx */
- gen_op_mulx_T1_T0();
- break;
-#endif
- case 0xa:
- gen_op_umul_T1_T0();
- if (xop & 0x10)
- gen_op_logic_T0_cc();
- break;
- case 0xb:
- gen_op_smul_T1_T0();
- if (xop & 0x10)
- gen_op_logic_T0_cc();
- break;
- case 0xc:
- if (xop & 0x10)
- gen_op_subx_T1_T0_cc();
- else
- gen_op_subx_T1_T0();
- break;
-#ifdef TARGET_SPARC64
- case 0xd: /* V9 udivx */
- gen_op_udivx_T1_T0();
- break;
-#endif
- case 0xe:
- gen_op_udiv_T1_T0();
- if (xop & 0x10)
- gen_op_div_cc();
- break;
- case 0xf:
- gen_op_sdiv_T1_T0();
- if (xop & 0x10)
- gen_op_div_cc();
- break;
- default:
- goto illegal_insn;
- }
- gen_movl_T0_reg(rd);
- } else {
- switch (xop) {
- case 0x20: /* taddcc */
- case 0x21: /* tsubcc */
- case 0x22: /* taddcctv */
- case 0x23: /* tsubcctv */
- goto illegal_insn;
- case 0x24: /* mulscc */
- gen_op_mulscc_T1_T0();
- gen_movl_T0_reg(rd);
- break;
-#ifndef TARGET_SPARC64
- case 0x25: /* sll */
- gen_op_sll();
- gen_movl_T0_reg(rd);
- break;
- case 0x26: /* srl */
- gen_op_srl();
- gen_movl_T0_reg(rd);
- break;
- case 0x27: /* sra */
- gen_op_sra();
- gen_movl_T0_reg(rd);
- break;
-#endif
- case 0x30:
- {
- switch(rd) {
- case 0: /* wry */
- gen_op_xor_T1_T0();
- gen_op_movtl_env_T0(offsetof(CPUSPARCState, y));
- break;
-#ifdef TARGET_SPARC64
- case 0x2: /* V9 wrccr */
- gen_op_wrccr();
- break;
- case 0x3: /* V9 wrasi */
- gen_op_movl_env_T0(offsetof(CPUSPARCState, asi));
- break;
- case 0x6: /* V9 wrfprs */
- gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs));
- break;
- case 0xf: /* V9 sir, nop if user */
-#if !defined(CONFIG_USER_ONLY)
- if (supervisor(dc))
- gen_op_sir();
-#endif
- break;
- case 0x13: /* Graphics Status */
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- gen_op_movtl_env_T0(offsetof(CPUSPARCState, gsr));
- break;
- case 0x17: /* Tick compare */
-#if !defined(CONFIG_USER_ONLY)
- if (!supervisor(dc))
- goto illegal_insn;
-#endif
- gen_op_movtl_env_T0(offsetof(CPUSPARCState, tick_cmpr));
- break;
- case 0x18: /* System tick */
-#if !defined(CONFIG_USER_ONLY)
- if (!supervisor(dc))
- goto illegal_insn;
-#endif
- gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr));
- break;
- case 0x19: /* System tick compare */
-#if !defined(CONFIG_USER_ONLY)
- if (!supervisor(dc))
- goto illegal_insn;
-#endif
- gen_op_movtl_env_T0(offsetof(CPUSPARCState, stick_cmpr));
- break;
-
- case 0x10: /* Performance Control */
- case 0x11: /* Performance Instrumentation Counter */
- case 0x12: /* Dispatch Control */
- case 0x14: /* Softint set */
- case 0x15: /* Softint clear */
- case 0x16: /* Softint write */
-#endif
- default:
- goto illegal_insn;
- }
- }
- break;
-#if !defined(CONFIG_USER_ONLY)
- case 0x31: /* wrpsr, V9 saved, restored */
- {
- if (!supervisor(dc))
- goto priv_insn;
-#ifdef TARGET_SPARC64
- switch (rd) {
- case 0:
- gen_op_saved();
- break;
- case 1:
- gen_op_restored();
- break;
- default:
- goto illegal_insn;
- }
-#else
- gen_op_xor_T1_T0();
- gen_op_wrpsr();
- save_state(dc);
- gen_op_next_insn();
- gen_op_movl_T0_0();
- gen_op_exit_tb();
- dc->is_br = 1;
-#endif
- }
- break;
- case 0x32: /* wrwim, V9 wrpr */
- {
- if (!supervisor(dc))
- goto priv_insn;
- gen_op_xor_T1_T0();
-#ifdef TARGET_SPARC64
- switch (rd) {
- case 0: // tpc
- gen_op_wrtpc();
- break;
- case 1: // tnpc
- gen_op_wrtnpc();
- break;
- case 2: // tstate
- gen_op_wrtstate();
- break;
- case 3: // tt
- gen_op_wrtt();
- break;
- case 4: // tick
- gen_op_wrtick();
- break;
- case 5: // tba
- gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr));
- break;
- case 6: // pstate
- gen_op_wrpstate();
- save_state(dc);
- gen_op_next_insn();
- gen_op_movl_T0_0();
- gen_op_exit_tb();
- dc->is_br = 1;
- break;
- case 7: // tl
- gen_op_movl_env_T0(offsetof(CPUSPARCState, tl));
- break;
- case 8: // pil
- gen_op_movl_env_T0(offsetof(CPUSPARCState, psrpil));
- break;
- case 9: // cwp
- gen_op_wrcwp();
- break;
- case 10: // cansave
- gen_op_movl_env_T0(offsetof(CPUSPARCState, cansave));
- break;
- case 11: // canrestore
- gen_op_movl_env_T0(offsetof(CPUSPARCState, canrestore));
- break;
- case 12: // cleanwin
- gen_op_movl_env_T0(offsetof(CPUSPARCState, cleanwin));
- break;
- case 13: // otherwin
- gen_op_movl_env_T0(offsetof(CPUSPARCState, otherwin));
- break;
- case 14: // wstate
- gen_op_movl_env_T0(offsetof(CPUSPARCState, wstate));
- break;
- default:
- goto illegal_insn;
- }
-#else
- gen_op_movl_env_T0(offsetof(CPUSPARCState, wim));
-#endif
- }
- break;
-#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));
- }
- break;
-#endif
-#endif
-#ifdef TARGET_SPARC64
- case 0x2c: /* V9 movcc */
- {
- int cc = GET_FIELD_SP(insn, 11, 12);
- int cond = GET_FIELD_SP(insn, 14, 17);
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELD_SPs(insn, 0, 10);
- gen_movl_simm_T1(rs2);
- }
- else {
- rs2 = GET_FIELD_SP(insn, 0, 4);
- gen_movl_reg_T1(rs2);
- }
- gen_movl_reg_T0(rd);
- flush_T2(dc);
- if (insn & (1 << 18)) {
- if (cc == 0)
- gen_cond[0][cond]();
- else if (cc == 2)
- gen_cond[1][cond]();
- else
- goto illegal_insn;
- } else {
- gen_fcond[cc][cond]();
- }
- gen_op_mov_cc();
- gen_movl_T0_reg(rd);
- break;
- }
- case 0x2d: /* V9 sdivx */
- gen_op_sdivx_T1_T0();
- gen_movl_T0_reg(rd);
- break;
- case 0x2e: /* V9 popc */
- {
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELD_SPs(insn, 0, 12);
- gen_movl_simm_T1(rs2);
- // XXX optimize: popc(constant)
- }
- else {
- rs2 = GET_FIELD_SP(insn, 0, 4);
- gen_movl_reg_T1(rs2);
- }
- gen_op_popc();
- gen_movl_T0_reg(rd);
- }
- case 0x2f: /* V9 movr */
- {
- int cond = GET_FIELD_SP(insn, 10, 12);
- rs1 = GET_FIELD(insn, 13, 17);
- flush_T2(dc);
- gen_movl_reg_T0(rs1);
- gen_cond_reg(cond);
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELD_SPs(insn, 0, 10);
- gen_movl_simm_T1(rs2);
- }
- else {
- rs2 = GET_FIELD_SP(insn, 0, 4);
- gen_movl_reg_T1(rs2);
- }
- gen_movl_reg_T0(rd);
- gen_op_mov_cc();
- 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;
- }
- }
-#ifdef TARGET_SPARC64
- } else if (xop == 0x39) { /* V9 return */
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 19, 31);
-#if defined(OPTIM)
- if (rs2) {
-#endif
- gen_movl_simm_T1(rs2);
- gen_op_add_T1_T0();
-#if defined(OPTIM)
- }
-#endif
- } else { /* register */
- rs2 = GET_FIELD(insn, 27, 31);
-#if defined(OPTIM)
- if (rs2) {
-#endif
- gen_movl_reg_T1(rs2);
- gen_op_add_T1_T0();
-#if defined(OPTIM)
- }
-#endif
- }
- gen_op_restore();
- gen_mov_pc_npc(dc);
- gen_op_movl_npc_T0();
- dc->npc = DYNAMIC_PC;
- goto jmp_insn;
-#endif
- } else {
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 19, 31);
-#if defined(OPTIM)
- if (rs2) {
-#endif
- gen_movl_simm_T1(rs2);
- gen_op_add_T1_T0();
-#if defined(OPTIM)
- }
-#endif
- } else { /* register */
- rs2 = GET_FIELD(insn, 27, 31);
-#if defined(OPTIM)
- if (rs2) {
-#endif
- gen_movl_reg_T1(rs2);
- gen_op_add_T1_T0();
-#if defined(OPTIM)
- }
-#endif
- }
- switch (xop) {
- case 0x38: /* jmpl */
- {
- if (rd != 0) {
-#ifdef TARGET_SPARC64
- if (dc->pc == (uint32_t)dc->pc) {
- gen_op_movl_T1_im(dc->pc);
- } else {
- gen_op_movq_T1_im64(dc->pc >> 32, dc->pc);
- }
-#else
- gen_op_movl_T1_im(dc->pc);
-#endif
- gen_movl_T1_reg(rd);
- }
- gen_mov_pc_npc(dc);
- gen_op_movl_npc_T0();
- dc->npc = DYNAMIC_PC;
- }
- goto jmp_insn;
-#if !defined(CONFIG_USER_ONLY) && !defined(TARGET_SPARC64)
- case 0x39: /* rett, V9 return */
- {
- if (!supervisor(dc))
- goto priv_insn;
- gen_mov_pc_npc(dc);
- gen_op_movl_npc_T0();
- dc->npc = DYNAMIC_PC;
- gen_op_rett();
- }
- goto jmp_insn;
-#endif
- case 0x3b: /* flush */
- gen_op_flush_T0();
- break;
- case 0x3c: /* save */
- save_state(dc);
- gen_op_save();
- gen_movl_T0_reg(rd);
- break;
- case 0x3d: /* restore */
- save_state(dc);
- gen_op_restore();
- gen_movl_T0_reg(rd);
- break;
-#if !defined(CONFIG_USER_ONLY) && defined(TARGET_SPARC64)
- case 0x3e: /* V9 done/retry */
- {
- switch (rd) {
- case 0:
- if (!supervisor(dc))
- goto priv_insn;
- dc->npc = DYNAMIC_PC;
- dc->pc = DYNAMIC_PC;
- gen_op_done();
- goto jmp_insn;
- case 1:
- if (!supervisor(dc))
- goto priv_insn;
- dc->npc = DYNAMIC_PC;
- dc->pc = DYNAMIC_PC;
- gen_op_retry();
- goto jmp_insn;
- default:
- goto illegal_insn;
- }
- }
- break;
-#endif
- default:
- goto illegal_insn;
- }
- }
- break;
- }
- break;
- case 3: /* load/store instructions */
- {
- unsigned int xop = GET_FIELD(insn, 7, 12);
- rs1 = GET_FIELD(insn, 13, 17);
- gen_movl_reg_T0(rs1);
- if (IS_IMM) { /* immediate */
- rs2 = GET_FIELDs(insn, 19, 31);
-#if defined(OPTIM)
- if (rs2 != 0) {
-#endif
- gen_movl_simm_T1(rs2);
- gen_op_add_T1_T0();
-#if defined(OPTIM)
- }
-#endif
- } else { /* register */
- rs2 = GET_FIELD(insn, 27, 31);
-#if defined(OPTIM)
- if (rs2 != 0) {
-#endif
- gen_movl_reg_T1(rs2);
- gen_op_add_T1_T0();
-#if defined(OPTIM)
- }
-#endif
- }
- if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || \
- (xop > 0x17 && xop < 0x1d ) || \
- (xop > 0x2c && xop < 0x33) || xop == 0x1f) {
- switch (xop) {
- case 0x0: /* load word */
- gen_op_ldst(ld);
- break;
- case 0x1: /* load unsigned byte */
- gen_op_ldst(ldub);
- break;
- case 0x2: /* load unsigned halfword */
- gen_op_ldst(lduh);
- break;
- case 0x3: /* load double word */
- gen_op_ldst(ldd);
- gen_movl_T0_reg(rd + 1);
- break;
- case 0x9: /* load signed byte */
- gen_op_ldst(ldsb);
- break;
- case 0xa: /* load signed halfword */
- gen_op_ldst(ldsh);
- break;
- case 0xd: /* ldstub -- XXX: should be atomically */
- gen_op_ldst(ldstub);
- break;
- case 0x0f: /* swap register with memory. Also atomically */
- gen_movl_reg_T1(rd);
- gen_op_ldst(swap);
- break;
-#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
- case 0x10: /* load word alternate */
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_op_lda(insn, 1, 4, 0);
- break;
- case 0x11: /* load unsigned byte alternate */
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_op_lduba(insn, 1, 1, 0);
- break;
- case 0x12: /* load unsigned halfword alternate */
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_op_lduha(insn, 1, 2, 0);
- break;
- case 0x13: /* load double word alternate */
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_op_ldda(insn, 1, 8, 0);
- gen_movl_T0_reg(rd + 1);
- break;
- case 0x19: /* load signed byte alternate */
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_op_ldsba(insn, 1, 1, 1);
- break;
- case 0x1a: /* load signed halfword alternate */
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_op_ldsha(insn, 1, 2 ,1);
- break;
- case 0x1d: /* ldstuba -- XXX: should be atomically */
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_op_ldstuba(insn, 1, 1, 0);
- break;
- case 0x1f: /* swap reg with alt. memory. Also atomically */
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_movl_reg_T1(rd);
- gen_op_swapa(insn, 1, 4, 0);
- break;
-
-#ifndef TARGET_SPARC64
- /* avoid warnings */
- (void) &gen_op_stfa;
- (void) &gen_op_stdfa;
- (void) &gen_op_ldfa;
- (void) &gen_op_lddfa;
-#else
-#if !defined(CONFIG_USER_ONLY)
- (void) &gen_op_cas;
- (void) &gen_op_casx;
-#endif
-#endif
-#endif
-#ifdef TARGET_SPARC64
- case 0x08: /* V9 ldsw */
- gen_op_ldst(ldsw);
- break;
- case 0x0b: /* V9 ldx */
- gen_op_ldst(ldx);
- break;
- case 0x18: /* V9 ldswa */
- gen_op_ldswa(insn, 1, 4, 1);
- break;
- case 0x1b: /* V9 ldxa */
- gen_op_ldxa(insn, 1, 8, 0);
- break;
- case 0x2d: /* V9 prefetch, no effect */
- goto skip_move;
- case 0x30: /* V9 ldfa */
- gen_op_ldfa(insn, 1, 8, 0); // XXX
- break;
- case 0x33: /* V9 lddfa */
- gen_op_lddfa(insn, 1, 8, 0); // XXX
-
- break;
- case 0x3d: /* V9 prefetcha, no effect */
- goto skip_move;
- case 0x32: /* V9 ldqfa */
- goto nfpu_insn;
-#endif
- default:
- goto illegal_insn;
- }
- gen_movl_T1_reg(rd);
-#ifdef TARGET_SPARC64
- skip_move: ;
-#endif
- } else if (xop >= 0x20 && xop < 0x24) {
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- switch (xop) {
- case 0x20: /* load fpreg */
- gen_op_ldst(ldf);
- gen_op_store_FT0_fpr(rd);
- break;
- case 0x21: /* load fsr */
- gen_op_ldst(ldf);
- gen_op_ldfsr();
- break;
- case 0x22: /* load quad fpreg */
- goto nfpu_insn;
- case 0x23: /* load double fpreg */
- gen_op_ldst(lddf);
- gen_op_store_DT0_fpr(DFPREG(rd));
- break;
- default:
- goto illegal_insn;
- }
- } else if (xop < 8 || (xop >= 0x14 && xop < 0x18) || \
- xop == 0xe || xop == 0x1e) {
- gen_movl_reg_T1(rd);
- switch (xop) {
- case 0x4:
- gen_op_ldst(st);
- break;
- case 0x5:
- gen_op_ldst(stb);
- break;
- case 0x6:
- gen_op_ldst(sth);
- break;
- case 0x7:
- flush_T2(dc);
- gen_movl_reg_T2(rd + 1);
- gen_op_ldst(std);
- break;
-#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
- case 0x14:
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_op_sta(insn, 0, 4, 0);
- break;
- case 0x15:
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_op_stba(insn, 0, 1, 0);
- break;
- case 0x16:
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- gen_op_stha(insn, 0, 2, 0);
- break;
- case 0x17:
-#ifndef TARGET_SPARC64
- if (!supervisor(dc))
- goto priv_insn;
-#endif
- flush_T2(dc);
- gen_movl_reg_T2(rd + 1);
- gen_op_stda(insn, 0, 8, 0);
- break;
-#endif
-#ifdef TARGET_SPARC64
- case 0x0e: /* V9 stx */
- gen_op_ldst(stx);
- break;
- case 0x1e: /* V9 stxa */
- gen_op_stxa(insn, 0, 8, 0); // XXX
- break;
-#endif
- default:
- goto illegal_insn;
- }
- } else if (xop > 0x23 && xop < 0x28) {
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- switch (xop) {
- case 0x24:
- gen_op_load_fpr_FT0(rd);
- gen_op_ldst(stf);
- break;
- case 0x25: /* stfsr, V9 stxfsr */
- gen_op_stfsr();
- gen_op_ldst(stf);
- break;
- case 0x26: /* stdfq */
- goto nfpu_insn;
- case 0x27:
- gen_op_load_fpr_DT0(DFPREG(rd));
- gen_op_ldst(stdf);
- break;
- default:
- goto illegal_insn;
- }
- } else if (xop > 0x33 && xop < 0x3f) {
-#ifdef TARGET_SPARC64
- switch (xop) {
- case 0x34: /* V9 stfa */
- gen_op_stfa(insn, 0, 0, 0); // XXX
- break;
- case 0x37: /* V9 stdfa */
- gen_op_stdfa(insn, 0, 0, 0); // XXX
- break;
- case 0x3c: /* V9 casa */
- gen_op_casa(insn, 0, 4, 0); // XXX
- break;
- case 0x3e: /* V9 casxa */
- gen_op_casxa(insn, 0, 8, 0); // XXX
- break;
- case 0x36: /* V9 stqfa */
- goto nfpu_insn;
- default:
- goto illegal_insn;
- }
-#else
- goto illegal_insn;
-#endif
- }
- else
- goto illegal_insn;
- }
- break;
- }
- /* default case for non jump instructions */
- if (dc->npc == DYNAMIC_PC) {
- dc->pc = DYNAMIC_PC;
- gen_op_next_insn();
- } else if (dc->npc == JUMP_PC) {
- /* we can do a static jump */
- gen_branch2(dc, (long)dc->tb, dc->jump_pc[0], dc->jump_pc[1]);
- dc->is_br = 1;
- } else {
- dc->pc = dc->npc;
- dc->npc = dc->npc + 4;
- }
- jmp_insn:
- return;
- illegal_insn:
- save_state(dc);
- gen_op_exception(TT_ILL_INSN);
- dc->is_br = 1;
- return;
-#if !defined(CONFIG_USER_ONLY)
- priv_insn:
- save_state(dc);
- gen_op_exception(TT_PRIV_INSN);
- dc->is_br = 1;
- return;
-#endif
- nfpu_insn:
- save_state(dc);
- gen_op_fpexception_im(FSR_FTT_UNIMPFPOP);
- dc->is_br = 1;
-}
-
-static inline int gen_intermediate_code_internal(TranslationBlock * tb,
- int spc, CPUSPARCState *env)
-{
- target_ulong pc_start, last_pc;
- uint16_t *gen_opc_end;
- DisasContext dc1, *dc = &dc1;
- int j, lj = -1;
-
- memset(dc, 0, sizeof(DisasContext));
- dc->tb = tb;
- pc_start = tb->pc;
- dc->pc = pc_start;
- last_pc = dc->pc;
- dc->npc = (target_ulong) tb->cs_base;
-#if defined(CONFIG_USER_ONLY)
- dc->mem_idx = 0;
- dc->fpu_enabled = 1;
-#else
- dc->mem_idx = ((env->psrs) != 0);
-#ifdef TARGET_SPARC64
- dc->fpu_enabled = (((env->pstate & PS_PEF) != 0) && ((env->fprs & FPRS_FEF) != 0));
-#else
- dc->fpu_enabled = ((env->psref) != 0);
-#endif
-#endif
- 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;
-
- do {
- if (env->nb_breakpoints > 0) {
- for(j = 0; j < env->nb_breakpoints; j++) {
- if (env->breakpoints[j] == dc->pc) {
- if (dc->pc != pc_start)
- save_state(dc);
- gen_op_debug();
- gen_op_movl_T0_0();
- gen_op_exit_tb();
- dc->is_br = 1;
- goto exit_gen_loop;
- }
- }
- }
- if (spc) {
- if (loglevel > 0)
- fprintf(logfile, "Search PC...\n");
- j = gen_opc_ptr - gen_opc_buf;
- if (lj < j) {
- lj++;
- while (lj < j)
- gen_opc_instr_start[lj++] = 0;
- gen_opc_pc[lj] = dc->pc;
- gen_opc_npc[lj] = dc->npc;
- gen_opc_instr_start[lj] = 1;
- }
- }
- last_pc = dc->pc;
- disas_sparc_insn(dc);
-
- if (dc->is_br)
- break;
- /* if the next PC is different, we abort now */
- if (dc->pc != (last_pc + 4))
- break;
- /* if we reach a page boundary, we stop generation so that the
- PC of a TT_TFAULT exception is always in the right page */
- if ((dc->pc & (TARGET_PAGE_SIZE - 1)) == 0)
- break;
- /* if single step mode, we generate only one instruction and
- generate an exception */
- if (env->singlestep_enabled) {
- gen_jmp_im(dc->pc);
- gen_op_movl_T0_0();
- gen_op_exit_tb();
- break;
- }
- } while ((gen_opc_ptr < gen_opc_end) &&
- (dc->pc - pc_start) < (TARGET_PAGE_SIZE - 32));
-
- exit_gen_loop:
- if (!dc->is_br) {
- if (dc->pc != DYNAMIC_PC &&
- (dc->npc != DYNAMIC_PC && dc->npc != JUMP_PC)) {
- /* static PC and NPC: we can use direct chaining */
- gen_branch(dc, (long)tb, dc->pc, dc->npc);
- } else {
- if (dc->pc != DYNAMIC_PC)
- gen_jmp_im(dc->pc);
- save_npc(dc);
- gen_op_movl_T0_0();
- gen_op_exit_tb();
- }
- }
- *gen_opc_ptr = INDEX_op_end;
- if (spc) {
- 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
- gen_opc_jump_pc[0] = dc->jump_pc[0];
- gen_opc_jump_pc[1] = dc->jump_pc[1];
- } else {
- tb->size = last_pc + 4 - pc_start;
- }
-#ifdef DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "--------------\n");
- fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
- target_disas(logfile, pc_start, last_pc + 4 - pc_start, 0);
- 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(CPUSPARCState * env, TranslationBlock * tb)
-{
- return gen_intermediate_code_internal(tb, 0, env);
-}
-
-int gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
-{
- return gen_intermediate_code_internal(tb, 1, env);
-}
-
-extern int ram_size;
-
-void cpu_reset(CPUSPARCState *env)
-{
- memset(env, 0, sizeof(*env));
- tlb_flush(env, 1);
- env->cwp = 0;
- env->wim = 1;
- env->regwptr = env->regbase + (env->cwp * 16);
-#if defined(CONFIG_USER_ONLY)
- env->user_mode_only = 1;
-#ifdef TARGET_SPARC64
- env->cleanwin = NWINDOWS - 1;
- env->cansave = NWINDOWS - 1;
-#endif
-#else
- 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;
-#endif
- env->npc = env->pc + 4;
-#endif
-}
-
-CPUSPARCState *cpu_sparc_init(void)
-{
- CPUSPARCState *env;
-
- env = qemu_mallocz(sizeof(CPUSPARCState));
- if (!env)
- return NULL;
- cpu_exec_init(env);
- cpu_reset(env);
- return (env);
-}
-
-#define GET_FLAG(a,b) ((env->psr & a)?b:'-')
-
-void cpu_dump_state(CPUState *env, FILE *f,
- int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
- int flags)
-{
- int i, x;
-
- cpu_fprintf(f, "pc: " TARGET_FMT_lx " npc: " TARGET_FMT_lx "\n", env->pc, env->npc);
- cpu_fprintf(f, "General Registers:\n");
- for (i = 0; i < 4; i++)
- cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]);
- cpu_fprintf(f, "\n");
- for (; i < 8; i++)
- cpu_fprintf(f, "%%g%c: " TARGET_FMT_lx "\t", i + '0', env->gregs[i]);
- cpu_fprintf(f, "\nCurrent Register Window:\n");
- for (x = 0; x < 3; x++) {
- for (i = 0; i < 4; i++)
- cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t",
- (x == 0 ? 'o' : (x == 1 ? 'l' : 'i')), i,
- env->regwptr[i + x * 8]);
- cpu_fprintf(f, "\n");
- for (; i < 8; i++)
- cpu_fprintf(f, "%%%c%d: " TARGET_FMT_lx "\t",
- (x == 0 ? 'o' : x == 1 ? 'l' : 'i'), i,
- env->regwptr[i + x * 8]);
- cpu_fprintf(f, "\n");
- }
- cpu_fprintf(f, "\nFloating Point Registers:\n");
- for (i = 0; i < 32; i++) {
- if ((i & 3) == 0)
- cpu_fprintf(f, "%%f%02d:", i);
- cpu_fprintf(f, " %016lf", env->fpr[i]);
- if ((i & 3) == 3)
- 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, "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);
-#else
- cpu_fprintf(f, "psr: 0x%08x -> %c%c%c%c %c%c%c wim: 0x%08x\n", GET_PSR(env),
- GET_FLAG(PSR_ZERO, 'Z'), GET_FLAG(PSR_OVF, 'V'),
- GET_FLAG(PSR_NEG, 'N'), GET_FLAG(PSR_CARRY, 'C'),
- env->psrs?'S':'-', env->psrps?'P':'-',
- env->psret?'E':'-', env->wim);
-#endif
- cpu_fprintf(f, "fsr: 0x%08x\n", GET_FSR32(env));
-}
-
-#if defined(CONFIG_USER_ONLY)
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
-{
- return addr;
-}
-
-#else
-extern int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot,
- 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 phys_addr;
- int prot, access_index;
-
- if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 2, 0) != 0)
- if (get_physical_address(env, &phys_addr, &prot, &access_index, addr, 0, 0) != 0)
- return -1;
- return phys_addr;
-}
-#endif
-
-void helper_flush(target_ulong addr)
-{
- addr &= ~7;
- tb_invalidate_page_range(addr, addr + 8);
-}
diff --git a/telephony/Jamfile b/telephony/Jamfile
new file mode 100644
index 0000000..0f2b7b9
--- /dev/null
+++ b/telephony/Jamfile
@@ -0,0 +1,13 @@
+Main telephony : telephony.c ;
+
+Library sysdeps : sysdeps_posix.c ;
+Library android_modem : android_modem.c sim_card.c ;
+
+for prog in test1 test2 {
+ Main $(prog) : $(prog).c ;
+ LinkLibraries $(prog) : sysdeps ;
+}
+
+Main simulator : simulator.c ;
+LinkLibraries simulator : sysdeps android_modem ;
+
diff --git a/telephony/android_modem.c b/telephony/android_modem.c
new file mode 100644
index 0000000..2321c87
--- /dev/null
+++ b/telephony/android_modem.c
@@ -0,0 +1,1869 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android.h"
+#include "android_modem.h"
+#include "android_timezone.h"
+#include "sim_card.h"
+#include "sysdeps.h"
+#include <memory.h>
+#include <stdarg.h>
+#include <time.h>
+#include <assert.h>
+#include <stdio.h>
+#include "sms.h"
+#include "remote_call.h"
+#include "vl.h"
+
+#define DEBUG 1
+
+#if 1
+# define D_ACTIVE VERBOSE_CHECK(modem)
+#else
+# define D_ACTIVE DEBUG
+#endif
+
+#if 1
+# define R_ACTIVE VERBOSE_CHECK(radio)
+#else
+# define R_ACTIVE DEBUG
+#endif
+
+#if DEBUG
+# define D(...) do { if (D_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0)
+# define R(...) do { if (R_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0)
+#else
+# define D(...) ((void)0)
+# define R(...) ((void)0)
+#endif
+
+#define CALL_DELAY_DIAL 1000
+#define CALL_DELAY_ALERT 1000
+
+/* the Android GSM stack checks that the operator's name has changed
+ * when roaming is on. If not, it will not update the Roaming status icon
+ *
+ * this means that we need to emulate two distinct operators:
+ * - the first one for the 'home' registration state, must also correspond
+ * to the emulated user's IMEI
+ *
+ * - the second one for the 'roaming' registration state, must have a
+ * different name and MCC/MNC
+ */
+
+#define OPERATOR_HOME_INDEX 0
+#define OPERATOR_HOME_MCC 310
+#define OPERATOR_HOME_MNC 260
+#define OPERATOR_HOME_NAME "Android"
+#define OPERATOR_HOME_MCCMNC STRINGIFY(OPERATOR_HOME_MCC) \
+ STRINGIFY(OPERATOR_HOME_MNC)
+
+#define OPERATOR_ROAMING_INDEX 1
+#define OPERATOR_ROAMING_MCC 310
+#define OPERATOR_ROAMING_MNC 295
+#define OPERATOR_ROAMING_NAME "TelKila"
+#define OPERATOR_ROAMING_MCCMNC STRINGIFY(OPERATOR_ROAMING_MCC) \
+ STRINGIFY(OPERATOR_ROAMING_MNC)
+
+#if DEBUG
+static const char* quote( const char* line )
+{
+ static char temp[1024];
+ const char* hexdigits = "0123456789abcdef";
+ char* p = temp;
+ int c;
+
+ while ((c = *line++) != 0) {
+ c &= 255;
+ if (c >= 32 && c < 127) {
+ *p++ = c;
+ }
+ else if (c == '\r') {
+ memcpy( p, "<CR>", 4 );
+ p += 4;
+ }
+ else if (c == '\n') {
+ memcpy( p, "<LF>", 4 );strcat( p, "<LF>" );
+ p += 4;
+ }
+ else {
+ p[0] = '\\';
+ p[1] = 'x';
+ p[2] = hexdigits[ (c) >> 4 ];
+ p[3] = hexdigits[ (c) & 15 ];
+ p += 4;
+ }
+ }
+ *p = 0;
+ return temp;
+}
+#endif
+
+extern AGprsNetworkType
+android_parse_network_type( const char* speed )
+{
+ const struct { const char* name; AGprsNetworkType type; } types[] = {
+ { "gprs", A_GPRS_NETWORK_GPRS },
+ { "edge", A_GPRS_NETWORK_EDGE },
+ { "umts", A_GPRS_NETWORK_UMTS },
+ { "hsdpa", A_GPRS_NETWORK_UMTS }, /* not handled yet by Android GSM framework */
+ { "full", A_GPRS_NETWORK_UMTS },
+ { NULL, 0 }
+ };
+ int nn;
+
+ for (nn = 0; types[nn].name; nn++) {
+ if ( !strcmp(speed, types[nn].name) )
+ return types[nn].type;
+ }
+ /* not found, be conservative */
+ return A_GPRS_NETWORK_GPRS;
+}
+
+/* 'mode' for +CREG/+CGREG commands */
+typedef enum {
+ A_REGISTRATION_UNSOL_DISABLED = 0,
+ A_REGISTRATION_UNSOL_ENABLED = 1,
+ A_REGISTRATION_UNSOL_ENABLED_FULL = 2
+} ARegistrationUnsolMode;
+
+/* Operator selection mode, see +COPS commands */
+typedef enum {
+ A_SELECTION_AUTOMATIC,
+ A_SELECTION_MANUAL,
+ A_SELECTION_DEREGISTRATION,
+ A_SELECTION_SET_FORMAT,
+ A_SELECTION_MANUAL_AUTOMATIC
+} AOperatorSelection;
+
+/* Operator status, see +COPS commands */
+typedef enum {
+ A_STATUS_UNKNOWN = 0,
+ A_STATUS_AVAILABLE,
+ A_STATUS_CURRENT,
+ A_STATUS_DENIED
+} AOperatorStatus;
+
+typedef struct {
+ AOperatorStatus status;
+ char name[3][16];
+} AOperatorRec, *AOperator;
+
+typedef struct AVoiceCallRec {
+ ACallRec call;
+ SysTimer timer;
+ AModem modem;
+ char is_remote;
+} AVoiceCallRec, *AVoiceCall;
+
+#define MAX_OPERATORS 4
+
+typedef enum {
+ A_DATA_IP = 0,
+ A_DATA_PPP
+} ADataType;
+
+#define A_DATA_APN_SIZE 32
+
+typedef struct {
+ int id;
+ int active;
+ ADataType type;
+ char apn[ A_DATA_APN_SIZE ];
+
+} ADataContextRec, *ADataContext;
+
+/* the spec says that there can only be a max of 4 contexts */
+#define MAX_DATA_CONTEXTS 4
+#define MAX_CALLS 4
+
+#define A_MODEM_SELF_SIZE 3
+
+typedef struct AModemRec_
+{
+ /* Radio state */
+ ARadioState radio_state;
+ int area_code;
+ int cell_id;
+ int base_port;
+
+ /* SMS */
+ int wait_sms;
+
+ /* SIM card */
+ ASimCard sim;
+
+ /* voice and data network registration */
+ ARegistrationUnsolMode voice_mode;
+ ARegistrationState voice_state;
+ ARegistrationUnsolMode data_mode;
+ ARegistrationState data_state;
+ AGprsNetworkType data_network;
+
+ /* operator names */
+ AOperatorSelection oper_selection_mode;
+ ANameIndex oper_name_index;
+ int oper_index;
+ int oper_count;
+ AOperatorRec operators[ MAX_OPERATORS ];
+
+ /* data connection contexts */
+ ADataContextRec data_contexts[ MAX_DATA_CONTEXTS ];
+
+ /* active calls */
+ AVoiceCallRec calls[ MAX_CALLS ];
+ int call_count;
+
+ /* unsolicited callback */ /* XXX: TODO: use this */
+ AModemUnsolFunc unsol_func;
+ void* unsol_opaque;
+
+ SmsReceiver sms_receiver;
+
+ int out_size;
+ char out_buff[1024];
+
+} AModemRec;
+
+
+static void
+amodem_unsol( AModem modem, const char* format, ... )
+{
+ if (modem->unsol_func) {
+ va_list args;
+ va_start(args, format);
+ vsnprintf( modem->out_buff, sizeof(modem->out_buff), format, args );
+ va_end(args);
+
+ modem->unsol_func( modem->unsol_opaque, modem->out_buff );
+ }
+}
+
+void
+amodem_receive_sms( AModem modem, SmsPDU sms )
+{
+#define SMS_UNSOL_HEADER "+CMT: 0\r\n"
+
+ if (modem->unsol_func) {
+ int len, max;
+ char* p;
+
+ strcpy( modem->out_buff, SMS_UNSOL_HEADER );
+ p = modem->out_buff + (sizeof(SMS_UNSOL_HEADER)-1);
+ max = sizeof(modem->out_buff) - 3 - (sizeof(SMS_UNSOL_HEADER)-1);
+ len = smspdu_to_hex( sms, p, max );
+ if (len > max) /* too long */
+ return;
+ p[len] = '\r';
+ p[len+1] = '\n';
+ p[len+2] = 0;
+
+ R( "SMS>> %s\n", p );
+
+ modem->unsol_func( modem->unsol_opaque, modem->out_buff );
+ }
+}
+
+static const char*
+amodem_printf( AModem modem, const char* format, ... )
+{
+ va_list args;
+ va_start(args, format);
+ vsnprintf( modem->out_buff, sizeof(modem->out_buff), format, args );
+ va_end(args);
+
+ return modem->out_buff;
+}
+
+static void
+amodem_begin_line( AModem modem )
+{
+ modem->out_size = 0;
+}
+
+static void
+amodem_add_line( AModem modem, const char* format, ... )
+{
+ va_list args;
+ va_start(args, format);
+ modem->out_size += vsnprintf( modem->out_buff + modem->out_size,
+ sizeof(modem->out_buff) - modem->out_size,
+ format, args );
+ va_end(args);
+}
+
+static const char*
+amodem_end_line( AModem modem )
+{
+ modem->out_buff[ modem->out_size ] = 0;
+ return modem->out_buff;
+}
+
+static void
+amodem_reset( AModem modem )
+{
+ modem->radio_state = A_RADIO_STATE_OFF;
+ modem->wait_sms = 0;
+
+ modem->oper_name_index = 2;
+ modem->oper_selection_mode = A_SELECTION_AUTOMATIC;
+ modem->oper_index = 0;
+ modem->oper_count = 2;
+
+ modem->area_code = -1;
+ modem->cell_id = -1;
+
+ strcpy( modem->operators[0].name[0], OPERATOR_HOME_NAME );
+ strcpy( modem->operators[0].name[1], OPERATOR_HOME_NAME );
+ strcpy( modem->operators[0].name[2], OPERATOR_HOME_MCCMNC );
+
+ modem->operators[0].status = A_STATUS_AVAILABLE;
+
+ strcpy( modem->operators[1].name[0], OPERATOR_ROAMING_NAME );
+ strcpy( modem->operators[1].name[1], OPERATOR_ROAMING_NAME );
+ strcpy( modem->operators[1].name[2], OPERATOR_ROAMING_MCCMNC );
+
+ modem->operators[1].status = A_STATUS_AVAILABLE;
+
+ modem->voice_mode = A_REGISTRATION_UNSOL_ENABLED_FULL;
+ modem->voice_state = A_REGISTRATION_HOME;
+ modem->data_mode = A_REGISTRATION_UNSOL_ENABLED_FULL;
+ modem->data_state = A_REGISTRATION_HOME;
+ modem->data_network = A_GPRS_NETWORK_UMTS;
+}
+
+static AModemRec _android_modem[1];
+
+AModem
+amodem_create( int base_port, AModemUnsolFunc unsol_func, void* unsol_opaque )
+{
+ AModem modem = _android_modem;
+
+ amodem_reset( modem );
+ modem->base_port = base_port;
+ modem->unsol_func = unsol_func;
+ modem->unsol_opaque = unsol_opaque;
+
+ modem->sim = asimcard_create();
+
+ return modem;
+}
+
+void
+amodem_destroy( AModem modem )
+{
+ asimcard_destroy( modem->sim );
+ modem->sim = NULL;
+}
+
+
+static int
+amodem_has_network( AModem modem )
+{
+ return !(modem->radio_state == A_RADIO_STATE_OFF ||
+ modem->oper_index < 0 ||
+ modem->oper_index >= modem->oper_count ||
+ modem->oper_selection_mode == A_SELECTION_DEREGISTRATION );
+}
+
+
+ARadioState
+amodem_get_radio_state( AModem modem )
+{
+ return modem->radio_state;
+}
+
+void
+amodem_set_radio_state( AModem modem, ARadioState state )
+{
+ modem->radio_state = state;
+}
+
+ASimCard
+amodem_get_sim( AModem modem )
+{
+ return modem->sim;
+}
+
+ARegistrationState
+amodem_get_voice_registration( AModem modem )
+{
+ return modem->voice_state;
+}
+
+void
+amodem_set_voice_registration( AModem modem, ARegistrationState state )
+{
+ modem->voice_state = state;
+
+ if (state == A_REGISTRATION_HOME)
+ modem->oper_index = OPERATOR_HOME_INDEX;
+ else if (state == A_REGISTRATION_ROAMING)
+ modem->oper_index = OPERATOR_ROAMING_INDEX;
+
+ switch (modem->voice_mode) {
+ case A_REGISTRATION_UNSOL_ENABLED:
+ amodem_unsol( modem, "+CREG: %d,%d\r",
+ modem->voice_mode, modem->voice_state );
+ break;
+
+ case A_REGISTRATION_UNSOL_ENABLED_FULL:
+ amodem_unsol( modem, "+CREG: %d,%d, \"%04x\", \"%04x\"\r",
+ modem->voice_mode, modem->voice_state,
+ modem->area_code, modem->cell_id );
+ break;
+ default:
+ ;
+ }
+}
+
+ARegistrationState
+amodem_get_data_registration( AModem modem )
+{
+ return modem->data_state;
+}
+
+void
+amodem_set_data_registration( AModem modem, ARegistrationState state )
+{
+ modem->data_state = state;
+
+ switch (modem->data_mode) {
+ case A_REGISTRATION_UNSOL_ENABLED:
+ amodem_unsol( modem, "+CGREG: %d,%d\r",
+ modem->data_mode, modem->data_state );
+ break;
+
+ case A_REGISTRATION_UNSOL_ENABLED_FULL:
+ amodem_unsol( modem, "+CGREG: %d,%d,\"%04x\",\"%04x\",\"%04x\"\r",
+ modem->data_mode, modem->data_state,
+ modem->area_code, modem->cell_id,
+ modem->data_network );
+ break;
+
+ default:
+ ;
+ }
+}
+
+void
+amodem_set_data_network_type( AModem modem, AGprsNetworkType type )
+{
+ modem->data_network = type;
+ amodem_set_data_registration( modem, modem->data_state );
+}
+
+int
+amodem_get_operator_name ( AModem modem, ANameIndex index, char* buffer, int buffer_size )
+{
+ AOperator oper;
+ int len;
+
+ if ( (unsigned)modem->oper_index >= (unsigned)modem->oper_count ||
+ (unsigned)index > 2 )
+ return 0;
+
+ oper = modem->operators + modem->oper_index;
+ len = strlen(oper->name[index]) + 1;
+
+ if (buffer_size > len)
+ buffer_size = len;
+
+ if (buffer_size > 0) {
+ memcpy( buffer, oper->name[index], buffer_size-1 );
+ buffer[buffer_size] = 0;
+ }
+ return len;
+}
+
+/* reset one operator name from a user-provided buffer, set buffer_size to -1 for zero-terminated strings */
+void
+amodem_set_operator_name( AModem modem, ANameIndex index, const char* buffer, int buffer_size )
+{
+ AOperator oper;
+ int avail;
+
+ if ( (unsigned)modem->oper_index >= (unsigned)modem->oper_count ||
+ (unsigned)index > 2 )
+ return;
+
+ oper = modem->operators + modem->oper_index;
+
+ avail = sizeof(oper->name[0]);
+ if (buffer_size < 0)
+ buffer_size = strlen(buffer);
+ if (buffer_size > avail-1)
+ buffer_size = avail-1;
+ memcpy( oper->name[index], buffer, buffer_size );
+ oper->name[index][buffer_size] = 0;
+}
+
+/** CALLS
+ **/
+int
+amodem_get_call_count( AModem modem )
+{
+ return modem->call_count;
+}
+
+ACall
+amodem_get_call( AModem modem, int index )
+{
+ if ((unsigned)index >= (unsigned)modem->call_count)
+ return NULL;
+
+ return &modem->calls[index].call;
+}
+
+static AVoiceCall
+amodem_alloc_call( AModem modem )
+{
+ AVoiceCall call = NULL;
+ int count = modem->call_count;
+
+ if (count < MAX_CALLS) {
+ int id;
+
+ /* find a valid id for this call */
+ for (id = 0; id < modem->call_count; id++) {
+ int found = 0;
+ int nn;
+ for (nn = 0; nn < count; nn++) {
+ if ( modem->calls[nn].call.id == (id+1) ) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ break;
+ }
+ call = modem->calls + count;
+ call->call.id = id + 1;
+ call->modem = modem;
+
+ modem->call_count += 1;
+ }
+ return call;
+}
+
+
+static void
+amodem_free_call( AModem modem, AVoiceCall call )
+{
+ int nn;
+
+ if (call->timer) {
+ sys_timer_destroy( call->timer );
+ call->timer = NULL;
+ }
+
+ if (call->is_remote) {
+ remote_call_cancel( call->call.number, modem->base_port );
+ call->is_remote = 0;
+ }
+
+ for (nn = 0; nn < modem->call_count; nn++) {
+ if ( modem->calls + nn == call )
+ break;
+ }
+ assert( nn < modem->call_count );
+
+ memmove( modem->calls + nn,
+ modem->calls + nn + 1,
+ (modem->call_count - 1 - nn)*sizeof(*call) );
+
+ modem->call_count -= 1;
+}
+
+
+static AVoiceCall
+amodem_find_call( AModem modem, int id )
+{
+ int nn;
+
+ for (nn = 0; nn < modem->call_count; nn++) {
+ AVoiceCall call = modem->calls + nn;
+ if (call->call.id == id)
+ return call;
+ }
+ return NULL;
+}
+
+static void
+amodem_send_calls_update( AModem modem )
+{
+ /* despite its name, this really tells the system that the call
+ * state has changed */
+ amodem_unsol( modem, "RING\r" );
+}
+
+
+int
+amodem_add_inbound_call( AModem modem, const char* number )
+{
+ AVoiceCall vcall = amodem_alloc_call( modem );
+ ACall call = &vcall->call;
+ int len;
+
+ if (call == NULL)
+ return -1;
+
+ call->dir = A_CALL_INBOUND;
+ call->state = A_CALL_INCOMING;
+ call->mode = A_CALL_VOICE;
+ call->multi = 0;
+
+ vcall->is_remote = (remote_number_string_to_port(number) > 0);
+
+ len = strlen(number);
+ if (len >= sizeof(call->number))
+ len = sizeof(call->number)-1;
+
+ memcpy( call->number, number, len );
+ call->number[len] = 0;
+
+ amodem_send_calls_update( modem );
+ return 0;
+}
+
+ACall
+amodem_find_call_by_number( AModem modem, const char* number )
+{
+ AVoiceCall vcall = modem->calls;
+ AVoiceCall vend = vcall + modem->call_count;
+
+ if (!number)
+ return NULL;
+
+ for ( ; vcall < vend; vcall++ )
+ if ( !strcmp(vcall->call.number, number) )
+ return &vcall->call;
+
+ return NULL;
+}
+
+
+static void
+acall_set_state( AVoiceCall call, ACallState state )
+{
+ if (state != call->call.state)
+ {
+ if (call->is_remote)
+ {
+ const char* number = call->call.number;
+ int port = call->modem->base_port;
+
+ switch (state) {
+ case A_CALL_HELD:
+ remote_call_other( number, port, REMOTE_CALL_HOLD );
+ break;
+
+ case A_CALL_ACTIVE:
+ remote_call_other( number, port, REMOTE_CALL_ACCEPT );
+ break;
+
+ default: ;
+ }
+ }
+ call->call.state = state;
+ }
+}
+
+
+int
+amodem_update_call( AModem modem, const char* fromNumber, ACallState state )
+{
+ AVoiceCall vcall = (AVoiceCall) amodem_find_call_by_number(modem, fromNumber);
+
+ if (vcall == NULL)
+ return -1;
+
+ acall_set_state( vcall, state );
+ amodem_send_calls_update(modem);
+ return 0;
+}
+
+
+int
+amodem_disconnect_call( AModem modem, const char* number )
+{
+ AVoiceCall vcall = (AVoiceCall) amodem_find_call_by_number(modem, number);
+
+ if (!vcall)
+ return -1;
+
+ amodem_free_call( modem, vcall );
+ amodem_send_calls_update(modem);
+ return 0;
+}
+
+/** COMMAND HANDLERS
+ **/
+
+static const char*
+unknownCommand( const char* cmd, AModem modem )
+{
+ modem=modem;
+ fprintf(stderr, ">>> unknown command '%s'\n", cmd );
+ return "ERROR: unknown command\r";
+}
+
+static const char*
+handleRadioPower( const char* cmd, AModem modem )
+{
+ if ( !strcmp( cmd, "+CFUN=0" ) )
+ {
+ /* turn radio off */
+ modem->radio_state = A_RADIO_STATE_OFF;
+ }
+ else if ( !strcmp( cmd, "+CFUN=1" ) )
+ {
+ /* turn radio on */
+ modem->radio_state = A_RADIO_STATE_ON;
+ }
+ return NULL;
+}
+
+static const char*
+handleRadioPowerReq( const char* cmd, AModem modem )
+{
+ if (modem->radio_state != A_RADIO_STATE_OFF)
+ return "+CFUN=1";
+ else
+ return "+CFUN=0";
+}
+
+static const char*
+handleSIMStatusReq( const char* cmd, AModem modem )
+{
+ const char* answer = NULL;
+
+ switch (asimcard_get_status(modem->sim)) {
+ case A_SIM_STATUS_ABSENT: answer = "+CPIN: ABSENT"; break;
+ case A_SIM_STATUS_READY: answer = "+CPIN: READY"; break;
+ case A_SIM_STATUS_NOT_READY: answer = "+CMERROR: NOT READY"; break;
+ case A_SIM_STATUS_PIN: answer = "+CPIN: SIM PIN"; break;
+ case A_SIM_STATUS_PUK: answer = "+CPIN: SIM PUK"; break;
+ case A_SIM_STATUS_NETWORK_PERSONALIZATION: answer = "+CPIN: PH-NET PIN"; break;
+ default:
+ answer = "ERROR: internal error";
+ }
+ return answer;
+}
+
+static const char*
+handleNetworkRegistration( const char* cmd, AModem modem )
+{
+ if ( !memcmp( cmd, "+CREG", 5 ) ) {
+ cmd += 5;
+ if (cmd[0] == '?') {
+ return amodem_printf( modem, "+CREG: %d,%d, \"%04x\", \"%04x\"",
+ modem->voice_mode, modem->voice_state,
+ modem->area_code, modem->cell_id );
+ } else if (cmd[0] == '=') {
+ switch (cmd[1]) {
+ case '0':
+ modem->voice_mode = A_REGISTRATION_UNSOL_DISABLED;
+ break;
+
+ case '1':
+ modem->voice_mode = A_REGISTRATION_UNSOL_ENABLED;
+ break;
+
+ case '2':
+ modem->voice_mode = A_REGISTRATION_UNSOL_ENABLED_FULL;
+ break;
+
+ case '?':
+ return "+CREG: (0-2)";
+
+ default:
+ return "ERROR: BAD COMMAND";
+ }
+ } else {
+ assert( 0 && "unreachable" );
+ }
+ } else if ( !memcmp( cmd, "+CGREG", 6 ) ) {
+ cmd += 6;
+ if (cmd[0] == '?') {\
+ return amodem_printf( modem, "+CGREG: %d,%d,\"%04x\",\"%04x\",\"%04x\"",
+ modem->data_mode, modem->data_state,
+ modem->area_code, modem->cell_id,
+ modem->data_network );
+ } else if (cmd[0] == '=') {
+ switch (cmd[1]) {
+ case '0':
+ modem->data_mode = A_REGISTRATION_UNSOL_DISABLED;
+ break;
+
+ case '1':
+ modem->data_mode = A_REGISTRATION_UNSOL_ENABLED;
+ break;
+
+ case '2':
+ modem->data_mode = A_REGISTRATION_UNSOL_ENABLED_FULL;
+ break;
+
+ case '?':
+ return "+CGREG: (0-2)";
+
+ default:
+ return "ERROR: BAD COMMAND";
+ }
+ } else {
+ assert( 0 && "unreachable" );
+ }
+ }
+ return NULL;
+}
+
+static const char*
+handleSetDialTone( const char* cmd, AModem modem )
+{
+ /* XXX: TODO */
+ return NULL;
+}
+
+static const char*
+handleDeleteSMSonSIM( const char* cmd, AModem modem )
+{
+ /* XXX: TODO */
+ return NULL;
+}
+
+static const char*
+handleSIM_IO( const char* cmd, AModem modem )
+{
+ return asimcard_io( modem->sim, cmd );
+}
+
+
+static const char*
+handleOperatorSelection( const char* cmd, AModem modem )
+{
+ assert( !memcmp( "+COPS", cmd, 5 ) );
+ cmd += 5;
+ if (cmd[0] == '?') { /* ask for current operator */
+ AOperator oper = &modem->operators[ modem->oper_index ];
+
+ if ( !amodem_has_network( modem ) )
+ {
+ /* this error code means "no network" */
+ return amodem_printf( modem, "+CME ERROR: 30" );
+ }
+
+ oper = &modem->operators[ modem->oper_index ];
+
+ if ( modem->oper_name_index == 2 )
+ return amodem_printf( modem, "+COPS: %d,2,%s",
+ modem->oper_selection_mode,
+ oper->name[2] );
+
+ return amodem_printf( modem, "+COPS: %d,%d,\"%s\"",
+ modem->oper_selection_mode,
+ modem->oper_name_index,
+ oper->name[ modem->oper_name_index ] );
+ }
+ else if (cmd[0] == '=' && cmd[1] == '?') { /* ask for all available operators */
+ const char* comma = "+COPS: ";
+ int nn;
+ amodem_begin_line( modem );
+ for (nn = 0; nn < modem->oper_count; nn++) {
+ AOperator oper = &modem->operators[nn];
+ amodem_add_line( modem, "%s(%d,\"%s\",\"%s\",\"%s\")", comma,
+ oper->status, oper->name[0], oper->name[1], oper->name[2] );
+ comma = ", ";
+ }
+ return amodem_end_line( modem );
+ }
+ else if (cmd[0] == '=') {
+ switch (cmd[1]) {
+ case '0':
+ modem->oper_selection_mode = A_SELECTION_AUTOMATIC;
+ return NULL;
+
+ case '1':
+ {
+ int format, nn, len, found = -1;
+
+ if (cmd[2] != ',')
+ goto BadCommand;
+ format = cmd[3] - '0';
+ if ( (unsigned)format > 2 )
+ goto BadCommand;
+ if (cmd[4] != ',')
+ goto BadCommand;
+ cmd += 5;
+ len = strlen(cmd);
+ if (*cmd == '"') {
+ cmd++;
+ len -= 2;
+ }
+ if (len <= 0)
+ goto BadCommand;
+
+ for (nn = 0; nn < modem->oper_count; nn++) {
+ AOperator oper = modem->operators + nn;
+ char* name = oper->name[ format ];
+
+ if ( !memcpy( name, cmd, len ) && name[len] == 0 ) {
+ found = nn;
+ break;
+ }
+ }
+
+ if (found < 0) {
+ /* Selection failed */
+ return "+CME ERROR: 529";
+ } else if (modem->operators[found].status == A_STATUS_DENIED) {
+ /* network not allowed */
+ return "+CME ERROR: 32";
+ }
+ modem->oper_index = found;
+
+ /* set the voice and data registration states to home or roaming
+ * depending on the operator index
+ */
+ if (found == OPERATOR_HOME_INDEX) {
+ modem->voice_state = A_REGISTRATION_HOME;
+ modem->data_state = A_REGISTRATION_HOME;
+ } else if (found == OPERATOR_ROAMING_INDEX) {
+ modem->voice_state = A_REGISTRATION_ROAMING;
+ modem->data_state = A_REGISTRATION_ROAMING;
+ }
+ return NULL;
+ }
+
+ case '2':
+ modem->oper_selection_mode = A_SELECTION_DEREGISTRATION;
+ return NULL;
+
+ case '3':
+ {
+ int format;
+
+ if (cmd[2] != ',')
+ goto BadCommand;
+
+ format = cmd[3] - '0';
+ if ( (unsigned)format > 2 )
+ goto BadCommand;
+
+ modem->oper_name_index = format;
+ return NULL;
+ }
+ default:
+ ;
+ }
+ }
+BadCommand:
+ return unknownCommand(cmd,modem);
+}
+
+static const char*
+handleRequestOperator( const char* cmd, AModem modem )
+{
+ AOperator oper;
+ cmd=cmd;
+
+ if ( !amodem_has_network(modem) )
+ return "+CME ERROR: 30";
+
+ oper = modem->operators + modem->oper_index;
+ modem->oper_name_index = 2;
+ return amodem_printf( modem, "+COPS: 0,0,\"%s\"\r"
+ "+COPS: 0,1,\"%s\"\r"
+ "+COPS: 0,2,\"%s\"",
+ oper->name[0], oper->name[1], oper->name[2] );
+}
+
+static const char*
+handleSendSMStoSIM( const char* cmd, AModem modem )
+{
+ /* XXX: TODO */
+ return "ERROR: unimplemented";
+}
+
+static const char*
+handleSendSMS( const char* cmd, AModem modem )
+{
+ modem->wait_sms = 1;
+ return "> ";
+}
+
+#if 0
+static void
+sms_address_dump( SmsAddress address, FILE* out )
+{
+ int nn, len = address->len;
+
+ if (address->toa == 0x91) {
+ fprintf( out, "+" );
+ }
+ for (nn = 0; nn < len; nn += 2)
+ {
+ static const char dialdigits[16] = "0123456789*#,N%";
+ int c = address->data[nn/2];
+
+ fprintf( out, "%c", dialdigits[c & 0xf] );
+ if (nn+1 >= len)
+ break;
+
+ fprintf( out, "%c", dialdigits[(c >> 4) & 0xf] );
+ }
+}
+
+static void
+smspdu_dump( SmsPDU pdu, FILE* out )
+{
+ SmsAddressRec address;
+ unsigned char temp[256];
+ int len;
+
+ if (pdu == NULL) {
+ fprintf( out, "SMS PDU is (null)\n" );
+ return;
+ }
+
+ fprintf( out, "SMS PDU type: " );
+ switch (smspdu_get_type(pdu)) {
+ case SMS_PDU_DELIVER: fprintf(out, "DELIVER"); break;
+ case SMS_PDU_SUBMIT: fprintf(out, "SUBMIT"); break;
+ case SMS_PDU_STATUS_REPORT: fprintf(out, "STATUS_REPORT"); break;
+ default: fprintf(out, "UNKNOWN");
+ }
+ fprintf( out, "\n sender: " );
+ if (smspdu_get_sender_address(pdu, &address) < 0)
+ fprintf( out, "(N/A)" );
+ else
+ sms_address_dump(&address, out);
+ fprintf( out, "\n receiver: " );
+ if (smspdu_get_receiver_address(pdu, &address) < 0)
+ fprintf(out, "(N/A)");
+ else
+ sms_address_dump(&address, out);
+ fprintf( out, "\n text: " );
+ len = smspdu_get_text_message( pdu, temp, sizeof(temp)-1 );
+ if (len > sizeof(temp)-1 )
+ len = sizeof(temp)-1;
+ fprintf( out, "'%.*s'\n", len, temp );
+}
+#endif
+
+static const char*
+handleSendSMSText( const char* cmd, AModem modem )
+{
+#if 1
+ SmsAddressRec address;
+ char number[16];
+ int numlen;
+ int len = strlen(cmd);
+ SmsPDU pdu;
+
+ /* get rid of trailing escape */
+ if (len > 0 && cmd[len-1] == 0x1a)
+ len -= 1;
+
+ pdu = smspdu_create_from_hex( cmd, len );
+ if (pdu == NULL) {
+ D("%s: invalid SMS PDU ?: '%s'\n", __FUNCTION__, cmd);
+ return "+CMS ERROR: INVALID SMS PDU";
+ }
+ if (smspdu_get_receiver_address(pdu, &address) < 0) {
+ D("%s: could not get SMS receiver address from '%s'\n",
+ __FUNCTION__, cmd);
+ return "+CMS ERROR: BAD SMS RECEIVER ADDRESS";
+ }
+
+ do {
+ int index;
+
+ numlen = sms_address_to_str( &address, number, sizeof(number) );
+ if (numlen > sizeof(number)-1)
+ break;
+
+ number[numlen] = 0;
+ if ( remote_number_string_to_port( number ) < 0 )
+ break;
+
+ if (modem->sms_receiver == NULL) {
+ modem->sms_receiver = sms_receiver_create();
+ if (modem->sms_receiver == NULL) {
+ D( "%s: could not create SMS receiver\n", __FUNCTION__ );
+ break;
+ }
+ }
+
+ index = sms_receiver_add_submit_pdu( modem->sms_receiver, pdu );
+ if (index < 0) {
+ D( "%s: could not add submit PDU\n", __FUNCTION__ );
+ break;
+ }
+ /* the PDU is now owned by the receiver */
+ pdu = NULL;
+
+ if (index > 0) {
+ SmsAddressRec from[1];
+ char temp[10];
+ SmsPDU* deliver;
+ int nn;
+
+ sprintf( temp, "%d", modem->base_port );
+ sms_address_from_str( from, temp, strlen(temp) );
+
+ deliver = sms_receiver_create_deliver( modem->sms_receiver, index, from );
+ if (deliver == NULL) {
+ D( "%s: could not create deliver PDUs for SMS index %d\n",
+ __FUNCTION__, index );
+ break;
+ }
+
+ for (nn = 0; deliver[nn] != NULL; nn++) {
+ if ( remote_call_sms( number, modem->base_port, deliver[nn] ) < 0 ) {
+ D( "%s: could not send SMS PDU to remote emulator\n",
+ __FUNCTION__ );
+ break;
+ }
+ }
+
+ smspdu_free_list(deliver);
+ }
+
+ } while (0);
+
+ if (pdu != NULL)
+ smspdu_free(pdu);
+
+#elif 1
+ SmsAddressRec address;
+ char number[16];
+ int numlen;
+ int len = strlen(cmd);
+ SmsPDU pdu;
+
+ /* get rid of trailing escape */
+ if (len > 0 && cmd[len-1] == 0x1a)
+ len -= 1;
+
+ pdu = smspdu_create_from_hex( cmd, len );
+ if (pdu == NULL) {
+ D("%s: invalid SMS PDU ?: '%s'\n", __FUNCTION__, cmd);
+ return "+CMS ERROR: INVALID SMS PDU";
+ }
+ if (smspdu_get_receiver_address(pdu, &address) < 0) {
+ D("%s: could not get SMS receiver address from '%s'\n",
+ __FUNCTION__, cmd);
+ return "+CMS ERROR: BAD SMS RECEIVER ADDRESS";
+ }
+ do {
+ numlen = sms_address_to_str( &address, number, sizeof(number) );
+ if (numlen > sizeof(number)-1)
+ break;
+
+ number[numlen] = 0;
+ if ( remote_number_string_to_port( number ) < 0 )
+ break;
+
+ if ( remote_call_sms( number, modem->base_port, pdu ) < 0 )
+ {
+ D("%s: could not send SMS PDU to remote emulator\n",
+ __FUNCTION__);
+ return "+CMS ERROR: NO EMULATOR RECEIVER";
+ }
+ } while (0);
+#else
+ fprintf(stderr, "SMS<< %s\n", cmd);
+ SmsPDU pdu = smspdu_create_from_hex( cmd, strlen(cmd) );
+ if (pdu == NULL) {
+ fprintf(stderr, "invalid SMS PDU ?: '%s'\n", cmd);
+ } else {
+ smspdu_dump(pdu, stderr);
+ }
+#endif
+ return "+CMGS: 0\rOK\r";
+}
+
+static const char*
+handleChangeOrEnterPIN( const char* cmd, AModem modem )
+{
+ assert( !memcmp( cmd, "+CPIN=", 6 ) );
+ cmd += 6;
+
+ switch (asimcard_get_status(modem->sim)) {
+ case A_SIM_STATUS_ABSENT:
+ return "+CME ERROR: SIM ABSENT";
+
+ case A_SIM_STATUS_NOT_READY:
+ return "+CME ERROR: SIM NOT READY";
+
+ case A_SIM_STATUS_READY:
+ /* this may be a request to change the PIN */
+ {
+ if (strlen(cmd) == 9 && cmd[4] == ',') {
+ char pin[5];
+ memcpy( pin, cmd, 4 ); pin[4] = 0;
+
+ if ( !asimcard_check_pin( modem->sim, pin ) )
+ return "+CME ERROR: BAD PIN";
+
+ memcpy( pin, cmd+5, 4 );
+ asimcard_set_pin( modem->sim, pin );
+ return "+CPIN: READY";
+ }
+ }
+ break;
+
+ case A_SIM_STATUS_PIN: /* waiting for PIN */
+ if ( asimcard_check_pin( modem->sim, cmd ) )
+ return "+CPIN: READY";
+ else
+ return "+CME ERROR: BAD PIN";
+
+ case A_SIM_STATUS_PUK:
+ if (strlen(cmd) == 9 && cmd[4] == ',') {
+ char puk[5];
+ memcpy( puk, cmd, 4 );
+ puk[4] = 0;
+ if ( asimcard_check_puk( modem->sim, puk, cmd+5 ) )
+ return "+CPIN: READY";
+ else
+ return "+CME ERROR: BAD PUK";
+ }
+ return "+CME ERROR: BAD PUK";
+
+ default:
+ return "+CPIN: PH-NET PIN";
+ }
+
+ return "+CME ERROR: BAD FORMAT";
+}
+
+
+static const char*
+handleListCurrentCalls( const char* cmd, AModem modem )
+{
+ int nn;
+ amodem_begin_line( modem );
+ for (nn = 0; nn < modem->call_count; nn++) {
+ AVoiceCall vcall = modem->calls + nn;
+ ACall call = &vcall->call;
+ if (call->mode == A_CALL_VOICE)
+ amodem_add_line( modem, "+CLCC: %d,%d,%d,%d,%d,\"%s\",%d\r\n",
+ call->id, call->dir, call->state, call->mode,
+ call->multi, call->number, 129 );
+ }
+ return amodem_end_line( modem );
+}
+
+/* retrieve the current time and zone in a format suitable
+ * for %CTZV: unsolicited message
+ * "yy/mm/dd,hh:mm:ss(+/-)tz"
+ * mm is 0-based
+ * tz is in number of quarter-hours
+ *
+ * it seems reference-ril doesn't parse the comma (,) as anything else than a token
+ * separator, so use a column (:) instead, the Java parsing code won't see a difference
+ *
+ */
+static const char*
+handleEndOfInit( const char* cmd, AModem modem )
+{
+ time_t now = time(NULL);
+ struct tm utc, local;
+ long e_local, e_utc;
+ long tzdiff;
+ char tzname[64];
+
+ tzset();
+
+ utc = *gmtime( &now );
+ local = *localtime( &now );
+
+ e_local = local.tm_min + 60*(local.tm_hour + 24*local.tm_yday);
+ e_utc = utc.tm_min + 60*(utc.tm_hour + 24*utc.tm_yday);
+
+ if ( utc.tm_year < local.tm_year )
+ e_local += 24*60;
+ else if ( utc.tm_year > local.tm_year )
+ e_utc += 24*60;
+
+ tzdiff = e_local - e_utc; /* timezone offset in minutes */
+
+ /* retrieve a zoneinfo-compatible name for the host timezone
+ */
+ {
+ char* end = tzname + sizeof(tzname);
+ char* p = bufprint_zoneinfo_timezone( tzname, end );
+ if (p >= end)
+ strcpy(tzname, "Unknown/Unknown");
+
+ /* now replace every / in the timezone name by a "!"
+ * that's because the code that reads the CTZV line is
+ * dumb and treats a / as a field separator...
+ */
+ p = tzname;
+ while (1) {
+ p = strchr(p, '/');
+ if (p == NULL)
+ break;
+ *p = '!';
+ p += 1;
+ }
+ }
+
+ /* as a special extension, we append the name of the host's time zone to the
+ * string returned with %CTZ. the system should contain special code to detect
+ * and deal with this case (since it normally relied on the operator's country code
+ * which is hard to simulate on a general-purpose computer
+ */
+ return amodem_printf( modem, "%%CTZV: %02d/%02d/%02d:%02d:%02d:%02d%c%d:%d:%s",
+ (utc.tm_year + 1900) % 100, utc.tm_mon + 1, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec,
+ (tzdiff >= 0) ? '+' : '-', (tzdiff >= 0 ? tzdiff : -tzdiff) / 15,
+ (local.tm_isdst > 0),
+ tzname );
+}
+
+
+static const char*
+handleListPDPContexts( const char* cmd, AModem modem )
+{
+ int nn;
+ assert( !memcmp( cmd, "+CGACT?", 7 ) );
+ amodem_begin_line( modem );
+ for (nn = 0; nn < MAX_DATA_CONTEXTS; nn++) {
+ ADataContext data = modem->data_contexts + nn;
+ if (!data->active)
+ continue;
+ amodem_add_line( modem, "+CGACT: %d,%d\r", data->id, data->active );
+ }
+ return amodem_end_line( modem );
+}
+
+static const char*
+handleDefinePDPContext( const char* cmd, AModem modem )
+{
+ assert( !memcmp( cmd, "+CGDCONT=", 9 ) );
+ cmd += 9;
+ if (cmd[0] == '?') {
+ int nn;
+ amodem_begin_line(modem);
+ for (nn = 0; nn < MAX_DATA_CONTEXTS; nn++) {
+ ADataContext data = modem->data_contexts + nn;
+ if (!data->active)
+ continue;
+ amodem_add_line( modem, "+CGDCONT: %d,%s,\"%s\",,0,0\r\n",
+ data->id,
+ data->type == A_DATA_IP ? "IP" : "PPP",
+ data->apn );
+ }
+ return amodem_end_line(modem);
+ } else {
+ /* template is +CGDCONT=<id>,"<type>","<apn>",,0,0 */
+ int id = cmd[0] - '1';
+ ADataType type;
+ char apn[32];
+ ADataContext data;
+
+ if ((unsigned)id > 3)
+ goto BadCommand;
+
+ if ( !memcmp( cmd+1, ",\"IP\",\"", 7 ) ) {
+ type = A_DATA_IP;
+ cmd += 8;
+ } else if ( !memcmp( cmd+1, ",\"PPP\",\"", 8 ) ) {
+ type = A_DATA_PPP;
+ cmd += 9;
+ } else
+ goto BadCommand;
+
+ {
+ const char* p = strchr( cmd, '"' );
+ int len;
+ if (p == NULL)
+ goto BadCommand;
+ len = (int)( p - cmd );
+ if (len > sizeof(apn)-1 )
+ len = sizeof(apn)-1;
+ memcpy( apn, cmd, len );
+ apn[len] = 0;
+ }
+
+ data = modem->data_contexts + id;
+
+ data->id = id + 1;
+ data->active = 1;
+ data->type = type;
+ memcpy( data->apn, apn, sizeof(data->apn) );
+ }
+ return NULL;
+BadCommand:
+ return "ERROR: BAD COMMAND";
+}
+
+
+static const char*
+handleStartPDPContext( const char* cmd, AModem modem )
+{
+ /* XXX: TODO: handle PDP start appropriately */
+ /* for the moment, always return success */
+#if 0
+ AVoiceCall vcall = amodem_alloc_call( modem );
+ ACall call = (ACall) vcall;
+ if (call == NULL) {
+ return "ERROR: TOO MANY CALLS";
+ }
+ call->id = 1;
+ call->dir = A_CALL_OUTBOUND;
+ /* XXX: it would be better to delay this */
+ call->state = A_CALL_ACTIVE;
+ call->mode = A_CALL_DATA;
+ call->multi = 0;
+ strcpy( call->number, "012345" );
+#endif
+ return NULL;
+}
+
+
+static void
+remote_voice_call_event( void* _vcall, int success )
+{
+ AVoiceCall vcall = _vcall;
+ AModem modem = vcall->modem;
+
+ /* NOTE: success only means we could send the "gsm in new" command
+ * to the remote emulator, nothing more */
+
+ if (!success) {
+ /* aargh, the remote emulator probably quitted at that point */
+ amodem_free_call(modem, vcall);
+ amodem_send_calls_update(modem);
+ }
+}
+
+
+static void
+voice_call_event( void* _vcall )
+{
+ AVoiceCall vcall = _vcall;
+ ACall call = &vcall->call;
+
+ switch (call->state) {
+ case A_CALL_DIALING:
+ call->state = A_CALL_ALERTING;
+
+ if (vcall->is_remote) {
+ if ( remote_call_dial( call->number,
+ vcall->modem->base_port,
+ remote_voice_call_event, vcall ) < 0 )
+ {
+ /* we could not connect, probably because the corresponding
+ * emulator is not running, so simply destroy this call.
+ * XXX: should we send some sort of message to indicate BAD NUMBER ? */
+ /* it seems the Android code simply waits for changes in the list */
+ amodem_free_call( vcall->modem, vcall );
+ }
+ } else {
+ /* this is not a remote emulator number, so just simulate
+ * a small ringing delay */
+ sys_timer_set( vcall->timer, sys_time_ms() + CALL_DELAY_ALERT,
+ voice_call_event, vcall );
+ }
+ break;
+
+ case A_CALL_ALERTING:
+ call->state = A_CALL_ACTIVE;
+ break;
+
+ default:
+ assert( 0 && "unreachable event call state" );
+ }
+ amodem_send_calls_update(vcall->modem);
+}
+
+
+static const char*
+handleDial( const char* cmd, AModem modem )
+{
+ AVoiceCall vcall = amodem_alloc_call( modem );
+ ACall call = &vcall->call;
+ int len;
+
+ if (call == NULL)
+ return "ERROR: TOO MANY CALLS";
+
+ assert( cmd[0] == 'D' );
+ call->dir = A_CALL_OUTBOUND;
+ call->state = A_CALL_DIALING;
+ call->mode = A_CALL_VOICE;
+ call->multi = 0;
+
+ cmd += 1;
+ len = strlen(cmd);
+ if (len > 0 && cmd[len-1] == ';')
+ len--;
+ if (len >= sizeof(call->number))
+ len = sizeof(call->number)-1;
+
+ memcpy( call->number, cmd, len );
+ call->number[len] = 0;
+
+ vcall->is_remote = (remote_number_string_to_port(call->number) > 0);
+
+ vcall->timer = sys_timer_create();
+ sys_timer_set( vcall->timer, sys_time_ms() + CALL_DELAY_DIAL,
+ voice_call_event, vcall );
+
+ return NULL;
+}
+
+
+static const char*
+handleAnswer( const char* cmd, AModem modem )
+{
+ int nn;
+ for (nn = 0; nn < modem->call_count; nn++) {
+ AVoiceCall vcall = modem->calls + nn;
+ ACall call = &vcall->call;
+
+ if (cmd[0] == 'A') {
+ if (call->state == A_CALL_INCOMING) {
+ acall_set_state( vcall, A_CALL_ACTIVE );
+ }
+ else if (call->state == A_CALL_ACTIVE) {
+ acall_set_state( vcall, A_CALL_HELD );
+ }
+ } else if (cmd[0] == 'H') {
+ /* ATH: hangup, since user is busy */
+ if (call->state == A_CALL_INCOMING) {
+ amodem_free_call( modem, vcall );
+ break;
+ }
+ }
+ }
+ return NULL;
+}
+
+static const char*
+handleHangup( const char* cmd, AModem modem )
+{
+ if ( !memcmp(cmd, "+CHLD=", 6) ) {
+ int nn;
+ cmd += 6;
+ switch (cmd[0]) {
+ case '0': /* release all held, and set busy for waiting calls */
+ for (nn = 0; nn < modem->call_count; nn++) {
+ AVoiceCall vcall = modem->calls + nn;
+ ACall call = &vcall->call;
+ if (call->mode != A_CALL_VOICE)
+ continue;
+ if (call->state == A_CALL_HELD ||
+ call->state == A_CALL_WAITING ||
+ call->state == A_CALL_INCOMING) {
+ amodem_free_call(modem, vcall);
+ nn--;
+ }
+ }
+ break;
+
+ case '1':
+ if (cmd[1] == 0) { /* release all active, accept held one */
+ for (nn = 0; nn < modem->call_count; nn++) {
+ AVoiceCall vcall = modem->calls + nn;
+ ACall call = &vcall->call;
+ if (call->mode != A_CALL_VOICE)
+ continue;
+ if (call->state == A_CALL_ACTIVE) {
+ amodem_free_call(modem, vcall);
+ nn--;
+ }
+ else if (call->state == A_CALL_HELD ||
+ call->state == A_CALL_WAITING) {
+ acall_set_state( vcall, A_CALL_ACTIVE );
+ }
+ }
+ } else { /* release specific call */
+ int id = cmd[1] - '0';
+ AVoiceCall vcall = amodem_find_call( modem, id );
+ if (vcall != NULL)
+ amodem_free_call( modem, vcall );
+ }
+ break;
+
+ case '2':
+ if (cmd[1] == 0) { /* place all active on hold, accept held or waiting one */
+ for (nn = 0; nn < modem->call_count; nn++) {
+ AVoiceCall vcall = modem->calls + nn;
+ ACall call = &vcall->call;
+ if (call->mode != A_CALL_VOICE)
+ continue;
+ if (call->state == A_CALL_ACTIVE) {
+ acall_set_state( vcall, A_CALL_HELD );
+ }
+ else if (call->state == A_CALL_HELD ||
+ call->state == A_CALL_WAITING) {
+ acall_set_state( vcall, A_CALL_ACTIVE );
+ }
+ }
+ } else { /* place all active on hold, except a specific one */
+ int id = cmd[1] - '0';
+ for (nn = 0; nn < modem->call_count; nn++) {
+ AVoiceCall vcall = modem->calls + nn;
+ ACall call = &vcall->call;
+ if (call->mode != A_CALL_VOICE)
+ continue;
+ if (call->state == A_CALL_ACTIVE && call->id != id) {
+ acall_set_state( vcall, A_CALL_HELD );
+ }
+ }
+ }
+ break;
+
+ case '3': /* add a held call to the conversation */
+ for (nn = 0; nn < modem->call_count; nn++) {
+ AVoiceCall vcall = modem->calls + nn;
+ ACall call = &vcall->call;
+ if (call->mode != A_CALL_VOICE)
+ continue;
+ if (call->state == A_CALL_HELD) {
+ acall_set_state( vcall, A_CALL_ACTIVE );
+ break;
+ }
+ }
+ break;
+
+ case '4': /* connect the two calls */
+ for (nn = 0; nn < modem->call_count; nn++) {
+ AVoiceCall vcall = modem->calls + nn;
+ ACall call = &vcall->call;
+ if (call->mode != A_CALL_VOICE)
+ continue;
+ if (call->state == A_CALL_HELD) {
+ acall_set_state( vcall, A_CALL_ACTIVE );
+ break;
+ }
+ }
+ break;
+ }
+ }
+ else
+ return "ERROR: BAD COMMAND";
+
+ return NULL;
+}
+
+
+/* a function used to deal with a non-trivial request */
+typedef const char* (*ResponseHandler)(const char* cmd, AModem modem);
+
+static const struct {
+ const char* cmd; /* command coming from libreference-ril.so, if first
+ character is '!', then the rest is a prefix only */
+
+ const char* answer; /* default answer, NULL if needs specific handling or
+ if OK is good enough */
+
+ ResponseHandler handler; /* specific handler, ignored if 'answer' is not NULL,
+ NULL if OK is good enough */
+} sDefaultResponses[] =
+{
+ /* see onRadioPowerOn() */
+ { "%CPHS=1", NULL, NULL },
+ { "%CTZV=1", NULL, NULL },
+
+ /* see onSIMReady() */
+ { "+CSMS=1", "+CSMS: 1, 1, 1", NULL },
+ { "+CNMI=1,2,2,1,1", NULL, NULL },
+
+ /* see requestRadioPower() */
+ { "+CFUN=0", NULL, handleRadioPower },
+ { "+CFUN=1", NULL, handleRadioPower },
+
+ /* see requestOrSendPDPContextList() */
+ { "+CGACT?", "", handleListPDPContexts },
+
+ /* see requestOperator() */
+ { "+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS?", NULL, handleRequestOperator },
+
+ /* see requestQueryNetworkSelectionMode() */
+ { "!+COPS", NULL, handleOperatorSelection },
+
+ /* see requestGetCurrentCalls() */
+ { "+CLCC", NULL, handleListCurrentCalls },
+
+ /* see requestWriteSmsToSim() */
+ { "!+CMGW=", NULL, handleSendSMStoSIM },
+
+ /* see requestHangup() */
+ { "!+CHLD=", NULL, handleHangup },
+
+ /* see requestSignalStrength() */
+ { "+CSQ", "+CSQ: 7,99", NULL }, /* XXX: TODO: implement variable signal strength and error rates */
+
+ /* see requestRegistrationState() */
+ { "!+CREG", NULL, handleNetworkRegistration },
+ { "!+CGREG", NULL, handleNetworkRegistration },
+
+ /* see requestSendSMS() */
+ { "!+CMGS=", NULL, handleSendSMS },
+
+ /* see requestSetupDefaultPDP() */
+ { "%CPRIM=\"GMM\",\"CONFIG MULTISLOT_CLASS=<10>\"", NULL, NULL },
+ { "%DATA=2,\"UART\",1,,\"SER\",\"UART\",0", NULL, NULL },
+
+ { "!+CGDCONT=", NULL, handleDefinePDPContext },
+
+ { "+CGQREQ=1", NULL, NULL },
+ { "+CGQMIN=1", NULL, NULL },
+ { "+CGEREP=1,0", NULL, NULL },
+ { "+CGACT=1,0", NULL, NULL },
+ { "D*99***1#", NULL, handleStartPDPContext },
+
+ /* see requestDial() */
+ { "!D", NULL, handleDial }, /* the code says that success/error is ignored, the call state will
+ be polled through +CLCC instead */
+
+ /* see requestSMSAcknowledge() */
+ { "+CNMA=1", NULL, NULL },
+ { "+CNMA=2", NULL, NULL },
+
+ /* see requestSIM_IO() */
+ { "!+CRSM=", NULL, handleSIM_IO },
+
+ /* see onRequest() */
+ { "+CHLD=0", NULL, handleHangup },
+ { "+CHLD=1", NULL, handleHangup },
+ { "+CHLD=2", NULL, handleHangup },
+ { "+CHLD=3", NULL, handleHangup },
+ { "A", NULL, handleAnswer }, /* answer the call */
+ { "H", NULL, handleAnswer }, /* user is busy */
+ { "!+VTS=", NULL, handleSetDialTone },
+ { "+CIMI", OPERATOR_HOME_MCCMNC "000000000", NULL }, /* request internation subscriber identification number */
+ { "+CGSN", "000000000000000", NULL }, /* request model version */
+ { "+CUSD=2",NULL, NULL }, /* Cancel USSD */
+ { "+COPS=0", NULL, handleOperatorSelection }, /* set network selection to automatic */
+ { "!+CMGD=", NULL, handleDeleteSMSonSIM }, /* delete SMS on SIM */
+ { "!+CPIN=", NULL, handleChangeOrEnterPIN },
+
+ /* see getSIMStatus() */
+ { "+CPIN?", NULL, handleSIMStatusReq },
+ { "+CNMI?", "+CNMI: 1,2,2,1,1", NULL },
+
+ /* see isRadioOn() */
+ { "+CFUN?", NULL, handleRadioPowerReq },
+
+ /* see initializeCallback() */
+ { "E0Q0V1", NULL, NULL },
+ { "S0=0", NULL, NULL },
+ { "+CMEE=1", NULL, NULL },
+ { "+CREG=2", NULL, handleNetworkRegistration },
+ { "+CREG=1", NULL, handleNetworkRegistration },
+ { "+CGREG=1", NULL, handleNetworkRegistration },
+ { "+CCWA=1", NULL, NULL },
+ { "+CMOD=0", NULL, NULL },
+ { "+CMUT=0", NULL, NULL },
+ { "+CSSN=0,1", NULL, NULL },
+ { "+COLP=0", NULL, NULL },
+ { "+CSCS=\"HEX\"", NULL, NULL },
+ { "+CUSD=1", NULL, NULL },
+ { "+CGEREP=1,0", NULL, NULL },
+ { "+CMGF=0", NULL, handleEndOfInit }, /* now is a goof time to send the current tme and timezone */
+ { "%CPI=3", NULL, NULL },
+ { "%CSTAT=1", NULL, NULL },
+
+ /* end of list */
+ {NULL, NULL, NULL}
+};
+
+
+#define REPLY(str) do { const char* s = (str); R(">> %s\n", quote(s)); return s; } while (0)
+
+const char* amodem_send( AModem modem, const char* cmd )
+{
+ const char* answer;
+
+ if ( modem->wait_sms != 0 ) {
+ modem->wait_sms = 0;
+ R( "SMS<< %s\n", quote(cmd) );
+ answer = handleSendSMSText( cmd, modem );
+ REPLY(answer);
+ }
+
+ /* everything that doesn't start with 'AT' is not a command, right ? */
+ if ( cmd[0] != 'A' || cmd[1] != 'T' || cmd[2] == 0 ) {
+ /* R( "-- %s\n", quote(cmd) ); */
+ return NULL;
+ }
+ R( "<< %s\n", quote(cmd) );
+
+ cmd += 2;
+
+ /* TODO: implement command handling */
+ {
+ int nn, found = 0;
+
+ for (nn = 0; ; nn++) {
+ const char* scmd = sDefaultResponses[nn].cmd;
+
+ if (!scmd) /* end of list */
+ break;
+
+ if (scmd[0] == '!') { /* prefix match */
+ int len = strlen(++scmd);
+
+ if ( !memcmp( scmd, cmd, len ) ) {
+ found = 1;
+ break;
+ }
+ } else { /* full match */
+ if ( !strcmp( scmd, cmd ) ) {
+ found = 1;
+ break;
+ }
+ }
+ }
+
+ if ( !found )
+ {
+ D( "** UNSUPPORTED COMMAND **\n" );
+ REPLY( "ERROR: UNSUPPORTED" );
+ }
+ else
+ {
+ const char* answer = sDefaultResponses[nn].answer;
+ ResponseHandler handler = sDefaultResponses[nn].handler;
+
+ if ( answer != NULL ) {
+ REPLY( amodem_printf( modem, "%s\rOK", answer ) );
+ }
+
+ if (handler == NULL) {
+ REPLY( "OK" );
+ }
+
+ answer = handler( cmd, modem );
+ if (answer == NULL)
+ REPLY( "OK" );
+
+ if ( !memcmp( answer, "> ", 2 ) ||
+ !memcmp( answer, "ERROR", 5 ) ||
+ !memcmp( answer, "+CME ERROR", 6 ) )
+ {
+ REPLY( answer );
+ }
+
+ if (answer != modem->out_buff)
+ REPLY( amodem_printf( modem, "%s\rOK", answer ) );
+
+ strcat( modem->out_buff, "\rOK" );
+ REPLY( answer );
+ }
+ }
+}
diff --git a/telephony/android_modem.h b/telephony/android_modem.h
new file mode 100644
index 0000000..80d22c5
--- /dev/null
+++ b/telephony/android_modem.h
@@ -0,0 +1,137 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _android_modem_h_
+#define _android_modem_h_
+
+#include "sim_card.h"
+#include "sms.h"
+
+/** MODEM OBJECT
+ **/
+typedef struct AModemRec_* AModem;
+
+/* a function used by the modem to send unsolicited messages to the channel controller */
+typedef void (*AModemUnsolFunc)( void* opaque, const char* message );
+
+extern AModem amodem_create( int base_port, AModemUnsolFunc unsol_func, void* unsol_opaque );
+extern void amodem_destroy( AModem modem );
+
+/* send a command to the modem */
+extern const char* amodem_send( AModem modem, const char* cmd );
+
+/* simulate the receipt on an incoming SMS message */
+extern void amodem_receive_sms( AModem modem, SmsPDU pdu );
+
+/** RADIO STATE
+ **/
+typedef enum {
+ A_RADIO_STATE_OFF = 0, /* Radio explictly powered off (eg CFUN=0) */
+ A_RADIO_STATE_ON, /* Radio on */
+} ARadioState;
+
+extern ARadioState amodem_get_radio_state( AModem modem );
+extern void amodem_set_radio_state( AModem modem, ARadioState state );
+
+/** SIM CARD STATUS
+ **/
+extern ASimCard amodem_get_sim( AModem modem );
+
+/** VOICE AND DATA NETWORK REGISTRATION
+ **/
+
+/* 'stat' for +CREG/+CGREG commands */
+typedef enum {
+ A_REGISTRATION_UNREGISTERED = 0,
+ A_REGISTRATION_HOME = 1,
+ A_REGISTRATION_SEARCHING,
+ A_REGISTRATION_DENIED,
+ A_REGISTRATION_UNKNOWN,
+ A_REGISTRATION_ROAMING
+} ARegistrationState;
+
+typedef enum {
+ A_GPRS_NETWORK_UNKNOWN = 0,
+ A_GPRS_NETWORK_GPRS,
+ A_GPRS_NETWORK_EDGE,
+ A_GPRS_NETWORK_UMTS
+} AGprsNetworkType;
+
+extern ARegistrationState amodem_get_voice_registration( AModem modem );
+extern void amodem_set_voice_registration( AModem modem, ARegistrationState state );
+
+extern ARegistrationState amodem_get_data_registration( AModem modem );
+extern void amodem_set_data_registration( AModem modem, ARegistrationState state );
+extern void amodem_set_data_network_type( AModem modem, AGprsNetworkType type );
+
+extern AGprsNetworkType android_parse_network_type( const char* speed );
+
+
+/** OPERATOR NAMES
+ **/
+typedef enum {
+ A_NAME_LONG = 0,
+ A_NAME_SHORT,
+ A_NAME_NUMERIC,
+ A_NAME_MAX /* don't remove */
+} ANameIndex;
+
+/* retrieve operator name into user-provided buffer. returns number of writes written, including terminating zero */
+extern int amodem_get_operator_name ( AModem modem, ANameIndex index, char* buffer, int buffer_size );
+
+/* reset one operator name from a user-provided buffer, set buffer_size to -1 for zero-terminated strings */
+extern void amodem_set_operator_name( AModem modem, ANameIndex index, const char* buffer, int buffer_size );
+
+/** CALL STATES
+ **/
+
+typedef enum {
+ A_CALL_OUTBOUND = 0,
+ A_CALL_INBOUND = 1,
+} ACallDir;
+
+typedef enum {
+ A_CALL_ACTIVE = 0,
+ A_CALL_HELD,
+ A_CALL_DIALING,
+ A_CALL_ALERTING,
+ A_CALL_INCOMING,
+ A_CALL_WAITING
+} ACallState;
+
+typedef enum {
+ A_CALL_VOICE = 0,
+ A_CALL_DATA,
+ A_CALL_FAX,
+ A_CALL_UNKNOWN = 9
+} ACallMode;
+
+#define A_CALL_NUMBER_MAX_SIZE 16
+
+typedef struct {
+ int id;
+ ACallDir dir;
+ ACallState state;
+ ACallMode mode;
+ int multi;
+ char number[ A_CALL_NUMBER_MAX_SIZE+1 ];
+} ACallRec, *ACall;
+
+extern int amodem_get_call_count( AModem modem );
+extern ACall amodem_get_call( AModem modem, int index );
+extern ACall amodem_find_call_by_number( AModem modem, const char* number );
+extern int amodem_add_inbound_call( AModem modem, const char* number );
+extern int amodem_update_call( AModem modem, const char* number, ACallState state );
+extern int amodem_disconnect_call( AModem modem, const char* number );
+
+/**/
+
+#endif /* _android_modem_h_ */
diff --git a/telephony/gsm.c b/telephony/gsm.c
new file mode 100644
index 0000000..89ff79e
--- /dev/null
+++ b/telephony/gsm.c
@@ -0,0 +1,1217 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "gsm.h"
+#include <stdlib.h>
+#include <string.h>
+
+/** UTILITIES
+ **/
+byte_t
+gsm_int_to_bcdi( int value )
+{
+ return (byte_t)((value / 10) | ((value % 10) << 4));
+}
+
+int
+gsm_int_from_bcdi( byte_t val )
+{
+ int ret = 0;
+
+ if ((val & 0xf0) <= 0x90)
+ ret = (val >> 4);
+
+ if ((val & 0x0f) <= 0x90)
+ ret |= (val % 0xf)*10;
+
+ return ret;
+}
+
+
+static int
+gsm_bcdi_to_ascii( cbytes_t bcd, int bcdlen, bytes_t dst )
+{
+ static byte_t bcdichars[14] = "0123456789*#,N";
+
+ int result = 0;
+ int shift = 0;
+
+ while (bcdlen > 0) {
+ int c = (bcd[0] >> shift) & 0xf;
+
+ if (c == 0xf && bcdlen == 1)
+ break;
+
+ if (c < 14) {
+ if (dst) dst[result] = bcdichars[c];
+ result += 1;
+ }
+ bcdlen --;
+ shift += 4;
+ if (shift == 8) {
+ bcd++;
+ shift = 0;
+ }
+ }
+ return result;
+}
+
+
+static int
+gsm_bcdi_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst )
+{
+ cbytes_t end = ascii + asciilen;
+ int result = 0;
+ int phase = 0x01;
+
+ while (ascii < end) {
+ int c = *ascii++;
+
+ if (c == '*')
+ c = 11;
+ else if (c == '#')
+ c = 12;
+ else if (c == ',')
+ c = 13;
+ else if (c == 'N')
+ c = 14;
+ else {
+ c -= '0';
+ if ((unsigned)c >= 10)
+ break;
+ }
+ phase = (phase << 4) | c;
+ if (phase & 0x100) {
+ if (dst) dst[result] = (byte_t) phase;
+ result += 1;
+ phase = 0x01;
+ }
+ }
+ if (phase != 0x01) {
+ if (dst) dst[result] = (byte_t)( phase | 0xf0 );
+ result += 1;
+ }
+ return result;
+}
+
+
+int
+gsm_hexchar_to_int( char c )
+{
+ if ((unsigned)(c - '0') < 10)
+ return c - '0';
+ if ((unsigned)(c - 'a') < 6)
+ return 10 + (c - 'a');
+ if ((unsigned)(c - 'A') < 6)
+ return 10 + (c - 'A');
+ return -1;
+}
+
+int
+gsm_hexchar_to_int0( char c )
+{
+ int ret = gsm_hexchar_to_int(c);
+
+ return (ret < 0) ? 0 : ret;
+}
+
+int
+gsm_hex2_to_byte( const char* hex )
+{
+ int hi = gsm_hexchar_to_int(hex[0]);
+ int lo = gsm_hexchar_to_int(hex[1]);
+
+ if (hi < 0 || lo < 0)
+ return -1;
+
+ return ( (hi << 4) | lo );
+}
+
+int
+gsm_hex4_to_short( const char* hex )
+{
+ int hi = gsm_hex2_to_byte(hex);
+ int lo = gsm_hex2_to_byte(hex+2);
+
+ if (hi < 0 || lo < 0)
+ return -1;
+
+ return ((hi << 8) | lo);
+}
+
+int
+gsm_hex2_to_byte0( const char* hex )
+{
+ int hi = gsm_hexchar_to_int0(hex[0]);
+ int lo = gsm_hexchar_to_int0(hex[1]);
+
+ return (byte_t)( (hi << 4) | lo );
+}
+
+void
+gsm_hex_from_byte( char* hex, int val )
+{
+ static const char hexdigits[] = "0123456789abcdef";
+
+ hex[0] = hexdigits[(val >> 4) & 15];
+ hex[1] = hexdigits[val & 15];
+}
+
+void
+gsm_hex_from_short( char* hex, int val )
+{
+ gsm_hex_from_byte( hex, (val >> 8) );
+ gsm_hex_from_byte( hex+2, val );
+}
+
+
+
+/** HEX
+ **/
+void
+gsm_hex_to_bytes0( cbytes_t hex, int hexlen, bytes_t dst )
+{
+ int nn;
+
+ for (nn = 0; nn < hexlen/2; nn++ ) {
+ dst[nn] = (byte_t) gsm_hex2_to_byte0( (const char*)hex+2*nn );
+ }
+ if (hexlen & 1) {
+ dst[nn] = gsm_hexchar_to_int0( hex[2*nn] ) << 4;
+ }
+}
+
+int
+gsm_hex_to_bytes( cbytes_t hex, int hexlen, bytes_t dst )
+{
+ int nn;
+
+ if (hexlen & 1) /* must be even */
+ return -1;
+
+ for (nn = 0; nn < hexlen/2; nn++ ) {
+ int c = gsm_hex2_to_byte( (const char*)hex+2*nn );
+ if (c < 0) return -1;
+ dst[nn] = (byte_t) c;
+ }
+ return hexlen/2;
+}
+
+void
+gsm_hex_from_bytes( char* hex, cbytes_t src, int srclen )
+{
+ int nn;
+
+ for (nn = 0; nn < srclen; nn++) {
+ gsm_hex_from_byte( hex + 2*nn, src[nn] );
+ }
+}
+
+/** ROPES
+ **/
+
+void
+gsm_rope_init( GsmRope rope )
+{
+ rope->data = NULL;
+ rope->pos = 0;
+ rope->max = 0;
+ rope->error = 0;
+}
+
+void
+gsm_rope_init_alloc( GsmRope rope, int count )
+{
+ rope->data = rope->data0;
+ rope->pos = 0;
+ rope->max = sizeof(rope->data0);
+ rope->error = 0;
+
+ if (count > 0) {
+ rope->data = calloc( count, 1 );
+ rope->max = count;
+
+ if (rope->data == NULL) {
+ rope->error = 1;
+ rope->max = 0;
+ }
+ }
+}
+
+int
+gsm_rope_done( GsmRope rope )
+{
+ int result = rope->error;
+
+ if (rope->data && rope->data != rope->data0)
+ free(rope->data);
+
+ rope->data = NULL;
+ rope->pos = 0;
+ rope->max = 0;
+ rope->error = 0;
+
+ return result;
+}
+
+
+bytes_t
+gsm_rope_done_acquire( GsmRope rope, int *psize )
+{
+ bytes_t result = rope->data;
+
+ *psize = rope->pos;
+ if (result == rope->data0) {
+ result = malloc( rope->pos );
+ if (result != NULL)
+ memcpy( result, rope->data, rope->pos );
+ }
+ return result;
+}
+
+
+int
+gsm_rope_ensure( GsmRope rope, int new_count )
+{
+ if (rope->data != NULL) {
+ int old_max = rope->max;
+ bytes_t old_data = rope->data == rope->data0 ? NULL : rope->data;
+ int new_max = old_max;
+ bytes_t new_data;
+
+ while (new_max < new_count) {
+ new_max += (new_max >> 1) + 4;
+ }
+ new_data = realloc( old_data, new_max );
+ if (new_data == NULL) {
+ rope->error = 1;
+ return -1;
+ }
+ rope->data = new_data;
+ rope->max = new_max;
+ } else {
+ rope->max = new_count;
+ }
+ return 0;
+}
+
+static int
+gsm_rope_can_grow( GsmRope rope, int count )
+{
+ if (!rope->data || rope->error)
+ return 0;
+
+ if (rope->pos + count > rope->max)
+ {
+ if (rope->data == NULL)
+ rope->max = rope->pos + count;
+
+ else if (rope->error ||
+ gsm_rope_ensure( rope, rope->pos + count ) < 0)
+ return 0;
+ }
+ return 1;
+}
+
+void
+gsm_rope_add_c( GsmRope rope, char c )
+{
+ if (gsm_rope_can_grow(rope, 1)) {
+ rope->data[ rope->pos ] = (byte_t) c;
+ }
+ rope->pos += 1;
+}
+
+void
+gsm_rope_add( GsmRope rope, const void* buf, int buflen )
+{
+ if (gsm_rope_can_grow(rope, buflen)) {
+ memcpy( rope->data + rope->pos, (const char*)buf, buflen );
+ }
+ rope->pos += buflen;
+}
+
+void*
+gsm_rope_reserve( GsmRope rope, int count )
+{
+ void* result = NULL;
+
+ if (gsm_rope_can_grow(rope, count))
+ {
+ if (rope->data != NULL)
+ result = rope->data + rope->pos;
+ }
+ rope->pos += count;
+
+ return result;
+}
+
+/* skip a given number of Unicode characters in a utf-8 byte string */
+cbytes_t
+utf8_skip( cbytes_t utf8,
+ cbytes_t utf8end,
+ int count)
+{
+ cbytes_t p = utf8;
+ cbytes_t end = utf8end;
+
+ for ( ; count > 0; count-- ) {
+ int c;
+
+ if (p >= end)
+ break;
+
+ c = *p++;
+ if (c > 128) {
+ while (p < end && (p[0] & 0xc0) == 0x80)
+ p++;
+ }
+ }
+ return p;
+}
+
+
+static __inline__ int
+utf8_next( cbytes_t *pp, cbytes_t end )
+{
+ cbytes_t p = *pp;
+ int result = -1;
+
+ if (p < end) {
+ int c= *p++;
+ if (c >= 128) {
+ if ((c & 0xe0) == 0xc0)
+ c &= 0x1f;
+ else if ((c & 0xf0) == 0xe0)
+ c &= 0x0f;
+ else
+ c &= 0x07;
+
+ while (p < end && (p[0] & 0xc0) == 0x80) {
+ c = (c << 6) | (p[0] & 0x3f);
+ p ++;
+ }
+ }
+ result = c;
+ *pp = p;
+ }
+ return result;
+}
+
+
+__inline__ int
+utf8_write( bytes_t utf8, int offset, int v )
+{
+ int result;
+
+ if (v < 128) {
+ result = 1;
+ if (utf8)
+ utf8[offset] = (byte_t) v;
+ } else if (v < 0x800) {
+ result = 2;
+ if (utf8) {
+ utf8[offset+0] = (byte_t)( 0xc0 | (v >> 6) );
+ utf8[offset+1] = (byte_t)( 0x80 | (v & 0x3f) );
+ }
+ } else if (v < 0x10000) {
+ result = 3;
+ if (utf8) {
+ utf8[offset+0] = (byte_t)( 0xe0 | (v >> 12) );
+ utf8[offset+1] = (byte_t)( 0x80 | ((v >> 6) & 0x3f) );
+ utf8[offset+2] = (byte_t)( 0x80 | (v & 0x3f) );
+ }
+ } else {
+ result = 4;
+ if (utf8) {
+ utf8[offset+0] = (byte_t)( 0xf0 | ((v >> 18) & 0x7) );
+ utf8[offset+1] = (byte_t)( 0x80 | ((v >> 12) & 0x3f) );
+ utf8[offset+2] = (byte_t)( 0x80 | ((v >> 6) & 0x3f) );
+ utf8[offset+3] = (byte_t)( 0x80 | (v & 0x3f) );
+ }
+ }
+ return result;
+}
+
+static __inline__ int
+ucs2_write( bytes_t ucs2, int offset, int v )
+{
+ if (ucs2) {
+ ucs2[offset+0] = (byte_t) (v >> 8);
+ ucs2[offset+1] = (byte_t) (v);
+ }
+ return 2;
+}
+
+int
+utf8_check( cbytes_t p, int utf8len )
+{
+ cbytes_t end = p + utf8len;
+ int result = 0;
+
+ if (p) {
+ while (p < end) {
+ int c = *p++;
+ if (c >= 128) {
+ int len;
+ if ((c & 0xe0) == 0xc0) {
+ len = 1;
+ }
+ else if ((c & 0xf0) == 0xe0) {
+ len = 2;
+ }
+ else if ((c & 0xf8) == 0xf0) {
+ len = 3;
+ }
+ else
+ goto Exit; /* malformed utf-8 */
+
+ if (p+len > end) /* string too short */
+ goto Exit;
+
+ for ( ; len > 0; len--, p++ ) {
+ if ((p[0] & 0xc0) != 0x80)
+ goto Exit;
+ }
+ }
+ }
+ result = 1;
+ }
+Exit:
+ return result;
+}
+
+/** UCS2 to UTF8
+ **/
+
+/* convert a UCS2 string into a UTF8 byte string, assumes 'buf' is correctly sized */
+int
+ucs2_to_utf8( cbytes_t ucs2,
+ int ucs2len,
+ bytes_t buf )
+{
+ int nn;
+ int result = 0;
+
+ for (nn = 0; nn < ucs2len; ucs2 += 2, nn++) {
+ int c= (ucs2[0] << 8) | ucs2[1];
+ result += utf8_write(buf, result, c);
+ }
+ return result;
+}
+
+/* count the number of UCS2 chars contained in a utf8 byte string */
+int
+utf8_to_ucs2( cbytes_t utf8,
+ int utf8len,
+ bytes_t ucs2 )
+{
+ cbytes_t p = utf8;
+ cbytes_t end = p + utf8len;
+ int result = 0;
+
+ while (p < end) {
+ int c = utf8_next(&p, end);
+
+ if (c < 0)
+ break;
+
+ result += ucs2_write(ucs2, result, c);
+ }
+ return result/2;
+}
+
+
+
+/** GSM ALPHABET
+ **/
+
+#define GSM_7BITS_ESCAPE 0x1b
+#define GSM_7BITS_UNKNOWN 0
+
+static const unsigned short gsm7bits_to_unicode[128] = {
+ '@', 0xa3, '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec, 0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5,
+0x394, '_',0x3a6,0x393,0x39b,0x3a9,0x3a0,0x3a8,0x3a3,0x398,0x39e, 0, 0xc6, 0xe6, 0xdf, 0xc9,
+ ' ', '!', '"', '#', 0xa4, '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
+ 0xa1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0xc4, 0xd6,0x147, 0xdc, 0xa7,
+ 0xbf, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0,
+};
+
+static const unsigned short gsm7bits_extend_to_unicode[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\f', 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, '^', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, '{', '}', 0, 0, 0, 0, 0,'\\',
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[', '~', ']', 0,
+ '|', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,0x20ac, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+
+static int
+unichar_to_gsm7( int unicode )
+{
+ int nn;
+ for (nn = 0; nn < 128; nn++) {
+ if (gsm7bits_to_unicode[nn] == unicode) {
+ return nn;
+ }
+ }
+ return -1;
+}
+
+static int
+unichar_to_gsm7_extend( int unichar )
+{
+ int nn;
+ for (nn = 0; nn < 128; nn++) {
+ if (gsm7bits_extend_to_unicode[nn] == unichar) {
+ return nn;
+ }
+ }
+ return -1;
+}
+
+
+/* return the number of septets needed to encode a unicode charcode */
+static int
+unichar_to_gsm7_count( int unicode )
+{
+ int nn;
+
+ nn = unichar_to_gsm7(unicode);
+ if (nn >= 0)
+ return 1;
+
+ nn = unichar_to_gsm7_extend(unicode);
+ if (nn >= 0)
+ return 2;
+
+ return 0;
+}
+
+
+cbytes_t
+utf8_skip_gsm7( cbytes_t utf8, cbytes_t utf8end, int gsm7len )
+{
+ cbytes_t p = utf8;
+ cbytes_t end = utf8end;
+
+ while (gsm7len >0) {
+ cbytes_t q = p;
+ int c = utf8_next( &q, end );
+ int len;
+
+ if (c < 0)
+ break;
+
+ len = unichar_to_gsm7_count( c );
+ if (len == 0) /* unknown chars are replaced by spaces */
+ len = 1;
+
+ if (len > gsm7len)
+ break;
+
+ gsm7len -= len;
+ p = q;
+ }
+ return p;
+}
+
+
+int
+utf8_check_gsm7( cbytes_t utf8,
+ int utf8len )
+{
+ cbytes_t utf8end = utf8 + utf8len;
+
+ while (utf8 < utf8end) {
+ int c = utf8_next( &utf8, utf8end );
+ if (unichar_to_gsm7_count(c) == 0)
+ return 0;
+ }
+ return 1;
+}
+
+
+int
+utf8_from_gsm7( cbytes_t src,
+ int septet_offset,
+ int septet_count,
+ bytes_t utf8 )
+{
+ int shift = (septet_offset & 7);
+ int escaped = 0;
+ int result = 0;
+
+ src += (septet_offset >> 3);
+ for ( ; septet_count > 0; septet_count-- )
+ {
+ int c = (src[0] >> shift) & 0x7f;
+ int v;
+
+ if (shift > 1) {
+ c = ((src[1] << (8-shift)) | c) & 0x7f;
+ }
+
+ if (escaped) {
+ v = gsm7bits_extend_to_unicode[c];
+ } else if (c == GSM_7BITS_ESCAPE) {
+ escaped = 1;
+ goto NextSeptet;
+ } else {
+ v = gsm7bits_to_unicode[c];
+ }
+
+ result += utf8_write( utf8, result, v );
+
+ NextSeptet:
+ shift += 7;
+ if (shift >= 8) {
+ shift -= 8;
+ src += 1;
+ }
+ }
+ return result;
+}
+
+
+int
+utf8_from_gsm8( cbytes_t src, int count, bytes_t utf8 )
+{
+ int result = 0;
+ int escaped = 0;
+
+
+ for ( ; count > 0; count-- )
+ {
+ int c = *src++;
+
+ if (c == 0xff)
+ break;
+
+ if (c == GSM_7BITS_ESCAPE) {
+ if (escaped) { /* two escape characters => one space */
+ c = 0x20;
+ escaped = 0;
+ } else {
+ escaped = 1;
+ continue;
+ }
+ }
+ else
+ {
+ if (c >= 0x80) {
+ c = 0x20;
+ escaped = 0;
+ } else if (escaped) {
+ c = gsm7bits_extend_to_unicode[c];
+ } else
+ c = gsm7bits_to_unicode[c];
+ }
+
+ result += utf8_write( utf8, result, c );
+ }
+ return result;
+}
+
+/* convert a GSM 7-bit message into a unicode character array
+ * the 'dst' array must contain at least 160 chars. the function
+ * returns the number of characters decoded
+ *
+ * assumes the 'dst' array has at least septet_count items, returns the
+ * number of unichars really written
+ */
+int
+ucs2_from_gsm7( bytes_t ucs2,
+ cbytes_t src,
+ int septet_offset,
+ int septet_count )
+{
+ const unsigned char* p = src + (septet_offset >> 3);
+ int shift = (septet_offset & 7);
+ int escaped = 0;
+ int result = 0;
+
+ for ( ; septet_count > 0; septet_count-- )
+ {
+ unsigned val = (p[0] >> shift) & 0x7f;
+
+ if (shift > 1)
+ val = (val | (p[1] << (8-shift))) & 0x7f;
+
+ if (escaped) {
+ int c = gsm7bits_to_unicode[val];
+
+ result += ucs2_write(ucs2, result, c);
+ escaped = 0;
+ }
+ else if (val == GSM_7BITS_ESCAPE) {
+ escaped = 1;
+ }
+ else {
+ val = gsm7bits_extend_to_unicode[val];
+ if (val == 0)
+ val = 0x20;
+
+ result += ucs2_write( ucs2, result, val );
+ }
+ }
+ return result/2;
+}
+
+
+/* count the number of septets required to write a utf8 string */
+static int
+utf8_to_gsm7_count( cbytes_t utf8, int utf8len )
+{
+ cbytes_t utf8end = utf8 + utf8len;
+ int result = 0;
+
+ while ( utf8 < utf8end ) {
+ int len;
+ int c = utf8_next( &utf8, utf8end );
+
+ if (c < 0)
+ break;
+
+ len = unichar_to_gsm7_count(c);
+ if (len == 0) /* replace non-representables with space */
+ len = 1;
+
+ result += len;
+ }
+ return result;
+}
+
+typedef struct {
+ bytes_t dst;
+ unsigned pad;
+ int bits;
+ int offset;
+} BWriterRec, *BWriter;
+
+static void
+bwriter_init( BWriter writer, bytes_t dst, int start )
+{
+ int shift = start & 7;
+
+ writer->dst = dst + (start >> 3);
+ writer->pad = 0;
+ writer->bits = shift;
+ writer->offset = start;
+
+ if (shift > 0) {
+ writer->pad = writer->dst[0] & ~(0xFF << shift);
+ }
+}
+
+static void
+bwriter_add7( BWriter writer, unsigned value )
+{
+ writer->pad |= (unsigned)(value << writer->bits);
+ writer->bits += 7;
+ if (writer->bits >= 8) {
+ writer->dst[0] = (byte_t)writer->pad;
+ writer->bits -= 8;
+ writer->pad >>= 8;
+ writer->dst += 1;
+ }
+ writer->offset += 7;
+}
+
+static int
+bwriter_done( BWriter writer )
+{
+ if (writer->bits > 0) {
+ writer->dst[0] = (byte_t)writer->pad;
+ writer->pad = 0;
+ writer->bits = 0;
+ writer->dst += 1;
+ }
+ return writer->offset;
+}
+
+/* convert a utf8 string to a gsm7 byte string - return the number of septets written */
+int
+utf8_to_gsm7( cbytes_t utf8, int utf8len, bytes_t dst, int offset )
+{
+ const unsigned char* utf8end = utf8 + utf8len;
+ BWriterRec writer[1];
+
+ if (dst == NULL)
+ return utf8_to_gsm7_count(utf8, utf8len);
+
+ bwriter_init( writer, dst, offset );
+ while ( utf8 < utf8end ) {
+ int c = utf8_next( &utf8, utf8end );
+ int nn;
+
+ if (c < 0)
+ break;
+
+ nn = unichar_to_gsm7(c);
+ if (nn >= 0) {
+ bwriter_add7( writer, nn );
+ continue;
+ }
+
+ nn = unichar_to_gsm7_extend(c);
+ if (nn >= 0) {
+ bwriter_add7( writer, GSM_7BITS_ESCAPE );
+ bwriter_add7( writer, nn );
+ continue;
+ }
+
+ /* unknown => replaced by space */
+ bwriter_add7( writer, 0x20 );
+ }
+ return bwriter_done( writer );
+}
+
+
+int
+utf8_to_gsm8( cbytes_t utf8, int utf8len, bytes_t dst )
+{
+ const unsigned char* utf8end = utf8 + utf8len;
+ int result = 0;
+
+ while ( utf8 < utf8end ) {
+ int c = utf8_next( &utf8, utf8end );
+ int nn;
+
+ if (c < 0)
+ break;
+
+ nn = unichar_to_gsm7(c);
+ if (nn >= 0) {
+ if (dst)
+ dst[result] = (byte_t)nn;
+ result += 1;
+ continue;
+ }
+
+ nn = unichar_to_gsm7_extend(c);
+ if (nn >= 0) {
+ if (dst) {
+ dst[result+0] = (byte_t) GSM_7BITS_ESCAPE;
+ dst[result+1] = (byte_t) nn;
+ }
+ result += 2;
+ continue;
+ }
+
+ /* unknown => space */
+ if (dst)
+ dst[result] = 0x20;
+ result += 1;
+ }
+ return result;
+}
+
+
+int
+ucs2_to_gsm7( cbytes_t ucs2, int ucs2len, bytes_t dst, int offset )
+{
+ const unsigned char* ucs2end = ucs2 + ucs2len*2;
+ BWriterRec writer[1];
+
+ bwriter_init( writer, dst, offset );
+ while ( ucs2 < ucs2end ) {
+ int c = *ucs2++;
+ int nn;
+
+ for (nn = 0; nn < 128; nn++) {
+ if ( gsm7bits_to_unicode[nn] == c ) {
+ bwriter_add7( writer, nn );
+ goto NextUnicode;
+ }
+ }
+ for (nn = 0; nn < 128; nn++) {
+ if ( gsm7bits_extend_to_unicode[nn] == c ) {
+ bwriter_add7( writer, GSM_7BITS_ESCAPE );
+ bwriter_add7( writer, nn );
+ goto NextUnicode;
+ }
+ }
+
+ /* unknown */
+ bwriter_add7( writer, 0x20 );
+
+ NextUnicode:
+ ;
+ }
+ return bwriter_done( writer );
+}
+
+
+int
+ucs2_to_gsm8( cbytes_t ucs2, int ucs2len, bytes_t dst )
+{
+ const unsigned char* ucs2end = ucs2 + ucs2len*2;
+ bytes_t dst0 = dst;
+
+ while ( ucs2 < ucs2end ) {
+ int c = *ucs2++;
+ int nn;
+
+ for (nn = 0; nn < 128; nn++) {
+ if ( gsm7bits_to_unicode[nn] == c ) {
+ *dst++ = (byte_t)nn;
+ goto NextUnicode;
+ }
+ }
+ for (nn = 0; nn < 128; nn++) {
+ if ( gsm7bits_extend_to_unicode[nn] == c ) {
+ dst[0] = (byte_t) GSM_7BITS_ESCAPE;
+ dst[1] = (byte_t) nn;
+ dst += 2;
+ goto NextUnicode;
+ }
+ }
+
+ /* unknown */
+ *dst++ = 0x20;
+
+ NextUnicode:
+ ;
+ }
+ return (dst - dst0);
+}
+
+int
+gsm_bcdnum_to_ascii( cbytes_t bcd, int count, bytes_t dst )
+{
+ int result = 0;
+ int shift = 0;
+
+ while (count > 0) {
+ int c = (bcd[0] >> shift) & 0xf;
+
+ if (c == 15 && count == 1) /* ignore trailing 0xf */
+ break;
+
+ if (c >= 14)
+ c = 0;
+
+ if (dst) dst[result] = "0123456789*#,N"[c];
+ result += 1;
+
+ shift += 4;
+ if (shift == 8) {
+ shift = 0;
+ bcd += 1;
+ }
+ }
+ return result;
+}
+
+
+int
+gsm_bcdnum_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst )
+{
+ cbytes_t end = ascii + asciilen;
+ int result = 0;
+ int phase = 0x01;
+
+ while (ascii < end) {
+ int c = *ascii++;
+
+ if (c == '*')
+ c = 10;
+ else if (c == '#')
+ c = 11;
+ else if (c == ',')
+ c = 12;
+ else if (c == 'N')
+ c = 13;
+ else {
+ c -= '0';
+ if ((unsigned)c >= 10U)
+ return -1;
+ }
+ phase = (phase << 4) | c;
+ result += 1;
+ if (phase & 0x100) {
+ if (dst) dst[result/2] = (byte_t) phase;
+ phase = 0x01;
+ }
+ }
+
+ if (result & 1) {
+ if (dst) dst[result/2] = (byte_t)(phase | 0xf0);
+ }
+ return result;
+}
+
+/** ADN: Abbreviated Dialing Number
+ **/
+
+#define ADN_FOOTER_SIZE 14
+#define ADN_OFFSET_NUMBER_LENGTH 0
+#define ADN_OFFSET_TON_NPI 1
+#define ADN_OFFSET_NUMBER_START 2
+#define ADN_OFFSET_NUMBER_END 11
+#define ADN_OFFSET_CAPABILITY_ID 12
+#define ADN_OFFSET_EXTENSION_ID 13
+
+/* see 10.5.1 of 3GPP 51.011 */
+static int
+sim_adn_alpha_to_utf8( cbytes_t alpha, cbytes_t end, bytes_t dst )
+{
+ int result = 0;
+
+ /* ignore trailing 0xff */
+ while (alpha < end && end[-1] == 0xff)
+ end--;
+
+ if (alpha >= end)
+ return 0;
+
+ if (alpha[0] == 0x80) { /* UCS/2 source encoding */
+ alpha += 1;
+ result = ucs2_to_utf8( alpha, (end-alpha)/2, dst );
+ }
+ else
+ {
+ int is_ucs2 = 0;
+ int len = 0, base = 0;
+
+ if (alpha+3 <= end && alpha[0] == 0x81) {
+ is_ucs2 = 1;
+ len = alpha[1];
+ base = alpha[2] << 7;
+ alpha += 3;
+ if (len > end-alpha)
+ len = end-alpha;
+ } else if (alpha+4 <= end && alpha[0] == 0x82) {
+ is_ucs2 = 1;
+ len = alpha[1];
+ base = (alpha[2] << 8) | alpha[3];
+ alpha += 4;
+ if (len > end-alpha)
+ len = end-alpha;
+ }
+
+ if (is_ucs2) {
+ end = alpha + len;
+ while (alpha < end) {
+ int c = alpha[0];
+ if (c >= 0x80) {
+ result += utf8_write(dst, result, base + (c & 0x7f));
+ alpha += 1;
+ } else {
+ /* GSM character set */
+ int count;
+ for (count = 0; alpha+count < end && alpha[count] < 128; count++)
+ ;
+ result += utf8_from_gsm8(alpha, count, (dst ? dst+result : NULL));
+ alpha += count;
+ }
+ }
+ }
+ else {
+ result = utf8_from_gsm8(alpha, end-alpha, dst);
+ }
+ }
+ return result;
+}
+
+static int
+sim_adn_alpha_from_utf8( cbytes_t utf8, int utf8len, bytes_t dst )
+{
+ int result = 0;
+
+ if (utf8_check_gsm7(utf8, utf8len)) {
+ /* GSM 7-bit compatible, encode directly as 8-bit string */
+ result = utf8_to_gsm8(utf8, utf8len, dst);
+ } else {
+ /* otherwise, simply try UCS-2 encoding, nothing more serious at the moment */
+ if (dst) {
+ dst[0] = 0x80;
+ }
+ result = 1 + utf8_to_ucs2(utf8, utf8len, dst ? (dst+1) : NULL)*2;
+ }
+ return result;
+}
+
+int
+sim_adn_record_from_bytes( SimAdnRecord rec, cbytes_t data, int len )
+{
+ cbytes_t end = data + len;
+ cbytes_t footer = end - ADN_FOOTER_SIZE;
+ int num_len;
+
+ rec->adn.alpha[0] = 0;
+ rec->adn.number[0] = 0;
+ rec->ext_record = 0xff;
+
+ if (len < ADN_FOOTER_SIZE)
+ return -1;
+
+ /* alpha is optional */
+ if (len > ADN_FOOTER_SIZE) {
+ cbytes_t dataend = data + len - ADN_FOOTER_SIZE;
+ int count = sim_adn_alpha_to_utf8(data, dataend, NULL);
+
+ if (count > sizeof(rec->adn.alpha)-1) /* too long */
+ return -1;
+
+ sim_adn_alpha_to_utf8(data, dataend, rec->adn.alpha);
+ rec->adn.alpha[count] = 0;
+ }
+
+ num_len = footer[ADN_OFFSET_NUMBER_LENGTH];
+ if (num_len > 11)
+ return -1;
+
+ /* decode TON and number to ASCII, NOTE: this is lossy !! */
+ {
+ int ton = footer[ADN_OFFSET_TON_NPI];
+ bytes_t number = (bytes_t) rec->adn.number;
+ int len = sizeof(rec->adn.number)-1;
+ int count;
+
+ if (ton != 0x81 && ton != 0x91)
+ return -1;
+
+ if (ton == 0x91) {
+ *number++ = '+';
+ len -= 1;
+ }
+
+ count = gsm_bcdnum_to_ascii( footer + ADN_OFFSET_NUMBER_START,
+ num_len*2, number );
+ number[count] = 0;
+ }
+ return 0;
+}
+
+int
+sim_adn_record_to_bytes( SimAdnRecord rec, bytes_t data, int datalen )
+{
+ bytes_t end = data + datalen;
+ bytes_t footer = end - ADN_FOOTER_SIZE;
+ int ton = 0x81;
+ cbytes_t number = (cbytes_t) rec->adn.number;
+
+ if (number[0] == '+') {
+ ton = 0x91;
+ number += 1;
+ }
+ footer[0] = (strlen((const char*)number)+1)/2 + 1;
+ /* XXXX: TODO */
+ return 0;
+}
diff --git a/telephony/gsm.h b/telephony/gsm.h
new file mode 100644
index 0000000..f799dea
--- /dev/null
+++ b/telephony/gsm.h
@@ -0,0 +1,196 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _android_gsm_h
+#define _android_gsm_h
+
+/** USEFUL TYPES
+ **/
+
+typedef unsigned char byte_t;
+typedef byte_t* bytes_t;
+typedef const byte_t* cbytes_t;
+
+/** BCD
+ **/
+
+/* convert a 8-bit value into the corresponding nibble-bcd byte */
+extern byte_t gsm_int_to_bcdi( int value );
+
+/* convert a nibble-bcd byte into an int, invalid nibbles are silently converted to 0 */
+extern int gsm_int_from_bcdi( byte_t value );
+
+/** HEX
+ **/
+
+/* try to convert a hex string into a byte string, assumes 'dst' is properly sized, and hexlen is even.
+ * returns the number of bytes on exit, or -1 in case of badly formatted data */
+extern int gsm_hex_to_bytes ( cbytes_t hex, int hexlen, bytes_t dst );
+
+/* convert a hex string into a byte string, assumes 'dst' is properly sized, and hexlen is even.
+ * no checks are performed */
+extern void gsm_hex_to_bytes0 ( cbytes_t hex, int hexlen, bytes_t dst );
+
+/* convert a byte string into a hex string, assumes 'hex' is properly sized */
+extern void gsm_hex_from_bytes( char* hex, cbytes_t src, int srclen );
+
+/* convert a hexchar to an int, returns -1 on error */
+extern int gsm_hexchar_to_int( char c );
+
+/* convert a hexchar to an int, returns 0 on error */
+extern int gsm_hexchar_to_int0( char c );
+
+/* convert a 2-char hex value into an int, returns -1 on error */
+extern int gsm_hex2_to_byte( const char* hex );
+
+/* convert a 2-char hex value into an int, returns 0 on error */
+extern int gsm_hex2_to_byte0( const char* hex );
+
+/* convert a 4-char hex value into an int, returns -1 on error */
+extern int gsm_hex4_to_short( const char* hex );
+
+/* convert a 4-char hex value into an int, returns 0 on error */
+extern int gsm_hex4_to_short0( const char* hex );
+
+/* write a byte to a 2-byte hex string */
+extern void gsm_hex_from_byte( char* hex, int val );
+
+extern void gsm_hex_from_short( char* hex, int val );
+
+/** UTF-8 and GSM Alphabet
+ **/
+
+/* check that a given utf8 string is well-formed, returns 1 on success, 0 otherwise */
+extern int utf8_check( cbytes_t utf8, int utf8len );
+
+/* check that all characters in a given utf8 string can be encoded into the GSM alphabet.
+ returns 1 if TRUE, 0 otherwise */
+extern int utf8_check_gsm7( cbytes_t utf8, int utf8len );
+
+/* try to skip enough utf8 characters to generate gsm7len GSM septets */
+extern cbytes_t utf8_skip_gsm7( cbytes_t utf8, cbytes_t utf8end, int gsm7len );
+
+/* convert a utf-8 string into a GSM septet string, assumes 'dst' is NULL or is properly sized,
+ and that all characters are representable. 'offset' is the starting bit offset in 'dst'.
+ non-representable characters are replaced by spaces.
+ returns the number of septets, */
+extern int utf8_to_gsm7( cbytes_t utf8, int utf8len, bytes_t dst, int offset );
+
+/* convert a utf8 string into an array of 8-bit unpacked GSM septets,
+ * assumes 'dst' is NULL or is properly sized, returns the number of GSM bytes */
+extern int utf8_to_gsm8( cbytes_t utf8, int utf8len, bytes_t dst );
+
+/* convert a GSM septets string into a utf-8 byte string. assumes that 'utf8' is NULL or properly
+ sized. 'offset' is the starting bit offset in 'src', 'count' is the number of input septets.
+ return the number of utf8 bytes. */
+extern int utf8_from_gsm7( cbytes_t src, int offset, int count, bytes_t utf8 );
+
+/* convert an unpacked 8-bit GSM septets string into a utf-8 byte string. assumes that 'utf8'
+ is NULL or properly sized. 'count' is the number of input bytes.
+ returns the number of utf8 bytes */
+extern int utf8_from_gsm8( cbytes_t src, int count, bytes_t utf8 );
+
+
+/** UCS-2 and GSM Alphabet
+ **
+ ** Note that here, 'ucs2' really refers to non-aligned UCS2-BE, as used by the GSM standard
+ **/
+
+/* check that all characters in a given ucs2 string can be encoded into the GSM alphabet.
+ returns 1 if TRUE, 0 otherwise */
+extern int ucs2_check_gsm7( cbytes_t ucs2, int ucs2len );
+
+/* convert a ucs2 string into a GSM septet string, assumes 'dst' is NULL or properly sized,
+ 'offset' is the starting bit offset in 'dst'. non-representable characters are replaced
+ by spaces. returns the number of septets */
+extern int ucs2_to_gsm7( cbytes_t ucs2, int ucs2len, bytes_t dst, int offset );
+
+/* convert a ucs2 string into a GSM septet string, assumes 'dst' is NULL or properly sized,
+ non-representable characters are replaced by spaces. returns the number of bytes */
+extern int ucs2_to_gsm8( cbytes_t ucs2, int ucs2len, bytes_t dst );
+
+/* convert a GSM septets string into a ucs2 string. assumes that 'ucs2' is NULL or
+ properly sized. 'offset' is the starting bit offset in 'src', 'count' is the number
+ of input septets. return the number of ucs2 characters (not bytes) */
+extern int ucs2_from_gsm7( bytes_t ucs2, cbytes_t src, int offset, int count );
+
+/* convert an 8-bit unpacked GSM septets string into a ucs2 string. assumes that 'ucs2'
+ is NULL or properly sized. 'count' is the number of input septets. return the number
+ of ucs2 characters (not bytes) */
+extern int ucs2_from_gsm8( bytes_t ucs2, cbytes_t src, int count );
+
+
+/** UCS2 to/from UTF8
+ **/
+
+/* convert a ucs2 string into a utf8 byte string, assumes 'utf8' NULL or properly sized.
+ returns the number of utf8 bytes*/
+extern int ucs2_to_utf8( cbytes_t ucs2, int ucs2len, bytes_t utf8 );
+
+/* convert a utf8 byte string into a ucs2 string, assumes 'ucs2' NULL or properly sized.
+ returns the number of ucs2 chars */
+extern int utf8_to_ucs2( cbytes_t utf8, int utf8len, bytes_t ucs2 );
+
+/* try to skip a given number of characters in a utf-8 byte string, return new position */
+extern cbytes_t utf8_skip( cbytes_t utf8, cbytes_t utf8end, int count);
+
+/** Dial Numbers: TON byte + 'count' bcd numbers
+ **/
+
+/* convert a bcd-coded GSM dial number into an ASCII string (not zero-terminated)
+ assumes 'dst' is NULL or properly sized, returns 0 in case of success, -1 in case of error.
+ 'num_digits' is the number of digits, not input bytes. a trailing 0xf0 is ignored automatically
+ return the number of ASCII chars */
+extern int gsm_bcdnum_to_ascii ( cbytes_t bcd, int num_digits, bytes_t dst );
+
+/* convert an ASCII dial-number into a bcd-coded string, returns the number of 4-bit nibbles written, */
+extern int gsm_bcdnum_from_ascii( cbytes_t ascii, int asciilen, bytes_t dst );
+
+/** ADN: Abbreviated Dialing Numbers
+ **/
+#define SIM_ADN_MAX_ALPHA 20 /* maximum number of characters in ADN alpha tag */
+#define SIM_ADN_MAX_NUMBER 20 /* maximum digits in ADN number */
+
+typedef struct {
+ byte_t alpha [ SIM_ADN_MAX_ALPHA*3+1 ]; /* alpha tag in zero-terminated utf-8 */
+ char number[ SIM_ADN_MAX_NUMBER+1 ]; /* dialing number in zero-terminated ASCII */
+}
+SimAdnRec, *SimAdn;
+
+typedef struct {
+ SimAdnRec adn;
+ byte_t ext_record; /* 0 or 0xFF means no extension */
+}
+SimAdnRecordRec, *SimAdnRecord;
+
+extern int sim_adn_record_from_bytes( SimAdnRecord rec, cbytes_t data, int datalen );
+extern int sim_adn_record_to_bytes ( SimAdnRecord rec, bytes_t data, int datalen );
+
+/** ROPES
+ **/
+
+typedef struct {
+ bytes_t data;
+ int max;
+ int pos;
+ int error;
+ unsigned char data0[16];
+} GsmRopeRec, *GsmRope;
+
+extern void gsm_rope_init( GsmRope rope );
+extern void gsm_rope_init_alloc( GsmRope rope, int alloc );
+extern int gsm_rope_done( GsmRope rope );
+extern bytes_t gsm_rope_done_acquire( GsmRope rope, int *psize );
+extern void gsm_rope_add_c( GsmRope rope, char c );
+extern void gsm_rope_add( GsmRope rope, const void* str, int len );
+extern void* gsm_rope_reserve( GsmRope rope, int len );
+
+#endif /* _android_gsm_h */
diff --git a/telephony/modem_driver.c b/telephony/modem_driver.c
new file mode 100644
index 0000000..7de475f
--- /dev/null
+++ b/telephony/modem_driver.c
@@ -0,0 +1,147 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+/* implement the modem character device for Android within the QEMU event loop.
+ * it communicates through a serial port with "rild" (Radio Interface Layer Daemon)
+ * on the emulated device.
+ */
+#include "modem_driver.h"
+
+#define xxDEBUG
+
+#ifdef DEBUG
+# include <stdio.h>
+# define D(...) ( fprintf( stderr, __VA_ARGS__ ) )
+#else
+# define D(...) ((void)0)
+#endif
+
+AModem android_modem;
+CharDriverState* android_modem_cs;
+
+typedef struct {
+ CharDriverState* cs;
+ AModem modem;
+ char in_buff[ 1024 ];
+ int in_pos;
+ int in_sms;
+} ModemDriver;
+
+/* send unsollicited messages to the device */
+static void
+modem_driver_unsol( void* _md, const char* message)
+{
+ ModemDriver* md = _md;
+ int len = strlen(message);
+
+ qemu_chr_write(md->cs, (const uint8_t*)message, len);
+}
+
+static int
+modem_driver_can_read( void* _md )
+{
+ ModemDriver* md = _md;
+ int ret = sizeof(md->in_buff) - md->in_pos;
+
+ return ret;
+}
+
+/* despite its name, this function is called when the device writes to the modem */
+static void
+modem_driver_read( void* _md, const uint8_t* src, int len )
+{
+ ModemDriver* md = _md;
+ const uint8_t* end = src + len;
+ int nn;
+
+ D( "%s: reading %d from %p bytes:", __FUNCTION__, len, src );
+ for (nn = 0; nn < len; nn++) {
+ int c = src[nn];
+ if (c >= 32 && c < 127)
+ D( "%c", c );
+ else if (c == '\n')
+ D( "<LF>" );
+ else if (c == '\r')
+ D( "<CR>" );
+ else
+ D( "\\x%02x", c );
+ }
+ D( "\n" );
+
+ for ( ; src < end; src++ ) {
+ char c = src[0];
+
+ if (md->in_sms) {
+ if (c != 26)
+ goto AppendChar;
+
+ md->in_buff[ md->in_pos ] = c;
+ md->in_pos++;
+ md->in_sms = 0;
+ c = '\n';
+ }
+
+ if (c == '\n' || c == '\r') {
+ const char* answer;
+
+ if (md->in_pos == 0) /* skip empty lines */
+ continue;
+
+ md->in_buff[ md->in_pos ] = 0;
+ md->in_pos = 0;
+
+ D( "%s: << %s\n", __FUNCTION__, md->in_buff );
+ answer = amodem_send(android_modem, md->in_buff);
+ if (answer != NULL) {
+ D( "%s: >> %s\n", __FUNCTION__, answer );
+ len = strlen(answer);
+ if (len == 2 && answer[0] == '>' && answer[1] == ' ')
+ md->in_sms = 1;
+
+ qemu_chr_write(md->cs, (const uint8_t*)answer, len);
+ qemu_chr_write(md->cs, "\r", 1);
+ } else
+ D( "%s: -- NO ANSWER\n", __FUNCTION__ );
+
+ continue;
+ }
+ AppendChar:
+ md->in_buff[ md->in_pos++ ] = c;
+ if (md->in_pos == sizeof(md->in_buff)) {
+ /* input is too long !! */
+ md->in_pos = 0;
+ }
+ }
+ D( "%s: done\n", __FUNCTION__ );
+}
+
+
+static void
+modem_driver_init( int base_port, ModemDriver* dm, CharDriverState* cs )
+{
+ dm->cs = cs;
+ dm->in_pos = 0;
+ dm->in_sms = 0;
+ dm->modem = amodem_create( base_port, modem_driver_unsol, dm );
+
+ qemu_chr_add_read_handler( cs, modem_driver_can_read, modem_driver_read, dm );
+}
+
+
+void android_modem_init( int base_port )
+{
+ static ModemDriver modem_driver[1];
+
+ if (android_modem_cs != NULL) {
+ modem_driver_init( base_port, modem_driver, android_modem_cs );
+ android_modem = modem_driver->modem;
+ }
+}
diff --git a/telephony/modem_driver.h b/telephony/modem_driver.h
new file mode 100644
index 0000000..9acf23f
--- /dev/null
+++ b/telephony/modem_driver.h
@@ -0,0 +1,29 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _modem_driver_h
+#define _modem_driver_h
+
+#include "android_modem.h"
+#include "vl.h"
+
+/** in telephony/modem_driver.c */
+/* this is the internal character driver used to communicate with the
+ * emulated GSM modem. see qemu_chr_open() in vl.c */
+extern CharDriverState* android_modem_cs;
+
+/* the emulated GSM modem itself */
+extern AModem android_modem;
+
+/* must be called before the VM runs if there is a modem to emulate */
+extern void android_modem_init( int base_port );
+
+#endif /* _modem_driver_h */
diff --git a/telephony/remote_call.c b/telephony/remote_call.c
new file mode 100644
index 0000000..d5b58eb
--- /dev/null
+++ b/telephony/remote_call.c
@@ -0,0 +1,429 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "remote_call.h"
+#include "android_utils.h"
+#include "sysdeps.h"
+#include "gsm.h"
+#include "android.h"
+#include "sockets.h"
+#include <stdlib.h>
+
+#define DEBUG 1
+
+#if 1
+# define D_ACTIVE VERBOSE_CHECK(modem)
+#else
+# define D_ACTIVE DEBUG
+#endif
+
+#if 1
+# define S_ACTIVE VERBOSE_CHECK(socket)
+#else
+# define S_ACTIVE DEBUG
+#endif
+
+#if DEBUG
+# include <stdio.h>
+# define D(...) do { if (D_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0)
+# define S(...) do { if (S_ACTIVE) fprintf( stderr, __VA_ARGS__ ); } while (0)
+#else
+# define D(...) ((void)0)
+# define S(...) ((void)0)
+#endif
+
+/** By convention, remote numbers are the console ports, i.e. 5554, 5556, etc...
+ **/
+#define REMOTE_NUMBER_BASE 5554
+#define REMOTE_NUMBER_MAX 16
+#define REMOTE_NUMBER_MAX_CHARS 4
+#define REMOTE_CONSOLE_PORT 5554
+
+int
+remote_number_from_port( int port )
+{
+ if (port & 1) /* must be even */
+ return -1;
+
+ port = (port - REMOTE_CONSOLE_PORT) >> 1;
+ if ((unsigned)port >= REMOTE_NUMBER_MAX)
+ return -1;
+
+ return REMOTE_NUMBER_BASE + port*2;
+}
+
+int
+remote_number_to_port( int number )
+{
+ if (number & 1) /* must be even */
+ return -1;
+
+ number = (number - REMOTE_NUMBER_BASE) >> 1;
+ if ((unsigned)number >= REMOTE_NUMBER_MAX)
+ return -1;
+
+ return REMOTE_CONSOLE_PORT + number*2;
+}
+
+int
+remote_number_string_to_port( const char* number )
+{
+ char* end;
+ long num = strtol( number, &end, 10 );
+
+ if (end == NULL || *end || (int)num != num )
+ return -1;
+
+ return remote_number_to_port( (int)num );
+}
+
+/** REMOTE CALL OBJECTS
+ **/
+
+typedef struct RemoteCallRec {
+ struct RemoteCallRec* next;
+ struct RemoteCallRec** pref;
+ RemoteCallType type;
+ int to_port;
+ int from_port;
+ SysChannel channel;
+ RemoteResultFunc result_func;
+ void* result_opaque;
+
+ char quitting;
+
+ /* the output buffer */
+ char* buff;
+ int buff_pos;
+ int buff_len;
+ int buff_size;
+ char buff0[32];
+
+} RemoteCallRec, *RemoteCall;
+
+static void
+remote_call_done( RemoteCall call )
+{
+ call->pref[0] = call->next;
+ call->next = NULL;
+ call->pref = &call->next;
+
+ if (call->buff && call->buff != call->buff0) {
+ free(call->buff);
+ call->buff = call->buff0;
+ call->buff_size = (int) sizeof(call->buff0);
+ }
+
+ if ( call->channel ) {
+ sys_channel_close( call->channel );
+ call->channel = NULL;
+ }
+
+ call->buff_pos = 0;
+ call->buff_len = 0;
+}
+
+
+static void
+remote_call_free( RemoteCall call )
+{
+ if (call) {
+ remote_call_done( call );
+ free(call);
+ }
+}
+
+
+static void remote_call_event( void* opaque, int events ); /* forward */
+
+static RemoteCall
+remote_call_alloc( RemoteCallType type, int to_port, int from_port )
+{
+ RemoteCall rcall = calloc( sizeof(*rcall), 1 );
+ int from_num = remote_number_from_port(from_port);
+
+ if (rcall != NULL) {
+ char *p, *end;
+
+ rcall->pref = &rcall->next;
+ rcall->type = type;
+ rcall->to_port = to_port;
+ rcall->from_port = from_port;
+ rcall->buff = rcall->buff0;
+ rcall->buff_size = sizeof(rcall->buff0);
+ rcall->buff_pos = 0;
+
+ p = rcall->buff;
+ end = p + rcall->buff_size;
+
+ switch (type) {
+ case REMOTE_CALL_DIAL:
+ p = bufprint(p, end, "gsm call %d\n", from_num );
+ break;
+
+ case REMOTE_CALL_BUSY:
+ p = bufprint(p, end, "gsm busy %d\n", from_num);
+ break;
+
+ case REMOTE_CALL_HOLD:
+ p = bufprint(p, end, "gsm hold %d\n", from_num);
+ break;
+
+ case REMOTE_CALL_ACCEPT:
+ p = bufprint(p, end, "gsm accept %d\n", from_num);
+ break;
+
+ case REMOTE_CALL_HANGUP:
+ p = bufprint(p, end, "gsm cancel %d\n", from_num );
+ break;
+
+ default:
+ ;
+ }
+ if (p >= end) {
+ D("%s: buffer too short\n", __FUNCTION__ );
+ remote_call_free(rcall);
+ return NULL;
+ }
+
+ rcall->buff_len = p - rcall->buff;
+
+ rcall->channel = sys_channel_create_tcp_client( "localhost", to_port );
+ if (rcall->channel == NULL) {
+ D("%s: could not create channel to port %d\n", __FUNCTION__, to_port);
+ remote_call_free(rcall);
+ return NULL;
+ }
+
+ sys_channel_on( rcall->channel, SYS_EVENT_WRITE, remote_call_event, rcall );
+ }
+ return rcall;
+}
+
+
+static int
+remote_call_set_sms_pdu( RemoteCall call,
+ SmsPDU pdu )
+{
+ char *p, *end;
+ int msg2len;
+
+ msg2len = 32 + smspdu_to_hex( pdu, NULL, 0 );
+ if (msg2len > call->buff_size) {
+ char* old_buff = call->buff == call->buff0 ? NULL : call->buff;
+ char* new_buff = realloc( old_buff, msg2len );
+ if (new_buff == NULL) {
+ D("%s: not enough memory to alloc %d bytes", __FUNCTION__, msg2len);
+ return -1;
+ }
+ call->buff = new_buff;
+ call->buff_size = msg2len;
+ }
+
+ p = call->buff;
+ end = p + call->buff_size;
+
+ p = bufprint(p, end, "sms pdu ");
+ p += smspdu_to_hex( pdu, p, end-p );
+ *p++ = '\n';
+ *p = 0;
+
+ call->buff_len = p - call->buff;
+ call->buff_pos = 0;
+ return 0;
+}
+
+
+static void
+remote_call_add( RemoteCall call,
+ RemoteCall *plist )
+{
+ RemoteCall first = *plist;
+
+ call->next = first;
+ call->pref = plist;
+
+ if (first)
+ first->pref = &call->next;
+}
+
+static void
+remote_call_event( void* opaque, int events )
+{
+ RemoteCall call = opaque;
+
+ S("%s: called for call (%d,%d), events=%02x\n", __FUNCTION__,
+ call->from_port, call->to_port, events);
+
+ if (events & SYS_EVENT_READ) {
+ /* simply drain the channel */
+ char temp[32];
+ int n = sys_channel_read( call->channel, temp, sizeof(temp) );
+ if (n <= 0) {
+ /* remote emulator probably quitted */
+ //S("%s: emulator %d quitted with %d: %s\n", __FUNCTION__, call->to_port, socket_errno, socket_errstr());
+ remote_call_free( call );
+ return;
+ }
+ }
+
+ if (events & SYS_EVENT_WRITE) {
+ int n;
+
+ if (S_ACTIVE) {
+ int nn;
+ S("%s: call (%d,%d) sending %d bytes '", __FUNCTION__,
+ call->from_port, call->to_port, call->buff_len - call->buff_pos );
+ for (nn = call->buff_pos; nn < call->buff_len; nn++) {
+ int c = call->buff[nn];
+ if (c < 32) {
+ if (c == '\n')
+ S("\\n");
+ else if (c == '\t')
+ S("\\t");
+ else if (c == '\r')
+ S("\\r");
+ else
+ S("\\x%02x", c);
+ } else
+ S("%c", c);
+ }
+ S("'\n");
+ }
+
+ n = sys_channel_write( call->channel,
+ call->buff + call->buff_pos,
+ call->buff_len - call->buff_pos );
+ if (n <= 0) {
+ /* remote emulator probably quitted */
+ S("%s: emulator %d quitted unexpectedly with error %d: %s\n",
+ __FUNCTION__, call->to_port, socket_errno, socket_errstr());
+ if (call->result_func)
+ call->result_func( call->result_opaque, 0 );
+ remote_call_free( call );
+ return;
+ }
+ call->buff_pos += n;
+
+ if (call->buff_pos >= call->buff_len) {
+ /* cool, we sent everything */
+ S("%s: finished sending data to %d\n", __FUNCTION__, call->to_port);
+ if (!call->quitting) {
+ call->quitting = 1;
+ sprintf( call->buff, "quit\n" );
+ call->buff_len = strlen(call->buff);
+ call->buff_pos = 0;
+ } else {
+ call->quitting = 0;
+ if (call->result_func)
+ call->result_func( call->result_opaque, 1 );
+
+ sys_channel_on( call->channel, SYS_EVENT_READ, remote_call_event, call );
+ }
+ }
+ }
+}
+
+static RemoteCall _the_remote_calls;
+
+
+static int
+remote_from_number( const char* from )
+{
+ char* end;
+ long num = strtol( from, &end, 10 );
+
+ if (end == NULL || *end)
+ return -1;
+
+ if ((unsigned)(num - REMOTE_NUMBER_BASE) >= REMOTE_NUMBER_MAX)
+ return -1;
+
+ return (int) num;
+}
+
+
+static RemoteCall
+remote_call_generic( RemoteCallType type, const char* to_number, int from_port )
+{
+ int to_port = remote_number_string_to_port(to_number);
+ RemoteCall call;
+
+ if ( remote_number_from_port(from_port) < 0 ) {
+ D("%s: from_port value %d is not valid", __FUNCTION__, from_port);
+ return NULL;
+ }
+ if ( to_port < 0 ) {
+ D("%s: phone number '%s' is not decimal or remote", __FUNCTION__, to_number);
+ return NULL;
+ }
+ if (to_port == from_port) {
+ D("%s: trying to call self\n", __FUNCTION__);
+ return NULL;
+ }
+ call = remote_call_alloc( type, to_port, from_port );
+ if (call == NULL) {
+ return NULL;
+ }
+ remote_call_add( call, &_the_remote_calls );
+ D("%s: adding new call from port %d to port %d\n", __FUNCTION__, from_port, to_port);
+ return call;
+}
+
+
+int
+remote_call_dial( const char* number,
+ int from,
+ RemoteResultFunc result_func,
+ void* result_opaque )
+{
+ RemoteCall call = remote_call_generic( REMOTE_CALL_DIAL, number, from );
+
+ if (call != NULL) {
+ call->result_func = result_func;
+ call->result_opaque = result_opaque;
+ }
+ return call ? 0 : -1;
+}
+
+
+void
+remote_call_other( const char* to_number, int from_port, RemoteCallType type )
+{
+ remote_call_generic( type, to_number, from_port );
+}
+
+/* call this function to send a SMS to a remote emulator */
+int
+remote_call_sms( const char* number,
+ int from,
+ SmsPDU pdu )
+{
+ RemoteCall call = remote_call_generic( REMOTE_CALL_SMS, number, from );
+
+ if (call == NULL)
+ return -1;
+
+ if (call != NULL) {
+ if ( remote_call_set_sms_pdu( call, pdu ) < 0 ) {
+ remote_call_free(call);
+ return -1;
+ }
+ }
+ return call ? 0 : -1;
+}
+
+
+void
+remote_call_cancel( const char* to_number, int from_port )
+{
+ remote_call_generic( REMOTE_CALL_HANGUP, to_number, from_port );
+}
diff --git a/telephony/remote_call.h b/telephony/remote_call.h
new file mode 100644
index 0000000..c6891b8
--- /dev/null
+++ b/telephony/remote_call.h
@@ -0,0 +1,55 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _REMOTE_CALL_H
+#define _REMOTE_CALL_H
+
+#include "sms.h"
+
+/* convert a base console port into a remote phone number, -1 on error */
+extern int remote_number_from_port( int port );
+
+/* convert a remote phone number into a remote console port, -1 on error */
+extern int remote_number_to_port( int number );
+
+extern int remote_number_string_to_port( const char* number );
+
+typedef void (*RemoteResultFunc)( void* opaque, int success );
+
+typedef enum {
+ REMOTE_CALL_DIAL = 0,
+ REMOTE_CALL_BUSY,
+ REMOTE_CALL_HANGUP,
+ REMOTE_CALL_HOLD,
+ REMOTE_CALL_ACCEPT,
+ REMOTE_CALL_SMS
+} RemoteCallType;
+
+/* call this function when you need to dial a remote voice call.
+ * this will try to connect to a remote emulator. the result function
+ * is called to indicate success or failure after some time.
+ *
+ * returns 0 if the number is to a remote phone, or -1 otherwise
+ */
+extern int remote_call_dial( const char* to_number,
+ int from_port,
+ RemoteResultFunc result_func,
+ void* result_opaque );
+
+/* call this function to send a SMS to a remote emulator */
+extern int remote_call_sms( const char* number, int from_port, SmsPDU pdu );
+
+/* call this function to indicate that you're busy to a remote caller */
+extern void remote_call_other( const char* to_number, int from_port, RemoteCallType type );
+
+extern void remote_call_cancel( const char* to_number, int from_port );
+
+#endif /* _REMOTE_CALL_H */
diff --git a/telephony/sim_card.c b/telephony/sim_card.c
new file mode 100644
index 0000000..9e48200
--- /dev/null
+++ b/telephony/sim_card.c
@@ -0,0 +1,432 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "sim_card.h"
+#include <string.h>
+#include <assert.h>
+
+#define A_SIM_PIN_SIZE 4
+#define A_SIM_PUK_SIZE 8
+
+typedef struct ASimCardRec_ {
+ ASimStatus status;
+ char pin[ A_SIM_PIN_SIZE+1 ];
+ char puk[ A_SIM_PUK_SIZE+1 ];
+ int pin_retries;
+
+ char out_buff[ 256 ];
+ int out_size;
+
+} ASimCardRec;
+
+static ASimCardRec _s_card[1];
+
+ASimCard
+asimcard_create( void )
+{
+ ASimCard card = _s_card;
+ card->status = A_SIM_STATUS_READY;
+ card->pin_retries = 0;
+ strncpy( card->pin, "0000", sizeof(card->pin) );
+ strncpy( card->puk, "12345678", sizeof(card->puk) );
+ return card;
+}
+
+void
+asimcard_destroy( ASimCard card )
+{
+ /* nothing really */
+ card=card;
+}
+
+static __inline__ int
+asimcard_ready( ASimCard card )
+{
+ return card->status == A_SIM_STATUS_READY;
+}
+
+ASimStatus
+asimcard_get_status( ASimCard sim )
+{
+ return sim->status;
+}
+
+void
+asimcard_set_status( ASimCard sim, ASimStatus status )
+{
+ sim->status = status;
+}
+
+const char*
+asimcard_get_pin( ASimCard sim )
+{
+ return sim->pin;
+}
+
+const char*
+asimcard_get_puk( ASimCard sim )
+{
+ return sim->puk;
+}
+
+void
+asimcard_set_pin( ASimCard sim, const char* pin )
+{
+ strncpy( sim->pin, pin, A_SIM_PIN_SIZE );
+ sim->pin_retries = 0;
+}
+
+void
+asimcard_set_puk( ASimCard sim, const char* puk )
+{
+ strncpy( sim->puk, puk, A_SIM_PUK_SIZE );
+ sim->pin_retries = 0;
+}
+
+
+int
+asimcard_check_pin( ASimCard sim, const char* pin )
+{
+ if (sim->status != A_SIM_STATUS_PIN &&
+ sim->status != A_SIM_STATUS_READY )
+ return 0;
+
+ if ( !strcmp( sim->pin, pin ) ) {
+ sim->status = A_SIM_STATUS_READY;
+ sim->pin_retries = 0;
+ return 1;
+ }
+
+ if (sim->status != A_SIM_STATUS_READY) {
+ if (++sim->pin_retries == 3)
+ sim->status = A_SIM_STATUS_PUK;
+ }
+ return 0;
+}
+
+
+int
+asimcard_check_puk( ASimCard sim, const char* puk, const char* pin )
+{
+ if (sim->status != A_SIM_STATUS_PUK)
+ return 0;
+
+ if ( !strcmp( sim->puk, puk ) ) {
+ strncpy( sim->puk, puk, A_SIM_PUK_SIZE );
+ strncpy( sim->pin, pin, A_SIM_PIN_SIZE );
+ sim->status = A_SIM_STATUS_READY;
+ sim->pin_retries = 0;
+ return 1;
+ }
+
+ if ( ++sim->pin_retries == 6 ) {
+ sim->status = A_SIM_STATUS_ABSENT;
+ }
+ return 0;
+}
+
+typedef enum {
+ SIM_FILE_DM = 0,
+ SIM_FILE_DF,
+ SIM_FILE_EF_DEDICATED,
+ SIM_FILE_EF_LINEAR,
+ SIM_FILE_EF_CYCLIC
+} SimFileType;
+
+typedef enum {
+ SIM_FILE_READ_ONLY = (1 << 0),
+ SIM_FILE_NEED_PIN = (1 << 1),
+} SimFileFlags;
+
+/* descriptor for a known SIM File */
+#define SIM_FILE_HEAD \
+ SimFileType type; \
+ unsigned short id; \
+ unsigned short flags;
+
+typedef struct {
+ SIM_FILE_HEAD
+} SimFileAnyRec, *SimFileAny;
+
+typedef struct {
+ SIM_FILE_HEAD
+ cbytes_t data;
+ int length;
+} SimFileEFDedicatedRec, *SimFileEFDedicated;
+
+typedef struct {
+ SIM_FILE_HEAD
+ byte_t rec_count;
+ byte_t rec_len;
+ cbytes_t records;
+} SimFileEFLinearRec, *SimFileEFLinear;
+
+typedef SimFileEFLinearRec SimFileEFCyclicRec;
+typedef SimFileEFCyclicRec* SimFileEFCyclic;
+
+typedef union {
+ SimFileAnyRec any;
+ SimFileEFDedicatedRec dedicated;
+ SimFileEFLinearRec linear;
+ SimFileEFCyclicRec cyclic;
+} SimFileRec, *SimFile;
+
+
+/* convert a SIM File descriptor into an ASCII string,
+ assumes 'dst' is NULL or properly sized.
+ return the number of chars, or -1 on error */
+static int
+sim_file_to_hex( SimFile file, bytes_t dst )
+{
+ SimFileType type = file->any.type;
+ int result = 0;
+
+ /* see 9.2.1 in TS 51.011 */
+ switch (type) {
+ case SIM_FILE_EF_DEDICATED:
+ case SIM_FILE_EF_LINEAR:
+ case SIM_FILE_EF_CYCLIC:
+ {
+ if (dst) {
+ int file_size, file_type, perm;
+
+ memcpy(dst, "0000", 4); /* bytes 1-2 are RFU */
+ dst += 4;
+
+ /* bytes 3-4 are the file size */
+ if (type == SIM_FILE_EF_DEDICATED)
+ file_size = file->dedicated.length;
+ else
+ file_size = file->linear.rec_count * file->linear.rec_len;
+
+ gsm_hex_from_short( dst, file_size );
+ dst += 4;
+
+ /* bytes 5-6 are the file id */
+ gsm_hex_from_short( dst, file->any.id );
+ dst += 4;
+
+ /* byte 7 is the file type - always EF, i.e. 0x04 */
+ dst[0] = '0';
+ dst[1] = '4';
+ dst += 2;
+
+ /* byte 8 is RFU, except bit 7 for cyclic files, which indicates
+ that INCREASE is allowed. Since we don't support this yet... */
+ dst[0] = '0';
+ dst[1] = '0';
+ dst += 2;
+
+ /* byte 9-11 are access conditions */
+ if (file->any.flags & SIM_FILE_READ_ONLY) {
+ if (file->any.flags & SIM_FILE_NEED_PIN)
+ perm = 0x1a;
+ else
+ perm = 0x0a;
+ } else {
+ if (file->any.flags & SIM_FILE_NEED_PIN)
+ perm = 0x11;
+ else
+ perm = 0x00;
+ }
+ gsm_hex_from_byte(dst, perm);
+ memcpy( dst+2, "a0aa", 4 );
+ dst += 6;
+
+ /* byte 12 is file status, we don't support invalidation */
+ dst[0] = '0';
+ dst[1] = '0';
+ dst += 2;
+
+ /* byte 13 is length of the following data, always 2 */
+ dst[0] = '0';
+ dst[1] = '2';
+ dst += 2;
+
+ /* byte 14 is struct of EF */
+ dst[0] = '0';
+ if (type == SIM_FILE_EF_DEDICATED)
+ dst[1] = '0';
+ else if (type == SIM_FILE_EF_LINEAR)
+ dst[1] = '1';
+ else
+ dst[1] = '3';
+
+ /* byte 15 is lenght of record, or 0 */
+ if (type == SIM_FILE_EF_DEDICATED) {
+ dst[0] = '0';
+ dst[1] = '0';
+ } else
+ gsm_hex_from_byte( dst, file->linear.rec_len );
+ }
+ result = 30;
+ }
+ break;
+
+ default:
+ result = -1;
+ }
+ return result;
+}
+
+
+static const byte_t _const_spn_cphs[20] = {
+ 0x41, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static const byte_t _const_voicemail_cphs[1] = {
+ 0x55
+};
+
+static const byte_t _const_iccid[10] = {
+ 0x98, 0x10, 0x14, 0x30, 0x12, 0x11, 0x81, 0x15, 0x70, 0x02
+};
+
+static const byte_t _const_cff_cphs[1] = {
+ 0x55
+};
+
+static SimFileEFDedicatedRec _const_files_dedicated[] =
+{
+ { SIM_FILE_EF_DEDICATED, 0x6f14, SIM_FILE_READ_ONLY | SIM_FILE_NEED_PIN,
+ _const_spn_cphs, sizeof(_const_spn_cphs) },
+
+ { SIM_FILE_EF_DEDICATED, 0x6f11, SIM_FILE_NEED_PIN,
+ _const_voicemail_cphs, sizeof(_const_voicemail_cphs) },
+
+ { SIM_FILE_EF_DEDICATED, 0x2fe2, SIM_FILE_READ_ONLY,
+ _const_iccid, sizeof(_const_iccid) },
+
+ { SIM_FILE_EF_DEDICATED, 0x6f13, SIM_FILE_NEED_PIN,
+ _const_cff_cphs, sizeof(_const_cff_cphs) },
+
+ { 0, 0, 0, NULL, 0 } /* end of list */
+};
+
+
+const char*
+asimcard_io( ASimCard sim, const char* cmd )
+{
+ int nn;
+ int command, id, p1, p2, p3;
+
+ static const struct { const char* cmd; const char* answer; } answers[] =
+ {
+ { "+CRSM=192,28436,0,0,15", "+CRSM: 144,0,000000146f1404001aa0aa01020000" },
+ { "+CRSM=176,28436,0,0,20", "+CRSM: 144,0,416e64726f6964ffffffffffffffffffffffffff" },
+
+ { "+CRSM=192,28433,0,0,15", "+CRSM: 144,0,000000016f11040011a0aa01020000" },
+ { "+CRSM=176,28433,0,0,1", "+CRSM: 144,0,55" },
+
+ { "+CRSM=192,12258,0,0,15", "+CRSM: 144,0,0000000a2fe204000fa0aa01020000" },
+ { "+CRSM=176,12258,0,0,10", "+CRSM: 144,0,98101430121181157002" },
+
+ { "+CRSM=192,28435,0,0,15", "+CRSM: 144,0,000000016f13040011a0aa01020000" },
+ { "+CRSM=176,28435,0,0,1", "+CRSM: 144,0,55" },
+
+ { "+CRSM=192,28472,0,0,15", "+CRSM: 144,0,0000000f6f3804001aa0aa01020000" },
+ { "+CRSM=176,28472,0,0,15", "+CRSM: 144,0,ff30ffff3c003c03000c0000f03f00" },
+
+ { "+CRSM=192,28617,0,0,15", "+CRSM: 144,0,000000086fc9040011a0aa01020104" },
+ { "+CRSM=178,28617,1,4,4", "+CRSM: 144,0,01000000" },
+
+ { "+CRSM=192,28618,0,0,15", "+CRSM: 144,0,0000000a6fca040011a0aa01020105" },
+ { "+CRSM=178,28618,1,4,5", "+CRSM: 144,0,0000000000" },
+
+ { "+CRSM=192,28589,0,0,15", "+CRSM: 144,0,000000046fad04000aa0aa01020000" },
+ { "+CRSM=176,28589,0,0,4", "+CRSM: 144,0,00000003" },
+
+ { "+CRSM=192,28438,0,0,15", "+CRSM: 144,0,000000026f1604001aa0aa01020000" },
+ { "+CRSM=176,28438,0,0,2", "+CRSM: 144,0,0233" },
+
+ { "+CRSM=192,28486,0,0,15", "+CRSM: 148,4" },
+ { "+CRSM=192,28621,0,0,15", "+CRSM: 148,4" },
+
+ { "+CRSM=192,28613,0,0,15", "+CRSM: 144,0,000000f06fc504000aa0aa01020118" },
+ { "+CRSM=178,28613,1,4,24", "+CRSM: 144,0,43058441aa890affffffffffffffffffffffffffffffffff" },
+
+ { "+CRSM=192,28480,0,0,15", "+CRSM: 144,0,000000806f40040011a0aa01020120" },
+ { "+CRSM=178,28480,1,4,32", "+CRSM: 144,0,ffffffffffffffffffffffffffffffffffff07815155258131f5ffffffffffff" },
+
+ { "+CRSM=192,28615,0,0,15", "+CRSM: 144,0,000000406fc7040011a0aa01020120" },
+ { "+CRSM=178,28615,1,4,32", "+CRSM: 144,0,566f6963656d61696cffffffffffffffffff07915155125740f9ffffffffffff" },
+
+ { NULL, NULL }
+ };
+
+ assert( memcmp( cmd, "+CRSM=", 6 ) == 0 );
+
+#if 0 /* this code officially disabled in the depot until properly tested and debugged */
+ if ( sscanf(cmd, "+CRSM=%d,%d,%d,%d,%d", &command, &id, &p1, &p2, &p3) == 5 ) {
+ switch (command) {
+ case A_SIM_CMD_GET_RESPONSE:
+ {
+ const SimFileEFDedicatedRec* file = _const_files_dedicated;
+
+ assert(p1 == 0 && p2 == 0 && p3 == 15);
+
+ for ( ; file->id != 0; file++ ) {
+ if (file->id == id) {
+ int count;
+ char* out = sim->out_buff;
+ strcpy( out, "+CRSM: 144,0," );
+ out += strlen(out);
+ count = sim_file_to_hex( (SimFile) file, out );
+ if (count < 0)
+ return "ERROR: INTERNAL SIM ERROR";
+ out[count] = 0;
+ return sim->out_buff;
+ }
+ }
+ break;
+ }
+
+ case A_SIM_CMD_READ_BINARY:
+ {
+ const SimFileEFDedicatedRec* file = _const_files_dedicated;
+
+ assert(p1 == 0 && p2 == 0);
+
+ for ( ; file->id != 0; file++ ) {
+ if (file->id == id) {
+ char* out = sim->out_buff;
+
+ if (p3 > file->length)
+ return "ERROR: BINARY LENGTH IS TOO LONG";
+
+ strcpy( out, "+CRSM: 144,0," );
+ out += strlen(out);
+ gsm_hex_from_bytes( out, file->data, p3 );
+ out[p3*2] = 0;
+ return sim->out_buff;
+ }
+ }
+ break;
+ }
+
+ case A_SIM_CMD_READ_RECORD:
+ break;
+
+ default:
+ return "ERROR: UNSUPPORTED SIM COMMAND";
+ }
+ }
+#endif
+
+ for (nn = 0; answers[nn].cmd != NULL; nn++) {
+ if ( !strcmp( answers[nn].cmd, cmd ) ) {
+ return answers[nn].answer;
+ }
+ }
+ return "ERROR: BAD COMMAND";
+}
+
diff --git a/telephony/sim_card.h b/telephony/sim_card.h
new file mode 100644
index 0000000..af78237
--- /dev/null
+++ b/telephony/sim_card.h
@@ -0,0 +1,54 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _android_sim_card_h
+#define _android_sim_card_h
+
+#include "gsm.h"
+
+typedef struct ASimCardRec_* ASimCard;
+
+extern ASimCard asimcard_create( void );
+extern void asimcard_destroy( ASimCard sim );
+
+typedef enum {
+ A_SIM_STATUS_ABSENT = 0,
+ A_SIM_STATUS_NOT_READY,
+ A_SIM_STATUS_READY,
+ A_SIM_STATUS_PIN,
+ A_SIM_STATUS_PUK,
+ A_SIM_STATUS_NETWORK_PERSONALIZATION
+} ASimStatus;
+
+extern ASimStatus asimcard_get_status( ASimCard sim );
+extern void asimcard_set_status( ASimCard sim, ASimStatus status );
+
+extern const char* asimcard_get_pin( ASimCard sim );
+extern const char* asimcard_get_puk( ASimCard sim );
+extern void asimcard_set_pin( ASimCard sim, const char* pin );
+extern void asimcard_set_puk( ASimCard sim, const char* puk );
+
+extern int asimcard_check_pin( ASimCard sim, const char* pin );
+extern int asimcard_check_puk( ASimCard sim, const char* puk, const char* pin );
+
+/* Restricted SIM Access command, as defined by 8.18 of 3GPP 27.007 */
+typedef enum {
+ A_SIM_CMD_READ_BINARY = 176,
+ A_SIM_CMD_READ_RECORD = 178,
+ A_SIM_CMD_GET_RESPONSE = 192,
+ A_SIM_CMD_UPDATE_BINARY = 214,
+ A_SIM_CMD_UPDATE_RECORD = 220,
+ A_SIM_CMD_STATUS = 242
+} ASimCommand;
+
+extern const char* asimcard_io( ASimCard sim, const char* cmd );
+
+#endif /* _android_sim_card_h */
diff --git a/telephony/simulator.c b/telephony/simulator.c
new file mode 100644
index 0000000..43f267a
--- /dev/null
+++ b/telephony/simulator.c
@@ -0,0 +1,195 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "android_modem.h"
+#include "sysdeps.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#define DEFAULT_PORT 6703
+
+static AModem modem;
+
+typedef struct {
+ SysChannel channel;
+ char in_buff[ 128 ];
+ int in_pos;
+
+ char out_buff[ 128 ];
+ int out_pos;
+ int out_size;
+} ClientRec, *Client;
+
+static Client
+client_alloc( SysChannel channel )
+{
+ Client client = calloc( sizeof(*client), 1 );
+
+ client->channel = channel;
+ return client;
+}
+
+static void
+client_free( Client client )
+{
+ sys_channel_close( client->channel );
+ client->channel = NULL;
+ free( client );
+}
+
+static void
+client_append( Client client, const char* str, int len );
+
+static void
+dump_line( const char* line, const char* prefix )
+{
+ if (prefix)
+ printf( "%s", prefix );
+
+ for ( ; *line; line++ ) {
+ int c = line[0];
+
+ if (c >= 32 && c < 127)
+ printf( "%c", c );
+ else if (c == '\r')
+ printf( "<CR>" );
+ else if (c == '\n')
+ printf( "<LF>" );
+ else
+ printf( "\\x%02x", c );
+ }
+ printf( "\n" );
+}
+
+static void
+client_handle_line( Client client, const char* cmd )
+{
+ const char* answer;
+
+ dump_line( cmd, "<< " );
+ answer = amodem_send( modem, cmd );
+ if (answer == NULL) /* not an AT command, ignored */ {
+ printf( "-- NO ANSWER\n" );
+ return;
+ }
+
+ dump_line( answer, ">> " );
+ client_append( client, answer, -1 );
+ client_append( client, "\r", 1 );
+}
+
+static void
+client_handler( void* _client, int events )
+{
+ Client client = _client;
+
+ if (events & SYS_EVENT_READ) {
+ int ret;
+ /* read into buffer, one character at a time */
+ ret = sys_channel_read( client->channel, client->in_buff + client->in_pos, 1 );
+ if (ret != 1) {
+ fprintf(stderr, "client %p could not read byte, result = %d, error: %s\n",
+ client, ret, strerror(errno) );
+ goto ExitClient;
+ }
+ if (client->in_buff[client->in_pos] == '\r' ||
+ client->in_buff[client->in_pos] == '\n' ) {
+ const char* cmd = client->in_buff;
+ client->in_buff[client->in_pos] = 0;
+
+ if (client->in_pos > 0) {
+ client_handle_line( client, cmd );
+ client->in_pos = 0;
+ }
+ } else
+ client->in_pos += 1;
+ }
+
+ if (events & SYS_EVENT_WRITE) {
+ int ret;
+ /* write from output buffer, one char at a time */
+ ret = sys_channel_write( client->channel, client->out_buff + client->out_pos, 1 );
+ if (ret != 1) {
+ fprintf(stderr, "client %p could not write byte, result = %d, error: %s\n",
+ client, ret, strerror(errno) );
+ goto ExitClient;
+ }
+ client->out_pos += 1;
+ if (client->out_pos == client->out_size) {
+ client->out_size = 0;
+ client->out_pos = 0;
+ /* we don't need to write */
+ sys_channel_on( client->channel, SYS_EVENT_READ, client_handler, client );
+ }
+ }
+ return;
+
+ExitClient:
+ printf( "client %p exiting\n", client );
+ client_free( client );
+}
+
+
+static void
+client_append( Client client, const char* str, int len )
+{
+ int avail;
+
+ if (len < 0)
+ len = strlen(str);
+
+ avail = sizeof(client->out_buff) - client->out_size;
+ if (len > avail)
+ len = avail;
+
+ memcpy( client->out_buff + client->out_size, str, len );
+ if (client->out_size == 0) {
+ sys_channel_on( client->channel, SYS_EVENT_READ | SYS_EVENT_WRITE, client_handler, client );
+ }
+ client->out_size += len;
+}
+
+
+static void
+accept_func( void* _server, int events )
+{
+ SysChannel server = _server;
+ SysChannel handler;
+ Client client;
+
+ printf( "connection accepted for server channel, getting handler socket\n" );
+ handler = sys_channel_create_tcp_handler( server );
+ client = client_alloc( handler );
+ printf( "got one. created client %p\n", client );
+
+ events=events;
+ sys_channel_on( handler, SYS_EVENT_READ, client_handler, client );
+}
+
+
+int main( void )
+{
+ int port = DEFAULT_PORT;
+ SysChannel server;
+
+ sys_main_init();
+ modem = amodem_create( NULL, NULL );
+
+ server = sys_channel_create_tcp_server( port );
+ printf( "GSM simulator listening on local port %d\n", port );
+
+ sys_channel_on( server, SYS_EVENT_READ, accept_func, server );
+ sys_main_loop();
+ printf( "GSM simulator exiting\n" );
+ return 0;
+}
diff --git a/telephony/sms.c b/telephony/sms.c
new file mode 100644
index 0000000..7a394d4
--- /dev/null
+++ b/telephony/sms.c
@@ -0,0 +1,1655 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "sms.h"
+#include "gsm.h"
+#include <memory.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#define DEBUG 1
+
+#if 1
+# include "android_debug.h"
+# define D_ACTIVE VERBOSE_CHECK(modem)
+#else
+# define D_ACTIVE DEBUG
+#endif
+
+#if DEBUG
+# define D(...) VERBOSE_PRINT(modem,__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
+/* maximum number of data bytes in a SMS data message */
+#define MAX_USER_DATA_BYTES 140
+
+/* maximum number of 7-bit septets in a SMS text message */
+#define MAX_USER_DATA_SEPTETS 160
+
+/* size of the user data header in bytes */
+#define USER_DATA_HEADER_SIZE 6
+
+/** MESSAGE TEXT
+ **/
+int
+sms_utf8_from_message_str( const char* str, int strlen, unsigned char* utf8, int utf8len )
+{
+ cbytes_t p = (cbytes_t)str;
+ cbytes_t end = p + strlen;
+ int count = 0;
+ int escaped = 0;
+
+ while (p < end)
+ {
+ int c = p[0];
+
+ /* read the value from the string */
+ p += 1;
+ if (c >= 128) {
+ if ((c & 0xe0) == 0xc0)
+ c &= 0x1f;
+ else if ((c & 0xf0) == 0xe0)
+ c &= 0x0f;
+ else
+ c &= 0x07;
+ p++;
+ while (p < end && (p[0] & 0xc0) == 0x80) {
+ c = (c << 6) | (p[0] & 0x3f);
+ p++;
+ }
+ }
+ if (escaped) {
+ switch (c) {
+ case '\\':
+ break;
+ case 'n': /* \n is line feed */
+ c = 10;
+ break;
+
+ case 'x': /* \xNN, where NN is a 2-digit hexadecimal value */
+ if (p+2 > end)
+ return -1;
+ c = gsm_hex2_to_byte( (const char*)p );
+ if (c < 0)
+ return -1;
+ p += 2;
+ break;
+
+ case 'u': /* \uNNNN where NNNN is a 4-digiti hexadecimal value */
+ if (p + 4 > end)
+ return -1;
+ c = gsm_hex4_to_short( (const char*)p );
+ if (c < 0)
+ return -1;
+ p += 4;
+ break;
+
+ default: /* invalid escape, return -1 */
+ return -1;
+ }
+ escaped = 0;
+ }
+ else if (c == '\\')
+ {
+ escaped = 1;
+ continue;
+ }
+
+ /* now, try to write it to the destination */
+ if (c < 128) {
+ if (count < utf8len)
+ utf8[count] = (byte_t) c;
+ count += 1;
+ }
+ else if (c < 0x800) {
+ if (count < utf8len)
+ utf8[count] = (byte_t)(0xc0 | ((c >> 6) & 0x1f));
+ if (count+1 < utf8len)
+ utf8[count+1] = (byte_t)(0x80 | (c & 0x3f));
+ count += 2;
+ }
+ else {
+ if (count < utf8len)
+ utf8[count] = (byte_t)(0xc0 | ((c >> 12) & 0xf));
+ if (count+1 < utf8len)
+ utf8[count+1] = (byte_t)(0x80 | ((c >> 6) & 0x3f));
+ if (count+2 < utf8len)
+ utf8[count+2] = (byte_t)(0x80 | (c & 0x3f));
+ count += 3;
+ }
+ }
+
+ if (escaped) /* bad final escape */
+ return -1;
+
+ return count;
+}
+
+/* to convert utf-8 to a message string, we only need to deal with control characters
+ * and that's it */
+int sms_utf8_to_message_str( const unsigned char* utf8, int utf8len, char* str, int strlen )
+{
+ cbytes_t p = utf8;
+ cbytes_t end = p + utf8len;
+ int count = 0;
+
+ while (p < end)
+ {
+ int c = p[0];
+ int escape = 0;
+
+ /* read the value from the string */
+ p += 1;
+ if (c >= 128) {
+ if ((c & 0xe0) == 0xc0)
+ c &= 0x1f;
+ else if ((c & 0xf0) == 0xe0)
+ c &= 0x0f;
+ else
+ c &= 0x07;
+ p++;
+ while (p < end && (p[0] & 0xc0) == 0x80) {
+ c = (c << 6) | (p[0] & 0x3f);
+ p++;
+ }
+ }
+
+ if (c < ' ') {
+ escape = 1;
+ if (c == '\n') {
+ c = 'n';
+ escape = 2;
+ }
+ }
+ else if (c == '\\')
+ escape = 2;
+
+ switch (escape) {
+ case 0:
+ if (c < 128) {
+ if (count < strlen)
+ str[count] = (char) c;
+ count += 1;
+ }
+ else if (c < 0x800) {
+ if (count < strlen)
+ str[count] = (byte_t)(0xc0 | ((c >> 6) & 0x1f));
+ if (count+1 < strlen)
+ str[count+1] = (byte_t)(0x80 | (c & 0x3f));
+ count += 2;
+ }
+ else {
+ if (count < strlen)
+ str[count] = (byte_t)(0xc0 | ((c >> 12) & 0xf));
+ if (count+1 < strlen)
+ str[count+1] = (byte_t)(0x80 | ((c >> 6) & 0x3f));
+ if (count+2 < strlen)
+ str[count+2] = (byte_t)(0x80 | (c & 0x3f));
+ count += 3;
+ }
+ break;
+
+ case 1:
+ if (count+3 < strlen) {
+ str[count+0] = '\\';
+ str[count+1] = 'x';
+ gsm_hex_from_byte(str + count + 2, c);
+ }
+ count += 4;
+ break;
+
+ default:
+ if (count+2 < strlen) {
+ str[count+0] = '\\';
+ str[count+1] = (char) c;
+ }
+ count += 2;
+ }
+ }
+ return count;
+}
+
+
+/** TIMESTAMPS
+ **/
+void
+sms_timestamp_now( SmsTimeStamp stamp )
+{
+ time_t now_time = time(NULL);
+ struct tm gm = *(gmtime(&now_time));
+ struct tm local = *(localtime(&now_time));
+ int tzdiff = 0;
+
+ stamp->data[0] = gsm_int_to_bcdi( local.tm_year % 100 );
+ stamp->data[1] = gsm_int_to_bcdi( local.tm_mon+1 );
+ stamp->data[2] = gsm_int_to_bcdi( local.tm_mday );
+ stamp->data[3] = gsm_int_to_bcdi( local.tm_hour );
+ stamp->data[4] = gsm_int_to_bcdi( local.tm_min );
+ stamp->data[5] = gsm_int_to_bcdi( local.tm_sec );
+
+ tzdiff = (local.tm_hour*4 + local.tm_min/15) - (gm.tm_hour*4 + gm.tm_min/15);
+ if (local.tm_yday > gm.tm_yday)
+ tzdiff += 24*4;
+ else if (local.tm_yday < gm.tm_yday)
+ tzdiff -= 24*4;
+
+ stamp->data[6] = gsm_int_to_bcdi( tzdiff >= 0 ? tzdiff : -tzdiff );
+ if (tzdiff < 0)
+ stamp->data[6] |= 0x08;
+}
+
+int
+sms_timestamp_to_tm( SmsTimeStamp stamp, struct tm* tm )
+{
+ int tzdiff;
+
+ tm->tm_year = gsm_int_from_bcdi( stamp->data[0] );
+ if (tm->tm_year < 50)
+ tm->tm_year += 100;
+ tm->tm_mon = gsm_int_from_bcdi( stamp->data[1] ) -1;
+ tm->tm_mday = gsm_int_from_bcdi( stamp->data[2] );
+ tm->tm_hour = gsm_int_from_bcdi( stamp->data[3] );
+ tm->tm_min = gsm_int_from_bcdi( stamp->data[4] );
+ tm->tm_sec = gsm_int_from_bcdi( stamp->data[5] );
+
+ tm->tm_isdst = -1;
+
+ tzdiff = gsm_int_from_bcdi( stamp->data[6] & 0xf7 );
+ if (stamp->data[6] & 0x8)
+ tzdiff = -tzdiff;
+
+ return tzdiff;
+}
+
+static void
+gsm_rope_add_timestamp( GsmRope rope, const SmsTimeStampRec* ts )
+{
+ gsm_rope_add( rope, ts->data, 7 );
+}
+
+
+/** SMS ADDRESSES
+ **/
+
+int
+sms_address_from_str( SmsAddress address, const char* src, int srclen )
+{
+ const char* end = src + srclen;
+ int shift = 0, len = 0;
+ bytes_t data = address->data;
+
+ address->len = 0;
+ address->toa = 0x81;
+
+ if (src >= end)
+ return -1;
+
+ if ( src[0] == '+' ) {
+ address->toa = 0x91;
+ if (++src == end)
+ goto Fail;
+ }
+
+ memset( address->data, 0, sizeof(address->data) );
+
+ shift = 0;
+
+ while (src < end) {
+ int c = *src++ - '0';
+
+ if ( (unsigned)c >= 10 ||
+ data >= address->data + sizeof(address->data) )
+ goto Fail;
+
+ data[0] |= c << shift;
+ len += 1;
+ shift += 4;
+ if (shift == 8) {
+ shift = 0;
+ data += 1;
+ }
+ }
+ if (shift != 0)
+ data[0] |= 0xf0;
+
+ address->len = len;
+ return 0;
+
+Fail:
+ return -1;
+}
+
+int
+sms_address_to_str( SmsAddress address, char* str, int strlen )
+{
+ static const char dialdigits[16] = "0123456789*#,N%";
+ int n, count = 0;
+
+ if (address->toa == 0x91) {
+ if (count < strlen)
+ str[count] = '+';
+ count++;
+ }
+ for (n = 0; n < address->len; n += 2)
+ {
+ int c = address->data[n/2];
+
+ if (count < strlen)
+ str[count] = dialdigits[c & 0xf];
+ count += 1;
+
+ if (n+1 > address->len)
+ break;
+
+ if (count < strlen)
+ str[count] = dialdigits[(c >> 4) & 0xf];
+ count += 1;
+ }
+ return count;
+}
+
+int
+sms_address_from_bytes( SmsAddress address, const unsigned char* buf, int buflen )
+{
+ int len = sizeof(address->data), num_digits;
+
+ if (buflen < 2)
+ return -1;
+
+ address->len = num_digits = buf[0];
+ address->toa = buf[1];
+
+ len = (num_digits+1)/2;
+ if ( len > sizeof(address->data) )
+ return -1;
+
+ memcpy( address->data, buf+2, len );
+ return 0;
+}
+
+int
+sms_address_to_bytes( SmsAddress address, unsigned char* buf, int bufsize )
+{
+ int len = (address->len + 1)/2 + 2;
+
+ if (buf == NULL)
+ bufsize = 0;
+
+ if (bufsize < 1) goto Exit;
+ buf[0] = address->len;
+
+ if (bufsize < 2) goto Exit;
+ buf[1] = address->toa;
+
+ buf += 2;
+ bufsize -= 2;
+ if (bufsize > len-2)
+ bufsize = len - 2;
+
+ memcpy( buf, address->data, bufsize );
+Exit:
+ return len;
+}
+
+int
+sms_address_from_hex ( SmsAddress address, const char* hex, int hexlen )
+{
+ const char* hexend = hex + hexlen;
+ int nn, len, num_digits;
+
+ if (hexlen < 4)
+ return -1;
+
+ address->len = num_digits = gsm_hex2_to_byte( hex );
+ address->toa = gsm_hex2_to_byte( hex+2 );
+ hex += 4;
+
+ len = (num_digits + 1)/2;
+ if (hex + len*2 > hexend)
+ return -1;
+
+ for ( nn = 0; nn < len; nn++ )
+ address->data[nn] = gsm_hex2_to_byte( hex + nn*2 );
+
+ return 0;
+}
+
+int
+sms_address_to_hex ( SmsAddress address, char* hex, int hexlen )
+{
+ int len = (address->len + 1)/2 + 2;
+ int nn;
+
+ if (hex == NULL)
+ hexlen = 0;
+
+ if (hexlen < 2) goto Exit;
+ gsm_hex_from_byte( hex, address->len );
+ if (hexlen < 4) goto Exit;
+ gsm_hex_from_byte( hex+2, address->toa );
+ hex += 4;
+ hexlen -= 4;
+ if ( hexlen > 2*(len - 2) )
+ hexlen = (len - 2)/2;
+
+ for ( nn = 0; nn < hexlen; nn += 2 )
+ gsm_hex_from_byte( hex+nn, address->data[nn/2] );
+
+Exit:
+ return len*2;
+}
+
+static void
+gsm_rope_add_address( GsmRope rope, const SmsAddressRec* addr )
+{
+ gsm_rope_add_c( rope, addr->len );
+ gsm_rope_add_c( rope, addr->toa );
+ gsm_rope_add( rope, addr->data, (addr->len+1)/2 );
+ if (addr->len & 1) {
+ if (!rope->error && rope->data != NULL)
+ rope->data[ rope->pos-1 ] |= 0xf0;
+ }
+}
+
+static int
+sms_address_eq( const SmsAddressRec* addr1, const SmsAddressRec* addr2 )
+{
+ if ( addr1->toa != addr2->toa ||
+ addr1->len != addr2->len )
+ return 0;
+
+ return ( !memcmp( addr1->data, addr2->data, addr1->len ) );
+}
+
+/** SMS PARSER
+ **/
+static int
+sms_get_byte( cbytes_t *pcur, cbytes_t end )
+{
+ cbytes_t cur = *pcur;
+ int result = -1;
+
+ if (cur < end) {
+ result = cur[0];
+ *pcur = cur + 1;
+ }
+ return result;
+}
+
+/* parse a service center address, returns -1 in case of error */
+static int
+sms_get_sc_address( cbytes_t *pcur,
+ cbytes_t end,
+ SmsAddress address )
+{
+ cbytes_t cur = *pcur;
+ int result = -1;
+
+ if (cur < end) {
+ int len = cur[0];
+ int dlen, adjust = 0;
+
+ cur += 1;
+
+ if (len == 0) { /* empty address */
+ address->len = 0;
+ address->toa = 0x00;
+ result = 0;
+ goto Exit;
+ }
+
+ if (cur + len > end) {
+ goto Exit;
+ }
+
+ address->toa = *cur++;
+ len -= 1;
+ result = 0;
+
+ for (dlen = 0; dlen < len; dlen+=1)
+ {
+ int c = cur[dlen];
+ int v;
+
+ adjust = 0;
+ if (dlen >= sizeof(address->data)) {
+ result = -1;
+ break;
+ }
+
+ v = (c & 0xf);
+ if (v >= 0xe)
+ break;
+
+ adjust = 1;
+ address->data[dlen] = (byte_t) c;
+
+ v = (c >> 4) & 0xf;
+ if (v >= 0xe) {
+ break;
+ }
+ }
+ address->len = 2*dlen + adjust;
+ }
+Exit:
+ if (!result)
+ *pcur = cur;
+
+ return result;
+}
+
+static int
+sms_skip_sc_address( cbytes_t *pcur,
+ cbytes_t end )
+{
+ cbytes_t cur = *pcur;
+ int result = -1;
+ int len;
+
+ if (cur >= end)
+ goto Exit;
+
+ len = cur[0];
+ cur += 1 + len;
+ if (cur > end)
+ goto Exit;
+
+ *pcur = cur;
+ result = 0;
+Exit:
+ return result;
+}
+
+/* parse a sender/receiver address, returns -1 in case of error */
+static int
+sms_get_address( cbytes_t *pcur,
+ cbytes_t end,
+ SmsAddress address )
+{
+ cbytes_t cur = *pcur;
+ int result = -1;
+ int len, dlen;
+
+ if (cur >= end)
+ goto Exit;
+
+ dlen = *cur++;
+
+ if (dlen == 0) {
+ address->len = 0;
+ address->toa = 0;
+ result = 0;
+ goto Exit;
+ }
+
+ if (cur + 1 + (dlen+1)/2 > end)
+ goto Exit;
+
+ address->len = dlen;
+ address->toa = *cur++;
+
+ len = (dlen + 1)/2;
+ if (len > sizeof(address->data))
+ goto Exit;
+
+ memcpy( address->data, cur, len );
+ cur += len;
+ result = 0;
+
+Exit:
+ if (!result)
+ *pcur = cur;
+
+ return result;
+}
+
+static int
+sms_skip_address( cbytes_t *pcur,
+ cbytes_t end )
+{
+ cbytes_t cur = *pcur;
+ int result = -1;
+ int dlen;
+
+ if (cur + 2 > end)
+ goto Exit;
+
+ dlen = cur[0];
+ cur += 2 + (dlen + 1)/2;
+ if (cur > end)
+ goto Exit;
+
+ result = 0;
+Exit:
+ return result;
+}
+
+/* parse a service center timestamp */
+static int
+sms_get_timestamp( cbytes_t *pcur,
+ cbytes_t end,
+ SmsTimeStamp ts )
+{
+ cbytes_t cur = *pcur;
+
+ if (cur + 7 > end)
+ return -1;
+
+ memcpy( ts->data, cur, 7 );
+ *pcur = cur + 7;
+ return 0;
+}
+
+static int
+sms_skip_timestamp( cbytes_t *pcur,
+ cbytes_t end )
+{
+ cbytes_t cur = *pcur;
+
+ if (cur + 7 > end)
+ return -1;
+
+ *pcur = cur + 7;
+ return 0;
+}
+
+
+static int
+sms_skip_validity_period( cbytes_t *pcur,
+ cbytes_t end,
+ int mtiByte )
+{
+ cbytes_t cur = *pcur;
+
+ switch ((mtiByte >> 3) & 3) {
+ case 1: /* relative format */
+ cur += 1;
+ break;
+
+ case 2: /* enhanced format */
+ case 3: /* absolute format */
+ cur += 7;
+ }
+ if (cur > end)
+ return -1;
+
+ *pcur = cur;
+ return 0;
+}
+
+/** SMS PDU
+ **/
+
+typedef struct SmsPDURec {
+ bytes_t base;
+ bytes_t end;
+ bytes_t tpdu;
+} SmsPDURec;
+
+void
+smspdu_free( SmsPDU pdu )
+{
+ if (pdu) {
+ free( pdu->base );
+ pdu->base = NULL;
+ pdu->end = NULL;
+ pdu->tpdu = NULL;
+ }
+}
+
+SmsPduType
+smspdu_get_type( SmsPDU pdu )
+{
+ cbytes_t data = pdu->tpdu;
+ cbytes_t end = pdu->end;
+ int mtiByte = sms_get_byte(&data, end);
+
+ switch (mtiByte & 3) {
+ case 0: return SMS_PDU_DELIVER;
+ case 1: return SMS_PDU_SUBMIT;
+ case 2: return SMS_PDU_STATUS_REPORT;
+ default: return SMS_PDU_INVALID;
+ }
+}
+
+int
+smspdu_get_sender_address( SmsPDU pdu, SmsAddress address )
+{
+ cbytes_t data = pdu->tpdu;
+ cbytes_t end = pdu->end;
+ int mtiByte = sms_get_byte(&data, end);
+
+ switch (mtiByte & 3) {
+ case 0: /* SMS_PDU_DELIVER; */
+ return sms_get_sc_address( &data, end, address );
+
+ default: return -1;
+ }
+}
+
+int
+smspdu_get_sc_timestamp( SmsPDU pdu, SmsTimeStamp ts )
+{
+ cbytes_t data = pdu->tpdu;
+ cbytes_t end = pdu->end;
+ int mtiByte = sms_get_byte( &data, end );
+
+ switch (mtiByte & 3) {
+ case 0: /* SMS_PDU_DELIVER */
+ {
+ SmsAddressRec address;
+
+ if ( sms_get_sc_address( &data, end, &address ) < 0 )
+ return -1;
+
+ data += 2; /* skip protocol identifer + coding scheme */
+
+ return sms_get_timestamp( &data, end, ts );
+ }
+
+ default: return -1;
+ }
+}
+
+int
+smspdu_get_receiver_address( SmsPDU pdu, SmsAddress address )
+{
+ cbytes_t data = pdu->tpdu;
+ cbytes_t end = pdu->end;
+ int mtiByte = sms_get_byte( &data, end );
+
+ switch (mtiByte & 3) {
+ case 1: /* SMS_PDU_SUBMIT */
+ {
+ data += 1; /* skip message reference */
+ return sms_get_address( &data, end, address );
+ }
+
+ default: return -1;
+ }
+}
+
+typedef enum {
+ SMS_CODING_SCHEME_UNKNOWN = 0,
+ SMS_CODING_SCHEME_GSM7,
+ SMS_CODING_SCHEME_UCS2
+
+} SmsCodingScheme;
+
+/* see TS 23.038 Section 5 for details */
+static SmsCodingScheme
+sms_get_coding_scheme( cbytes_t *pcur,
+ cbytes_t end )
+{
+ cbytes_t cur = *pcur;
+ int dataCoding;
+
+ if (cur >= end)
+ return SMS_CODING_SCHEME_UNKNOWN;
+
+ dataCoding = *cur++;
+ *pcur = cur;
+
+ switch (dataCoding >> 4) {
+ case 0x00:
+ case 0x02:
+ case 0x03:
+ return SMS_CODING_SCHEME_GSM7;
+
+ case 0x01:
+ if (dataCoding == 0x10) return SMS_CODING_SCHEME_GSM7;
+ if (dataCoding == 0x11) return SMS_CODING_SCHEME_UCS2;
+ break;
+
+ case 0x04: case 0x05: case 0x06: case 0x07:
+ if (dataCoding & 0x20) return SMS_CODING_SCHEME_UNKNOWN; /* compressed 7-bits */
+ if (((dataCoding >> 2) & 3) == 0) return SMS_CODING_SCHEME_GSM7;
+ if (((dataCoding >> 2) & 3) == 2) return SMS_CODING_SCHEME_UCS2;
+ break;
+
+ case 0xF:
+ if (!(dataCoding & 4)) return SMS_CODING_SCHEME_GSM7;
+ break;
+ }
+ return SMS_CODING_SCHEME_UNKNOWN;
+}
+
+
+/* see TS 23.040 section 9.2.3.24 for details */
+static int
+sms_get_text_utf8( cbytes_t *pcur,
+ cbytes_t end,
+ int hasUDH,
+ SmsCodingScheme coding,
+ GsmRope rope )
+{
+ cbytes_t cur = *pcur;
+ int result = -1;
+ int len;
+
+ if (cur >= end)
+ goto Exit;
+
+ len = *cur++;
+
+ /* skip user data header if any */
+ if ( hasUDH )
+ {
+ int hlen;
+
+ if (cur >= end)
+ goto Exit;
+
+ hlen = *cur++;
+ if (cur + hlen > end)
+ goto Exit;
+
+ cur += hlen;
+
+ if (coding == SMS_CODING_SCHEME_GSM7)
+ len -= 2*(hlen+1);
+ else
+ len -= hlen+1;
+
+ if (len < 0)
+ goto Exit;
+ }
+
+ /* switch the user data header if any */
+ if (coding == SMS_CODING_SCHEME_GSM7)
+ {
+ int count = utf8_from_gsm7( cur, 0, len, NULL );
+
+ if (rope != NULL)
+ {
+ bytes_t dst = gsm_rope_reserve( rope, count );
+ if (dst != NULL)
+ utf8_from_gsm7( cur, 0, len, dst );
+ }
+ cur += (len+1)/2;
+ }
+ else if (coding == SMS_CODING_SCHEME_UCS2)
+ {
+ int count = ucs2_to_utf8( cur, len/2, NULL );
+
+ if (rope != NULL)
+ {
+ bytes_t dst = gsm_rope_reserve( rope, count );
+ if (dst != NULL)
+ ucs2_to_utf8( cur, len/2, dst );
+ }
+ cur += len;
+ }
+ result = 0;
+
+Exit:
+ if (!result)
+ *pcur = cur;
+
+ return result;
+}
+
+/* get the message embedded in a SMS PDU as a utf8 byte array, returns the length of the message in bytes */
+/* or -1 in case of error */
+int
+smspdu_get_text_message( SmsPDU pdu, unsigned char* utf8, int utf8len )
+{
+ cbytes_t data = pdu->tpdu;
+ cbytes_t end = pdu->end;
+ int mtiByte = sms_get_byte( &data, end );
+
+ switch (mtiByte & 3) {
+ case 0: /* SMS_PDU_DELIVER */
+ {
+ SmsAddressRec address;
+ SmsTimeStampRec timestamp;
+ SmsCodingScheme coding;
+ GsmRopeRec rope[1];
+ int result;
+
+ if ( sms_get_sc_address( &data, end, &address ) < 0 )
+ goto Fail;
+
+ data += 1; /* skip protocol identifier */
+ coding = sms_get_coding_scheme( &data, end );
+ if (coding == SMS_CODING_SCHEME_UNKNOWN)
+ goto Fail;
+
+ if ( sms_get_timestamp( &data, end, &timestamp ) < 0 )
+ goto Fail;
+
+ if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 )
+ goto Fail;
+
+ result = rope->pos;
+ if (utf8len > result)
+ utf8len = result;
+
+ if (utf8len > 0)
+ memcpy( utf8, rope->data, utf8len );
+
+ gsm_rope_done( rope );
+ return result;
+ }
+
+ case 1: /* SMS_PDU_SUBMIT */
+ {
+ SmsAddressRec address;
+ SmsCodingScheme coding;
+ GsmRopeRec rope[1];
+ int result;
+
+ data += 1; /* message reference */
+
+ if ( sms_get_address( &data, end, &address ) < 0 )
+ goto Fail;
+
+ data += 1; /* skip protocol identifier */
+ coding = sms_get_coding_scheme( &data, end );
+ if (coding == SMS_CODING_SCHEME_UNKNOWN)
+ goto Fail;
+
+ gsm_rope_init_alloc( rope, 0 );
+ if ( sms_get_text_utf8( &data, end, (mtiByte & 0x40), coding, rope ) < 0 ) {
+ gsm_rope_done( rope );
+ goto Fail;
+ }
+
+ result = rope->pos;
+ if (utf8len > result)
+ utf8len = result;
+
+ if (utf8len > 0)
+ memcpy( utf8, rope->data, utf8len );
+
+ gsm_rope_done( rope );
+ return result;
+ }
+ }
+Fail:
+ return -1;
+}
+
+static cbytes_t
+smspdu_get_user_data_ref( SmsPDU pdu )
+{
+ cbytes_t data = pdu->tpdu;
+ cbytes_t end = pdu->end;
+ int mtiByte = sms_get_byte( &data, end );
+ int len;
+
+ /* if there is no user-data-header, there is no message reference here */
+ if ((mtiByte & 0x40) == 0)
+ goto Fail;
+
+ switch (mtiByte & 3) {
+ case 0: /* SMS_PDU_DELIVER */
+ if ( sms_skip_address( &data, end ) < 0 )
+ goto Fail;
+
+ data += 2; /* skip protocol identifier + coding scheme */
+
+ if ( sms_skip_timestamp( &data, end ) < 0 )
+ goto Fail;
+
+ break;
+
+ case 1: /* SMS_PDU_SUBMIT */
+ data += 1; /* skip message reference */
+
+ if ( sms_skip_address( &data, end ) < 0 )
+ goto Fail;
+
+ data += 2; /* protocol identifier + oding schene */
+ if ( sms_skip_validity_period( &data, end, mtiByte ) < 0 )
+ goto Fail;
+
+ break;
+
+ default:
+ goto Fail;
+ }
+
+ /* skip user-data length */
+ if (data+1 >= end)
+ goto Fail;
+
+ len = data[1];
+ data += 2;
+
+ while (len >= 2 && data + 2 <= end) {
+ int htype = data[0];
+ int hlen = data[1];
+
+ if (htype == 00 && hlen == 3 && data + 5 <= end) {
+ return data + 2;
+ }
+
+ data += hlen;
+ len -= hlen - 2;
+ }
+Fail:
+ return NULL;
+}
+
+int
+smspdu_get_ref( SmsPDU pdu )
+{
+ cbytes_t user_ref = smspdu_get_user_data_ref( pdu );
+
+ if (user_ref != NULL)
+ {
+ return user_ref[0];
+ }
+ else
+ {
+ cbytes_t data = pdu->tpdu;
+ cbytes_t end = pdu->end;
+ int mtiByte = sms_get_byte( &data, end );
+
+ if ((mtiByte & 3) == 1) {
+ /* try to extract directly the reference for a SMS-SUBMIT */
+ if (data < end)
+ return data[0];
+ }
+ }
+ return -1;
+}
+
+int
+smspdu_get_max_index( SmsPDU pdu )
+{
+ cbytes_t user_ref = smspdu_get_user_data_ref( pdu );
+
+ if (user_ref != NULL) {
+ return user_ref[1];
+ } else {
+ return 1;
+ }
+}
+
+int
+smspdu_get_cur_index( SmsPDU pdu )
+{
+ cbytes_t user_ref = smspdu_get_user_data_ref( pdu );
+
+ if (user_ref != NULL) {
+ return user_ref[2] - 1;
+ } else {
+ return 0;
+ }
+}
+
+
+static void
+gsm_rope_add_sms_user_header( GsmRope rope,
+ int ref_number,
+ int pdu_count,
+ int pdu_index )
+{
+ gsm_rope_add_c( rope, 0x05 ); /* total header length == 5 bytes */
+ gsm_rope_add_c( rope, 0x00 ); /* element id: concatenated message reference number */
+ gsm_rope_add_c( rope, 0x03 ); /* element len: 3 bytes */
+ gsm_rope_add_c( rope, (byte_t)ref_number ); /* reference number */
+ gsm_rope_add_c( rope, (byte_t)pdu_count ); /* max pdu index */
+ gsm_rope_add_c( rope, (byte_t)pdu_index+1 ); /* current pdu index */
+}
+
+/* write a SMS-DELIVER PDU into a rope */
+static void
+gsm_rope_add_sms_deliver_pdu( GsmRope rope,
+ cbytes_t utf8,
+ int utf8len,
+ int use_gsm7,
+ const SmsAddressRec* sender_address,
+ const SmsTimeStampRec* timestamp,
+ int ref_num,
+ int pdu_count,
+ int pdu_index)
+{
+ int coding;
+ int mtiByte = 0x20; /* message type - SMS DELIVER */
+
+ if (pdu_count > 1)
+ mtiByte |= 0x40; /* user data header indicator */
+
+ gsm_rope_add_c( rope, 0 ); /* no SC Address */
+ gsm_rope_add_c( rope, mtiByte ); /* message type - SMS-DELIVER */
+ gsm_rope_add_address( rope, sender_address );
+ gsm_rope_add_c( rope, 0 ); /* protocol identifier */
+
+ /* data coding scheme - GSM 7 bits / no class - or - 16-bit UCS2 / class 1 */
+ coding = (use_gsm7 ? 0x00 : 0x09);
+
+ gsm_rope_add_c( rope, coding ); /* data coding scheme */
+ gsm_rope_add_timestamp( rope, timestamp ); /* service center timestamp */
+
+ if (use_gsm7) {
+ bytes_t dst;
+ int count = utf8_to_gsm7( utf8, utf8len, NULL, 0 );
+ int pad = 0;
+
+ assert( count <= MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE );
+
+ if (pdu_count > 1)
+ {
+ int headerBits = 6*8; /* 6 is size of header in bytes */
+ int headerSeptets = headerBits / 7;
+ if (headerBits % 7 > 0)
+ headerSeptets += 1;
+
+ pad = headerSeptets*7 - headerBits;
+
+ gsm_rope_add_c( rope, count + headerSeptets );
+ gsm_rope_add_sms_user_header(rope, ref_num, pdu_count, pdu_index);
+ }
+ else
+ gsm_rope_add_c( rope, count );
+
+ count = (count*7+pad+7)/8; /* convert to byte count */
+
+ dst = gsm_rope_reserve( rope, count );
+ if (dst != NULL) {
+ utf8_to_gsm7( utf8, utf8len, dst, pad );
+ }
+ } else {
+ bytes_t dst;
+ int count = utf8_to_ucs2( utf8, utf8len, NULL );
+
+ assert( count*2 <= MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE );
+
+ if (pdu_count > 1)
+ {
+ gsm_rope_add_c( rope, count*2 + 6 );
+ gsm_rope_add_sms_user_header( rope, ref_num, pdu_count, pdu_index );
+ }
+ else
+ gsm_rope_add_c( rope, count*2 );
+
+ gsm_rope_add_c( rope, count*2 );
+ dst = gsm_rope_reserve( rope, count*2 );
+ if (dst != NULL) {
+ utf8_to_ucs2( utf8, utf8len, dst );
+ }
+ }
+}
+
+
+static SmsPDU
+smspdu_create_deliver( cbytes_t utf8,
+ int utf8len,
+ int use_gsm7,
+ const SmsAddressRec* sender_address,
+ const SmsTimeStampRec* timestamp,
+ int ref_num,
+ int pdu_count,
+ int pdu_index )
+{
+ SmsPDU p;
+ GsmRopeRec rope[1];
+ int size;
+
+ p = calloc( sizeof(*p), 1 );
+ if (!p) goto Exit;
+
+ gsm_rope_init( rope );
+ gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7,
+ sender_address, timestamp,
+ ref_num, pdu_count, pdu_index);
+ if (rope->error)
+ goto Fail;
+
+ gsm_rope_init_alloc( rope, rope->pos );
+
+ gsm_rope_add_sms_deliver_pdu( rope, utf8, utf8len, use_gsm7,
+ sender_address, timestamp,
+ ref_num, pdu_count, pdu_index );
+
+ p->base = gsm_rope_done_acquire( rope, &size );
+ if (p->base == NULL)
+ goto Fail;
+
+ p->end = p->base + size;
+ p->tpdu = p->base + 1;
+Exit:
+ return p;
+
+Fail:
+ free(p);
+ return NULL;
+}
+
+
+void
+smspdu_free_list( SmsPDU* pdus )
+{
+ if (pdus) {
+ int nn;
+ for (nn = 0; pdus[nn] != NULL; nn++)
+ smspdu_free( pdus[nn] );
+
+ free( pdus );
+ }
+}
+
+
+
+SmsPDU*
+smspdu_create_deliver_utf8( const unsigned char* utf8,
+ int utf8len,
+ const SmsAddressRec* sender_address,
+ const SmsTimeStampRec* timestamp )
+{
+ SmsTimeStampRec ts0;
+ int use_gsm7;
+ int count, block;
+ int num_pdus = 0;
+ int leftover = 0;
+ SmsPDU* list = NULL;
+
+ static unsigned char ref_num = 0;
+
+ if (timestamp == NULL) {
+ sms_timestamp_now( &ts0 );
+ timestamp = &ts0;
+ }
+
+ /* can we encode the message with the GSM 7-bit alphabet ? */
+ use_gsm7 = utf8_check_gsm7( utf8, utf8len );
+
+ /* count the number of SMS PDUs we'll need */
+ block = MAX_USER_DATA_SEPTETS - USER_DATA_HEADER_SIZE;
+
+ if (use_gsm7) {
+ count = utf8_to_gsm7( utf8, utf8len, NULL, 0 );
+ } else {
+ count = utf8_to_ucs2( utf8, utf8len, NULL );
+ block = MAX_USER_DATA_BYTES - USER_DATA_HEADER_SIZE;
+ }
+
+ num_pdus = count / block;
+ leftover = count - num_pdus*block;
+ if (leftover > 0)
+ num_pdus += 1;
+
+ list = calloc( sizeof(SmsPDU*), num_pdus + 1 );
+ if (list == NULL)
+ return NULL;
+
+ /* now create each SMS PDU */
+ {
+ cbytes_t src = utf8;
+ cbytes_t src_end = utf8 + utf8len;
+ int nn;
+
+ for (nn = 0; nn < num_pdus; nn++)
+ {
+ int skip = block;
+ cbytes_t src_next;
+
+ if (leftover > 0 && nn == num_pdus-1)
+ skip = leftover;
+
+ src_next = utf8_skip_gsm7( src, src_end, skip );
+
+ list[nn] = smspdu_create_deliver( src, src_next - src, use_gsm7, sender_address, timestamp,
+ ref_num, num_pdus, nn );
+ if (list[nn] == NULL)
+ goto Fail;
+
+ src = src_next;
+ }
+ }
+
+ ref_num++;
+ return list;
+
+Fail:
+ smspdu_free_list(list);
+ return NULL;
+}
+
+
+SmsPDU
+smspdu_create_from_hex( const char* hex, int hexlen )
+{
+ SmsPDU p;
+ cbytes_t data;
+
+ p = calloc( sizeof(*p), 1 );
+ if (!p) goto Exit;
+
+ p->base = malloc( (hexlen+1)/2 );
+ if (p->base == NULL) {
+ free(p);
+ p = NULL;
+ goto Exit;
+ }
+
+ if ( gsm_hex_to_bytes( (cbytes_t)hex, hexlen, p->base ) < 0 )
+ goto Fail;
+
+ p->end = p->base + (hexlen+1)/2;
+
+ data = p->base;
+ if ( sms_skip_sc_address( &data, p->end ) < 0 )
+ goto Fail;
+
+ p->tpdu = (bytes_t) data;
+
+Exit:
+ return p;
+
+Fail:
+ free(p->base);
+ free(p);
+ return NULL;
+}
+
+int
+smspdu_to_hex( SmsPDU pdu, char* hex, int hexlen )
+{
+ int result = (pdu->end - pdu->base)*2;
+ int nn;
+
+ if (hexlen > result)
+ hexlen = result;
+
+ for (nn = 0; nn*2 < hexlen; nn++) {
+ gsm_hex_from_byte( &hex[nn*2], pdu->base[nn] );
+ }
+ return result;
+}
+
+
+/** SMS SUBMIT RECEIVER
+ ** collects one or more SMS-SUBMIT PDUs to generate a single message to deliver
+ **/
+
+typedef struct SmsFragmentRec {
+ struct SmsFragmentRec* next;
+ SmsAddressRec from[1];
+ byte_t ref;
+ byte_t max;
+ byte_t count;
+ int index;
+ SmsPDU* pdus;
+
+} SmsFragmentRec, *SmsFragment;
+
+
+typedef struct SmsReceiverRec {
+ int last;
+ SmsFragment fragments;
+
+} SmsReceiverRec;
+
+
+static void
+sms_fragment_free( SmsFragment frag )
+{
+ int nn;
+
+ for (nn = 0; nn < frag->max; nn++) {
+ if (frag->pdus[nn] != NULL) {
+ smspdu_free( frag->pdus[nn] );
+ frag->pdus[nn] = NULL;
+ }
+ }
+ frag->pdus = NULL;
+ frag->count = 0;
+ frag->max = 0;
+ frag->index = 0;
+ free( frag );
+}
+
+static SmsFragment
+sms_fragment_alloc( SmsReceiver rec, const SmsAddressRec* from, int ref, int max )
+{
+ SmsFragment frag = calloc(sizeof(*frag) + max*sizeof(SmsPDU), 1 );
+
+ if (frag != NULL) {
+ frag->from[0] = from[0];
+ frag->ref = ref;
+ frag->max = max;
+ frag->pdus = (SmsPDU*)(frag + 1);
+ frag->index = ++rec->last;
+ }
+ return frag;
+}
+
+
+
+SmsReceiver sms_receiver_create( void )
+{
+ SmsReceiver rec = calloc(sizeof(*rec),1);
+ return rec;
+}
+
+void
+sms_receiver_destroy( SmsReceiver rec )
+{
+ while (rec->fragments) {
+ SmsFragment frag = rec->fragments;
+ rec->fragments = frag->next;
+ sms_fragment_free(frag);
+ }
+}
+
+static SmsFragment*
+sms_receiver_find_p( SmsReceiver rec, const SmsAddressRec* from, int ref )
+{
+ SmsFragment* pnode = &rec->fragments;
+ SmsFragment node;
+
+ for (;;) {
+ node = *pnode;
+ if (node == NULL)
+ break;
+ if (node->ref == ref && sms_address_eq( node->from, from ))
+ break;
+ pnode = &node->next;
+ }
+ return pnode;
+}
+
+static SmsFragment*
+sms_receiver_find_index_p( SmsReceiver rec, int index )
+{
+ SmsFragment* pnode = &rec->fragments;
+ SmsFragment node;
+
+ for (;;) {
+ node = *pnode;
+ if (node == NULL)
+ break;
+ if (node->index == index)
+ break;
+ pnode = &node->next;
+ }
+ return pnode;
+}
+
+int
+sms_receiver_add_submit_pdu( SmsReceiver rec, SmsPDU submit_pdu )
+{
+ SmsAddressRec from[1];
+ int ref, max, cur;
+ SmsFragment* pnode;
+ SmsFragment frag;
+
+ if ( smspdu_get_receiver_address( submit_pdu, from ) < 0 ) {
+ D( "%s: could not extract receiver address\n", __FUNCTION__ );
+ return -1;
+ }
+
+ ref = smspdu_get_ref( submit_pdu );
+ if (ref < 0) {
+ D( "%s: could not extract message reference from pdu\n", __FUNCTION__ );
+ return -1;
+ }
+ max = smspdu_get_max_index( submit_pdu );
+ if (max < 0) {
+ D( "%s: invalid max fragment value: %d should be >= 1\n",
+ __FUNCTION__, max );
+ return -1;
+ }
+ pnode = sms_receiver_find_p( rec, from, ref );
+ frag = *pnode;
+ if (frag == NULL) {
+ frag = sms_fragment_alloc( rec, from, ref, max );
+ if (frag == NULL) {
+ D("%s: not enough memory to allocate new fragment\n", __FUNCTION__ );
+ return -1;
+ }
+ if (D_ACTIVE) {
+ char tmp[32];
+ int len;
+
+ len = sms_address_to_str( from, tmp, sizeof(tmp) );
+ if (len < 0) {
+ strcpy( tmp, "<unknown>" );
+ len = strlen(tmp);
+ }
+ D("%s: created SMS index %d, from %.*s, ref %d, max %d\n", __FUNCTION__,
+ frag->index, len, tmp, frag->ref, frag->max);
+ }
+ *pnode = frag;
+ }
+
+ cur = smspdu_get_cur_index( submit_pdu );
+ if (cur < 0) {
+ D("%s: SMS fragment index is too small: %d should be >= 1\n", __FUNCTION__, cur+1 );
+ return -1;
+ }
+ if (cur >= max) {
+ D("%s: SMS fragment index is too large (%d >= %d)\n", __FUNCTION__, cur, max);
+ return -1;
+ }
+ if ( frag->pdus[cur] != NULL ) {
+ D("%s: receiving duplicate SMS fragment for %d/%d, ref=%d, discarding old one\n",
+ __FUNCTION__, cur+1, max, ref);
+ smspdu_free( frag->pdus[cur] );
+ frag->count -= 1;
+ }
+ frag->pdus[cur] = submit_pdu;
+ frag->count += 1;
+
+ if (frag->count >= frag->max) {
+ /* yes, we received all fragments for this SMS */
+ D( "%s: SMS index %d, received all %d fragments\n", __FUNCTION__, frag->index, frag->count );
+ return frag->index;
+ }
+ else {
+ /* still waiting for more */
+ D( "%s: SMS index %d, received %d/%d, waiting for %d more\n", __FUNCTION__,
+ frag->index, cur+1, max, frag->max - frag->count );
+ return 0;
+ }
+}
+
+
+int
+sms_receiver_get_text_message( SmsReceiver rec, int index, bytes_t utf8, int utf8len )
+{
+ SmsFragment* pnode = sms_receiver_find_index_p( rec, index );
+ SmsFragment frag = *pnode;
+ int nn, total;
+
+ if (frag == NULL) {
+ D( "%s: invalid SMS index %d\n", __FUNCTION__, index );
+ return -1;
+ }
+ if (frag->count != frag->max) {
+ D( "%s: SMS index %d still needs %d fragments\n", __FUNCTION__,
+ frag->index, frag->max - frag->count );
+ return -1;
+ }
+ /* get the size of all combined text */
+ total = 0;
+ for ( nn = 0; nn < frag->count; nn++ ) {
+ int partial;
+ if (utf8 && utf8len > 0) {
+ partial = smspdu_get_text_message( frag->pdus[nn], utf8, utf8len );
+ utf8 += partial;
+ utf8len -= partial;
+ } else {
+ partial = smspdu_get_text_message( frag->pdus[nn], NULL, 0 );
+ }
+ total += partial;
+ }
+ return total;
+}
+
+
+static void
+sms_receiver_remove( SmsReceiver rec, int index )
+{
+ SmsFragment* pnode = sms_receiver_find_index_p( rec, index );
+ SmsFragment frag = *pnode;
+ if (frag != NULL) {
+ *pnode = frag->next;
+ sms_fragment_free(frag);
+ }
+}
+
+
+SmsPDU*
+sms_receiver_create_deliver( SmsReceiver rec, int index, const SmsAddressRec* from )
+{
+ SmsPDU* result = NULL;
+ SmsFragment* pnode = sms_receiver_find_index_p( rec, index );
+ SmsFragment frag = *pnode;
+ SmsTimeStampRec now[1];
+ int nn, total;
+ bytes_t utf8;
+ int utf8len;
+
+ if (frag == NULL) {
+ D( "%s: invalid SMS index %d\n", __FUNCTION__, index );
+ return NULL;
+ }
+ if (frag->count != frag->max) {
+ D( "%s: SMS index %d still needs %d fragments\n", __FUNCTION__,
+ frag->index, frag->max - frag->count );
+ return NULL;
+ }
+
+ /* get the combined text message */
+ utf8len = sms_receiver_get_text_message( rec, index, NULL, 0 );
+ if (utf8len < 0)
+ goto Exit;
+
+ utf8 = malloc( utf8len + 1 );
+ if (utf8 == NULL) {
+ D( "%s: not enough memory to allocate %d bytes\n",
+ __FUNCTION__, utf8len+1 );
+ goto Exit;
+ }
+
+ total = 0;
+ for ( nn = 0; nn < frag->count; nn++ ) {
+ total += smspdu_get_text_message( frag->pdus[nn], utf8 + total, utf8len - total );
+ }
+
+ sms_timestamp_now( now );
+
+ result = smspdu_create_deliver_utf8( utf8, utf8len, from, now );
+
+ free(utf8);
+
+Exit:
+ sms_receiver_remove( rec, index );
+ return result;
+}
+
diff --git a/telephony/sms.h b/telephony/sms.h
new file mode 100644
index 0000000..7059ee3
--- /dev/null
+++ b/telephony/sms.h
@@ -0,0 +1,117 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef _android_sms_h
+#define _android_sms_h
+
+#include <time.h>
+
+/** MESSAGE TEXT
+ **/
+/* convert a quoted message text into a utf8 string. Note: you can use 'str' as the destination buffer
+ * with the current implementation. always return the number of utf8 bytes corresponding to the original
+ * message string, even if utf8 is NULL and utf8len is 0
+ */
+extern int sms_utf8_from_message_str( const char* str, int strlen, unsigned char* utf8, int utf8len );
+
+/* the equivalent in the opposite direction
+ */
+extern int sms_utf8_to_message_str( const unsigned char* utf8, int utf8len, char* str, int strlen );
+
+/** TIMESTAMPS
+ **/
+
+/* An SMS timestamp structure */
+typedef struct {
+ unsigned char data[7];
+} SmsTimeStampRec, *SmsTimeStamp;
+
+extern void sms_timestamp_now( SmsTimeStamp stamp );
+extern int sms_timestamp_to_tm( SmsTimeStamp stamp, struct tm* tm );
+
+/** SMS ADDRESSES
+ **/
+
+#define SMS_ADDRESS_MAX_SIZE 16
+
+typedef struct {
+ unsigned char len;
+ unsigned char toa;
+ unsigned char data[ SMS_ADDRESS_MAX_SIZE ];
+} SmsAddressRec, *SmsAddress;
+
+extern int sms_address_from_str( SmsAddress address, const char* src, int srclen );
+extern int sms_address_to_str( SmsAddress address, char* src, int srclen );
+
+extern int sms_address_from_bytes( SmsAddress address, const unsigned char* buf, int buflen );
+extern int sms_address_to_bytes ( SmsAddress address, unsigned char* buf, int bufsize );
+extern int sms_address_from_hex ( SmsAddress address, const char* hex, int hexlen );
+extern int sms_address_to_hex ( SmsAddress address, char* hex, int hexsize );
+
+/** SMS PROTOCOL DATA UNITS
+ **/
+
+typedef struct SmsPDURec* SmsPDU;
+
+extern SmsPDU* smspdu_create_deliver_utf8( const unsigned char* utf8,
+ int utf8len,
+ const SmsAddressRec* sender_address,
+ const SmsTimeStampRec* timestamp );
+
+extern void smspdu_free_list( SmsPDU* pdus );
+
+extern SmsPDU smspdu_create_from_hex( const char* hex, int hexlen );
+
+extern int smspdu_to_hex( SmsPDU pdu, char* hex, int hexsize );
+
+/* free a given SMS PDU */
+extern void smspdu_free( SmsPDU pdu );
+
+typedef enum {
+ SMS_PDU_INVALID = 0,
+ SMS_PDU_DELIVER,
+ SMS_PDU_SUBMIT,
+ SMS_PDU_STATUS_REPORT
+} SmsPduType;
+
+extern SmsPduType smspdu_get_type( SmsPDU pdu );
+
+/* retrieve the sender address of a SMS-DELIVER pdu, returns -1 otherwise */
+extern int smspdu_get_sender_address( SmsPDU pdu, SmsAddress address );
+
+/* retrieve the service center timestamp of a SMS-DELIVER pdu, return -1 otherwise */
+extern int smspdu_get_sc_timestamp( SmsPDU pdu, SmsTimeStamp timestamp );
+
+/* retrieve the receiver address of a SMS-SUBMIT pdu, return -1 otherwise */
+extern int smspdu_get_receiver_address( SmsPDU pdu, SmsAddress address );
+
+extern int smspdu_get_ref ( SmsPDU pdu );
+extern int smspdu_get_max_index( SmsPDU pdu );
+extern int smspdu_get_cur_index( SmsPDU pdu );
+
+/* get the message embedded in a SMS PDU as a utf8 byte array, returns the length of the message in bytes */
+/* or -1 in case of error */
+extern int smspdu_get_text_message( SmsPDU pdu, unsigned char* utf8, int utf8len );
+
+/** SMS SUBMIT RECEIVER
+ ** collects one or more SMS-SUBMIT PDUs to generate a single message to deliver
+ **/
+
+typedef struct SmsReceiverRec *SmsReceiver;
+
+extern SmsReceiver sms_receiver_create( void );
+extern void sms_receiver_destroy( SmsReceiver rec );
+
+extern int sms_receiver_add_submit_pdu( SmsReceiver rec, SmsPDU submit_pdu );
+extern int sms_receiver_get_text_message( SmsReceiver rec, int index, unsigned char* utf8, int utf8len );
+extern SmsPDU* sms_receiver_create_deliver( SmsReceiver rec, int index, const SmsAddressRec* from );
+
+#endif /* _android_sms_h */
diff --git a/telephony/sysdeps.h b/telephony/sysdeps.h
new file mode 100644
index 0000000..19ca8d3
--- /dev/null
+++ b/telephony/sysdeps.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#ifndef __sysdeps_h__
+#define __sysdeps_h__
+
+/* system-dependent platform abstraction used by the emulated GSM modem
+ */
+
+/* to be called before anything else */
+
+extern void sys_main_init( void );
+
+/** callbacks
+ **/
+typedef void (*SysCallback)( void* opaque );
+
+/** events
+ **/
+enum {
+ SYS_EVENT_READ = 0x01,
+ SYS_EVENT_WRITE = 0x02,
+ SYS_EVENT_ERROR = 0x04,
+ SYS_EVENT_ALL = 0x07
+};
+
+/** channels
+ **/
+typedef struct SysChannelRec_* SysChannel;
+
+typedef void (*SysChannelCallback)( void* opaque, int event_flags );
+
+/* XXX: TODO: channel creation functions */
+extern SysChannel sys_channel_create_tcp_server( int port );
+extern SysChannel sys_channel_create_tcp_handler( SysChannel server_channel );
+extern SysChannel sys_channel_create_tcp_client( const char* hostname, int port );
+extern int sys_channel_set_non_block( SysChannel channel );
+
+extern void sys_channel_on( SysChannel channel,
+ int event_flags,
+ SysChannelCallback event_callback,
+ void* event_opaqe );
+
+extern int sys_channel_read( SysChannel channel, void* buffer, int size );
+
+extern int sys_channel_write( SysChannel channel, const void* buffer, int size );
+
+extern void sys_channel_close( SysChannel channel );
+
+
+/** time measurement
+ **/
+typedef long long SysTime;
+
+extern SysTime sys_time_now( void );
+
+/** timers
+ **/
+typedef struct SysTimerRec_* SysTimer;
+
+extern SysTimer sys_timer_create( void );
+extern void sys_timer_set( SysTimer timer, SysTime when, SysCallback callback, void* opaque );
+extern void sys_timer_unset( SysTimer timer );
+extern void sys_timer_destroy( SysTimer timer );
+
+extern long long sys_time_ms( void );
+
+/** main loop (may return immediately on some platform)
+ **/
+extern int sys_main_loop( void );
+
+#endif /* __sysdeps_h__ */
diff --git a/telephony/sysdeps_posix.c b/telephony/sysdeps_posix.c
new file mode 100644
index 0000000..8c5eb12
--- /dev/null
+++ b/telephony/sysdeps_posix.c
@@ -0,0 +1,645 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "sysdeps.h"
+#include <assert.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <errno.h>
+#include <memory.h>
+#include <stdio.h>
+#ifndef HAVE_WINSOCK
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#endif
+
+/** QUEUE
+ **/
+#define SYS_MAX_QUEUE 16
+
+typedef struct {
+ int start;
+ int end;
+ void* pending[ SYS_MAX_QUEUE ];
+}
+SysQueueRec, *SysQueue;
+
+static void
+sys_queue_reset( SysQueue queue )
+{
+ queue->start = queue->end = 0;
+}
+
+static void
+sys_queue_add( SysQueue queue, void* item )
+{
+ assert( queue->end - queue->start < SYS_MAX_QUEUE );
+ assert( queue->start == 0 );
+ assert( item != NULL );
+ queue->pending[ queue->end++ ] = item;
+}
+
+#if 0
+static void
+sys_queue_remove( SysQueue queue, void* item )
+{
+ int nn, count;
+ assert( queue->end > queue->start );
+ assert( item != NULL );
+ count = queue->end - queue->start;
+ for ( nn = queue->start; count > 0; ++nn, --count ) {
+ if ( queue->pending[nn] == item ) {
+ queue->pending[nn] = queue->pending[nn+count-1];
+ queue->end -= 1;
+ break;
+ }
+ }
+ assert( 0 && "sys_queue_remove: item not found" );
+}
+#endif
+
+static void*
+sys_queue_get( SysQueue queue )
+{
+ if (queue->end > queue->start) {
+ return queue->pending[ queue->start++ ];
+ }
+ return NULL;
+}
+
+/** CHANNELS
+ **/
+typedef struct SysChannelRec_ {
+ SysChannel next;
+ int fd;
+ char active;
+ char pending;
+ char closed;
+ int wanted;
+ int ready;
+ SysChannelCallback callback;
+ void* opaque;
+} SysChannelRec;
+
+
+/*** channel allocation ***/
+#define SYS_EVENT_MAX 3
+#define SYS_MAX_CHANNELS 16
+
+static SysChannelRec _s_channels0[ SYS_MAX_CHANNELS ];
+static SysChannel _s_free_channels;
+
+static SysChannel
+sys_channel_alloc( void )
+{
+ SysChannel channel = _s_free_channels;
+ assert( channel != NULL && "out of free channels" );
+ _s_free_channels = channel->next;
+ channel->next = NULL;
+ channel->active = 0;
+ channel->closed = 0;
+ channel->pending = 0;
+ channel->wanted = 0;
+ return channel;
+}
+
+static void
+sys_channel_free( SysChannel channel )
+{
+ if (channel->fd >= 0) {
+#ifdef _WIN32
+ shutdown( channel->fd, SD_BOTH );
+#else
+ shutdown( channel->fd, SHUT_RDWR );
+#endif
+ close(channel->fd);
+ channel->fd = -1;
+ }
+ channel->wanted = 0;
+ channel->ready = 0;
+ channel->callback = NULL;
+
+ channel->next = _s_free_channels;
+ _s_free_channels = channel;
+}
+
+
+/* list of active channels */
+static SysChannel _s_channels;
+
+/* used by select to wait on channel events */
+static fd_set _s_fdsets[SYS_EVENT_MAX];
+static int _s_maxfd;
+
+static void
+sys_channel_deactivate( SysChannel channel )
+{
+ assert( channel->active != 0 );
+ SysChannel *pnode = &_s_channels;
+ for (;;) {
+ SysChannel node = *pnode;
+ assert( node != NULL );
+ if (node == channel)
+ break;
+ pnode = &node->next;
+ }
+ *pnode = channel->next;
+ channel->next = NULL;
+ channel->active = 0;
+}
+
+static void
+sys_channel_activate( SysChannel channel )
+{
+ assert( channel->active == 0 );
+ channel->next = _s_channels;
+ _s_channels = channel;
+ channel->active = 1;
+ if (channel->fd > _s_maxfd)
+ _s_maxfd = channel->fd;
+}
+
+
+/* queue of pending channels */
+static SysQueueRec _s_pending_channels[1];
+
+
+static void
+sys_init_channels( void )
+{
+ int nn;
+
+ for (nn = 0; nn < SYS_MAX_CHANNELS-1; nn++)
+ _s_channels0[nn].next = &_s_channels0[nn+1];
+ _s_free_channels = &_s_channels0[0];
+
+ for (nn = 0; nn < SYS_EVENT_MAX; nn++)
+ FD_ZERO( &_s_fdsets[nn] );
+
+ _s_maxfd = -1;
+
+ sys_queue_reset( _s_pending_channels );
+}
+
+
+void
+sys_channel_on( SysChannel channel,
+ int events,
+ SysChannelCallback callback,
+ void* opaque )
+{
+ int adds = events & ~channel->wanted;
+ int removes = channel->wanted & ~events;
+
+ channel->wanted = events;
+ channel->callback = callback;
+ channel->opaque = opaque;
+
+ /* update global fdsets */
+ if (adds) {
+ int ee;
+ for (ee = 0; ee < SYS_EVENT_MAX; ee++)
+ if (adds & (1 << ee))
+ FD_SET( channel->fd, &_s_fdsets[ee] );
+ }
+ if (removes) {
+ int ee;
+ for (ee = 0; ee < SYS_EVENT_MAX; ee++)
+ if (removes & (1 << ee))
+ FD_CLR( channel->fd, &_s_fdsets[ee] );
+ }
+ if (events && !channel->active) {
+ sys_channel_activate( channel );
+ }
+ else if (!events && channel->active) {
+ sys_channel_deactivate( channel );
+ }
+}
+
+int
+sys_channel_read( SysChannel channel, void* buffer, int size )
+{
+ char* buff = buffer;
+ int count = 0;
+
+ assert( !channel->closed );
+
+ while (size > 0) {
+ int len = read(channel->fd, buff, size);
+ if (len < 0) {
+ if (errno == EINTR)
+ continue;
+ if (count == 0)
+ count = -1;
+ break;
+ }
+ buff += len;
+ size -= len;
+ count += len;
+ }
+ return count;
+}
+
+
+int
+sys_channel_write( SysChannel channel, const void* buffer, int size )
+{
+ const char* buff = buffer;
+ int count = 0;
+
+ assert( !channel->closed );
+
+ while (size > 0) {
+ int len = write(channel->fd, buff, size);
+ if (len < 0) {
+ if (errno == EINTR)
+ continue;
+ if (count == 0)
+ count = -1;
+ break;
+ }
+ buff += len;
+ size -= len;
+ count += len;
+ }
+ return count;
+}
+
+
+void
+sys_channel_close( SysChannel channel )
+{
+ if (channel->active) {
+ sys_channel_on( channel, 0, NULL, NULL );
+ }
+
+ if (channel->pending) {
+ /* we can't free the channel right now because it */
+ /* is in the pending list, set a flag */
+ channel->closed = 1;
+ return;
+ }
+
+ if (!channel->closed) {
+ channel->closed = 1;
+ }
+
+ sys_channel_free( channel );
+}
+
+/** time measurement
+ **/
+SysTime sys_time_ms( void )
+{
+ struct timeval tv;
+ gettimeofday( &tv, NULL );
+ return (SysTime)(tv.tv_usec / 1000) + (SysTime)tv.tv_sec * 1000;
+}
+
+/** timers
+ **/
+typedef struct SysTimerRec_
+{
+ SysTimer next;
+ SysTime when;
+ SysCallback callback;
+ void* opaque;
+} SysTimerRec;
+
+#define SYS_MAX_TIMERS 16
+
+static SysTimerRec _s_timers0[ SYS_MAX_TIMERS ];
+static SysTimer _s_free_timers;
+static SysTimer _s_timers;
+
+static SysQueueRec _s_pending_timers[1];
+
+
+static void
+sys_init_timers( void )
+{
+ int nn;
+ for (nn = 0; nn < SYS_MAX_TIMERS-1; nn++) {
+ _s_timers0[nn].next = & _s_timers0[nn+1];
+ }
+ _s_free_timers = &_s_timers0[0];
+
+ sys_queue_reset( _s_pending_timers );
+}
+
+
+SysTimer sys_timer_create( void )
+{
+ SysTimer timer = _s_free_timers;
+ assert( timer != NULL && "too many timers allocated" );
+ _s_free_timers = timer->next;
+ timer->next = NULL;
+ return timer;
+}
+
+
+void sys_timer_unset( SysTimer timer )
+{
+ if (timer->callback != NULL) {
+ SysTimer *pnode, node;
+ pnode = &_s_timers;
+ for (;;) {
+ node = *pnode;
+ if (node == NULL)
+ break;
+ if (node == timer) {
+ *pnode = node->next;
+ break;
+ }
+ pnode = &node->next;
+ }
+ timer->next = NULL;
+ timer->callback = NULL;
+ timer->opaque = NULL;
+ }
+}
+
+
+void sys_timer_set( SysTimer timer,
+ SysTime when,
+ SysCallback callback,
+ void* opaque )
+{
+ if (timer->callback != NULL)
+ sys_timer_unset(timer);
+
+ if (callback != NULL) {
+ SysTime now = sys_time_ms();
+
+ if (now >= when) {
+ callback( opaque );
+ } else {
+ SysTimer *pnode, node;
+ pnode = &_s_timers;
+ for (;;) {
+ node = *pnode;
+ if (node == NULL || node->when >= when) {
+ break;
+ }
+ pnode = &node->next;
+ }
+ timer->next = *pnode;
+ *pnode = timer;
+ timer->when = when;
+ timer->callback = callback;
+ timer->opaque = opaque;
+ }
+ }
+}
+
+
+void sys_timer_destroy( SysTimer timer )
+{
+ assert( timer != NULL && "sys_timer_destroy: bad argument" );
+ if (timer->callback != NULL)
+ sys_timer_unset(timer);
+
+ timer->next = _s_free_timers;
+ _s_free_timers = timer;
+}
+
+
+static void
+sys_single_loop( void )
+{
+ fd_set rfd, wfd, efd;
+ struct timeval timeout_tv, *timeout = NULL;
+ int n;
+
+ memcpy(&rfd, &_s_fdsets[0], sizeof(fd_set));
+ memcpy(&wfd, &_s_fdsets[1], sizeof(fd_set));
+ memcpy(&efd, &_s_fdsets[2], sizeof(fd_set));
+
+ if ( _s_timers != NULL ) {
+ SysTime now = sys_time_ms();
+ SysTimer first = _s_timers;
+
+ timeout = &timeout_tv;
+ if (first->when <= now) {
+ timeout->tv_sec = 0;
+ timeout->tv_usec = 0;
+ } else {
+ SysTime diff = first->when - now;
+ timeout->tv_sec = diff / 1000;
+ timeout->tv_usec = (diff - timeout->tv_sec*1000) * 1000;
+ }
+ }
+
+ n = select( _s_maxfd+1, &rfd, &wfd, &efd, timeout);
+ if(n < 0) {
+ if(errno == EINTR) return;
+ perror("select");
+ return;
+ }
+
+ /* enqueue pending channels */
+ {
+ int i;
+
+ sys_queue_reset( _s_pending_channels );
+ for(i = 0; (i <= _s_maxfd) && (n > 0); i++)
+ {
+ int events = 0;
+
+ if(FD_ISSET(i, &rfd)) events |= SYS_EVENT_READ;
+ if(FD_ISSET(i, &wfd)) events |= SYS_EVENT_WRITE;
+ if(FD_ISSET(i, &efd)) events |= SYS_EVENT_ERROR;
+
+ if (events) {
+ SysChannel channel;
+
+ n--;
+ for (channel = _s_channels; channel; channel = channel->next)
+ {
+ if (channel->fd != i)
+ continue;
+
+ channel->ready = events;
+ channel->pending = 1;
+ sys_queue_add( _s_pending_channels, channel );
+ break;
+ }
+ }
+ }
+ }
+
+ /* enqueue pending timers */
+ {
+ SysTimer timer = _s_timers;
+ SysTime now = sys_time_ms();
+
+ sys_queue_reset( _s_pending_timers );
+ while (timer != NULL)
+ {
+ if (timer->when > now)
+ break;
+
+ sys_queue_add( _s_pending_timers, timer );
+ _s_timers = timer = timer->next;
+ }
+ }
+}
+
+void sys_main_init( void )
+{
+ sys_init_channels();
+ sys_init_timers();
+}
+
+
+int sys_main_loop( void )
+{
+ for (;;) {
+ SysTimer timer;
+ SysChannel channel;
+
+ /* exit if we have nothing to do */
+ if (_s_channels == NULL && _s_timers == NULL)
+ break;
+
+ sys_single_loop();
+
+ while ((timer = sys_queue_get( _s_pending_timers )) != NULL) {
+ timer->callback( timer->opaque );
+ }
+
+ while ((channel = sys_queue_get( _s_pending_channels )) != NULL) {
+ int events;
+
+ channel->pending = 0;
+ if (channel->closed) {
+ /* the channel was closed by a previous callback */
+ sys_channel_close(channel);
+ }
+ events = channel->ready;
+ channel->ready = 0;
+ channel->callback( channel->opaque, events );
+ }
+ }
+ return 0;
+}
+
+
+
+
+SysChannel
+sys_channel_create_tcp_server( int port )
+{
+ SysChannel channel;
+ int on = 1;
+ const int BACKLOG = 4;
+
+ channel = sys_channel_alloc();
+ if (-1==(channel->fd=socket(AF_INET, SOCK_STREAM, 0))) {
+ perror("socket");
+ sys_channel_free( channel );
+ return NULL;
+ }
+
+ /* Enable address re-use for server mode */
+ if ( -1==setsockopt( channel->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) )) {
+ perror("setsockopt(SO_REUSEADDR)");
+ }
+
+ {
+ struct sockaddr_in servname;
+ long in_addr = INADDR_ANY;
+
+ servname.sin_family = AF_INET;
+ servname.sin_port = htons(port);
+
+ servname.sin_addr.s_addr=in_addr;
+
+ if (-1==bind(channel->fd, (struct sockaddr*)&servname, sizeof(servname))) {
+ perror("bind");
+ sys_channel_close(channel);
+ return NULL;
+ }
+
+ /* Listen but don't accept */
+ if ( listen(channel->fd, BACKLOG) < 0 ) {
+ perror("listen");
+ sys_channel_close(channel);
+ return NULL;
+ }
+ }
+ return channel;
+}
+
+
+SysChannel
+sys_channel_create_tcp_handler( SysChannel server_channel )
+{
+ int on = 1;
+ SysChannel channel = sys_channel_alloc();
+
+ channel->fd = accept( server_channel->fd, NULL, 0 );
+ if (channel->fd < 0) {
+ perror( "accept" );
+ sys_channel_free( channel );
+ return NULL;
+ }
+
+ /* set to non-blocking and disable TCP Nagle algorithm */
+ fcntl(channel->fd, F_SETFL, O_NONBLOCK);
+ setsockopt(channel->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
+ return channel;
+}
+
+
+SysChannel
+sys_channel_create_tcp_client( const char* hostname, int port )
+{
+ struct hostent* hp;
+ struct sockaddr_in addr;
+ SysChannel channel = sys_channel_alloc();
+ int on = 1;
+
+ hp = gethostbyname(hostname);
+ if(hp == 0) {
+ fprintf(stderr, "unknown host: %s\n", hostname);
+ sys_channel_free(channel);
+ return NULL;
+ };
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = hp->h_addrtype;
+ addr.sin_port = htons(port);
+ memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
+
+ channel->fd = socket(hp->h_addrtype, SOCK_STREAM, 0);
+ if(channel->fd < 0) {
+ sys_channel_free(channel);
+ return NULL;
+ }
+
+ if(connect( channel->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror( "connect" );
+ sys_channel_free(channel);
+ return NULL;
+ }
+
+ /* set to non-blocking and disable Nagle algorithm */
+ fcntl(channel->fd, F_SETFL, O_NONBLOCK);
+ setsockopt( channel->fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on) );
+ return channel;
+}
+
diff --git a/telephony/sysdeps_qemu.c b/telephony/sysdeps_qemu.c
new file mode 100644
index 0000000..e1107aa
--- /dev/null
+++ b/telephony/sysdeps_qemu.c
@@ -0,0 +1,376 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "sockets.h"
+#include "sysdeps.h"
+#include "vl.h"
+#ifdef _WIN32
+#include <winsock2.h>
+#else
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#endif
+
+#define DEBUG 1
+
+#define D_ACTIVE DEBUG
+
+#if DEBUG
+#define D(...) do { if (D_ACTIVE) fprintf(stderr, __VA_ARGS__); } while (0)
+#else
+#define D(...) ((void)0)
+#endif
+
+/** TIME
+ **/
+
+SysTime
+sys_time_ms( void )
+{
+ return qemu_get_clock( rt_clock );
+}
+
+/** TIMERS
+ **/
+
+typedef struct SysTimerRec_ {
+ QEMUTimer* timer;
+ QEMUTimerCB* callback;
+ void* opaque;
+ SysTimer next;
+} SysTimerRec;
+
+#define MAX_TIMERS 32
+
+static SysTimerRec _s_timers0[ MAX_TIMERS ];
+static SysTimer _s_free_timers;
+
+static void
+sys_init_timers( void )
+{
+ int nn;
+ for (nn = 0; nn < MAX_TIMERS-1; nn++)
+ _s_timers0[nn].next = _s_timers0 + (nn+1);
+
+ _s_free_timers = _s_timers0;
+}
+
+static SysTimer
+sys_timer_alloc( void )
+{
+ SysTimer timer = _s_free_timers;
+
+ if (timer != NULL) {
+ _s_free_timers = timer->next;
+ timer->next = NULL;
+ timer->timer = NULL;
+ }
+ return timer;
+}
+
+
+static void
+sys_timer_free( SysTimer timer )
+{
+ if (timer->timer) {
+ qemu_del_timer( timer->timer );
+ qemu_free_timer( timer->timer );
+ timer->timer = NULL;
+ }
+ timer->next = _s_free_timers;
+ _s_free_timers = timer;
+}
+
+
+SysTimer sys_timer_create( void )
+{
+ SysTimer timer = sys_timer_alloc();
+ return timer;
+}
+
+void
+sys_timer_set( SysTimer timer, SysTime when, SysCallback _callback, void* opaque )
+{
+ QEMUTimerCB* callback = (QEMUTimerCB*)_callback;
+
+ if (callback == NULL) { /* unsetting the timer */
+ if (timer->timer) {
+ qemu_del_timer( timer->timer );
+ qemu_free_timer( timer->timer );
+ timer->timer = NULL;
+ }
+ timer->callback = callback;
+ timer->opaque = NULL;
+ return;
+ }
+
+ if ( timer->timer ) {
+ if ( timer->callback == callback && timer->opaque == opaque )
+ goto ReuseTimer;
+
+ /* need to replace the timer */
+ qemu_free_timer( timer->timer );
+ }
+
+ timer->timer = qemu_new_timer( rt_clock, callback, opaque );
+ timer->callback = callback;
+ timer->opaque = opaque;
+
+ReuseTimer:
+ qemu_mod_timer( timer->timer, when );
+}
+
+void
+sys_timer_unset( SysTimer timer )
+{
+ if (timer->timer) {
+ qemu_del_timer( timer->timer );
+ }
+}
+
+void
+sys_timer_destroy( SysTimer timer )
+{
+ sys_timer_free( timer );
+}
+
+
+/** CHANNELS
+ **/
+
+typedef struct SysChannelRec_ {
+ int fd;
+ SysChannelCallback callback;
+ void* opaque;
+ SysChannel next;
+} SysChannelRec;
+
+#define MAX_CHANNELS 16
+
+static SysChannelRec _s_channels0[ MAX_CHANNELS ];
+static SysChannel _s_free_channels;
+
+static void
+sys_init_channels( void )
+{
+ int nn;
+
+ for ( nn = 0; nn < MAX_CHANNELS-1; nn++ ) {
+ _s_channels0[nn].next = _s_channels0 + (nn+1);
+ }
+ _s_free_channels = _s_channels0;
+}
+
+static SysChannel
+sys_channel_alloc( )
+{
+ SysChannel channel = _s_free_channels;
+ if (channel != NULL) {
+ _s_free_channels = channel->next;
+ channel->next = NULL;
+ channel->fd = -1;
+ channel->callback = NULL;
+ channel->opaque = NULL;
+ }
+ return channel;
+}
+
+static void
+sys_channel_free( SysChannel channel )
+{
+ if (channel->fd >= 0) {
+ socket_close( channel->fd );
+ channel->fd = -1;
+ }
+ channel->next = _s_free_channels;
+ _s_free_channels = channel;
+}
+
+
+static void
+sys_channel_read_handler( void* _channel )
+{
+ SysChannel channel = _channel;
+ D( "%s: read event for channel %p:%d\n", __FUNCTION__,
+ channel, channel->fd );
+ channel->callback( channel->opaque, SYS_EVENT_READ );
+}
+
+static void
+sys_channel_write_handler( void* _channel )
+{
+ SysChannel channel = _channel;
+ D( "%s: write event for channel %p:%d\n", __FUNCTION__, channel, channel->fd );
+ channel->callback( channel->opaque, SYS_EVENT_WRITE );
+}
+
+void
+sys_channel_on( SysChannel channel,
+ int events,
+ SysChannelCallback event_callback,
+ void* event_opaque )
+{
+ IOHandler* read_handler = NULL;
+ IOHandler* write_handler = NULL;
+
+ if (events & SYS_EVENT_READ) {
+ read_handler = sys_channel_read_handler;
+ }
+ if (events & SYS_EVENT_WRITE) {
+ write_handler = sys_channel_write_handler;
+ }
+ channel->callback = event_callback;
+ channel->opaque = event_opaque;
+ qemu_set_fd_handler( channel->fd, read_handler, write_handler, channel );
+}
+
+int
+sys_channel_read( SysChannel channel, void* buffer, int size )
+{
+ int len = size;
+ char* buf = (char*) buffer;
+
+ while (len > 0) {
+ int ret = recv(channel->fd, buf, len, 0);
+ if (ret < 0) {
+ if (socket_errno == EINTR)
+ continue;
+ if (socket_errno == EWOULDBLOCK)
+ break;
+ D( "%s: after reading %d bytes, recv() returned error %d: %s\n",
+ __FUNCTION__, size - len, socket_errno, socket_errstr());
+ return -1;
+ } else if (ret == 0) {
+ break;
+ } else {
+ buf += ret;
+ len -= ret;
+ }
+ }
+ return size - len;
+}
+
+
+int
+sys_channel_write( SysChannel channel, const void* buffer, int size )
+{
+ int len = size;
+ const char* buf = (const char*) buffer;
+
+ while (len > 0) {
+ int ret = send(channel->fd, buf, len, 0);
+ if (ret < 0) {
+ if (socket_errno == EINTR)
+ continue;
+ if (socket_errno == EWOULDBLOCK)
+ break;
+ D( "%s: send() returned error %d: %s\n",
+ __FUNCTION__, socket_errno, socket_errstr());
+ return -1;
+ } else if (ret == 0) {
+ break;
+ } else {
+ buf += ret;
+ len -= ret;
+ }
+ }
+ return size - len;
+}
+
+void sys_channel_close( SysChannel channel )
+{
+ qemu_set_fd_handler( channel->fd, NULL, NULL, NULL );
+ sys_channel_free( channel );
+}
+
+void sys_main_init( void )
+{
+ sys_init_channels();
+ sys_init_timers();
+}
+
+
+int sys_main_loop( void )
+{
+ /* no looping, qemu has its own event loop */
+ return 0;
+}
+
+
+
+
+SysChannel
+sys_channel_create_tcp_server( int port )
+{
+ SysChannel channel = sys_channel_alloc();
+ const int BACKLOG = 4;
+
+ channel->fd = socket_anyaddr_server( port, SOCK_STREAM );
+ if (channel->fd < 0) {
+ D( "%s: failed to created network socket on TCP:%d\n", port );
+ sys_channel_free( channel );
+ return NULL;
+ }
+
+ D( "%s: server channel %p:%d now listening on port %d\n",
+ __FUNCTION__, channel, channel->fd, port );
+
+ return channel;
+}
+
+
+SysChannel
+sys_channel_create_tcp_handler( SysChannel server_channel )
+{
+ SysChannel channel = sys_channel_alloc();
+
+ D( "%s: creating handler from server channel %p:%d\n", __FUNCTION__,
+ server_channel, server_channel->fd );
+
+ channel->fd = socket_accept_any( server_channel->fd );
+ if (channel->fd < 0) {
+ perror( "accept" );
+ sys_channel_free( channel );
+ return NULL;
+ }
+
+ /* disable Nagle algorithm */
+ socket_set_lowlatency( channel->fd );
+
+ D( "%s: handler %p:%d created from server %p:%d\n", __FUNCTION__,
+ server_channel, server_channel->fd, channel, channel->fd );
+
+ return channel;
+}
+
+
+SysChannel
+sys_channel_create_tcp_client( const char* hostname, int port )
+{
+ SysChannel channel = sys_channel_alloc();
+
+ channel->fd = socket_network_client( hostname, port, SOCK_STREAM );
+ if (channel->fd < 0) {
+ sys_channel_free(channel);
+ return NULL;
+ };
+
+ /* set to non-blocking and disable Nagle algorithm */
+ socket_set_nonblock( channel->fd );
+ socket_set_lowlatency( channel->fd );
+
+ return channel;
+}
+
diff --git a/telephony/test1.c b/telephony/test1.c
new file mode 100644
index 0000000..52701b9
--- /dev/null
+++ b/telephony/test1.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "sysdeps.h"
+#include <stdio.h>
+
+#define MAX_COUNTER 10
+
+static int counter = 0;
+
+static void
+timer_func( void* _timer )
+{
+ SysTimer timer = _timer;
+ SysTime now = sys_time_ms();
+
+ ++counter;
+ printf( "tick %d/%d a %.2fs\n", counter, MAX_COUNTER, now/1000. );
+ if (counter < MAX_COUNTER)
+ sys_timer_set( timer, now + 2000, timer_func, timer );
+ else
+ sys_timer_destroy( timer );
+}
+
+
+int main( void )
+{
+ SysTimer timer;
+
+ /* initialize event subsystem */
+ sys_main_init();
+
+ /* create timer and register it */
+ timer = sys_timer_create();
+ sys_timer_set( timer, sys_time_ms() + 1000, timer_func, timer );
+
+ printf("entering event loop\n");
+ sys_main_loop();
+ printf("exiting event loop\n" );
+ return 0;
+}
diff --git a/telephony/test2.c b/telephony/test2.c
new file mode 100644
index 0000000..a0cd66f
--- /dev/null
+++ b/telephony/test2.c
@@ -0,0 +1,215 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include "sysdeps.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define PORT 8000
+#define MAX_COUNTER 30
+#define INITIAL_DELAY 1000
+#define DELAY 5000
+
+static int counter = 0;
+
+static void
+timer_func( void* _timer )
+{
+ SysTimer timer = _timer;
+ SysTime now = sys_time_ms();
+
+ ++counter;
+ printf( "tick %d/%d a %.2fs\n", counter, MAX_COUNTER, now/1000. );
+ if (counter < MAX_COUNTER)
+ sys_timer_set( timer, now + DELAY, timer_func, timer );
+ else
+ sys_timer_destroy( timer );
+}
+
+typedef struct {
+ SysChannel channel;
+ char in_buff[ 128 ];
+ int in_pos;
+
+ char out_buff[ 128 ];
+ int out_pos;
+ int out_size;
+} ClientRec, *Client;
+
+static Client
+client_alloc( SysChannel channel )
+{
+ Client client = calloc( sizeof(*client), 1 );
+
+ client->channel = channel;
+ return client;
+}
+
+static void
+client_free( Client client )
+{
+ sys_channel_close( client->channel );
+ client->channel = NULL;
+ free( client );
+}
+
+static void
+client_append( Client client, const char* str, int len );
+
+static void
+client_handle_line( Client client, const char* cmd )
+{
+ char temp[256];
+ int nn, mm = 0;
+
+ for (nn = 0; cmd[nn] != 0; nn++) {
+ int c = cmd[nn];
+ if (c >= 32 && c <= 127)
+ temp[mm++] = c;
+ else if (c == '\n') {
+ strcat( temp+mm, "<LF>" );
+ mm += 4;
+ }
+ else if (c == '\r') {
+ strcat( temp+mm, "<CR>" );
+ mm += 4;
+ }
+ else {
+ sprintf( temp+mm, "\\x%02x", c );
+ mm += strlen( temp+mm );
+ }
+ }
+ temp[mm] = 0;
+ printf( "%p: << %s\n", client, temp );
+
+ if ( !strcmp( cmd, "quit" ) ) {
+ printf( "client %p quitting\n", client );
+ client_free( client );
+ return;
+ }
+ client_append( client, "type 'quit' to quit\n", -1 );
+}
+
+static void
+client_handler( void* _client, int events )
+{
+ Client client = _client;
+
+ if (events & SYS_EVENT_READ) {
+ int ret;
+ /* read into buffer, one character at a time */
+ ret = sys_channel_read( client->channel, client->in_buff + client->in_pos, 1 );
+ if (ret != 1) {
+ fprintf(stderr, "client %p could not read byte, result = %d, error: %s\n",
+ client, ret, strerror(errno) );
+ goto ExitClient;
+ }
+ if (client->in_buff[client->in_pos] == '\r' ||
+ client->in_buff[client->in_pos] == '\n' ) {
+ const char* cmd = client->in_buff;
+ client->in_buff[client->in_pos] = 0;
+
+ /* eat leading cr and lf, maybe left-overs from previous line */
+ while (*cmd == '\r' || *cmd =='\n')
+ cmd++;
+
+ client_handle_line( client, cmd );
+ client->in_pos = 0;
+ } else
+ client->in_pos += 1;
+ }
+
+ if (events & SYS_EVENT_WRITE) {
+ int ret;
+ /* write from output buffer, one char at a time */
+ ret = sys_channel_write( client->channel, client->out_buff + client->out_pos, 1 );
+ if (ret != 1) {
+ fprintf(stderr, "client %p could not write byte, result = %d, error: %s\n",
+ client, ret, strerror(errno) );
+ goto ExitClient;
+ }
+ client->out_pos += 1;
+ if (client->out_pos == client->out_size) {
+ client->out_size = 0;
+ client->out_pos = 0;
+ /* we don't need to write */
+ sys_channel_on( client->channel, SYS_EVENT_READ, client_handler, client );
+ }
+ }
+ return;
+
+ExitClient:
+ printf( "client %p exiting\n", client );
+ client_free( client );
+}
+
+static void
+client_append( Client client, const char* str, int len )
+{
+ int avail;
+
+ if (len < 0)
+ len = strlen(str);
+
+ avail = sizeof(client->out_buff) - client->out_size;
+ if (len > avail)
+ len = avail;
+
+ memcpy( client->out_buff + client->out_size, str, len );
+ if (client->out_size == 0) {
+ sys_channel_on( client->channel, SYS_EVENT_READ | SYS_EVENT_WRITE, client_handler, client );
+ }
+ client->out_size += len;
+}
+
+
+static void
+accept_func( void* _server, int events )
+{
+ SysChannel server = _server;
+ SysChannel handler;
+ Client client;
+
+ printf( "connection accepted for server channel, getting handler socket\n" );
+ handler = sys_channel_create_tcp_handler( server );
+ printf( "got one. creating client\n" );
+ client = client_alloc( handler );
+
+ events=events;
+ sys_channel_on( handler, SYS_EVENT_READ, client_handler, client );
+ client_append( client, "Welcome !\n", -1 );
+}
+
+
+int main( void )
+{
+ SysTimer timer;
+ SysChannel server_channel;
+
+ /* initialize event subsystem */
+ sys_main_init();
+
+ /* create timer and register it */
+ timer = sys_timer_create();
+ sys_timer_set( timer, sys_time_ms() + INITIAL_DELAY, timer_func, timer );
+
+ server_channel = sys_channel_create_tcp_server( PORT );
+ printf( "listening on port %d with %p\n", PORT, server_channel );
+
+ sys_channel_on( server_channel, SYS_EVENT_READ, accept_func, server_channel );
+
+ printf("entering event loop\n");
+ sys_main_loop();
+ printf("exiting event loop\n" );
+ return 0;
+}
diff --git a/tests/.cvsignore b/tests/.cvsignore
deleted file mode 100644
index 18a8298..0000000
--- a/tests/.cvsignore
+++ /dev/null
@@ -1,23 +0,0 @@
- gmon.out
- testsig
- hello-i386
- hello-arm
- sha1.test.c
- sha1.c
- test-i386
- sha1
- testclone
- .gdb_history
- testthread
- test-i386.s
- test-i386.ref
- sha1-i386
- runcom
- debug.com
- test-i386.out
- speed.txt
- test-i386.ref.P3
- pi_10.com
- test-i386.ref.P4
- ldso.c
- test_path
diff --git a/tests/qruncom.c b/tests/qruncom.c
index 421e6a9..8130a81 100644
--- a/tests/qruncom.c
+++ b/tests/qruncom.c
@@ -59,7 +59,7 @@ uint64_t cpu_get_tsc(CPUState *env)
return 0;
}
-static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
unsigned long addr, unsigned int sel)
{
unsigned int e1, e2;
@@ -141,7 +141,7 @@ static inline void pushw(CPUState *env, int val)
*(uint16_t *)seg_to_linear(env->segs[R_SS].selector, env->regs[R_ESP]) = val;
}
-static void host_segv_handler(int host_signum, siginfo_t *info,
+static void host_segv_handler(int host_signum, siginfo_t *info,
void *puc)
{
if (cpu_signal_handler(host_signum, info, puc)) {
@@ -160,9 +160,9 @@ int main(int argc, char **argv)
if (argc != 2)
usage();
filename = argv[1];
-
- vm86_mem = mmap((void *)0x00000000, 0x110000,
- PROT_WRITE | PROT_READ | PROT_EXEC,
+
+ vm86_mem = mmap((void *)0x00000000, 0x110000,
+ PROT_WRITE | PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
if (vm86_mem == MAP_FAILED) {
perror("mmap");
@@ -170,7 +170,7 @@ int main(int argc, char **argv)
}
/* load the MSDOS .com executable */
- fd = open(filename, O_RDONLY);
+ fd = open(filename, O_BINARY | O_RDONLY);
if (fd < 0) {
perror(filename);
exit(1);
@@ -185,7 +185,7 @@ int main(int argc, char **argv)
/* install exception handler for CPU emulator */
{
struct sigaction act;
-
+
sigfillset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
// act.sa_flags |= SA_ONSTACK;
@@ -218,23 +218,23 @@ int main(int argc, char **argv)
/* flags setup : we activate the IRQs by default as in user
mode. We also activate the VM86 flag to run DOS code */
env->eflags |= IF_MASK | VM_MASK;
-
+
/* init basic registers */
env->eip = 0x100;
env->regs[R_ESP] = 0xfffe;
seg = (COM_BASE_ADDR - 0x100) >> 4;
- cpu_x86_load_seg_cache(env, R_CS, seg,
+ cpu_x86_load_seg_cache(env, R_CS, seg,
(seg << 4), 0xffff, 0);
- cpu_x86_load_seg_cache(env, R_SS, seg,
+ cpu_x86_load_seg_cache(env, R_SS, seg,
(seg << 4), 0xffff, 0);
- cpu_x86_load_seg_cache(env, R_DS, seg,
+ cpu_x86_load_seg_cache(env, R_DS, seg,
(seg << 4), 0xffff, 0);
- cpu_x86_load_seg_cache(env, R_ES, seg,
+ cpu_x86_load_seg_cache(env, R_ES, seg,
(seg << 4), 0xffff, 0);
- cpu_x86_load_seg_cache(env, R_FS, seg,
+ cpu_x86_load_seg_cache(env, R_FS, seg,
(seg << 4), 0xffff, 0);
- cpu_x86_load_seg_cache(env, R_GS, seg,
+ cpu_x86_load_seg_cache(env, R_GS, seg,
(seg << 4), 0xffff, 0);
/* exception support */
@@ -260,7 +260,7 @@ int main(int argc, char **argv)
set_idt(17, 0);
set_idt(18, 0);
set_idt(19, 0);
-
+
/* put return code */
*seg_to_linear(env->segs[R_CS].selector, 0) = 0xb4; /* mov ah, $0 */
*seg_to_linear(env->segs[R_CS].selector, 1) = 0x00;
@@ -275,7 +275,7 @@ int main(int argc, char **argv)
env->regs[R_EDI] = 0xfffe;
/* inform the emulator of the mmaped memory */
- page_set_flags(0x00000000, 0x110000,
+ page_set_flags(0x00000000, 0x110000,
PAGE_WRITE | PAGE_READ | PAGE_EXEC | PAGE_VALID);
for(;;) {
diff --git a/tests/runcom.c b/tests/runcom.c
index 43deeca..f2781ce 100644
--- a/tests/runcom.c
+++ b/tests/runcom.c
@@ -51,7 +51,7 @@ static inline void pushw(struct vm86_regs *r, int val)
void dump_regs(struct vm86_regs *r)
{
- fprintf(stderr,
+ fprintf(stderr,
"EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
"ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n"
"EIP=%08lx EFL=%08lx\n"
@@ -80,9 +80,9 @@ int main(int argc, char **argv)
if (argc != 2)
usage();
filename = argv[1];
-
- vm86_mem = mmap((void *)0x00000000, 0x110000,
- PROT_WRITE | PROT_READ | PROT_EXEC,
+
+ vm86_mem = mmap((void *)0x00000000, 0x110000,
+ PROT_WRITE | PROT_READ | PROT_EXEC,
MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
if (vm86_mem == MAP_FAILED) {
perror("mmap");
@@ -101,7 +101,7 @@ int main(int argc, char **argv)
#endif
/* load the MSDOS .com executable */
- fd = open(filename, O_RDONLY);
+ fd = open(filename, O_BINARY | O_RDONLY);
if (fd < 0) {
perror(filename);
exit(1);
@@ -147,7 +147,7 @@ int main(int argc, char **argv)
case VM86_INTx:
{
int int_num, ah;
-
+
int_num = VM86_ARG(ret);
if (int_num != 0x21)
goto unknown_int;
diff --git a/trace.c b/trace.c
new file mode 100644
index 0000000..6cff83c
--- /dev/null
+++ b/trace.c
@@ -0,0 +1,1875 @@
+/* Copyright (C) 2006-2007 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <time.h>
+#include "cpu.h"
+#include "exec-all.h"
+#include "trace.h"
+#include "varint.h"
+#include "android_utils.h"
+
+TraceBB trace_bb;
+TraceInsn trace_insn;
+TraceStatic trace_static;
+TraceAddr trace_load;
+TraceAddr trace_store;
+TraceExc trace_exc;
+TracePid trace_pid;
+TraceMethod trace_method;
+static TraceHeader header;
+
+// The simulation time in cpu clock cycles
+uint64_t sim_time = 1;
+
+// The current process id
+int current_pid;
+
+// The start and end (wall-clock) time in microseconds
+uint64_t start_time, end_time;
+uint64_t elapsed_usecs;
+
+// For debugging output
+FILE *ftrace_debug;
+
+// The maximum number of bytes consumed by an InsnRec after compression.
+// This is very conservative but needed to ensure no buffer overflows.
+#define kMaxInsnCompressed 14
+
+// The maximum number of bytes consumed by an BBRec after compression.
+// This is very conservative but needed to ensure no buffer overflows.
+#define kMaxBBCompressed 32
+
+// The maximum number of bytes consumed by an AddrRec after compression.
+// This is very conservative but needed to ensure no buffer overflows.
+#define kMaxAddrCompressed 14
+
+// The maximum number of bytes consumed by a MethodRec after compression.
+// This is very conservative but needed to ensure no buffer overflows.
+#define kMaxMethodCompressed 18
+
+// The maximum number of bytes consumed by an exception record after
+// compression.
+#define kMaxExcCompressed 38
+
+// The maximum number of bytes consumed by a pid record for
+// kPidSwitch, or kPidExit after compression.
+#define kMaxPidCompressed 15
+
+// The maximum number of bytes consumed by a pid record for kPidFork,
+// or kPidClone after compression.
+#define kMaxPid2Compressed 20
+
+// The maximum number of bytes consumed by a pid record for kPidExecArgs
+// after compression, not counting the bytes for the args.
+#define kMaxExecArgsCompressed 15
+
+// The maximum number of bytes consumed by a pid record for kPidName
+// after compression, not counting the bytes for the name.
+#define kMaxNameCompressed 20
+
+// The maximum number of bytes consumed by a pid record for kPidMmap
+// after compression, not counting the bytes for the pathname.
+#define kMaxMmapCompressed 33
+
+// The maximum number of bytes consumed by a pid record for kPidMunmap,
+// after compression.
+#define kMaxMunmapCompressed 28
+
+// The maximum number of bytes consumed by a pid record for kPidSymbol
+// after compression, not counting the bytes for the symbol name.
+#define kMaxSymbolCompressed 24
+
+// The maximum number of bytes consumed by a pid record for kPidKthreadName
+// after compression, not counting the bytes for the name.
+#define kMaxKthreadNameCompressed 25
+
+void trace_cleanup();
+
+// Return current time in microseconds as a 64-bit integer.
+uint64 Now() {
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ uint64 val = tv.tv_sec;
+ val = val * 1000000ull + tv.tv_usec;
+ return val;
+}
+
+static void create_trace_dir(const char *dirname)
+{
+ int err;
+
+ err = path_mkdir(dirname, 0755);
+ if (err != 0 && errno != EEXIST) {
+ printf("err: %d\n", err);
+ perror(dirname);
+ exit(1);
+ }
+}
+
+static char *create_trace_path(const char *filename, const char *ext)
+{
+ char *fname;
+ const char *base_start, *base_end;
+ int ii, len, base_len, dir_len, path_len, qtrace_len;
+
+ // Handle error cases
+ if (filename == NULL || *filename == 0 || strcmp(filename, "/") == 0)
+ return NULL;
+
+ // Ignore a trailing slash, if any
+ len = strlen(filename);
+ if (filename[len - 1] == '/')
+ len -= 1;
+
+ // Find the basename. We don't use basename(3) because there are
+ // different behaviors for GNU and Posix in the case where the
+ // last character is a slash.
+ base_start = base_end = &filename[len];
+ for (ii = 0; ii < len; ++ii) {
+ base_start -= 1;
+ if (*base_start == '/') {
+ base_start += 1;
+ break;
+ }
+ }
+ base_len = base_end - base_start;
+ dir_len = len - base_len;
+ qtrace_len = strlen("/qtrace");
+
+ // Create space for the pathname: "/dir/basename/qtrace.ext"
+ // The "ext" string already contains the dot, so just add a byte
+ // for the terminating zero.
+ path_len = dir_len + base_len + qtrace_len + strlen(ext) + 1;
+ fname = malloc(path_len);
+ if (dir_len > 0)
+ strncpy(fname, filename, dir_len);
+ fname[dir_len] = 0;
+ strncat(fname, base_start, base_len);
+ strcat(fname, "/qtrace");
+ strcat(fname, ext);
+ return fname;
+}
+
+void convert_secs_to_date_time(time_t secs, uint32_t *pdate, uint32_t *ptime)
+{
+ struct tm *tm = localtime(&secs);
+ uint32_t year = tm->tm_year + 1900;
+ uint32_t thousands = year / 1000;
+ year -= thousands * 1000;
+ uint32_t hundreds = year / 100;
+ year -= hundreds * 100;
+ uint32_t tens = year / 10;
+ year -= tens * 10;
+ uint32_t ones = year;
+ year = (thousands << 12) | (hundreds << 8) | (tens << 4) | ones;
+
+ uint32_t mon = tm->tm_mon + 1;
+ tens = mon / 10;
+ ones = (mon - tens * 10);
+ mon = (tens << 4) | ones;
+
+ uint32_t day = tm->tm_mday;
+ tens = day / 10;
+ ones = (day - tens * 10);
+ day = (tens << 4) | ones;
+
+ *pdate = (year << 16) | (mon << 8) | day;
+
+ uint32_t hour = tm->tm_hour;
+ tens = hour / 10;
+ ones = (hour - tens * 10);
+ hour = (tens << 4) | ones;
+
+ uint32_t min = tm->tm_min;
+ tens = min / 10;
+ ones = (min - tens * 10);
+ min = (tens << 4) | ones;
+
+ uint32_t sec = tm->tm_sec;
+ tens = sec / 10;
+ ones = (sec - tens * 10);
+ sec = (tens << 4) | ones;
+
+ *ptime = (hour << 16) | (min << 8) | sec;
+}
+
+void write_trace_header(TraceHeader *header)
+{
+ TraceHeader swappedHeader;
+
+ memcpy(&swappedHeader, header, sizeof(TraceHeader));
+
+ convert32(swappedHeader.version);
+ convert32(swappedHeader.start_sec);
+ convert32(swappedHeader.start_usec);
+ convert32(swappedHeader.pdate);
+ convert32(swappedHeader.ptime);
+ convert32(swappedHeader.num_used_pids);
+ convert32(swappedHeader.first_unused_pid);
+ convert64(swappedHeader.num_static_bb);
+ convert64(swappedHeader.num_static_insn);
+ convert64(swappedHeader.num_dynamic_bb);
+ convert64(swappedHeader.num_dynamic_insn);
+ convert64(swappedHeader.elapsed_usecs);
+
+ fwrite(&swappedHeader, sizeof(TraceHeader), 1, trace_static.fstream);
+}
+
+void create_trace_bb(const char *filename)
+{
+ char *fname = create_trace_path(filename, ".bb");
+ trace_bb.filename = fname;
+
+ FILE *fstream = fopen(fname, "wb");
+ if (fstream == NULL) {
+ perror(fname);
+ exit(1);
+ }
+ trace_bb.fstream = fstream;
+ trace_bb.next = &trace_bb.buffer[0];
+ trace_bb.flush_time = 0;
+ trace_bb.compressed_ptr = trace_bb.compressed;
+ trace_bb.high_water_ptr = &trace_bb.compressed[kCompressedSize] - kMaxBBCompressed;
+ trace_bb.prev_bb_num = 0;
+ trace_bb.prev_bb_time = 0;
+ trace_bb.num_insns = 0;
+ trace_bb.recnum = 0;
+}
+
+void create_trace_insn(const char *filename)
+{
+ // Create the instruction time trace file
+ char *fname = create_trace_path(filename, ".insn");
+ trace_insn.filename = fname;
+
+ FILE *fstream = fopen(fname, "wb");
+ if (fstream == NULL) {
+ perror(fname);
+ exit(1);
+ }
+ trace_insn.fstream = fstream;
+ trace_insn.current = &trace_insn.dummy;
+ trace_insn.dummy.time_diff = 0;
+ trace_insn.dummy.repeat = 0;
+ trace_insn.prev_time = 0;
+ trace_insn.compressed_ptr = trace_insn.compressed;
+ trace_insn.high_water_ptr = &trace_insn.compressed[kCompressedSize] - kMaxInsnCompressed;
+}
+
+void create_trace_static(const char *filename)
+{
+ // Create the static basic block trace file
+ char *fname = create_trace_path(filename, ".static");
+ trace_static.filename = fname;
+
+ FILE *fstream = fopen(fname, "wb");
+ if (fstream == NULL) {
+ perror(fname);
+ exit(1);
+ }
+ trace_static.fstream = fstream;
+ trace_static.next_insn = 0;
+ trace_static.bb_num = 1;
+ trace_static.bb_addr = 0;
+
+ // Write an empty header to reserve space for it in the file.
+ // The header will be filled in later when post-processing the
+ // trace file.
+ memset(&header, 0, sizeof(TraceHeader));
+
+ // Write out the version number so that tools can detect if the trace
+ // file format is the same as what they expect.
+ header.version = TRACE_VERSION;
+
+ // Record the start time in the header now.
+ struct timeval tv;
+ struct timezone tz;
+ gettimeofday(&tv, &tz);
+ header.start_sec = tv.tv_sec;
+ header.start_usec = tv.tv_usec;
+ convert_secs_to_date_time(header.start_sec, &header.pdate, &header.ptime);
+ write_trace_header(&header);
+
+ // Write out the record for the unused basic block number 0.
+ uint64_t zero = 0;
+ fwrite(&zero, sizeof(uint64_t), 1, trace_static.fstream); // bb_num
+ fwrite(&zero, sizeof(uint32_t), 1, trace_static.fstream); // bb_addr
+ fwrite(&zero, sizeof(uint32_t), 1, trace_static.fstream); // num_insns
+}
+
+void create_trace_addr(const char *filename)
+{
+ // The "qtrace.load" and "qtrace.store" files are optional
+ trace_load.fstream = NULL;
+ trace_store.fstream = NULL;
+ if (trace_all_addr || trace_cache_miss) {
+ // Create the "qtrace.load" file
+ char *fname = create_trace_path(filename, ".load");
+ trace_load.filename = fname;
+
+ FILE *fstream = fopen(fname, "wb");
+ if (fstream == NULL) {
+ perror(fname);
+ exit(1);
+ }
+ trace_load.fstream = fstream;
+ trace_load.next = &trace_load.buffer[0];
+ trace_load.compressed_ptr = trace_load.compressed;
+ trace_load.high_water_ptr = &trace_load.compressed[kCompressedSize] - kMaxAddrCompressed;
+ trace_load.prev_addr = 0;
+ trace_load.prev_time = 0;
+
+ // Create the "qtrace.store" file
+ fname = create_trace_path(filename, ".store");
+ trace_store.filename = fname;
+
+ fstream = fopen(fname, "wb");
+ if (fstream == NULL) {
+ perror(fname);
+ exit(1);
+ }
+ trace_store.fstream = fstream;
+ trace_store.next = &trace_store.buffer[0];
+ trace_store.compressed_ptr = trace_store.compressed;
+ trace_store.high_water_ptr = &trace_store.compressed[kCompressedSize] - kMaxAddrCompressed;
+ trace_store.prev_addr = 0;
+ trace_store.prev_time = 0;
+ }
+}
+
+void create_trace_exc(const char *filename)
+{
+ // Create the exception trace file
+ char *fname = create_trace_path(filename, ".exc");
+ trace_exc.filename = fname;
+
+ FILE *fstream = fopen(fname, "wb");
+ if (fstream == NULL) {
+ perror(fname);
+ exit(1);
+ }
+ trace_exc.fstream = fstream;
+ trace_exc.compressed_ptr = trace_exc.compressed;
+ trace_exc.high_water_ptr = &trace_exc.compressed[kCompressedSize] - kMaxExcCompressed;
+ trace_exc.prev_time = 0;
+ trace_exc.prev_bb_recnum = 0;
+}
+
+void create_trace_pid(const char *filename)
+{
+ // Create the pid trace file
+ char *fname = create_trace_path(filename, ".pid");
+ trace_pid.filename = fname;
+
+ FILE *fstream = fopen(fname, "wb");
+ if (fstream == NULL) {
+ perror(fname);
+ exit(1);
+ }
+ trace_pid.fstream = fstream;
+ trace_pid.compressed_ptr = trace_pid.compressed;
+ trace_pid.prev_time = 0;
+}
+
+void create_trace_method(const char *filename)
+{
+ // Create the method trace file
+ char *fname = create_trace_path(filename, ".method");
+ trace_method.filename = fname;
+
+ FILE *fstream = fopen(fname, "wb");
+ if (fstream == NULL) {
+ perror(fname);
+ exit(1);
+ }
+ trace_method.fstream = fstream;
+ trace_method.compressed_ptr = trace_method.compressed;
+ trace_method.prev_time = 0;
+ trace_method.prev_addr = 0;
+ trace_method.prev_pid = 0;
+}
+
+void trace_init(const char *filename)
+{
+ // Create the trace files
+ create_trace_dir(filename);
+ create_trace_bb(filename);
+ create_trace_insn(filename);
+ create_trace_static(filename);
+ create_trace_addr(filename);
+ create_trace_exc(filename);
+ create_trace_pid(filename);
+ create_trace_method(filename);
+
+#if 0
+ char *fname = create_trace_path(filename, ".debug");
+ ftrace_debug = fopen(fname, "wb");
+ if (ftrace_debug == NULL) {
+ perror(fname);
+ exit(1);
+ }
+#else
+ ftrace_debug = NULL;
+#endif
+ atexit(trace_cleanup);
+
+ // If tracing is on, then start timing the simulator
+ if (tracing)
+ start_time = Now();
+}
+
+/* the following array is used to deal with def-use register interlocks, which we
+ * can compute statically, very fortunately.
+ *
+ * the idea is that interlock_base contains the number of cycles "executed" from
+ * the start of a basic block. It is set to 0 in trace_bb_start, and incremented
+ * in each call to get_insn_ticks.
+ *
+ * interlocks[N] correspond to the value of interlock_base after which a register N
+ * can be used by another operation, it is set each time an instruction writes to
+ * the register in get_insn_ticks()
+ */
+
+static int interlocks[16];
+static int interlock_base;
+
+static void
+_interlock_def(int reg, int delay)
+{
+ if (reg >= 0)
+ interlocks[reg] = interlock_base + delay;
+}
+
+static int
+_interlock_use(int reg)
+{
+ int delay = 0;
+
+ if (reg >= 0)
+ {
+ delay = interlocks[reg] - interlock_base;
+ if (delay < 0)
+ delay = 0;
+ }
+ return delay;
+}
+
+void trace_bb_start(uint32_t bb_addr)
+{
+ int nn;
+
+ trace_static.bb_addr = bb_addr;
+ trace_static.is_thumb = 0;
+
+ interlock_base = 0;
+ for (nn = 0; nn < 16; nn++)
+ interlocks[nn] = 0;
+}
+
+void trace_add_insn(uint32_t insn, int is_thumb)
+{
+ trace_static.insns[trace_static.next_insn++] = insn;
+ // This relies on the fact that a basic block does not contain a mix
+ // of ARM and Thumb instructions. If that is not true, then many
+ // software tools that read the trace will have to change.
+ trace_static.is_thumb = is_thumb;
+}
+
+void trace_bb_end()
+{
+ int ii, num_insns;
+ uint32_t insn;
+
+ uint64_t bb_num = hostToLE64(trace_static.bb_num);
+ // If these are Thumb instructions, then encode that fact by setting
+ // the low bit of the basic-block address to 1.
+ uint32_t bb_addr = trace_static.bb_addr | trace_static.is_thumb;
+ bb_addr = hostToLE32(bb_addr);
+ num_insns = hostToLE32(trace_static.next_insn);
+ fwrite(&bb_num, sizeof(bb_num), 1, trace_static.fstream);
+ fwrite(&bb_addr, sizeof(bb_addr), 1, trace_static.fstream);
+ fwrite(&num_insns, sizeof(num_insns), 1, trace_static.fstream);
+ for (ii = 0; ii < trace_static.next_insn; ++ii) {
+ insn = hostToLE32(trace_static.insns[ii]);
+ fwrite(&insn, sizeof(insn), 1, trace_static.fstream);
+ }
+
+ trace_static.bb_num += 1;
+ trace_static.next_insn = 0;
+}
+
+void trace_cleanup()
+{
+ if (tracing) {
+ end_time = Now();
+ elapsed_usecs += end_time - start_time;
+ }
+ header.elapsed_usecs = elapsed_usecs;
+ double elapsed_secs = elapsed_usecs / 1000000.0;
+ double cycles_per_sec = 0;
+ if (elapsed_secs != 0)
+ cycles_per_sec = sim_time / elapsed_secs;
+ char *suffix = "";
+ if (cycles_per_sec >= 1000000) {
+ cycles_per_sec /= 1000000.0;
+ suffix = "M";
+ } else if (cycles_per_sec > 1000) {
+ cycles_per_sec /= 1000.0;
+ suffix = "K";
+ }
+ printf("Elapsed seconds: %.2f, simulated cycles/sec: %.1f%s\n",
+ elapsed_secs, cycles_per_sec, suffix);
+ if (trace_bb.fstream) {
+ BBRec *ptr;
+ BBRec *next = trace_bb.next;
+ char *comp_ptr = trace_bb.compressed_ptr;
+ int64_t prev_bb_num = trace_bb.prev_bb_num;
+ uint64_t prev_bb_time = trace_bb.prev_bb_time;
+ for (ptr = trace_bb.buffer; ptr != next; ++ptr) {
+ if (comp_ptr >= trace_bb.high_water_ptr) {
+ uint32_t size = comp_ptr - trace_bb.compressed;
+ fwrite(trace_bb.compressed, sizeof(char), size,
+ trace_bb.fstream);
+ comp_ptr = trace_bb.compressed;
+ }
+ int64_t bb_diff = ptr->bb_num - prev_bb_num;
+ prev_bb_num = ptr->bb_num;
+ uint64_t time_diff = ptr->start_time - prev_bb_time;
+ prev_bb_time = ptr->start_time;
+ comp_ptr = varint_encode_signed(bb_diff, comp_ptr);
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ comp_ptr = varint_encode(ptr->repeat, comp_ptr);
+ if (ptr->repeat)
+ comp_ptr = varint_encode(ptr->time_diff, comp_ptr);
+ }
+
+ // Add an extra record at the end containing the ending simulation
+ // time and a basic block number of 0.
+ uint64_t time_diff = sim_time - prev_bb_time;
+ if (time_diff > 0) {
+ int64_t bb_diff = -prev_bb_num;
+ comp_ptr = varint_encode_signed(bb_diff, comp_ptr);
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ comp_ptr = varint_encode(0, comp_ptr);
+ }
+
+ uint32_t size = comp_ptr - trace_bb.compressed;
+ if (size)
+ fwrite(trace_bb.compressed, sizeof(char), size, trace_bb.fstream);
+
+ // Terminate the file with three zeros so that we can detect
+ // the end of file quickly.
+ uint32_t zeros = 0;
+ fwrite(&zeros, 3, 1, trace_bb.fstream);
+ fclose(trace_bb.fstream);
+ }
+
+ if (trace_insn.fstream) {
+ InsnRec *ptr;
+ InsnRec *current = trace_insn.current + 1;
+ char *comp_ptr = trace_insn.compressed_ptr;
+ for (ptr = trace_insn.buffer; ptr != current; ++ptr) {
+ if (comp_ptr >= trace_insn.high_water_ptr) {
+ uint32_t size = comp_ptr - trace_insn.compressed;
+ uint32_t rval = fwrite(trace_insn.compressed, sizeof(char),
+ size, trace_insn.fstream);
+ if (rval != size) {
+ fprintf(stderr, "fwrite() failed\n");
+ perror(trace_insn.filename);
+ exit(1);
+ }
+ comp_ptr = trace_insn.compressed;
+ }
+ comp_ptr = varint_encode(ptr->time_diff, comp_ptr);
+ comp_ptr = varint_encode(ptr->repeat, comp_ptr);
+ }
+
+ uint32_t size = comp_ptr - trace_insn.compressed;
+ if (size) {
+ uint32_t rval = fwrite(trace_insn.compressed, sizeof(char), size,
+ trace_insn.fstream);
+ if (rval != size) {
+ fprintf(stderr, "fwrite() failed\n");
+ perror(trace_insn.filename);
+ exit(1);
+ }
+ }
+ fclose(trace_insn.fstream);
+ }
+
+ if (trace_static.fstream) {
+ fseek(trace_static.fstream, 0, SEEK_SET);
+ write_trace_header(&header);
+ fclose(trace_static.fstream);
+ }
+
+ if (trace_load.fstream) {
+ AddrRec *ptr;
+ char *comp_ptr = trace_load.compressed_ptr;
+ AddrRec *next = trace_load.next;
+ uint32_t prev_addr = trace_load.prev_addr;
+ uint64_t prev_time = trace_load.prev_time;
+ for (ptr = trace_load.buffer; ptr != next; ++ptr) {
+ if (comp_ptr >= trace_load.high_water_ptr) {
+ uint32_t size = comp_ptr - trace_load.compressed;
+ fwrite(trace_load.compressed, sizeof(char), size,
+ trace_load.fstream);
+ comp_ptr = trace_load.compressed;
+ }
+
+ int addr_diff = ptr->addr - prev_addr;
+ uint64_t time_diff = ptr->time - prev_time;
+ prev_addr = ptr->addr;
+ prev_time = ptr->time;
+
+ comp_ptr = varint_encode_signed(addr_diff, comp_ptr);
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ }
+
+ uint32_t size = comp_ptr - trace_load.compressed;
+ if (size) {
+ fwrite(trace_load.compressed, sizeof(char), size,
+ trace_load.fstream);
+ }
+
+ // Terminate the file with two zeros so that we can detect
+ // the end of file quickly.
+ uint32_t zeros = 0;
+ fwrite(&zeros, 2, 1, trace_load.fstream);
+ fclose(trace_load.fstream);
+ }
+
+ if (trace_store.fstream) {
+ AddrRec *ptr;
+ char *comp_ptr = trace_store.compressed_ptr;
+ AddrRec *next = trace_store.next;
+ uint32_t prev_addr = trace_store.prev_addr;
+ uint64_t prev_time = trace_store.prev_time;
+ for (ptr = trace_store.buffer; ptr != next; ++ptr) {
+ if (comp_ptr >= trace_store.high_water_ptr) {
+ uint32_t size = comp_ptr - trace_store.compressed;
+ fwrite(trace_store.compressed, sizeof(char), size,
+ trace_store.fstream);
+ comp_ptr = trace_store.compressed;
+ }
+
+ int addr_diff = ptr->addr - prev_addr;
+ uint64_t time_diff = ptr->time - prev_time;
+ prev_addr = ptr->addr;
+ prev_time = ptr->time;
+
+ comp_ptr = varint_encode_signed(addr_diff, comp_ptr);
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ }
+
+ uint32_t size = comp_ptr - trace_store.compressed;
+ if (size) {
+ fwrite(trace_store.compressed, sizeof(char), size,
+ trace_store.fstream);
+ }
+
+ // Terminate the file with two zeros so that we can detect
+ // the end of file quickly.
+ uint32_t zeros = 0;
+ fwrite(&zeros, 2, 1, trace_store.fstream);
+ fclose(trace_store.fstream);
+ }
+
+ if (trace_exc.fstream) {
+ uint32_t size = trace_exc.compressed_ptr - trace_exc.compressed;
+ if (size) {
+ fwrite(trace_exc.compressed, sizeof(char), size,
+ trace_exc.fstream);
+ }
+
+ // Terminate the file with 7 zeros so that we can detect
+ // the end of file quickly.
+ uint64_t zeros = 0;
+ fwrite(&zeros, 7, 1, trace_exc.fstream);
+ fclose(trace_exc.fstream);
+ }
+ if (trace_pid.fstream) {
+ uint32_t size = trace_pid.compressed_ptr - trace_pid.compressed;
+ if (size) {
+ fwrite(trace_pid.compressed, sizeof(char), size,
+ trace_pid.fstream);
+ }
+
+ // Terminate the file with 2 zeros so that we can detect
+ // the end of file quickly.
+ uint64_t zeros = 0;
+ fwrite(&zeros, 2, 1, trace_pid.fstream);
+ fclose(trace_pid.fstream);
+ }
+ if (trace_method.fstream) {
+ uint32_t size = trace_method.compressed_ptr - trace_method.compressed;
+ if (size) {
+ fwrite(trace_method.compressed, sizeof(char), size,
+ trace_method.fstream);
+ }
+
+ // Terminate the file with 2 zeros so that we can detect
+ // the end of file quickly.
+ uint64_t zeros = 0;
+ fwrite(&zeros, 2, 1, trace_method.fstream);
+ fclose(trace_method.fstream);
+ }
+ if (ftrace_debug)
+ fclose(ftrace_debug);
+}
+
+// Define the number of clock ticks for some instructions. Add one to these
+// (in some cases) if there is an interlock. We currently do not check for
+// interlocks.
+#define TICKS_OTHER 1
+#define TICKS_SMULxy 1
+#define TICKS_SMLAWy 1
+#define TICKS_SMLALxy 2
+#define TICKS_MUL 2
+#define TICKS_MLA 2
+#define TICKS_MULS 4 // no interlock penalty
+#define TICKS_MLAS 4 // no interlock penalty
+#define TICKS_UMULL 3
+#define TICKS_UMLAL 3
+#define TICKS_SMULL 3
+#define TICKS_SMLAL 3
+#define TICKS_UMULLS 5 // no interlock penalty
+#define TICKS_UMLALS 5 // no interlock penalty
+#define TICKS_SMULLS 5 // no interlock penalty
+#define TICKS_SMLALS 5 // no interlock penalty
+
+// Compute the number of cycles that this instruction will take,
+// not including any I-cache or D-cache misses. This function
+// is called for each instruction in a basic block when that
+// block is being translated.
+int get_insn_ticks(uint32_t insn)
+{
+#if 1
+ int result = 1; /* by default, use 1 cycle */
+
+ /* See Chapter 12 of the ARM920T Reference Manual for details about clock cycles */
+
+ /* first check for invalid condition codes */
+ if ((insn >> 28) == 0xf)
+ {
+ if ((insn >> 25) == 0x7d) { /* BLX */
+ result = 3;
+ goto Exit;
+ }
+ /* XXX: if we get there, we're either in an UNDEFINED instruction */
+ /* or in co-processor related ones. For now, only return 1 cycle */
+ goto Exit;
+ }
+
+ /* other cases */
+ switch ((insn >> 25) & 7)
+ {
+ case 0:
+ if ((insn & 0x00000090) == 0x00000090) /* Multiplies, extra load/store, Table 3-2 */
+ {
+ /* XXX: TODO: Add support for multiplier operand content penalties in the translator */
+
+ if ((insn & 0x0fc000f0) == 0x00000090) /* 3-2: Multiply (accumulate) */
+ {
+ int Rm = (insn & 15);
+ int Rs = (insn >> 8) & 15;
+ int Rn = (insn >> 12) & 15;
+
+ if ((insn & 0x00200000) != 0) { /* MLA */
+ result += _interlock_use(Rn);
+ } else { /* MLU */
+ if (Rn != 0) /* UNDEFINED */
+ goto Exit;
+ }
+ /* cycles=2+m, assume m=1, this should be adjusted at interpretation time */
+ result += 2 + _interlock_use(Rm) + _interlock_use(Rs);
+ }
+ else if ((insn & 0x0f8000f0) == 0x00800090) /* 3-2: Multiply (accumulate) long */
+ {
+ int Rm = (insn & 15);
+ int Rs = (insn >> 8) & 15;
+ int RdLo = (insn >> 12) & 15;
+ int RdHi = (insn >> 16) & 15;
+
+ if ((insn & 0x00200000) != 0) { /* SMLAL & UMLAL */
+ result += _interlock_use(RdLo) + _interlock_use(RdHi);
+ }
+ /* else SMLL and UMLL */
+
+ /* cucles=3+m, assume m=1, this should be adjusted at interpretation time */
+ result += 3 + _interlock_use(Rm) + _interlock_use(Rs);
+ }
+ else if ((insn & 0x0fd00ff0) == 0x01000090) /* 3-2: Swap/swap byte */
+ {
+ int Rm = (insn & 15);
+ int Rd = (insn >> 8) & 15;
+
+ result = 2 + _interlock_use(Rm);
+ _interlock_def(Rd, result+1);
+ }
+ else if ((insn & 0x0e400ff0) == 0x00000090) /* 3-2: load/store halfword, reg offset */
+ {
+ int Rm = (insn & 15);
+ int Rd = (insn >> 12) & 15;
+ int Rn = (insn >> 16) & 15;
+
+ result += _interlock_use(Rn) + _interlock_use(Rm);
+ if ((insn & 0x00100000) != 0) /* it's a load, there's a 2-cycle interlock */
+ _interlock_def(Rd, result+2);
+ }
+ else if ((insn & 0x0e400ff0) == 0x00400090) /* 3-2: load/store halfword, imm offset */
+ {
+ int Rd = (insn >> 12) & 15;
+ int Rn = (insn >> 16) & 15;
+
+ result += _interlock_use(Rn);
+ if ((insn & 0x00100000) != 0) /* it's a load, there's a 2-cycle interlock */
+ _interlock_def(Rd, result+2);
+ }
+ else if ((insn & 0x0e500fd0) == 0x000000d0) /* 3-2: load/store two words, reg offset */
+ {
+ /* XXX: TODO: Enhanced DSP instructions */
+ }
+ else if ((insn & 0x0e500fd0) == 0x001000d0) /* 3-2: load/store half/byte, reg offset */
+ {
+ int Rm = (insn & 15);
+ int Rd = (insn >> 12) & 15;
+ int Rn = (insn >> 16) & 15;
+
+ result += _interlock_use(Rn) + _interlock_use(Rm);
+ if ((insn & 0x00100000) != 0) /* load, 2-cycle interlock */
+ _interlock_def(Rd, result+2);
+ }
+ else if ((insn & 0x0e5000d0) == 0x004000d0) /* 3-2: load/store two words, imm offset */
+ {
+ /* XXX: TODO: Enhanced DSP instructions */
+ }
+ else if ((insn & 0x0e5000d0) == 0x005000d0) /* 3-2: load/store half/byte, imm offset */
+ {
+ int Rd = (insn >> 12) & 15;
+ int Rn = (insn >> 16) & 15;
+
+ result += _interlock_use(Rn);
+ if ((insn & 0x00100000) != 0) /* load, 2-cycle interlock */
+ _interlock_def(Rd, result+2);
+ }
+ else
+ {
+ /* UNDEFINED */
+ }
+ }
+ else if ((insn & 0x0f900000) == 0x01000000) /* Misc. instructions, table 3-3 */
+ {
+ switch ((insn >> 4) & 15)
+ {
+ case 0:
+ if ((insn & 0x0fb0fff0) == 0x0120f000) /* move register to status register */
+ {
+ int Rm = (insn & 15);
+ result += _interlock_use(Rm);
+ }
+ break;
+
+ case 1:
+ if ( ((insn & 0x0ffffff0) == 0x01200010) || /* branch/exchange */
+ ((insn & 0x0fff0ff0) == 0x01600010) ) /* count leading zeroes */
+ {
+ int Rm = (insn & 15);
+ result += _interlock_use(Rm);
+ }
+ break;
+
+ case 3:
+ if ((insn & 0x0ffffff0) == 0x01200030) /* link/exchange */
+ {
+ int Rm = (insn & 15);
+ result += _interlock_use(Rm);
+ }
+ break;
+
+ default:
+ /* TODO: Enhanced DSP instructions */
+ ;
+ }
+ }
+ else /* Data processing */
+ {
+ int Rm = (insn & 15);
+ int Rn = (insn >> 16) & 15;
+
+ result += _interlock_use(Rn) + _interlock_use(Rm);
+ if ((insn & 0x10)) { /* register-controlled shift => 1 cycle penalty */
+ int Rs = (insn >> 8) & 15;
+ result += 1 + _interlock_use(Rs);
+ }
+ }
+ break;
+
+ case 1:
+ if ((insn & 0x01900000) == 0x01900000)
+ {
+ /* either UNDEFINED or move immediate to CPSR */
+ }
+ else /* Data processing immediate */
+ {
+ int Rn = (insn >> 12) & 15;
+ result += _interlock_use(Rn);
+ }
+ break;
+
+ case 2: /* load/store immediate */
+ {
+ int Rn = (insn >> 16) & 15;
+
+ result += _interlock_use(Rn);
+ if (insn & 0x00100000) { /* LDR */
+ int Rd = (insn >> 12) & 15;
+
+ if (Rd == 15) /* loading PC */
+ result = 5;
+ else
+ _interlock_def(Rd,result+1);
+ }
+ }
+ break;
+
+ case 3:
+ if ((insn & 0x10) == 0) /* load/store register offset */
+ {
+ int Rm = (insn & 15);
+ int Rn = (insn >> 16) & 15;
+
+ result += _interlock_use(Rm) + _interlock_use(Rn);
+
+ if (insn & 0x00100000) { /* LDR */
+ int Rd = (insn >> 12) & 15;
+ if (Rd == 15)
+ result = 5;
+ else
+ _interlock_def(Rd,result+1);
+ }
+ }
+ /* else UNDEFINED */
+ break;
+
+ case 4: /* load/store multiple */
+ {
+ int Rn = (insn >> 16) & 15;
+ uint32_t mask = (insn & 0xffff);
+ int count;
+
+ for (count = 0; mask; count++)
+ mask &= (mask-1);
+
+ result += _interlock_use(Rn);
+
+ if (insn & 0x00100000) /* LDM */
+ {
+ int nn;
+
+ if (insn & 0x8000) { /* loading PC */
+ result = count+4;
+ } else { /* not loading PC */
+ result = (count < 2) ? 2 : count;
+ }
+ /* create defs, all registers locked until the end of the load */
+ for (nn = 0; nn < 15; nn++)
+ if ((insn & (1U << nn)) != 0)
+ _interlock_def(nn,result);
+ }
+ else /* STM */
+ result = (count < 2) ? 2 : count;
+ }
+ break;
+
+ case 5: /* branch and branch+link */
+ break;
+
+ case 6: /* coprocessor load/store */
+ {
+ int Rn = (insn >> 16) & 15;
+
+ if (insn & 0x00100000)
+ result += _interlock_use(Rn);
+
+ /* XXX: other things to do ? */
+ }
+ break;
+
+ default: /* i.e. 7 */
+ /* XXX: TODO: co-processor related things */
+ ;
+ }
+Exit:
+ interlock_base += result;
+ return result;
+#else /* old code - this seems to be completely buggy ?? */
+ if ((insn & 0x0ff0f090) == 0x01600080) {
+ return TICKS_SMULxy;
+ } else if ((insn & 0x0ff00090) == 0x01200080) {
+ return TICKS_SMLAWy;
+ } else if ((insn & 0x0ff00090) == 0x01400080) {
+ return TICKS_SMLALxy;
+ } else if ((insn & 0x0f0000f0) == 0x00000090) {
+ // multiply
+ uint8_t bit23 = (insn >> 23) & 0x1;
+ uint8_t bit22_U = (insn >> 22) & 0x1;
+ uint8_t bit21_A = (insn >> 21) & 0x1;
+ uint8_t bit20_S = (insn >> 20) & 0x1;
+
+ if (bit23 == 0) {
+ // 32-bit multiply
+ if (bit22_U != 0) {
+ // This is an unexpected bit pattern.
+ return TICKS_OTHER;
+ }
+ if (bit21_A == 0) {
+ if (bit20_S)
+ return TICKS_MULS;
+ return TICKS_MUL;
+ }
+ if (bit20_S)
+ return TICKS_MLAS;
+ return TICKS_MLA;
+ }
+ // 64-bit multiply
+ if (bit22_U == 0) {
+ // Unsigned multiply long
+ if (bit21_A == 0) {
+ if (bit20_S)
+ return TICKS_UMULLS;
+ return TICKS_UMULL;
+ }
+ if (bit20_S)
+ return TICKS_UMLALS;
+ return TICKS_UMLAL;
+ }
+ // Signed multiply long
+ if (bit21_A == 0) {
+ if (bit20_S)
+ return TICKS_SMULLS;
+ return TICKS_SMULL;
+ }
+ if (bit20_S)
+ return TICKS_SMLALS;
+ return TICKS_SMLAL;
+ }
+ return TICKS_OTHER;
+#endif
+}
+
+int get_insn_ticks_thumb(uint32_t insn)
+{
+#if 1
+ int result = 1;
+
+ switch ((insn >> 11) & 31)
+ {
+ case 0:
+ case 1:
+ case 2: /* Shift by immediate */
+ {
+ int Rm = (insn >> 3) & 7;
+ result += _interlock_use(Rm);
+ }
+ break;
+
+ case 3: /* Add/Substract */
+ {
+ int Rn = (insn >> 3) & 7;
+ result += _interlock_use(Rn);
+
+ if ((insn & 0x0400) == 0) { /* register value */
+ int Rm = (insn >> 6) & 7;
+ result += _interlock_use(Rm);
+ }
+ }
+ break;
+
+ case 4: /* move immediate */
+ break;
+
+ case 5:
+ case 6:
+ case 7: /* add/substract/compare immediate */
+ {
+ int Rd = (insn >> 8) & 7;
+ result += _interlock_use(Rd);
+ }
+ break;
+
+ case 8:
+ {
+ if ((insn & 0x0400) == 0) /* data processing register */
+ {
+ /* the registers can also be Rs and Rn in some cases */
+ /* but they're always read anyway and located at the */
+ /* same place, so we don't check the opcode */
+ int Rm = (insn >> 3) & 7;
+ int Rd = (insn >> 3) & 7;
+
+ result += _interlock_use(Rm) + _interlock_use(Rd);
+ }
+ else switch ((insn >> 8) & 3)
+ {
+ case 0:
+ case 1:
+ case 2: /* special data processing */
+ {
+ int Rn = (insn & 7) | ((insn >> 4) & 0x8);
+ int Rm = ((insn >> 3) & 15);
+
+ result += _interlock_use(Rn) + _interlock_use(Rm);
+ }
+ break;
+
+ case 3:
+ if ((insn & 0xff07) == 0x4700) /* branch/exchange */
+ {
+ int Rm = (insn >> 3) & 15;
+
+ result = 3 + _interlock_use(Rm);
+ }
+ /* else UNDEFINED */
+ break;
+ }
+ }
+ break;
+
+ case 9: /* load from literal pool */
+ {
+ int Rd = (insn >> 8) & 7;
+ _interlock_def(Rd,result+1);
+ }
+ break;
+
+ case 10:
+ case 11: /* load/store register offset */
+ {
+ int Rd = (insn & 7);
+ int Rn = (insn >> 3) & 7;
+ int Rm = (insn >> 6) & 7;
+
+ result += _interlock_use(Rn) + _interlock_use(Rm);
+
+ switch ((insn >> 9) & 7)
+ {
+ case 0: /* STR */
+ case 1: /* STRH */
+ case 2: /* STRB */
+ result += _interlock_use(Rd);
+ break;
+
+ case 3: /* LDRSB */
+ case 5: /* LDRH */
+ case 6: /* LDRB */
+ case 7: /* LDRSH */
+ _interlock_def(Rd,result+2);
+ break;
+
+ case 4: /* LDR */
+ _interlock_def(Rd,result+1);
+ }
+ }
+ break;
+
+ case 12: /* store word immediate offset */
+ case 14: /* store byte immediate offset */
+ {
+ int Rd = (insn & 7);
+ int Rn = (insn >> 3) & 7;
+
+ result += _interlock_use(Rd) + _interlock_use(Rn);
+ }
+ break;
+
+ case 13: /* load word immediate offset */
+ {
+ int Rd = (insn & 7);
+ int Rn = (insn >> 3) & 7;
+
+ result += _interlock_use(Rn);
+ _interlock_def(Rd,result+1);
+ }
+ break;
+
+ case 15: /* load byte immediate offset */
+ {
+ int Rd = (insn & 7);
+ int Rn = (insn >> 3) & 7;
+
+ result += _interlock_use(Rn);
+ _interlock_def(Rd,result+2);
+ }
+ break;
+
+ case 16: /* store halfword immediate offset */
+ {
+ int Rd = (insn & 7);
+ int Rn = (insn >> 3) & 7;
+
+ result += _interlock_use(Rn) + _interlock_use(Rd);
+ }
+ break;
+
+ case 17: /* load halfword immediate offset */
+ {
+ int Rd = (insn & 7);
+ int Rn = (insn >> 3) & 7;
+
+ result += _interlock_use(Rn);
+ _interlock_def(Rd,result+2);
+ }
+ break;
+
+ case 18: /* store to stack */
+ {
+ int Rd = (insn >> 8) & 3;
+ result += _interlock_use(Rd);
+ }
+ break;
+
+ case 19: /* load from stack */
+ {
+ int Rd = (insn >> 8) & 3;
+ _interlock_def(Rd,result+1);
+ }
+ break;
+
+ case 20: /* add to PC */
+ case 21: /* add to SP */
+ {
+ int Rd = (insn >> 8) & 3;
+ result += _interlock_use(Rd);
+ }
+ break;
+
+ case 22:
+ case 23: /* misc. instructions, table 6-2 */
+ {
+ if ((insn & 0xff00) == 0xb000) /* adjust stack pointer */
+ {
+ result += _interlock_use(14);
+ }
+ else if ((insn & 0x0600) == 0x0400) /* push pop register list */
+ {
+ uint32_t mask = insn & 0x01ff;
+ int count, nn;
+
+ for (count = 0; mask; count++)
+ mask &= (mask-1);
+
+ result = (count < 2) ? 2 : count;
+
+ if (insn & 0x0800) /* pop register list */
+ {
+ for (nn = 0; nn < 9; nn++)
+ if (insn & (1 << nn))
+ _interlock_def(nn, result);
+ }
+ else /* push register list */
+ {
+ for (nn = 0; nn < 9; nn++)
+ if (insn & (1 << nn))
+ result += _interlock_use(nn);
+ }
+ }
+ /* else software breakpoint */
+ }
+ break;
+
+ case 24: /* store multiple */
+ {
+ int Rd = (insn >> 8) & 7;
+ uint32_t mask = insn & 255;
+ int count, nn;
+
+ for (count = 0; mask; count++)
+ mask &= (mask-1);
+
+ result = (count < 2) ? 2 : count;
+ result += _interlock_use(Rd);
+
+ for (nn = 0; nn < 8; nn++)
+ if (insn & (1 << nn))
+ result += _interlock_use(nn);
+ }
+ break;
+
+ case 25: /* load multiple */
+ {
+ int Rd = (insn >> 8) & 7;
+ uint32_t mask = insn & 255;
+ int count, nn;
+
+ for (count = 0; mask; count++)
+ mask &= (mask-1);
+
+ result = (count < 2) ? 2 : count;
+ result += _interlock_use(Rd);
+
+ for (nn = 0; nn < 8; nn++)
+ if (insn & (1 << nn))
+ _interlock_def(nn, result);
+ }
+ break;
+
+ case 26:
+ case 27: /* conditional branch / undefined / software interrupt */
+ switch ((insn >> 8) & 15)
+ {
+ case 14: /* UNDEFINED */
+ case 15: /* SWI */
+ break;
+
+ default: /* conditional branch */
+ result = 3;
+ }
+ break;
+
+ case 28: /* unconditional branch */
+ result = 3;
+ break;
+
+ case 29: /* BLX suffix or undefined */
+ if ((insn & 1) == 0)
+ result = 3;
+ break;
+
+ case 30: /* BLX/BLX prefix */
+ break;
+
+ case 31: /* BL suffix */
+ result = 3;
+ break;
+ }
+ interlock_base += result;
+ return result;
+#else /* old code */
+ if ((insn & 0xfc00) == 0x4340) /* MUL */
+ return TICKS_SMULxy;
+
+ return TICKS_OTHER;
+#endif
+}
+
+// Adds an exception trace record.
+void trace_exception(uint32 target_pc)
+{
+ if (trace_exc.fstream == NULL)
+ return;
+
+ // Sometimes we get an unexpected exception as the first record. If the
+ // basic block number is zero, then we know it is bogus.
+ if (trace_bb.current_bb_num == 0)
+ return;
+
+ uint32_t current_pc = trace_bb.current_bb_addr + 4 * (trace_bb.num_insns - 1);
+#if 0
+ if (ftrace_debug) {
+ fprintf(ftrace_debug, "t%llu exc pc: 0x%x bb_addr: 0x%x num_insns: %d current_pc: 0x%x bb_num %llu bb_start_time %llu\n",
+ sim_time, target_pc, trace_bb.current_bb_addr,
+ trace_bb.num_insns, current_pc, trace_bb.current_bb_num,
+ trace_bb.current_bb_start_time);
+ }
+#endif
+ char *comp_ptr = trace_exc.compressed_ptr;
+ if (comp_ptr >= trace_exc.high_water_ptr) {
+ uint32_t size = comp_ptr - trace_exc.compressed;
+ fwrite(trace_exc.compressed, sizeof(char), size, trace_exc.fstream);
+ comp_ptr = trace_exc.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_exc.prev_time;
+ trace_exc.prev_time = sim_time;
+ uint64_t bb_recnum_diff = trace_bb.recnum - trace_exc.prev_bb_recnum;
+ trace_exc.prev_bb_recnum = trace_bb.recnum;
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ comp_ptr = varint_encode(current_pc, comp_ptr);
+ comp_ptr = varint_encode(bb_recnum_diff, comp_ptr);
+ comp_ptr = varint_encode(target_pc, comp_ptr);
+ comp_ptr = varint_encode(trace_bb.current_bb_num, comp_ptr);
+ comp_ptr = varint_encode(trace_bb.current_bb_start_time, comp_ptr);
+ comp_ptr = varint_encode(trace_bb.num_insns, comp_ptr);
+ trace_exc.compressed_ptr = comp_ptr;
+}
+
+void trace_pid_1arg(int pid, int rec_type)
+{
+ if (trace_pid.fstream == NULL)
+ return;
+ char *comp_ptr = trace_pid.compressed_ptr;
+ char *max_end_ptr = comp_ptr + kMaxPidCompressed;
+ if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
+ uint32_t size = comp_ptr - trace_pid.compressed;
+ fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
+ comp_ptr = trace_pid.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_pid.prev_time;
+ trace_pid.prev_time = sim_time;
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ comp_ptr = varint_encode(rec_type, comp_ptr);
+ comp_ptr = varint_encode(pid, comp_ptr);
+ trace_pid.compressed_ptr = comp_ptr;
+}
+
+void trace_pid_2arg(int tgid, int pid, int rec_type)
+{
+ if (trace_pid.fstream == NULL)
+ return;
+ char *comp_ptr = trace_pid.compressed_ptr;
+ char *max_end_ptr = comp_ptr + kMaxPid2Compressed;
+ if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
+ uint32_t size = comp_ptr - trace_pid.compressed;
+ fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
+ comp_ptr = trace_pid.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_pid.prev_time;
+ trace_pid.prev_time = sim_time;
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ comp_ptr = varint_encode(rec_type, comp_ptr);
+ comp_ptr = varint_encode(tgid, comp_ptr);
+ comp_ptr = varint_encode(pid, comp_ptr);
+ trace_pid.compressed_ptr = comp_ptr;
+}
+
+void trace_switch(int pid)
+{
+#if 0
+ if (ftrace_debug && trace_pid.fstream)
+ fprintf(ftrace_debug, "t%lld switch %d\n", sim_time, pid);
+#endif
+ trace_pid_1arg(pid, kPidSwitch);
+ current_pid = pid;
+}
+
+void trace_fork(int tgid, int pid)
+{
+#if 0
+ if (ftrace_debug && trace_pid.fstream)
+ fprintf(ftrace_debug, "t%lld fork %d\n", sim_time, pid);
+#endif
+ trace_pid_2arg(tgid, pid, kPidFork);
+}
+
+void trace_clone(int tgid, int pid)
+{
+#if 0
+ if (ftrace_debug && trace_pid.fstream)
+ fprintf(ftrace_debug, "t%lld clone %d\n", sim_time, pid);
+#endif
+ trace_pid_2arg(tgid, pid, kPidClone);
+}
+
+void trace_exit(int exitcode)
+{
+#if 0
+ if (ftrace_debug && trace_pid.fstream)
+ fprintf(ftrace_debug, "t%lld exit %d\n", sim_time, exitcode);
+#endif
+ trace_pid_1arg(exitcode, kPidExit);
+}
+
+void trace_name(char *name)
+{
+#if 0
+ if (ftrace_debug && trace_pid.fstream) {
+ fprintf(ftrace_debug, "t%lld pid %d name %s\n",
+ sim_time, current_pid, name);
+ }
+#endif
+ if (trace_pid.fstream == NULL)
+ return;
+ int len = strlen(name);
+ char *comp_ptr = trace_pid.compressed_ptr;
+ char *max_end_ptr = comp_ptr + len + kMaxNameCompressed;
+ if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
+ uint32_t size = comp_ptr - trace_pid.compressed;
+ fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
+ comp_ptr = trace_pid.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_pid.prev_time;
+ trace_pid.prev_time = sim_time;
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ int rec_type = kPidName;
+ comp_ptr = varint_encode(rec_type, comp_ptr);
+ comp_ptr = varint_encode(current_pid, comp_ptr);
+ comp_ptr = varint_encode(len, comp_ptr);
+ strncpy(comp_ptr, name, len);
+ comp_ptr += len;
+ trace_pid.compressed_ptr = comp_ptr;
+}
+
+void trace_execve(const char *argv, int len)
+{
+ int ii;
+
+ if (trace_pid.fstream == NULL)
+ return;
+ // Count the number of args
+ int alen = 0;
+ int sum_len = 0;
+ int argc = 0;
+ const char *ptr = argv;
+ while (sum_len < len) {
+ argc += 1;
+ alen = strlen(ptr);
+ ptr += alen + 1;
+ sum_len += alen + 1;
+ }
+
+#if 0
+ if (ftrace_debug) {
+ fprintf(ftrace_debug, "t%lld argc: %d\n", sim_time, argc);
+ alen = 0;
+ ptr = argv;
+ for (ii = 0; ii < argc; ++ii) {
+ fprintf(ftrace_debug, " argv[%d]: %s\n", ii, ptr);
+ alen = strlen(ptr);
+ ptr += alen + 1;
+ }
+ }
+#endif
+
+ char *comp_ptr = trace_pid.compressed_ptr;
+ char *max_end_ptr = comp_ptr + len + 5 * argc + kMaxExecArgsCompressed;
+ if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
+ uint32_t size = comp_ptr - trace_pid.compressed;
+ fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
+ comp_ptr = trace_pid.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_pid.prev_time;
+ trace_pid.prev_time = sim_time;
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ int rec_type = kPidExec;
+ comp_ptr = varint_encode(rec_type, comp_ptr);
+ comp_ptr = varint_encode(argc, comp_ptr);
+
+ ptr = argv;
+ for (ii = 0; ii < argc; ++ii) {
+ alen = strlen(ptr);
+ comp_ptr = varint_encode(alen, comp_ptr);
+ strncpy(comp_ptr, ptr, alen);
+ comp_ptr += alen;
+ ptr += alen + 1;
+ }
+ trace_pid.compressed_ptr = comp_ptr;
+}
+
+void trace_mmap(unsigned long vstart, unsigned long vend,
+ unsigned long offset, const char *path)
+{
+ if (trace_pid.fstream == NULL)
+ return;
+#if 0
+ if (ftrace_debug)
+ fprintf(ftrace_debug, "t%lld mmap %08lx - %08lx, offset %08lx '%s'\n",
+ sim_time, vstart, vend, offset, path);
+#endif
+ int len = strlen(path);
+ char *comp_ptr = trace_pid.compressed_ptr;
+ char *max_end_ptr = comp_ptr + len + kMaxMmapCompressed;
+ if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
+ uint32_t size = comp_ptr - trace_pid.compressed;
+ fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
+ comp_ptr = trace_pid.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_pid.prev_time;
+ trace_pid.prev_time = sim_time;
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ int rec_type = kPidMmap;
+ comp_ptr = varint_encode(rec_type, comp_ptr);
+ comp_ptr = varint_encode(vstart, comp_ptr);
+ comp_ptr = varint_encode(vend, comp_ptr);
+ comp_ptr = varint_encode(offset, comp_ptr);
+ comp_ptr = varint_encode(len, comp_ptr);
+ strncpy(comp_ptr, path, len);
+ trace_pid.compressed_ptr = comp_ptr + len;
+}
+
+void trace_munmap(unsigned long vstart, unsigned long vend)
+{
+ if (trace_pid.fstream == NULL)
+ return;
+#if 0
+ if (ftrace_debug)
+ fprintf(ftrace_debug, "t%lld munmap %08lx - %08lx\n",
+ sim_time, vstart, vend);
+#endif
+ char *comp_ptr = trace_pid.compressed_ptr;
+ char *max_end_ptr = comp_ptr + kMaxMunmapCompressed;
+ if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
+ uint32_t size = comp_ptr - trace_pid.compressed;
+ fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
+ comp_ptr = trace_pid.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_pid.prev_time;
+ trace_pid.prev_time = sim_time;
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ int rec_type = kPidMunmap;
+ comp_ptr = varint_encode(rec_type, comp_ptr);
+ comp_ptr = varint_encode(vstart, comp_ptr);
+ comp_ptr = varint_encode(vend, comp_ptr);
+ trace_pid.compressed_ptr = comp_ptr;
+}
+
+void trace_dynamic_symbol_add(unsigned long vaddr, const char *name)
+{
+ if (trace_pid.fstream == NULL)
+ return;
+#if 0
+ if (ftrace_debug)
+ fprintf(ftrace_debug, "t%lld sym %08lx '%s'\n", sim_time, vaddr, name);
+#endif
+ int len = strlen(name);
+ char *comp_ptr = trace_pid.compressed_ptr;
+ char *max_end_ptr = comp_ptr + len + kMaxSymbolCompressed;
+ if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
+ uint32_t size = comp_ptr - trace_pid.compressed;
+ fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
+ comp_ptr = trace_pid.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_pid.prev_time;
+ trace_pid.prev_time = sim_time;
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ int rec_type = kPidSymbolAdd;
+ comp_ptr = varint_encode(rec_type, comp_ptr);
+ comp_ptr = varint_encode(vaddr, comp_ptr);
+ comp_ptr = varint_encode(len, comp_ptr);
+ strncpy(comp_ptr, name, len);
+ trace_pid.compressed_ptr = comp_ptr + len;
+}
+
+void trace_dynamic_symbol_remove(unsigned long vaddr)
+{
+ if (trace_pid.fstream == NULL)
+ return;
+#if 0
+ if (ftrace_debug)
+ fprintf(ftrace_debug, "t%lld remove %08lx\n", sim_time, vaddr);
+#endif
+ char *comp_ptr = trace_pid.compressed_ptr;
+ char *max_end_ptr = comp_ptr + kMaxSymbolCompressed;
+ if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
+ uint32_t size = comp_ptr - trace_pid.compressed;
+ fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
+ comp_ptr = trace_pid.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_pid.prev_time;
+ trace_pid.prev_time = sim_time;
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ int rec_type = kPidSymbolRemove;
+ comp_ptr = varint_encode(rec_type, comp_ptr);
+ comp_ptr = varint_encode(vaddr, comp_ptr);
+ trace_pid.compressed_ptr = comp_ptr;
+}
+
+void trace_init_name(int tgid, int pid, const char *name)
+{
+ if (trace_pid.fstream == NULL)
+ return;
+#if 0
+ if (ftrace_debug)
+ fprintf(ftrace_debug, "t%lld kthread %d %s\n", sim_time, pid, name);
+#endif
+ int len = strlen(name);
+ char *comp_ptr = trace_pid.compressed_ptr;
+ char *max_end_ptr = comp_ptr + len + kMaxKthreadNameCompressed;
+ if (max_end_ptr >= &trace_pid.compressed[kCompressedSize]) {
+ uint32_t size = comp_ptr - trace_pid.compressed;
+ fwrite(trace_pid.compressed, sizeof(char), size, trace_pid.fstream);
+ comp_ptr = trace_pid.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_pid.prev_time;
+ trace_pid.prev_time = sim_time;
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ int rec_type = kPidKthreadName;
+ comp_ptr = varint_encode(rec_type, comp_ptr);
+ comp_ptr = varint_encode(tgid, comp_ptr);
+ comp_ptr = varint_encode(pid, comp_ptr);
+ comp_ptr = varint_encode(len, comp_ptr);
+ strncpy(comp_ptr, name, len);
+ trace_pid.compressed_ptr = comp_ptr + len;
+}
+
+void trace_init_exec(unsigned long start, unsigned long end,
+ unsigned long offset, const char *exe)
+{
+}
+
+// This function is called by the generated code to record the basic
+// block number.
+void trace_bb_helper(uint64_t bb_num, TranslationBlock *tb)
+{
+ BBRec *bb_rec = tb->bb_rec;
+ uint64_t prev_time = tb->prev_time;
+ trace_bb.current_bb_addr = tb->pc;
+ trace_bb.current_bb_num = bb_num;
+ trace_bb.current_bb_start_time = sim_time;
+ trace_bb.num_insns = 0;
+ trace_bb.recnum += 1;
+
+#if 0
+ if (ftrace_debug)
+ fprintf(ftrace_debug, "t%lld %lld\n", sim_time, bb_num);
+#endif
+ if (bb_rec && bb_rec->bb_num == bb_num && prev_time > trace_bb.flush_time) {
+ uint64_t time_diff = sim_time - prev_time;
+ if (bb_rec->repeat == 0) {
+ bb_rec->repeat = 1;
+ bb_rec->time_diff = time_diff;
+ tb->prev_time = sim_time;
+ return;
+ } else if (time_diff == bb_rec->time_diff) {
+ bb_rec->repeat += 1;
+ tb->prev_time = sim_time;
+ return;
+ }
+ }
+
+ BBRec *next = trace_bb.next;
+ if (next == &trace_bb.buffer[kMaxNumBasicBlocks]) {
+ BBRec *ptr;
+ char *comp_ptr = trace_bb.compressed_ptr;
+ int64_t prev_bb_num = trace_bb.prev_bb_num;
+ uint64_t prev_bb_time = trace_bb.prev_bb_time;
+ for (ptr = trace_bb.buffer; ptr != next; ++ptr) {
+ if (comp_ptr >= trace_bb.high_water_ptr) {
+ uint32_t size = comp_ptr - trace_bb.compressed;
+ fwrite(trace_bb.compressed, sizeof(char), size, trace_bb.fstream);
+ comp_ptr = trace_bb.compressed;
+ }
+ int64_t bb_diff = ptr->bb_num - prev_bb_num;
+ prev_bb_num = ptr->bb_num;
+ uint64_t time_diff = ptr->start_time - prev_bb_time;
+ prev_bb_time = ptr->start_time;
+ comp_ptr = varint_encode_signed(bb_diff, comp_ptr);
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ comp_ptr = varint_encode(ptr->repeat, comp_ptr);
+ if (ptr->repeat)
+ comp_ptr = varint_encode(ptr->time_diff, comp_ptr);
+ }
+ trace_bb.compressed_ptr = comp_ptr;
+ trace_bb.prev_bb_num = prev_bb_num;
+ trace_bb.prev_bb_time = prev_bb_time;
+
+ next = trace_bb.buffer;
+ trace_bb.flush_time = sim_time;
+ }
+ tb->bb_rec = next;
+ next->bb_num = bb_num;
+ next->start_time = sim_time;
+ next->time_diff = 0;
+ next->repeat = 0;
+ tb->prev_time = sim_time;
+ next += 1;
+ trace_bb.next = next;
+}
+
+// This function is called by the generated code to record the simulation
+// time at the start of each instruction.
+void trace_insn_helper()
+{
+ InsnRec *current = trace_insn.current;
+ uint64_t time_diff = sim_time - trace_insn.prev_time;
+ trace_insn.prev_time = sim_time;
+
+ // Keep track of the number of traced instructions so far in this
+ // basic block in case we get an exception in the middle of the bb.
+ trace_bb.num_insns += 1;
+
+#if 0
+ if (ftrace_debug) {
+ uint32_t current_pc = trace_bb.current_bb_addr + 4 * (trace_bb.num_insns - 1);
+ fprintf(ftrace_debug, "%llu %x\n", sim_time, current_pc);
+ }
+#endif
+ if (time_diff == current->time_diff) {
+ current->repeat += 1;
+ if (current->repeat != 0)
+ return;
+
+ // The repeat count wrapped around, so back up one and create
+ // a new record.
+ current->repeat -= 1;
+ }
+ current += 1;
+
+ if (current == &trace_insn.buffer[kInsnBufferSize]) {
+ InsnRec *ptr;
+ char *comp_ptr = trace_insn.compressed_ptr;
+ for (ptr = trace_insn.buffer; ptr != current; ++ptr) {
+ if (comp_ptr >= trace_insn.high_water_ptr) {
+ uint32_t size = comp_ptr - trace_insn.compressed;
+ uint32_t rval = fwrite(trace_insn.compressed, sizeof(char),
+ size, trace_insn.fstream);
+ if (rval != size) {
+ fprintf(stderr, "fwrite() failed\n");
+ perror(trace_insn.filename);
+ exit(1);
+ }
+ comp_ptr = trace_insn.compressed;
+ }
+ comp_ptr = varint_encode(ptr->time_diff, comp_ptr);
+ comp_ptr = varint_encode(ptr->repeat, comp_ptr);
+ }
+ trace_insn.compressed_ptr = comp_ptr;
+ current = trace_insn.buffer;
+ }
+ current->time_diff = time_diff;
+ current->repeat = 0;
+ trace_insn.current = current;
+}
+
+// Adds an interpreted method trace record. Each trace record is a time
+// stamped entry or exit to a method in a language executed by a "virtual
+// machine". This allows profiling tools to show the method names instead
+// of the core virtual machine interpreter.
+void trace_interpreted_method(uint32_t addr, int call_type)
+{
+ if (trace_method.fstream == NULL)
+ return;
+#if 0
+ fprintf(stderr, "trace_method time: %llu p%d 0x%x %d\n",
+ sim_time, current_pid, addr, call_type);
+#endif
+ char *comp_ptr = trace_method.compressed_ptr;
+ char *max_end_ptr = comp_ptr + kMaxMethodCompressed;
+ if (max_end_ptr >= &trace_method.compressed[kCompressedSize]) {
+ uint32_t size = comp_ptr - trace_method.compressed;
+ fwrite(trace_method.compressed, sizeof(char), size, trace_method.fstream);
+ comp_ptr = trace_method.compressed;
+ }
+ uint64_t time_diff = sim_time - trace_method.prev_time;
+ trace_method.prev_time = sim_time;
+
+ int32_t addr_diff = addr - trace_method.prev_addr;
+ trace_method.prev_addr = addr;
+
+ int32_t pid_diff = current_pid - trace_method.prev_pid;
+ trace_method.prev_pid = current_pid;
+
+ comp_ptr = varint_encode(time_diff, comp_ptr);
+ comp_ptr = varint_encode_signed(addr_diff, comp_ptr);
+ comp_ptr = varint_encode_signed(pid_diff, comp_ptr);
+ comp_ptr = varint_encode(call_type, comp_ptr);
+ trace_method.compressed_ptr = comp_ptr;
+}
diff --git a/trace.h b/trace.h
new file mode 100644
index 0000000..026dfaf
--- /dev/null
+++ b/trace.h
@@ -0,0 +1,157 @@
+/* Copyright (C) 2006-2007 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+#ifndef TRACE_H
+#define TRACE_H
+
+#include <inttypes.h>
+#include "trace_common.h"
+
+extern uint64_t start_time, end_time;
+extern uint64_t elapsed_usecs;
+extern uint64 Now();
+
+// Define magic addresses so that the simulated program can interact with the
+// simulator.
+#define kMagicBaseAddr 0x08000000
+#define kMagicBaseMask 0xfffff000
+#define kMagicOffsetMask 0x00000fff
+
+#define kMethodTraceEnterOffset 0x0004
+#define kMethodTraceExitOffset 0x0008
+#define kMethodTraceExceptionOffset 0x000c
+
+struct TranslationBlock;
+
+// For tracing dynamic execution of basic blocks
+typedef struct TraceBB {
+ char *filename;
+ FILE *fstream;
+ BBRec buffer[kMaxNumBasicBlocks];
+ BBRec *next; // points to next record in buffer
+ uint64_t flush_time; // time of last buffer flush
+ char compressed[kCompressedSize];
+ char *compressed_ptr;
+ char *high_water_ptr;
+ int64_t prev_bb_num;
+ uint64_t prev_bb_time;
+ uint64_t current_bb_num;
+ uint64_t current_bb_start_time;
+ uint64_t recnum; // counts number of trace records
+ uint32_t current_bb_addr;
+ int num_insns;
+} TraceBB;
+
+// For tracing simuation start times of instructions
+typedef struct TraceInsn {
+ char *filename;
+ FILE *fstream;
+ InsnRec dummy; // this is here so we can use buffer[-1]
+ InsnRec buffer[kInsnBufferSize];
+ InsnRec *current;
+ uint64_t prev_time; // time of last instruction start
+ char compressed[kCompressedSize];
+ char *compressed_ptr;
+ char *high_water_ptr;
+} TraceInsn;
+
+// For tracing the static information about a basic block
+typedef struct TraceStatic {
+ char *filename;
+ FILE *fstream;
+ uint32_t insns[kMaxInsnPerBB];
+ int next_insn;
+ uint64_t bb_num;
+ uint32_t bb_addr;
+ int is_thumb;
+} TraceStatic;
+
+// For tracing load and store addresses
+typedef struct TraceAddr {
+ char *filename;
+ FILE *fstream;
+ AddrRec buffer[kMaxNumAddrs];
+ AddrRec *next;
+ char compressed[kCompressedSize];
+ char *compressed_ptr;
+ char *high_water_ptr;
+ uint32_t prev_addr;
+ uint64_t prev_time;
+} TraceAddr;
+
+// For tracing exceptions
+typedef struct TraceExc {
+ char *filename;
+ FILE *fstream;
+ char compressed[kCompressedSize];
+ char *compressed_ptr;
+ char *high_water_ptr;
+ uint64_t prev_time;
+ uint64_t prev_bb_recnum;
+} TraceExc;
+
+// For tracing process id changes
+typedef struct TracePid {
+ char *filename;
+ FILE *fstream;
+ char compressed[kCompressedSize];
+ char *compressed_ptr;
+ uint64_t prev_time;
+} TracePid;
+
+// For tracing Dalvik VM method enter and exit
+typedef struct TraceMethod {
+ char *filename;
+ FILE *fstream;
+ char compressed[kCompressedSize];
+ char *compressed_ptr;
+ uint64_t prev_time;
+ uint32_t prev_addr;
+ int32_t prev_pid;
+} TraceMethod;
+
+extern TraceBB trace_bb;
+extern TraceInsn trace_insn;
+extern TraceStatic trace_static;
+extern TraceAddr trace_load;
+extern TraceAddr trace_store;
+extern TraceExc trace_exc;
+extern TracePid trace_pid;
+extern TraceMethod trace_method;
+
+// The simulated time, in clock ticks, starting with one.
+extern uint64_t sim_time;
+
+// This variable == 1 if we are currently tracing, otherwise == 0.
+extern int tracing;
+extern int trace_all_addr;
+extern int trace_cache_miss;
+
+extern void start_tracing();
+extern void stop_tracing();
+extern void trace_init(const char *filename);
+extern void trace_bb_start(uint32_t bb_addr);
+extern void trace_add_insn(uint32_t insn, int is_thumb);
+extern void trace_bb_end();
+
+extern int get_insn_ticks(uint32_t insn);
+extern int get_insn_ticks_thumb(uint32_t insn);
+
+extern void trace_exception(uint32 pc);
+extern void trace_bb_helper(uint64_t bb_num, TranslationBlock *tb);
+extern void trace_insn_helper();
+extern void sim_dcache_load(uint32_t addr);
+extern void sim_dcache_store(uint32_t addr, uint32_t val);
+extern void sim_dcache_swp(uint32_t addr);
+extern void trace_interpreted_method(uint32_t addr, int call_type);
+
+#endif /* TRACE_H */
diff --git a/trace_common.h b/trace_common.h
new file mode 100644
index 0000000..3c4440d
--- /dev/null
+++ b/trace_common.h
@@ -0,0 +1,139 @@
+/* Copyright (C) 2006-2007 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+
+#ifndef TRACE_COMMON_H
+#define TRACE_COMMON_H
+
+#include <inttypes.h>
+
+// This should be the same as OPC_BUF_SIZE
+#define kMaxInsnPerBB 512
+
+#define kMaxNumBasicBlocks 1024
+
+#define kMaxNumAddrs 1024
+
+#define kInsnBufferSize 1024
+
+#define kCompressedSize 8192
+
+#define kMethodEnter 0
+#define kMethodExit 1
+#define kMethodException 2
+
+// The trace identifier string must be less than 16 characters.
+#define TRACE_IDENT "qemu_trace_file"
+#define TRACE_VERSION 1
+
+typedef struct TraceHeader {
+ char ident[16];
+ int version;
+ uint32_t start_sec;
+ uint32_t start_usec;
+ uint32_t pdate;
+ uint32_t ptime;
+ uint32_t num_used_pids; // number of distinct process ids used
+ int first_unused_pid; // -1 if all 32,768 pids are used (unlikely)
+ uint8_t padding[4]; // next field is 8-byte aligned
+ uint64_t num_static_bb;
+ uint64_t num_static_insn;
+ uint64_t num_dynamic_bb;
+ uint64_t num_dynamic_insn;
+ uint64_t elapsed_usecs;
+} TraceHeader;
+
+typedef struct BBRec {
+ uint64_t start_time; // time of first occurrence
+ uint64_t bb_num; // basic block number
+ uint32_t repeat; // repeat count (= 0 if just one occurrence)
+ uint64_t time_diff; // diff from previous time (if repeat > 0)
+} BBRec;
+
+// Define a trace record for addresses that miss in the cache
+typedef struct AddrRec {
+ uint64_t time;
+ uint32_t addr;
+} AddrRec;
+
+// Define a trace record for the start time of each instruction
+typedef struct InsnRec {
+ uint64_t time_diff; // time difference from last instruction
+ uint32_t repeat; // repeat count
+} InsnRec;
+
+// Define record types for process id changes.
+#define kPidEndOfFile 0
+#define kPidFork 1
+#define kPidClone 2
+#define kPidSwitch 3
+#define kPidExec 4
+#define kPidMmap 5
+#define kPidExit 6
+#define kPidKthreadName 7
+#define kPidSymbolAdd 8
+#define kPidSymbolRemove 9
+#define kPidMunmap 10
+#define kPidNoAction 11
+#define kPidName 12
+
+#define bswap16(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
+
+#define bswap32(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) \
+ | (((x) >> 8) & 0xff00) | (((x) >> 24) & 0xff))
+
+#define bswap64(x) (((x) << 56) | (((x) & 0xff00) << 40) \
+ | (((x) & 0xff0000) << 24) | (((x) & 0xff000000ull) << 8) \
+ | (((x) >> 8) & 0xff000000ull) | (((x) >> 24) & 0xff0000) \
+ | (((x) >> 40) & 0xff00) | ((x) >> 56))
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define hostToLE16(x) (x)
+#define hostToLE32(x) (x)
+#define hostToLE64(x) (x)
+#define LE16ToHost(x) (x)
+#define LE32ToHost(x) (x)
+#define LE64ToHost(x) (x)
+#define convert16(x)
+#define convert32(x)
+#define convert64(x)
+#else
+#define hostToLE16(x) bswap16(x)
+#define hostToLE32(x) bswap32(x)
+#define hostToLE64(x) bswap64(x)
+#define LE16ToHost(x) bswap16(x)
+#define LE32ToHost(x) bswap32(x)
+#define LE64ToHost(x) bswap64(x)
+#define convert16(x) (x = bswap16(x))
+#define convert32(x) (x = bswap32(x))
+#define convert64(x) (x = bswap64(x))
+#endif
+
+/* XXX: we wrap 16-bit thumb instructions into 32-bit undefined ARM instructions
+ * for simplicity reasons. See section 3.13.1 section of the ARM ARM for details
+ * on the undefined instruction space we're using
+ */
+static __inline__ int insn_is_thumb(uint32_t insn)
+{
+ return ((insn & 0xfff000f0) == 0xf7f000f0);
+}
+
+static __inline__ uint32_t insn_wrap_thumb(uint32_t insn)
+{
+ return 0xf7f000f0 | ((insn & 0xfff0) << 4) | (insn & 0x000f);
+}
+
+static __inline__ uint32_t insn_unwrap_thumb(uint32_t insn)
+{
+ return ((insn >> 4) & 0xfff0) | (insn & 0x000f);
+}
+
+#endif /* TRACE_COMMON_H */
diff --git a/translate-all.c b/translate-all.c
index 0de429f..fbcfeb8 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -30,13 +30,45 @@
#include "exec-all.h"
#include "disas.h"
+typedef int (*cpu_gen_code_func)(CPUState* env,
+ TranslationBlock* tb,
+ int max_code_size,
+ int* gen_code_size_ptr);
+
+typedef int (*cpu_restore_state_func)(TranslationBlock* tb,
+ CPUState* env,
+ unsigned long searched_pc,
+ void* puc);
+
+typedef void (*dump_ops_func)(const uint16_t *opc_buf, const uint32_t *opparam_buf);
+
+extern cpu_gen_code_func _cpu_gen_code;
+extern cpu_restore_state_func _cpu_restore_state;
+extern dump_ops_func _dump_ops;
+
+
+#ifdef GEN_TRACE
+#define OPC_H "opc-trace.h"
+#define CPU_GEN_CODE trace_cpu_gen_code
+#define CPU_RESTORE_STATE trace_cpu_restore_state
+#define DUMP_OPS trace_dump_ops
+#else
+#define OPC_H "opc.h"
+#define CPU_GEN_CODE default_cpu_gen_code
+#define CPU_RESTORE_STATE default_cpu_restore_state
+#define DUMP_OPS default_dump_ops
+#endif
+
+
+
+
extern int dyngen_code(uint8_t *gen_code_buf,
uint16_t *label_offsets, uint16_t *jmp_offsets,
const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels);
enum {
#define DEF(s, n, copy_size) INDEX_op_ ## s,
-#include "opc.h"
+#include OPC_H
#undef DEF
NB_OPS,
};
@@ -57,28 +89,30 @@ target_ulong gen_opc_jump_pc[2];
uint32_t gen_opc_hflags[OPC_BUF_SIZE];
#endif
+#ifndef GEN_TRACE
int code_copy_enabled = 1;
+#endif
#ifdef DEBUG_DISAS
static const char *op_str[] = {
#define DEF(s, n, copy_size) #s,
-#include "opc.h"
+#include OPC_H
#undef DEF
};
static uint8_t op_nb_args[] = {
#define DEF(s, n, copy_size) n,
-#include "opc.h"
+#include OPC_H
#undef DEF
};
static const unsigned short opc_copy_size[] = {
#define DEF(s, n, copy_size) copy_size,
-#include "opc.h"
+#include OPC_H
#undef DEF
};
-void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
+void DUMP_OPS(const uint16_t *opc_buf, const uint32_t *opparam_buf)
{
const uint16_t *opc_ptr;
const uint32_t *opparam_ptr;
@@ -138,7 +172,7 @@ static void dyngen_labels(long *gen_labels, int nb_gen_labels,
'*gen_code_size_ptr' contains the size of the generated code (host
code).
*/
-int cpu_gen_code(CPUState *env, TranslationBlock *tb,
+static int CPU_GEN_CODE(CPUState *env, TranslationBlock *tb,
int max_code_size, int *gen_code_size_ptr)
{
uint8_t *gen_code_buf;
@@ -187,7 +221,7 @@ int cpu_gen_code(CPUState *env, TranslationBlock *tb,
/* The cpu state corresponding to 'searched_pc' is restored.
*/
-int cpu_restore_state(TranslationBlock *tb,
+static int CPU_RESTORE_STATE(TranslationBlock *tb,
CPUState *env, unsigned long searched_pc,
void *puc)
{
@@ -309,3 +343,46 @@ int cpu_restore_state(TranslationBlock *tb,
#endif
return 0;
}
+
+
+#ifdef GEN_TRACE
+
+void qemu_trace_enable_gencode( void )
+{
+ _cpu_gen_code = CPU_GEN_CODE;
+ _cpu_restore_state = CPU_RESTORE_STATE;
+ _dump_ops = DUMP_OPS;
+}
+
+#else
+
+cpu_gen_code_func _cpu_gen_code = CPU_GEN_CODE;
+cpu_restore_state_func _cpu_restore_state = CPU_RESTORE_STATE;
+dump_ops_func _dump_ops = DUMP_OPS;
+
+void qemu_trace_disable_gencode( void )
+{
+ _cpu_gen_code = CPU_GEN_CODE;
+ _cpu_restore_state = CPU_RESTORE_STATE;
+ _dump_ops = DUMP_OPS;
+}
+
+int cpu_gen_code(CPUState *env, TranslationBlock *tb,
+ int max_code_size, int *gen_code_size_ptr)
+{
+ return (*_cpu_gen_code)(env, tb, max_code_size, gen_code_size_ptr);
+}
+
+int cpu_restore_state(TranslationBlock *tb,
+ CPUState *env, unsigned long searched_pc,
+ void *puc)
+{
+ return (*_cpu_restore_state)(tb, env, searched_pc, puc);
+}
+
+void dump_ops(const uint16_t *opc_buf, const uint32_t *opparam_buf)
+{
+ (*_dump_ops)(opc_buf, opparam_buf);
+}
+
+#endif
diff --git a/translate-op.c b/translate-op.c
index fddac70..c25a161 100644
--- a/translate-op.c
+++ b/translate-op.c
@@ -27,11 +27,55 @@
enum {
#define DEF(s, n, copy_size) INDEX_op_ ## s,
+#ifdef GEN_TRACE
+#include "opc-trace.h"
+#else
#include "opc.h"
+#endif
#undef DEF
NB_OPS,
};
#include "dyngen.h"
+#ifdef GEN_TRACE
+#define dyngen_code _trace_dyngen_code
+#include "op-trace.h"
+#else
+#define dyngen_code _default_dyngen_code
#include "op.h"
+#endif
+
+typedef int (*dyngen_code_func)(uint8_t *gen_code_buf,
+ uint16_t *label_offsets, uint16_t *jmp_offsets,
+ const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels);
+
+extern dyngen_code_func _dyngen_code;
+
+#ifdef GEN_TRACE
+
+void qemu_trace_enable_dyngen( void )
+{
+ _dyngen_code = dyngen_code;
+}
+
+#else
+
+void qemu_trace_disable_dyngen( void )
+{
+ _dyngen_code = dyngen_code;
+}
+
+dyngen_code_func _dyngen_code = _default_dyngen_code;
+
+#undef dyngen_code
+
+int dyngen_code(uint8_t *gen_code_buf,
+ uint16_t *label_offsets, uint16_t *jmp_offsets,
+ const uint16_t *opc_buf, const uint32_t *opparam_buf, const long *gen_labels)
+{
+ return (*_dyngen_code)(gen_code_buf, label_offsets, jmp_offsets, opc_buf, opparam_buf, gen_labels);
+}
+
+#endif
+
diff --git a/translate.make b/translate.make
new file mode 100644
index 0000000..136d5a5
--- /dev/null
+++ b/translate.make
@@ -0,0 +1,36 @@
+# this sub-Makefile is included to define a dynamic translating library
+#
+EMULATOR_OP_LIBRARIES := $(EMULATOR_OP_LIBRARIES) $(LOCAL_MODULE)
+
+# we need to compile this with GCC-3.3 preferabbly
+#
+LOCAL_NO_DEFAULT_COMPILER_FLAGS := true
+LOCAL_CC := $(MY_CC)
+
+LOCAL_CFLAGS += $(OP_CFLAGS)
+
+INTERMEDIATE := $(call intermediates-dir-for,STATIC_LIBRARIES,$(LOCAL_MODULE),true)
+OP_OBJ := $(INTERMEDIATE)/target-arm/op.o
+
+LOCAL_CFLAGS += -I$(INTERMEDIATE)
+
+OP_H := $(INTERMEDIATE)/op$(OP_SUFFIX).h
+OPC_H := $(INTERMEDIATE)/opc$(OP_SUFFIX).h
+GEN_OP_H := $(INTERMEDIATE)/gen-op$(OP_SUFFIX).h
+
+$(OP_H): $(OP_OBJ) $(DYNGEN)
+ $(DYNGEN) -o $@ $<
+
+$(OPC_H): $(OP_OBJ) $(DYNGEN)
+ $(DYNGEN) -c -o $@ $<
+
+$(GEN_OP_H): $(OP_OBJ) $(DYNGEN)
+ $(DYNGEN) -g -o $@ $<
+
+TRANSLATE_SOURCES := target-arm/translate.c \
+ translate-all.c \
+ translate-op.c
+
+LOCAL_SRC_FILES += target-arm/op.c $(TRANSLATE_SOURCES)
+
+$(TRANSLATE_SOURCES:%.c=$(INTERMEDIATE)/%.o): $(OP_H) $(OPC_H) $(GEN_OP_H)
diff --git a/usb-linux.c b/usb-linux.c
index 0a13753..aa1ded2 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -26,7 +26,6 @@
#if defined(__linux__)
#include <dirent.h>
#include <sys/ioctl.h>
-#include <linux/compiler.h>
#include <linux/usbdevice_fs.h>
#include <linux/version.h>
@@ -58,7 +57,7 @@ typedef struct USBHostDevice {
int fd;
} USBHostDevice;
-static void usb_host_handle_reset(USBDevice *dev)
+static void usb_host_handle_reset(USBDevice *dev, int destroy)
{
#if 0
USBHostDevice *s = (USBHostDevice *)dev;
@@ -68,15 +67,6 @@ static void usb_host_handle_reset(USBDevice *dev)
#endif
}
-static void usb_host_handle_destroy(USBDevice *dev)
-{
- USBHostDevice *s = (USBHostDevice *)dev;
-
- if (s->fd >= 0)
- close(s->fd);
- qemu_free(s);
-}
-
static int usb_host_handle_control(USBDevice *dev,
int request,
int value,
@@ -245,7 +235,6 @@ USBDevice *usb_host_device_open(const char *devname)
dev->dev.handle_reset = usb_host_handle_reset;
dev->dev.handle_control = usb_host_handle_control;
dev->dev.handle_data = usb_host_handle_data;
- dev->dev.handle_destroy = usb_host_handle_destroy;
if (product_name[0] == '\0')
snprintf(dev->dev.devname, sizeof(dev->dev.devname),
diff --git a/varint.c b/varint.c
new file mode 100644
index 0000000..41f6c67
--- /dev/null
+++ b/varint.c
@@ -0,0 +1,118 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include <inttypes.h>
+#include "varint.h"
+
+// Define some constants for powers of two.
+static const int k2Exp6 = 64;
+static const uint32_t k2Exp7 = 128;
+static const int k2Exp13 = 8192;
+static const uint32_t k2Exp14 = 16384;
+static const int k2Exp20 = (1 * 1024 * 1024);
+static const uint32_t k2Exp21 = (2 * 1024 * 1024);
+static const int k2Exp27 = (128 * 1024 * 1024);
+static const uint32_t k2Exp28 = (256 * 1024 * 1024);
+static const uint64_t k2Exp35 = (32LL * 1024LL * 1024LL * 1024LL);
+static const uint64_t k2Exp42 = (4LL * 1024LL * 1024LL * 1024LL * 1024LL);
+
+// Encodes the 64-bit value "value" using the varint encoding. The varint
+// encoding uses a prefix followed by some data bits. The valid prefixes
+// and the number of data bits are given in the table below.
+//
+// Prefix Bytes Data bits
+// 0 1 7
+// 10 2 14
+// 110 3 21
+// 1110 4 28
+// 11110 5 35
+// 111110 6 42
+// 11111100 9 64
+// 11111101 reserved
+// 11111110 reserved
+// 11111111 reserved
+char *varint_encode(uint64_t value, char *buf) {
+ if (value < k2Exp7) {
+ *buf++ = value;
+ } else if (value < k2Exp14) {
+ *buf++ = (2 << 6) | (value >> 8);
+ *buf++ = value & 0xff;
+ } else if (value < k2Exp21) {
+ *buf++ = (6 << 5) | (value >> 16);
+ *buf++ = (value >> 8) & 0xff;
+ *buf++ = value & 0xff;
+ } else if (value < k2Exp28) {
+ *buf++ = (0xe << 4) | (value >> 24);
+ *buf++ = (value >> 16) & 0xff;
+ *buf++ = (value >> 8) & 0xff;
+ *buf++ = value & 0xff;
+ } else if (value < k2Exp35) {
+ *buf++ = (0x1e << 3) | (value >> 32);
+ *buf++ = (value >> 24) & 0xff;
+ *buf++ = (value >> 16) & 0xff;
+ *buf++ = (value >> 8) & 0xff;
+ *buf++ = value & 0xff;
+ } else if (value < k2Exp42) {
+ *buf++ = (0x3e << 2) | (value >> 40);
+ *buf++ = (value >> 32) & 0xff;
+ *buf++ = (value >> 24) & 0xff;
+ *buf++ = (value >> 16) & 0xff;
+ *buf++ = (value >> 8) & 0xff;
+ *buf++ = value & 0xff;
+ } else {
+ *buf++ = (0x7e << 1);
+ *buf++ = (value >> 56) & 0xff;
+ *buf++ = (value >> 48) & 0xff;
+ *buf++ = (value >> 40) & 0xff;
+ *buf++ = (value >> 32) & 0xff;
+ *buf++ = (value >> 24) & 0xff;
+ *buf++ = (value >> 16) & 0xff;
+ *buf++ = (value >> 8) & 0xff;
+ *buf++ = value & 0xff;
+ }
+ return buf;
+}
+
+// Encodes the 35-bit signed value "value" using the varint encoding.
+// The varint encoding uses a prefix followed by some data bits. The
+// valid prefixes and the number of data bits is given in the table
+// below.
+//
+// Prefix Bytes Data bits
+// 0 1 7
+// 10 2 14
+// 110 3 21
+// 1110 4 28
+// 11110 5 35
+char *varint_encode_signed(int64_t value, char *buf) {
+ if (value < k2Exp6 && value >= -k2Exp6) {
+ *buf++ = value & 0x7f;
+ } else if (value < k2Exp13 && value >= -k2Exp13) {
+ *buf++ = (2 << 6) | ((value >> 8) & 0x3f);
+ *buf++ = value & 0xff;
+ } else if (value < k2Exp20 && value >= -k2Exp20) {
+ *buf++ = (6 << 5) | ((value >> 16) & 0x1f);
+ *buf++ = (value >> 8) & 0xff;
+ *buf++ = value & 0xff;
+ } else if (value < k2Exp27 && value >= -k2Exp27) {
+ *buf++ = (0xe << 4) | ((value >> 24) & 0xf);
+ *buf++ = (value >> 16) & 0xff;
+ *buf++ = (value >> 8) & 0xff;
+ *buf++ = value & 0xff;
+ } else {
+ *buf++ = (0x1e << 3);
+ *buf++ = (value >> 24) & 0xff;
+ *buf++ = (value >> 16) & 0xff;
+ *buf++ = (value >> 8) & 0xff;
+ *buf++ = value & 0xff;
+ }
+ return buf;
+}
diff --git a/varint.h b/varint.h
new file mode 100644
index 0000000..7822756
--- /dev/null
+++ b/varint.h
@@ -0,0 +1,15 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** 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.
+*/
+#include <inttypes.h>
+
+extern char *varint_encode(uint64_t value, char *buf);
+extern char *varint_encode_signed(int64_t value, char *buf);
diff --git a/vl.c b/vl.c
index 657116b..adb708c 100644
--- a/vl.c
+++ b/vl.c
@@ -1,8 +1,8 @@
/*
* QEMU System Emulator
- *
+ *
* Copyright (c) 2003-2005 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
@@ -23,6 +23,14 @@
*/
#include "vl.h"
+#include "android.h"
+#include "charpipe.h"
+#include "shaper.h"
+#include "modem_driver.h"
+#include "android_gps.h"
+#include "android_qemud.h"
+#include "android_kmsg.h"
+
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
@@ -52,7 +60,6 @@
#include <linux/if_tun.h>
#include <pty.h>
#include <malloc.h>
-#include <linux/rtc.h>
#include <linux/ppdev.h>
#endif
#endif
@@ -60,6 +67,7 @@
#if defined(CONFIG_SLIRP)
#include "libslirp.h"
+const char *bootp_filename;
#endif
#ifdef _WIN32
@@ -70,23 +78,34 @@
#define memalign(align, size) malloc(size)
#endif
-#include "qemu_socket.h"
+#include "sockets.h"
-#ifdef CONFIG_SDL
-#ifdef __APPLE__
-#include <SDL/SDL.h>
-#endif
-#endif /* CONFIG_SDL */
+extern void android_emulation_setup( void );
+extern void android_emulation_teardown( void );
#ifdef CONFIG_COCOA
#undef main
#define main qemu_main
#endif /* CONFIG_COCOA */
+#ifdef CONFIG_SKINS
+#undef main
+#define main qemu_main
+#endif
+
#include "disas.h"
#include "exec-all.h"
+#ifdef CONFIG_TRACE
+#include "trace.h"
+#include "dcache.h"
+#endif
+
+#ifdef CONFIG_NAND
+#include "hw/goldfish_nand.h"
+#endif
+
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
//#define DEBUG_UNUSED_IOPORT
@@ -97,10 +116,14 @@
#ifdef TARGET_PPC
#define DEFAULT_RAM_SIZE 144
#else
+#if 1 /* Android */
+#define DEFAULT_RAM_SIZE 96
+#else
#define DEFAULT_RAM_SIZE 128
#endif
+#endif
/* in ms */
-#define GUI_REFRESH_INTERVAL 30
+#define GUI_REFRESH_INTERVAL (1000/60)
/* Max number of USB devices that can be specified on the commandline. */
#define MAX_USB_CMDLINE 8
@@ -128,7 +151,6 @@ NICInfo nd_table[MAX_NICS];
QEMUTimer *gui_timer;
int vm_running;
int rtc_utc = 1;
-int cirrus_vga_enabled = 1;
#ifdef TARGET_SPARC
int graphic_width = 1024;
int graphic_height = 768;
@@ -157,6 +179,29 @@ int vnc_display = -1;
int acpi_enabled = 1;
int fd_bootchk = 1;
+static CPUState *cur_cpu;
+static int event_pending = 1;
+
+#ifdef CONFIG_TRACE
+const char *trace_filename;
+int tracing;
+int trace_cache_miss;
+int trace_all_addr;
+
+int dcache_size = 16 * 1024;
+int dcache_ways = 4;
+int dcache_line_size = 32;
+int dcache_replace_policy = kPolicyRandom;
+int dcache_load_miss_penalty = 30;
+int dcache_store_miss_penalty = 5;
+#endif
+
+extern int qemu_cpu_delay;
+
+extern void dprint( const char* format, ... );
+
+#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
+
/***********************************************************/
/* x86 ISA bus support */
@@ -225,7 +270,7 @@ void init_ioports(void)
}
/* size is the word size in byte */
-int register_ioport_read(int start, int length, int size,
+int register_ioport_read(int start, int length, int size,
IOPortReadFunc *func, void *opaque)
{
int i, bsize;
@@ -250,7 +295,7 @@ int register_ioport_read(int start, int length, int size,
}
/* size is the word size in byte */
-int register_ioport_write(int start, int length, int size,
+int register_ioport_write(int start, int length, int size,
IOPortWriteFunc *func, void *opaque)
{
int i, bsize;
@@ -313,7 +358,7 @@ char *pstrcat(char *buf, int buf_size, const char *s)
{
int len;
len = strlen(buf);
- if (len < buf_size)
+ if (len < buf_size)
pstrcpy(buf + len, buf_size - len, s);
return buf;
}
@@ -339,7 +384,7 @@ void cpu_outb(CPUState *env, int addr, int val)
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "outb: %04x %02x\n", addr, val);
-#endif
+#endif
ioport_write_table[0][addr](ioport_opaque[addr], addr, val);
#ifdef USE_KQEMU
if (env)
@@ -352,7 +397,7 @@ void cpu_outw(CPUState *env, int addr, int val)
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "outw: %04x %04x\n", addr, val);
-#endif
+#endif
ioport_write_table[1][addr](ioport_opaque[addr], addr, val);
#ifdef USE_KQEMU
if (env)
@@ -443,10 +488,19 @@ void hw_error(const char *fmt, ...)
/***********************************************************/
/* keyboard/mouse */
-static QEMUPutKBDEvent *qemu_put_kbd_event;
-static void *qemu_put_kbd_event_opaque;
-static QEMUPutMouseEvent *qemu_put_mouse_event;
-static void *qemu_put_mouse_event_opaque;
+static QEMUPutKBDEvent* qemu_put_kbd_event;
+static void* qemu_put_kbd_event_opaque;
+
+static QEMUPutKBDEventN* qemu_put_kbd_event_n;
+static void* qemu_put_kbd_event_n_opaque;
+
+
+static QEMUPutMouseEvent* qemu_put_mouse_event;
+static void* qemu_put_mouse_event_opaque;
+
+static QEMUPutGenericEvent* qemu_put_generic_event;
+static void* qemu_put_generic_event_opaque;
+
static int qemu_put_mouse_event_absolute;
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
@@ -455,6 +509,12 @@ void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque)
qemu_put_kbd_event = func;
}
+void qemu_add_kbd_event_n_handler(QEMUPutKBDEventN *func, void *opaque)
+{
+ qemu_put_kbd_event_n_opaque = opaque;
+ qemu_put_kbd_event_n = func;
+}
+
void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute)
{
qemu_put_mouse_event_opaque = opaque;
@@ -462,6 +522,12 @@ void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int abs
qemu_put_mouse_event_absolute = absolute;
}
+void qemu_add_generic_event_handler(QEMUPutGenericEvent *func, void* opaque)
+{
+ qemu_put_generic_event = func;
+ qemu_put_generic_event_opaque = opaque;
+}
+
void kbd_put_keycode(int keycode)
{
if (qemu_put_kbd_event) {
@@ -469,10 +535,27 @@ void kbd_put_keycode(int keycode)
}
}
+void kbd_put_keycodes(int* keycodes, int count)
+{
+ if (qemu_put_kbd_event_n)
+ {
+ qemu_put_kbd_event_n(qemu_put_kbd_event_n_opaque, keycodes, count);
+ }
+ else if (qemu_put_kbd_event)
+ {
+ int nn;
+
+ for (nn = 0; nn < count; nn++)
+ qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycodes[nn]);
+ }
+}
+
+
+
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
{
if (qemu_put_mouse_event) {
- qemu_put_mouse_event(qemu_put_mouse_event_opaque,
+ qemu_put_mouse_event(qemu_put_mouse_event_opaque,
dx, dy, dz, buttons_state);
}
}
@@ -482,6 +565,12 @@ int kbd_mouse_is_absolute(void)
return qemu_put_mouse_event_absolute;
}
+void kbd_generic_event(int type, int code, int value)
+{
+ if (qemu_put_generic_event)
+ qemu_put_generic_event(qemu_put_generic_event_opaque, type, code, value);
+}
+
/* compute with 96 bit intermediate result: (a*b)/c */
uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
{
@@ -492,7 +581,7 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
uint32_t high, low;
#else
uint32_t low, high;
-#endif
+#endif
} l;
} u, res;
uint64_t rl, rh;
@@ -506,523 +595,95 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
return res.ll;
}
-/***********************************************************/
-/* real time host monotonic timer */
-
-#define QEMU_TIMER_BASE 1000000000LL
-
-#ifdef WIN32
-
-static int64_t clock_freq;
-
-static void init_get_clock(void)
-{
- LARGE_INTEGER freq;
- int ret;
- ret = QueryPerformanceFrequency(&freq);
- if (ret == 0) {
- fprintf(stderr, "Could not calibrate ticks\n");
- exit(1);
- }
- clock_freq = freq.QuadPart;
-}
-static int64_t get_clock(void)
+/* this function is called each time the alarm timer is signaled */
+static void
+cpu_signal_alarm( void )
{
- LARGE_INTEGER ti;
- QueryPerformanceCounter(&ti);
- return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq);
-}
-
-#else
+ CPUState *env = cur_cpu;
-static int use_rt_clock;
-
-static void init_get_clock(void)
-{
- use_rt_clock = 0;
-#if defined(__linux__)
- {
- struct timespec ts;
- if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
- use_rt_clock = 1;
+ if (env) {
+ /* stop the currently executing cpu because a timer occured */
+ cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+#ifdef USE_KQEMU
+ if (env->kqemu_enabled) {
+ kqemu_cpu_interrupt(env);
}
- }
-#endif
-}
-
-static int64_t get_clock(void)
-{
-#if defined(__linux__)
- if (use_rt_clock) {
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- return ts.tv_sec * 1000000000LL + ts.tv_nsec;
- } else
#endif
- {
- /* XXX: using gettimeofday leads to problems if the date
- changes, so it should be avoided. */
- struct timeval tv;
- gettimeofday(&tv, NULL);
- return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
}
+ event_pending = 1;
}
-#endif
-/***********************************************************/
-/* guest cycle counter */
-static int64_t cpu_ticks_prev;
-static int64_t cpu_ticks_offset;
-static int64_t cpu_clock_offset;
-static int cpu_ticks_enabled;
-/* return the host CPU cycle counter and handle stop/restart */
-int64_t cpu_get_ticks(void)
-{
- if (!cpu_ticks_enabled) {
- return cpu_ticks_offset;
- } else {
- int64_t ticks;
- ticks = cpu_get_real_ticks();
- if (cpu_ticks_prev > ticks) {
- /* Note: non increasing ticks may happen if the host uses
- software suspend */
- cpu_ticks_offset += cpu_ticks_prev - ticks;
- }
- cpu_ticks_prev = ticks;
- return ticks + cpu_ticks_offset;
- }
-}
+#define get_clock() qemu_get_elapsed_ns()
-/* return the host CPU monotonic timer and handle stop/restart */
-static int64_t cpu_get_clock(void)
-{
- int64_t ti;
- if (!cpu_ticks_enabled) {
- return cpu_clock_offset;
- } else {
- ti = get_clock();
- return ti + cpu_clock_offset;
- }
-}
+#ifdef CONFIG_TRACE
+static int tbflush_requested;
+static int exit_requested;
-/* enable cpu_get_ticks() */
-void cpu_enable_ticks(void)
-{
- if (!cpu_ticks_enabled) {
- cpu_ticks_offset -= cpu_get_real_ticks();
- cpu_clock_offset -= get_clock();
- cpu_ticks_enabled = 1;
- }
-}
-
-/* disable cpu_get_ticks() : the clock is stopped. You must not call
- cpu_get_ticks() after that. */
-void cpu_disable_ticks(void)
-{
- if (cpu_ticks_enabled) {
- cpu_ticks_offset = cpu_get_ticks();
- cpu_clock_offset = cpu_get_clock();
- cpu_ticks_enabled = 0;
- }
-}
-
-/***********************************************************/
-/* timers */
-
-#define QEMU_TIMER_REALTIME 0
-#define QEMU_TIMER_VIRTUAL 1
-
-struct QEMUClock {
- int type;
- /* XXX: add frequency */
-};
-
-struct QEMUTimer {
- QEMUClock *clock;
- int64_t expire_time;
- QEMUTimerCB *cb;
- void *opaque;
- struct QEMUTimer *next;
-};
-
-QEMUClock *rt_clock;
-QEMUClock *vm_clock;
-
-static QEMUTimer *active_timers[2];
-#ifdef _WIN32
-static MMRESULT timerID;
-static HANDLE host_alarm = NULL;
-static unsigned int period = 1;
-#else
-/* frequency of the times() clock tick */
-static int timer_freq;
-#endif
-
-QEMUClock *qemu_new_clock(int type)
-{
- QEMUClock *clock;
- clock = qemu_mallocz(sizeof(QEMUClock));
- if (!clock)
- return NULL;
- clock->type = type;
- return clock;
-}
-
-QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque)
-{
- QEMUTimer *ts;
-
- ts = qemu_mallocz(sizeof(QEMUTimer));
- ts->clock = clock;
- ts->cb = cb;
- ts->opaque = opaque;
- return ts;
-}
-
-void qemu_free_timer(QEMUTimer *ts)
-{
- qemu_free(ts);
-}
-
-/* stop a timer, but do not dealloc it */
-void qemu_del_timer(QEMUTimer *ts)
-{
- QEMUTimer **pt, *t;
-
- /* NOTE: this code must be signal safe because
- qemu_timer_expired() can be called from a signal. */
- pt = &active_timers[ts->clock->type];
- for(;;) {
- t = *pt;
- if (!t)
- break;
- if (t == ts) {
- *pt = t->next;
- break;
- }
- pt = &t->next;
- }
-}
-
-/* modify the current timer so that it will be fired when current_time
- >= expire_time. The corresponding callback will be called. */
-void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
-{
- QEMUTimer **pt, *t;
-
- qemu_del_timer(ts);
-
- /* add the timer in the sorted list */
- /* NOTE: this code must be signal safe because
- qemu_timer_expired() can be called from a signal. */
- pt = &active_timers[ts->clock->type];
- for(;;) {
- t = *pt;
- if (!t)
- break;
- if (t->expire_time > expire_time)
- break;
- pt = &t->next;
- }
- ts->expire_time = expire_time;
- ts->next = *pt;
- *pt = ts;
-}
-
-int qemu_timer_pending(QEMUTimer *ts)
-{
- QEMUTimer *t;
- for(t = active_timers[ts->clock->type]; t != NULL; t = t->next) {
- if (t == ts)
- return 1;
- }
- return 0;
-}
-
-static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
-{
- if (!timer_head)
- return 0;
- return (timer_head->expire_time <= current_time);
-}
+extern void qemu_trace_enable();
+extern void qemu_trace_enable_gencode();
+extern void qemu_trace_enable_dyngen();
+extern void qemu_trace_disable();
+extern void qemu_trace_disable_gencode();
+extern void qemu_trace_disable_dyngen();
-static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time)
+void start_tracing()
{
- QEMUTimer *ts;
-
- for(;;) {
- ts = *ptimer_head;
- if (!ts || ts->expire_time > current_time)
- break;
- /* remove timer from the list before calling the callback */
- *ptimer_head = ts->next;
- ts->next = NULL;
-
- /* run the callback (the timer list can be modified) */
- ts->cb(ts->opaque);
- }
-}
-
-int64_t qemu_get_clock(QEMUClock *clock)
-{
- switch(clock->type) {
- case QEMU_TIMER_REALTIME:
- return get_clock() / 1000000;
- default:
- case QEMU_TIMER_VIRTUAL:
- return cpu_get_clock();
- }
-}
-
-static void init_timers(void)
-{
- init_get_clock();
- ticks_per_sec = QEMU_TIMER_BASE;
- rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
- vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
-}
-
-/* save a timer */
-void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
-{
- uint64_t expire_time;
-
- if (qemu_timer_pending(ts)) {
- expire_time = ts->expire_time;
- } else {
- expire_time = -1;
- }
- qemu_put_be64(f, expire_time);
-}
-
-void qemu_get_timer(QEMUFile *f, QEMUTimer *ts)
-{
- uint64_t expire_time;
-
- expire_time = qemu_get_be64(f);
- if (expire_time != -1) {
- qemu_mod_timer(ts, expire_time);
- } else {
- qemu_del_timer(ts);
- }
-}
-
-static void timer_save(QEMUFile *f, void *opaque)
-{
- if (cpu_ticks_enabled) {
- hw_error("cannot save state if virtual timers are running");
- }
- qemu_put_be64s(f, &cpu_ticks_offset);
- qemu_put_be64s(f, &ticks_per_sec);
-}
-
-static int timer_load(QEMUFile *f, void *opaque, int version_id)
-{
- if (version_id != 1)
- return -EINVAL;
- if (cpu_ticks_enabled) {
- return -EINVAL;
- }
- qemu_get_be64s(f, &cpu_ticks_offset);
- qemu_get_be64s(f, &ticks_per_sec);
- return 0;
+ if (trace_filename == NULL)
+ return;
+ if (!tracing) {
+ fprintf(stderr,"-- start tracing --\n");
+ start_time = Now();
+ }
+ tracing = 1;
+ tbflush_requested = 1;
+ qemu_polling_enable();
+ if (cpu_single_env)
+ cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
-#ifdef _WIN32
-void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
- DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
-#else
-static void host_alarm_handler(int host_signum)
-#endif
+void stop_tracing()
{
-#if 0
-#define DISP_FREQ 1000
- {
- static int64_t delta_min = INT64_MAX;
- static int64_t delta_max, delta_cum, last_clock, delta, ti;
- static int count;
- ti = qemu_get_clock(vm_clock);
- if (last_clock != 0) {
- delta = ti - last_clock;
- if (delta < delta_min)
- delta_min = delta;
- if (delta > delta_max)
- delta_max = delta;
- delta_cum += delta;
- if (++count == DISP_FREQ) {
- printf("timer: min=%" PRId64 " us max=%" PRId64 " us avg=%" PRId64 " us avg_freq=%0.3f Hz\n",
- muldiv64(delta_min, 1000000, ticks_per_sec),
- muldiv64(delta_max, 1000000, ticks_per_sec),
- muldiv64(delta_cum, 1000000 / DISP_FREQ, ticks_per_sec),
- (double)ticks_per_sec / ((double)delta_cum / DISP_FREQ));
- count = 0;
- delta_min = INT64_MAX;
- delta_max = 0;
- delta_cum = 0;
- }
- }
- last_clock = ti;
- }
-#endif
- if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
- qemu_get_clock(vm_clock)) ||
- qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
- qemu_get_clock(rt_clock))) {
-#ifdef _WIN32
- SetEvent(host_alarm);
-#endif
- CPUState *env = cpu_single_env;
- if (env) {
- /* stop the currently executing cpu because a timer occured */
- cpu_interrupt(env, CPU_INTERRUPT_EXIT);
-#ifdef USE_KQEMU
- if (env->kqemu_enabled) {
- kqemu_cpu_interrupt(env);
- }
-#endif
- }
- }
+ if (trace_filename == NULL)
+ return;
+ if (tracing) {
+ end_time = Now();
+ elapsed_usecs += end_time - start_time;
+ fprintf(stderr,"-- stop tracing --\n");
+ }
+ tracing = 0;
+ tbflush_requested = 1;
+ qemu_polling_disable();
+ if (cpu_single_env)
+ cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
#ifndef _WIN32
-
-#if defined(__linux__)
-
-#define RTC_FREQ 1024
-
-static int rtc_fd;
-
-static int start_rtc_timer(void)
-{
- rtc_fd = open("/dev/rtc", O_RDONLY);
- if (rtc_fd < 0)
- return -1;
- if (ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
- fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"
- "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"
- "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");
- goto fail;
- }
- if (ioctl(rtc_fd, RTC_PIE_ON, 0) < 0) {
- fail:
- close(rtc_fd);
- return -1;
- }
- pit_min_timer_count = PIT_FREQ / RTC_FREQ;
- return 0;
-}
-
-#else
-
-static int start_rtc_timer(void)
+/* This is the handler for the SIGUSR1 and SIGUSR2 signals.
+ * SIGUSR1 turns tracing on. SIGUSR2 turns tracing off.
+ */
+void sigusr_handler(int sig)
{
- return -1;
+ if (sig == SIGUSR1)
+ start_tracing();
+ else
+ stop_tracing();
}
-
-#endif /* !defined(__linux__) */
-
-#endif /* !defined(_WIN32) */
-
-static void init_timer_alarm(void)
-{
-#ifdef _WIN32
- {
- int count=0;
- TIMECAPS tc;
-
- ZeroMemory(&tc, sizeof(TIMECAPS));
- timeGetDevCaps(&tc, sizeof(TIMECAPS));
- if (period < tc.wPeriodMin)
- period = tc.wPeriodMin;
- timeBeginPeriod(period);
- timerID = timeSetEvent(1, // interval (ms)
- period, // resolution
- host_alarm_handler, // function
- (DWORD)&count, // user parameter
- TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
- if( !timerID ) {
- perror("failed timer alarm");
- exit(1);
- }
- host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!host_alarm) {
- perror("failed CreateEvent");
- exit(1);
- }
- qemu_add_wait_object(host_alarm, NULL, NULL);
- }
- pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000;
-#else
- {
- struct sigaction act;
- struct itimerval itv;
-
- /* get times() syscall frequency */
- timer_freq = sysconf(_SC_CLK_TCK);
-
- /* timer signal */
- sigfillset(&act.sa_mask);
- act.sa_flags = 0;
-#if defined (TARGET_I386) && defined(USE_CODE_COPY)
- act.sa_flags |= SA_ONSTACK;
#endif
- act.sa_handler = host_alarm_handler;
- sigaction(SIGALRM, &act, NULL);
- itv.it_interval.tv_sec = 0;
- itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */
- itv.it_value.tv_sec = 0;
- itv.it_value.tv_usec = 10 * 1000;
- setitimer(ITIMER_REAL, &itv, NULL);
- /* we probe the tick duration of the kernel to inform the user if
- the emulated kernel requested a too high timer frequency */
- getitimer(ITIMER_REAL, &itv);
+#endif /* CONFIG_TRACE */
-#if defined(__linux__)
- /* XXX: force /dev/rtc usage because even 2.6 kernels may not
- have timers with 1 ms resolution. The correct solution will
- be to use the POSIX real time timers available in recent
- 2.6 kernels */
- if (itv.it_interval.tv_usec > 1000 || 1) {
- /* try to use /dev/rtc to have a faster timer */
- if (start_rtc_timer() < 0)
- goto use_itimer;
- /* disable itimer */
- itv.it_interval.tv_sec = 0;
- itv.it_interval.tv_usec = 0;
- itv.it_value.tv_sec = 0;
- itv.it_value.tv_usec = 0;
- setitimer(ITIMER_REAL, &itv, NULL);
-
- /* use the RTC */
- sigaction(SIGIO, &act, NULL);
- fcntl(rtc_fd, F_SETFL, O_ASYNC);
- fcntl(rtc_fd, F_SETOWN, getpid());
- } else
-#endif /* defined(__linux__) */
- {
- use_itimer:
- pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec *
- PIT_FREQ) / 1000000;
- }
- }
-#endif
-}
-
-void quit_timers(void)
+/* This is the handler to catch control-C so that we can exit cleanly.
+ * This is needed when tracing to flush the buffers to disk.
+ */
+void sigint_handler(int sig)
{
-#ifdef _WIN32
- timeKillEvent(timerID);
- timeEndPeriod(period);
- if (host_alarm) {
- CloseHandle(host_alarm);
- host_alarm = NULL;
- }
-#endif
+ exit_requested = 1;
+ if (cpu_single_env)
+ cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
/***********************************************************/
@@ -1046,7 +707,7 @@ void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, sizeof(buf), fmt, ap);
- qemu_chr_write(s, buf, strlen(buf));
+ qemu_chr_write(s, (const uint8_t*)buf, strlen(buf));
va_end(ap);
}
@@ -1056,13 +717,13 @@ void qemu_chr_send_event(CharDriverState *s, int event)
s->chr_send_event(s, event);
}
-void qemu_chr_add_read_handler(CharDriverState *s,
- IOCanRWHandler *fd_can_read,
+void qemu_chr_add_read_handler(CharDriverState *s,
+ IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque)
{
s->chr_add_read_handler(s, fd_can_read, fd_read, opaque);
}
-
+
void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event)
{
s->chr_event = chr_event;
@@ -1073,8 +734,8 @@ static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
return len;
}
-static void null_chr_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *fd_can_read,
+static void null_chr_add_read_handler(CharDriverState *chr,
+ IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque)
{
}
@@ -1093,30 +754,10 @@ CharDriverState *qemu_chr_open_null(void)
#ifdef _WIN32
-static void socket_cleanup(void)
-{
- WSACleanup();
-}
-
-static int socket_init(void)
-{
- WSADATA Data;
- int ret, err;
-
- ret = WSAStartup(MAKEWORD(2,2), &Data);
- if (ret != 0) {
- err = WSAGetLastError();
- fprintf(stderr, "WSAStartup: %d\n", err);
- return -1;
- }
- atexit(socket_cleanup);
- return 0;
-}
-
static int send_all(int fd, const uint8_t *buf, int len1)
{
int ret, len;
-
+
len = len1;
while (len > 0) {
ret = send(fd, buf, len, 0);
@@ -1136,12 +777,6 @@ static int send_all(int fd, const uint8_t *buf, int len1)
return len1 - len;
}
-void socket_set_nonblock(int fd)
-{
- unsigned long opt = 1;
- ioctlsocket(fd, FIONBIO, &opt);
-}
-
#else
static int unix_write(int fd, const uint8_t *buf, int len1)
@@ -1169,17 +804,13 @@ static inline int send_all(int fd, const uint8_t *buf, int len1)
return unix_write(fd, buf, len1);
}
-void socket_set_nonblock(int fd)
-{
- fcntl(fd, F_SETFL, O_NONBLOCK);
-}
#endif /* !_WIN32 */
#ifndef _WIN32
typedef struct {
int fd_in, fd_out;
- IOCanRWHandler *fd_can_read;
+ IOCanRWHandler *fd_can_read;
IOReadHandler *fd_read;
void *fd_opaque;
int max_size;
@@ -1211,7 +842,7 @@ static void fd_chr_read(void *opaque)
FDCharDriver *s = chr->opaque;
int size, len;
uint8_t buf[1024];
-
+
len = sizeof(buf);
if (len > s->max_size)
len = s->max_size;
@@ -1223,8 +854,8 @@ static void fd_chr_read(void *opaque)
}
}
-static void fd_chr_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *fd_can_read,
+static void fd_chr_add_read_handler(CharDriverState *chr,
+ IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque)
{
FDCharDriver *s = chr->opaque;
@@ -1235,7 +866,7 @@ static void fd_chr_add_read_handler(CharDriverState *chr,
s->fd_opaque = opaque;
if (nographic && s->fd_in == 0) {
} else {
- qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
+ qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
fd_chr_read, NULL, chr);
}
}
@@ -1283,6 +914,27 @@ CharDriverState *qemu_chr_open_pipe(const char *filename)
return qemu_chr_open_fd(fd, fd);
}
+CharDriverState *qemu_chr_open_fdpair(const char *fd_pair)
+{
+ int fd_in, fd_out;
+ char *endptr;
+
+ /* fd_pair should contain two decimal fd values, separated by
+ * a colon. */
+ endptr = NULL;
+ fd_in = strtol(fd_pair, &endptr, 10);
+ if (endptr == NULL || endptr == fd_pair || *endptr != ':')
+ return NULL;
+ endptr++; // skip colon
+ fd_pair = endptr;
+ endptr = NULL;
+ fd_out = strtol(fd_pair, &endptr, 10);
+ if (endptr == NULL || endptr == fd_pair || *endptr != '\0')
+ return NULL;
+
+ return qemu_chr_open_fd(fd_in, fd_out);
+}
+
/* for STDIO, we handle the case where several clients use it
(nographic mode) */
@@ -1322,7 +974,7 @@ static void stdio_received_byte(int ch)
case 'x':
exit(0);
break;
- case 's':
+ case 's':
{
int i;
for (i = 0; i < MAX_DISKS; i++) {
@@ -1366,7 +1018,7 @@ static void stdio_received_byte(int ch)
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) {
@@ -1406,7 +1058,7 @@ static void stdio_read(void *opaque)
{
int size;
uint8_t buf[1];
-
+
size = read(0, buf, 1);
if (size > 0)
stdio_received_byte(buf[0]);
@@ -1432,13 +1084,13 @@ static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
term_timestamps_start = ti;
ti -= term_timestamps_start;
secs = ti / 1000000000;
- snprintf(buf1, sizeof(buf1),
+ 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));
+ unix_write(s->fd_out, (const uint8_t*)buf1, strlen(buf1));
}
}
return len;
@@ -1474,7 +1126,7 @@ static void term_init(void)
tty.c_cflag |= CS8;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
-
+
tcsetattr (0, TCSANOW, &tty);
atexit(term_exit);
@@ -1513,12 +1165,12 @@ CharDriverState *qemu_chr_open_pty(void)
struct termios tty;
char slave_name[1024];
int master_fd, slave_fd;
-
+
/* Not satisfying */
if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) {
return NULL;
}
-
+
/* Disabling local echo and line-buffered output */
tcgetattr (master_fd, &tty);
tty.c_lflag &= ~(ECHO|ICANON|ISIG);
@@ -1529,15 +1181,16 @@ CharDriverState *qemu_chr_open_pty(void)
fprintf(stderr, "char device redirected to %s\n", slave_name);
return qemu_chr_open_fd(master_fd, master_fd);
}
+#endif
-static void tty_serial_init(int fd, int speed,
+static void tty_serial_init(int fd, int speed,
int parity, int data_bits, int stop_bits)
{
struct termios tty;
speed_t spd;
#if 0
- printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
+ printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
speed, parity, data_bits, stop_bits);
#endif
tcgetattr (fd, &tty);
@@ -1616,19 +1269,19 @@ static void tty_serial_init(int fd, int speed,
tty.c_cflag |= PARENB | PARODD;
break;
}
-
+
tcsetattr (fd, TCSANOW, &tty);
}
static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
{
FDCharDriver *s = chr->opaque;
-
+
switch(cmd) {
case CHR_IOCTL_SERIAL_SET_PARAMS:
{
QEMUSerialSetParams *ssp = arg;
- tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
+ tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
ssp->data_bits, ssp->stop_bits);
}
break;
@@ -1650,7 +1303,7 @@ CharDriverState *qemu_chr_open_tty(const char *filename)
CharDriverState *chr;
int fd;
- fd = open(filename, O_RDWR | O_NONBLOCK);
+ fd = open(filename, O_RDWR | O_NONBLOCK | O_BINARY);
if (fd < 0)
return NULL;
fcntl(fd, F_SETFL, O_NONBLOCK);
@@ -1662,6 +1315,7 @@ CharDriverState *qemu_chr_open_tty(const char *filename)
return chr;
}
+#if defined(__linux__)
static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
{
int fd = (int)chr->opaque;
@@ -1724,7 +1378,6 @@ CharDriverState *qemu_chr_open_pp(const char *filename)
chr->chr_ioctl = pp_ioctl;
return chr;
}
-
#else
CharDriverState *qemu_chr_open_pty(void)
{
@@ -1735,15 +1388,19 @@ CharDriverState *qemu_chr_open_pty(void)
#endif /* !defined(_WIN32) */
#ifdef _WIN32
+
+typedef int (*WinPollFunc)(void* opaque);
+
typedef struct {
- IOCanRWHandler *fd_can_read;
+ IOCanRWHandler *fd_can_read;
IOReadHandler *fd_read;
void *win_opaque;
int max_size;
- HANDLE hcom, hrecv, hsend;
+ HANDLE hcom, rcom, hrecv, hsend;
OVERLAPPED orecv, osend;
BOOL fpipe;
DWORD len;
+ WinPollFunc poll_func;
} WinCharState;
#define NSENDBUF 2048
@@ -1764,14 +1421,16 @@ static void win_chr_close2(WinCharState *s)
CloseHandle(s->hrecv);
s->hrecv = NULL;
}
+ if (s->rcom && s->rcom != s->hcom) {
+ CloseHandle(s->rcom);
+ s->rcom = NULL;
+ }
if (s->hcom) {
CloseHandle(s->hcom);
s->hcom = NULL;
}
- if (s->fpipe)
- qemu_del_polling_cb(win_chr_pipe_poll, s);
- else
- qemu_del_polling_cb(win_chr_poll, s);
+ if (s->poll_func)
+ qemu_del_polling_cb(s->poll_func, s);
}
static void win_chr_close(CharDriverState *chr)
@@ -1787,7 +1446,7 @@ static int win_chr_init(WinCharState *s, const char *filename)
COMSTAT comstat;
DWORD size;
DWORD err;
-
+
s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!s->hsend) {
fprintf(stderr, "Failed CreateEvent\n");
@@ -1806,12 +1465,13 @@ static int win_chr_init(WinCharState *s, const char *filename)
s->hcom = NULL;
goto fail;
}
-
+ s->rcom = s->hcom;
+
if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
fprintf(stderr, "Failed SetupComm\n");
goto fail;
}
-
+
ZeroMemory(&comcfg, sizeof(COMMCONFIG));
size = sizeof(COMMCONFIG);
GetDefaultCommConfig(filename, &comcfg, &size);
@@ -1833,12 +1493,13 @@ static int win_chr_init(WinCharState *s, const char *filename)
fprintf(stderr, "Failed SetCommTimeouts\n");
goto fail;
}
-
+
if (!ClearCommError(s->hcom, &err, &comstat)) {
fprintf(stderr, "Failed ClearCommError\n");
goto fail;
}
- qemu_add_polling_cb(win_chr_poll, s);
+ s->poll_func = win_chr_poll;
+ qemu_add_polling_cb(s->poll_func, s);
return 0;
fail:
@@ -1885,20 +1546,20 @@ static int win_chr_read_poll(WinCharState *s)
s->max_size = s->fd_can_read(s->win_opaque);
return s->max_size;
}
-
+
static void win_chr_readfile(WinCharState *s)
{
int ret, err;
uint8_t buf[1024];
DWORD size;
-
+
ZeroMemory(&s->orecv, sizeof(s->orecv));
s->orecv.hEvent = s->hrecv;
- ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
+ ret = ReadFile(s->rcom, buf, s->len, &size, &s->orecv);
if (!ret) {
err = GetLastError();
if (err == ERROR_IO_PENDING) {
- ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
+ ret = GetOverlappedResult(s->rcom, &s->orecv, &size, TRUE);
}
}
@@ -1913,7 +1574,7 @@ static void win_chr_read(WinCharState *s)
s->len = s->max_size;
if (s->len == 0)
return;
-
+
win_chr_readfile(s);
}
@@ -1922,8 +1583,8 @@ static int win_chr_poll(void *opaque)
WinCharState *s = opaque;
COMSTAT status;
DWORD comerr;
-
- ClearCommError(s->hcom, &comerr, &status);
+
+ ClearCommError(s->rcom, &comerr, &status);
if (status.cbInQue > 0) {
s->len = status.cbInQue;
win_chr_read_poll(s);
@@ -1933,8 +1594,8 @@ static int win_chr_poll(void *opaque)
return 0;
}
-static void win_chr_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *fd_can_read,
+static void win_chr_add_read_handler(CharDriverState *chr,
+ IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque)
{
WinCharState *s = chr->opaque;
@@ -1948,7 +1609,7 @@ CharDriverState *qemu_chr_open_win(const char *filename)
{
CharDriverState *chr;
WinCharState *s;
-
+
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
@@ -1991,7 +1652,7 @@ static int win_chr_pipe_init(WinCharState *s, const char *filename)
int ret;
DWORD size;
char openname[256];
-
+
s->fpipe = TRUE;
s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -2004,7 +1665,7 @@ static int win_chr_pipe_init(WinCharState *s, const char *filename)
fprintf(stderr, "Failed CreateEvent\n");
goto fail;
}
-
+
snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename);
s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
@@ -2015,6 +1676,7 @@ static int win_chr_pipe_init(WinCharState *s, const char *filename)
s->hcom = NULL;
goto fail;
}
+ s->rcom = s->hcom;
ZeroMemory(&ov, sizeof(ov));
ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -2038,7 +1700,8 @@ static int win_chr_pipe_init(WinCharState *s, const char *filename)
CloseHandle(ov.hEvent);
ov.hEvent = NULL;
}
- qemu_add_polling_cb(win_chr_pipe_poll, s);
+ s->poll_func = win_chr_pipe_poll;
+ qemu_add_polling_cb(s->poll_func, s);
return 0;
fail:
@@ -2064,7 +1727,7 @@ CharDriverState *qemu_chr_open_win_pipe(const char *filename)
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) {
free(s);
free(chr);
@@ -2087,16 +1750,70 @@ CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
return NULL;
}
s->hcom = fd_out;
+ s->rcom = fd_out;
+ chr->opaque = s;
+ chr->chr_write = win_chr_write;
+ chr->chr_add_read_handler = win_chr_add_read_handler;
+ return chr;
+}
+
+static int win_chr_stdio_poll(void *opaque)
+{
+ WinCharState *s = opaque;
+ int result = 0;
+
+ for (;;) {
+ INPUT_RECORD rec;
+ DWORD count;
+
+ if ( !PeekConsoleInput(s->rcom, &rec, 1, &count) || count == 0 )
+ break;
+
+ ReadConsoleInput(s->rcom, &rec, 1, &count);
+
+ if (rec.EventType == KEY_EVENT)
+ {
+ if (rec.Event.KeyEvent.bKeyDown &&
+ rec.Event.KeyEvent.uChar.AsciiChar)
+ {
+ char c = rec.Event.KeyEvent.uChar.AsciiChar;
+ s->len = 1;
+ win_chr_read_poll(s);
+ s->fd_read( s->win_opaque, &c, 1);
+ result = 1;
+ }
+ }
+ }
+ return result;
+}
+
+CharDriverState *qemu_chr_open_win_stdio(void)
+{
+ CharDriverState *chr;
+ WinCharState *s;
+
+ chr = qemu_mallocz(sizeof(CharDriverState));
+ if (!chr)
+ return NULL;
+ s = qemu_mallocz(sizeof(WinCharState));
+ if (!s) {
+ free(chr);
+ return NULL;
+ }
+ s->hcom = GetStdHandle( STD_OUTPUT_HANDLE );
+ s->rcom = GetStdHandle( STD_INPUT_HANDLE );
chr->opaque = s;
chr->chr_write = win_chr_write;
chr->chr_add_read_handler = win_chr_add_read_handler;
+ s->poll_func = win_chr_stdio_poll;
+ qemu_add_polling_cb(s->poll_func, s);
return chr;
}
-
+
CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
{
HANDLE fd_out;
-
+
fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (fd_out == INVALID_HANDLE_VALUE)
@@ -2140,7 +1857,7 @@ static int udp_chr_read_poll(void *opaque)
* first
*/
while (s->max_size > 0 && s->bufptr < s->bufcnt) {
- s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
+ s->fd_read(s->fd_opaque, (uint8_t*)&s->buf[s->bufptr], 1);
s->bufptr++;
s->max_size = s->fd_can_read(s->fd_opaque);
}
@@ -2161,7 +1878,7 @@ static void udp_chr_read(void *opaque)
s->bufptr = 0;
while (s->max_size > 0 && s->bufptr < s->bufcnt) {
- s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
+ s->fd_read(s->fd_opaque, (uint8_t*)&s->buf[s->bufptr], 1);
s->bufptr++;
s->max_size = s->fd_can_read(s->fd_opaque);
}
@@ -2232,7 +1949,7 @@ return_err:
if (s)
free(s);
if (fd >= 0)
- closesocket(fd);
+ socket_close(fd);
return NULL;
}
@@ -2342,11 +2059,11 @@ static void tcp_chr_read(void *opaque)
qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
}
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
- closesocket(s->fd);
+ socket_close(s->fd);
s->fd = -1;
} else if (size > 0) {
if (s->do_telnetopt)
- tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+ tcp_chr_process_IAC_bytes(chr, s, (char*)buf, &size);
if (size > 0)
s->fd_read(s->fd_opaque, buf, size);
}
@@ -2417,18 +2134,18 @@ static void tcp_chr_close(CharDriverState *chr)
{
TCPCharDriver *s = chr->opaque;
if (s->fd >= 0)
- closesocket(s->fd);
+ socket_close(s->fd);
if (s->listen_fd >= 0)
- closesocket(s->listen_fd);
+ socket_close(s->listen_fd);
qemu_free(s);
}
-static CharDriverState *qemu_chr_open_tcp(const char *host_str,
+static CharDriverState *qemu_chr_open_tcp(const char *host_str,
int is_telnet)
{
CharDriverState *chr = NULL;
TCPCharDriver *s = NULL;
- int fd = -1, ret, err, val;
+ int fd = -1, ret, err;
int is_listen = 0;
int is_waitconnect = 1;
const char *ptr;
@@ -2458,9 +2175,9 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
s = qemu_mallocz(sizeof(TCPCharDriver));
if (!s)
goto fail;
-
+
fd = socket(PF_INET, SOCK_STREAM, 0);
- if (fd < 0)
+ if (fd < 0)
goto fail;
if (!is_waitconnect)
@@ -2471,11 +2188,10 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
s->listen_fd = -1;
if (is_listen) {
/* allow fast reuse */
- val = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
-
+ socket_set_xreuseaddr(fd);
+
ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
- if (ret < 0)
+ if (ret < 0)
goto fail;
ret = listen(fd, 0);
if (ret < 0)
@@ -2488,7 +2204,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
for(;;) {
ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0) {
- err = socket_error();
+ err = socket_errno;
if (err == EINTR || err == EWOULDBLOCK) {
} else if (err == EINPROGRESS) {
break;
@@ -2506,7 +2222,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
else
qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr);
}
-
+
chr->opaque = s;
chr->chr_write = tcp_chr_write;
chr->chr_add_read_handler = tcp_chr_add_read_handler;
@@ -2520,7 +2236,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
return chr;
fail:
if (fd >= 0)
- closesocket(fd);
+ socket_close(fd);
qemu_free(s);
qemu_free(chr);
return NULL;
@@ -2534,7 +2250,7 @@ CharDriverState *qemu_chr_open(const char *filename)
return text_console_init(&display_state);
} else if (!strcmp(filename, "null")) {
return qemu_chr_open_null();
- } else
+ } else
if (strstart(filename, "tcp:", &p)) {
return qemu_chr_open_tcp(p, 0);
} else
@@ -2553,16 +2269,33 @@ CharDriverState *qemu_chr_open(const char *filename)
return qemu_chr_open_pty();
} else if (!strcmp(filename, "stdio")) {
return qemu_chr_open_stdio();
- } else
+ } else if (strstart(filename, "fdpair:", &p)) {
+ return qemu_chr_open_fdpair(p);
+ } else
#endif
#if defined(__linux__)
if (strstart(filename, "/dev/parport", NULL)) {
return qemu_chr_open_pp(filename);
- } else
+ } else
+#endif
+#ifndef _WIN32
if (strstart(filename, "/dev/", NULL)) {
return qemu_chr_open_tty(filename);
- } else
+ } else
#endif
+ if (!strcmp(filename, "android-modem")) {
+ CharDriverState* cs;
+ qemu_chr_open_charpipe( &cs, &android_modem_cs );
+ return cs;
+ } else if (!strcmp(filename, "android-gps")) {
+ CharDriverState* cs;
+ qemu_chr_open_charpipe( &cs, &android_gps_cs );
+ return cs;
+ } else if (!strcmp(filename, "android-kmsg")) {
+ return android_kmsg_get_cs();
+ } else if (!strcmp(filename, "android-qemud")) {
+ return android_qemud_get_cs();
+ } else
#ifdef _WIN32
if (strstart(filename, "COM", NULL)) {
return qemu_chr_open_win(filename);
@@ -2572,6 +2305,9 @@ CharDriverState *qemu_chr_open(const char *filename)
} else
if (strstart(filename, "file:", &p)) {
return qemu_chr_open_win_file_out(p);
+ } else
+ if (!strcmp(filename, "stdio")) {
+ return qemu_chr_open_win_stdio();
}
#endif
{
@@ -2620,10 +2356,10 @@ static int parse_macaddr(uint8_t *macaddr, const char *p)
for(i = 0; i < 6; i++) {
macaddr[i] = strtol(p, (char **)&p, 16);
if (i == 5) {
- if (*p != '\0')
+ if (*p != '\0')
return -1;
} else {
- if (*p != ':')
+ if (*p != ':')
return -1;
p++;
}
@@ -2754,6 +2490,16 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan,
vc->opaque = opaque;
vc->vlan = vlan;
+ vc->tx_packets = 0;
+ vc->rx_packets = 0;
+ vc->tx_bytes = 0;
+ vc->rx_bytes = 0;
+ vc->tx_max_byte_rate = 0;
+ vc->rx_max_byte_rate = 0;
+ vc->tx_max_packet_rate = 0;
+ vc->rx_max_packet_rate = 0;
+ vc->clock_last = vc->clock_start = clock();
+
vc->next = NULL;
pvc = &vlan->first_client;
while (*pvc != NULL)
@@ -2762,6 +2508,198 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan,
return vc;
}
+
+//static void tap_receive(void *opaque, const uint8_t *buf, int size);
+static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size);
+static void net_socket_receive(void *opaque, const uint8_t *buf, int size);
+static void slirp_receive(void *opaque, const uint8_t *buf, int size);
+
+#if 0
+static char*
+vlan_client_get_name( VLANClientState *vc,
+ char* tmp_name )
+{
+ char* name = NULL;
+
+ extern IOReadHandler ne2000_receive;
+ extern IOReadHandler pcnet_receive;
+ extern IOReadHandler lance_receive;
+ extern IOReadHandler rtl8139_receive;
+ extern IOReadHandler smc91c111_receive;
+
+ /* hackish, but should work */
+ if (vc->fd_read == tap_receive)
+ name = "tap";
+ else if (vc->fd_read == net_socket_receive_dgram)
+ name = "socket-dgram";
+ else if (vc->fd_read == net_socket_receive)
+ name = "socket";
+ else if (vc->fd_read == slirp_receive) {
+ name = "slirp";
+ name = "upload";
+ }
+ else
+ {
+ sprintf( tmp_name, "<%p>", vc );
+ name = tmp_name;
+ name = "download";
+ }
+ return name;
+}
+#endif
+
+static uint64_t vc_clock_start;
+static uint64_t vc_clock_last;
+static VLANClientState* vc_upload;
+static VLANClientState* vc_download;
+
+static void
+vlan_dump_stats( void )
+{
+ long upload_bytes = 0;
+ long upload_packets = 0;
+ long download_bytes = 0;
+ long download_packets = 0;
+ int sec, msec, usec;
+ double nowf;
+
+ uint64_t now = get_clock();
+ int64_t diff;
+
+ if (vc_clock_start == 0) {
+ vc_clock_start = now;
+ vc_clock_last = now;
+ }
+
+ diff = now - vc_clock_last;
+
+ if (vc_upload != NULL) {
+ upload_bytes = vc_upload->rx_bytes;
+ upload_packets = vc_upload->rx_packets;
+
+ vc_upload->rx_bytes = 0;
+ vc_upload->rx_packets = 0;
+ }
+ if (vc_download != NULL) {
+ download_bytes = vc_download->rx_bytes;
+ download_packets = vc_download->rx_packets;
+
+ vc_download->rx_bytes = 0;
+ vc_download->rx_packets = 0;
+ }
+
+ nowf = (now - vc_clock_start)*(1.0/QEMU_TIMER_BASE);
+ sec = (int)nowf;
+ nowf = (nowf - sec)*1000;
+ msec = (int)nowf;
+ nowf = (nowf - msec)*1000;
+ usec = (int)nowf;
+ if (usec >= 500) {
+ msec += 1;
+ if (msec >= 1000) {
+ msec = 0;
+ sec += 1;
+ }
+ }
+
+ printf( "%03d.%03d: ", sec, msec );
+
+ nowf = diff*(1.0/QEMU_TIMER_BASE);
+ sec = (int)nowf;
+ nowf = (nowf - sec)*1e3;
+ msec = (int)nowf;
+ nowf = (nowf - msec)*1e3;
+ usec = (int)nowf;
+ if (usec >= 500) {
+ msec += 1;
+ if (msec >= 1000) {
+ msec = 0;
+ sec += 1;
+ }
+ }
+ printf( "%03d.%03d: ", sec, msec );
+
+ printf( "download: %6ld bytes, %4ld packets (%5.1f KB/s)",
+ download_bytes, download_packets, diff > 0 ? (download_bytes*(QEMU_TIMER_BASE/1024.)/diff) : 0. );
+ printf( " | " );
+ printf( "upload: %6ld bytes, %4ld packets (%5.1f KB/s)",
+ upload_bytes, upload_packets, diff > 0 ? (upload_bytes*(QEMU_TIMER_BASE/1024.)/diff) : 0. );
+ printf( "\n" );
+ fflush(stdout);
+
+ vc_clock_last = now;
+}
+
+
+static void
+vlan_client_update_rx( VLANClientState *vc,
+ unsigned long bytes )
+{
+ static int debug_vlan;
+
+ if ( !vc_upload && vc->fd_read == slirp_receive )
+ vc_upload = vc;
+
+ if ( !vc_download && vc->fd_read != slirp_receive )
+ vc_download = vc;
+
+ vc->rx_bytes += bytes;
+ vc->rx_packets += 1;
+
+ /* if the environment variable QEMU_NETWORK_STATS is defined and not 0,
+ * we dump network statistics
+ */
+ if ( !debug_vlan )
+ {
+ const char* env;
+ debug_vlan = 1;
+ env = getenv( "QEMU_NETWORK_STATS" );
+ if (env != NULL && env[0] != 0)
+ {
+ int val = atoi(env);
+
+ if (val != 0)
+ debug_vlan = 2;
+ }
+ }
+
+ if (debug_vlan > 1)
+ {
+ uint64_t now = get_clock();
+
+ if (now - vc_clock_last > (QEMU_TIMER_BASE*0.25) || vc->rx_packets > 100) {
+#if 1
+ vlan_dump_stats();
+#else
+ clock_t period = now - vc->clock_start;
+ double byte_rate = vc->rx_bytes*1e6/period;
+ double packet_rate = vc->rx_packets*1e6/period;
+ char tmp[14];
+
+ if ( byte_rate > vc->rx_max_byte_rate )
+ vc->rx_max_byte_rate = byte_rate;
+
+ if ( packet_rate > vc->rx_max_packet_rate )
+ vc->rx_max_packet_rate = packet_rate;
+
+ if (debug_vlan > 1)
+ fprintf( stderr, ">>>> %14s %6.1f KB/s %6.1f packet/s (max %6.1f KB/s, bytes %ld, packets %ld)\n",
+ vlan_client_get_name(vc, tmp),
+ byte_rate/1024., packet_rate, vc->rx_max_byte_rate/1024.,
+ vc->rx_bytes, vc->rx_packets );
+ if (vc->rx_packets > 100 || now - vc->clock_start > (CLOCKS_PER_SEC*0.5))
+ {
+ vc->rx_packets = 0;
+ vc->rx_bytes = 0;
+ vc->clock_start = now;
+ }
+ vc->clock_last = now;
+#endif
+ }
+ }
+}
+
+
int qemu_can_send_packet(VLANClientState *vc1)
{
VLANState *vlan = vc1->vlan;
@@ -2788,6 +2726,7 @@ void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)
for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
if (vc != vc1) {
vc->fd_read(vc->opaque, buf, size);
+ vlan_client_update_rx( vc, size );
}
}
}
@@ -2796,14 +2735,116 @@ void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)
/* slirp network adapter */
-static int slirp_inited;
+int slirp_inited;
static VLANClientState *slirp_vc;
+double qemu_net_upload_speed = 0.;
+double qemu_net_download_speed = 0.;
+int qemu_net_min_latency = 0;
+int qemu_net_max_latency = 0;
+int qemu_net_disable = 0;
+
+int
+ip_packet_is_internal( const uint8_t* data, size_t size )
+{
+ const uint8_t* end = data + size;
+
+ /* must have room for Mac + IP header */
+ if (data + 40 > end)
+ return 0;
+
+ if (data[12] != 0x08 || data[13] != 0x00 )
+ return 0;
+
+ /* must have valid IP header */
+ data += 14;
+ if ((data[0] >> 4) != 4 || (data[0] & 15) < 5)
+ return 0;
+
+ /* internal if both source and dest addresses are in 10.x.x.x */
+ return ( data[12] == 10 && data[16] == 10);
+}
+
+#ifdef CONFIG_SHAPER
+
+/* see http://en.wikipedia.org/wiki/List_of_device_bandwidths or a complete list */
+const NetworkSpeed android_netspeeds[] = {
+ { "gsm", "GSM/CSD", 14400, 14400 },
+ { "hscsd", "HSCSD", 14400, 43200 },
+ { "gprs", "GPRS", 40000, 80000 },
+ { "edge", "EDGE/EGPRS", 118400, 236800 },
+ { "umts", "UMTS/3G", 128000, 1920000 },
+ { "hsdpa", "HSDPA", 348000, 14400000 },
+ { "full", "no limit", 0, 0 },
+ { NULL, NULL, 0, 0 }
+};
+
+const NetworkLatency android_netdelays[] = {
+ /* FIXME: these numbers are totally imaginary */
+ { "gprs", "GPRS", 150, 550 },
+ { "edge", "EDGE/EGPRS", 80, 400 },
+ { "umts", "UMTS/3G", 35, 200 },
+ { "none", "no latency", 0, 0 },
+ { NULL, NULL, 0, 0 }
+};
+
+
+NetShaper slirp_shaper_in;
+NetShaper slirp_shaper_out;
+NetDelay slirp_delay_in;
+
+static void
+slirp_delay_in_cb( void* data,
+ size_t size,
+ void* opaque )
+{
+ slirp_input( (const uint8_t*)data, (int)size );
+ opaque = opaque;
+}
+
+static void
+slirp_shaper_in_cb( void* data,
+ size_t size,
+ void* opaque )
+{
+ netdelay_send_aux( slirp_delay_in, data, size, opaque );
+}
+
+static void
+slirp_shaper_out_cb( void* data,
+ size_t size,
+ void* opaque )
+{
+ qemu_send_packet( slirp_vc, (const uint8_t*)data, (int)size );
+}
+
+void
+slirp_init_shapers( void )
+{
+ slirp_delay_in = netdelay_create( slirp_delay_in_cb );
+ slirp_shaper_in = netshaper_create( 1, slirp_shaper_in_cb );
+ slirp_shaper_out = netshaper_create( 1, slirp_shaper_out_cb );
+
+ netdelay_set_latency( slirp_delay_in, qemu_net_min_latency, qemu_net_max_latency );
+ netshaper_set_rate( slirp_shaper_out, qemu_net_download_speed );
+ netshaper_set_rate( slirp_shaper_in, qemu_net_upload_speed );
+}
+
+#endif /* CONFIG_SHAPER */
+
int slirp_can_output(void)
{
+#ifdef CONFIG_SHAPER
+ return !slirp_vc ||
+ ( netshaper_can_send( slirp_shaper_out ) &&
+ qemu_can_send_packet(slirp_vc) );
+#else
return !slirp_vc || qemu_can_send_packet(slirp_vc);
+#endif
}
+
+
void slirp_output(const uint8_t *pkt, int pkt_len)
{
#if 0
@@ -2812,7 +2853,21 @@ void slirp_output(const uint8_t *pkt, int pkt_len)
#endif
if (!slirp_vc)
return;
+
+ /* always send internal packets */
+ if ( ip_packet_is_internal( pkt, pkt_len ) ) {
+ qemu_send_packet( slirp_vc, pkt, pkt_len );
+ return;
+ }
+
+ if ( qemu_net_disable )
+ return;
+
+#ifdef CONFIG_SHAPER
+ netshaper_send( slirp_shaper_out, (void*)pkt, pkt_len );
+#else
qemu_send_packet(slirp_vc, pkt, pkt_len);
+#endif
}
static void slirp_receive(void *opaque, const uint8_t *buf, int size)
@@ -2821,7 +2876,19 @@ static void slirp_receive(void *opaque, const uint8_t *buf, int size)
printf("slirp input:\n");
hex_dump(stdout, buf, size);
#endif
+ if ( ip_packet_is_internal( buf, size ) ) {
+ slirp_input(buf, size);
+ return;
+ }
+
+ if (qemu_net_disable)
+ return;
+
+#ifdef CONFIG_SHAPER
+ netshaper_send( slirp_shaper_in, (char*)buf, size );
+#else
slirp_input(buf, size);
+#endif
}
static int net_slirp_init(VLANState *vlan)
@@ -2830,20 +2897,20 @@ static int net_slirp_init(VLANState *vlan)
slirp_inited = 1;
slirp_init();
}
- slirp_vc = qemu_new_vlan_client(vlan,
+ slirp_vc = qemu_new_vlan_client(vlan,
slirp_receive, NULL, NULL);
snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector");
return 0;
}
-static void net_slirp_redir(const char *redir_str)
+static int net_slirp_redir(const char *redir_str)
{
int is_udp;
char buf[256], *r;
const char *p;
struct in_addr guest_addr;
int host_port, guest_port;
-
+
if (!slirp_inited) {
slirp_inited = 1;
slirp_init();
@@ -2873,22 +2940,23 @@ static void net_slirp_redir(const char *redir_str)
}
if (!inet_aton(buf, &guest_addr))
goto fail;
-
+
guest_port = strtol(p, &r, 0);
if (r == p)
goto fail;
-
+
if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) {
- fprintf(stderr, "qemu: could not set up redirection\n");
- exit(1);
+ return -1;
}
- return;
+
+ return 0;
fail:
fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n");
exit(1);
+ return -1;
}
-
-#ifndef _WIN32
+
+#if 0 /* ANDROID disabled */
char smb_dir[1024];
@@ -2906,7 +2974,7 @@ static void smb_exit(void)
break;
if (strcmp(de->d_name, ".") != 0 &&
strcmp(de->d_name, "..") != 0) {
- snprintf(filename, sizeof(filename), "%s/%s",
+ snprintf(filename, sizeof(filename), "%s/%s",
smb_dir, de->d_name);
unlink(filename);
}
@@ -2934,13 +3002,13 @@ void net_slirp_smb(const char *exported_dir)
exit(1);
}
snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf");
-
+
f = fopen(smb_conf, "w");
if (!f) {
fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf);
exit(1);
}
- fprintf(f,
+ fprintf(f,
"[global]\n"
"private dir=%s\n"
"smb ports=0\n"
@@ -2966,7 +3034,7 @@ void net_slirp_smb(const char *exported_dir)
snprintf(smb_cmdline, sizeof(smb_cmdline), "/usr/sbin/smbd -s %s",
smb_conf);
-
+
slirp_add_exec(0, smb_cmdline, 4, 139);
}
@@ -3053,7 +3121,7 @@ static int tap_open(char *ifname, int ifname_size)
{
struct ifreq ifr;
int fd, ret;
-
+
fd = open("/dev/net/tun", O_RDWR);
if (fd < 0) {
fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
@@ -3120,7 +3188,7 @@ static int net_tap_init(VLANState *vlan, const char *ifname1,
s = net_tap_fd_init(vlan, fd);
if (!s)
return -1;
- snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+ snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"tap: ifname=%s setup_script=%s", ifname, setup_script);
return 0;
}
@@ -3157,7 +3225,7 @@ static void net_socket_receive(void *opaque, const uint8_t *buf, int size)
static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size)
{
NetSocketState *s = opaque;
- sendto(s->fd, buf, size, 0,
+ sendto(s->fd, buf, size, 0,
(struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
}
@@ -3170,14 +3238,14 @@ static void net_socket_send(void *opaque)
size = recv(s->fd, buf1, sizeof(buf1), 0);
if (size < 0) {
- err = socket_error();
- if (err != EWOULDBLOCK)
+ err = socket_errno;
+ if (err != EWOULDBLOCK)
goto eoc;
} else if (size == 0) {
/* end of connection */
eoc:
qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
- closesocket(s->fd);
+ socket_close(s->fd);
return;
}
buf = buf1;
@@ -3223,7 +3291,7 @@ static void net_socket_send_dgram(void *opaque)
int size;
size = recv(s->fd, s->buf, sizeof(s->buf), 0);
- if (size < 0)
+ if (size < 0)
return;
if (size == 0) {
/* end of connection */
@@ -3240,7 +3308,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
int val, ret;
if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
- inet_ntoa(mcastaddr->sin_addr),
+ inet_ntoa(mcastaddr->sin_addr),
(int)ntohl(mcastaddr->sin_addr.s_addr));
return -1;
@@ -3251,9 +3319,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
return -1;
}
- val = 1;
- ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
- (const char *)&val, sizeof(val));
+ ret=socket_set_xreuseaddr(fd);
if (ret < 0) {
perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
goto fail;
@@ -3264,12 +3330,12 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
perror("bind");
goto fail;
}
-
+
/* Add host to multicast group */
imr.imr_multiaddr = mcastaddr->sin_addr;
imr.imr_interface.s_addr = htonl(INADDR_ANY);
- ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const char *)&imr, sizeof(struct ip_mreq));
if (ret < 0) {
perror("setsockopt(IP_ADD_MEMBERSHIP)");
@@ -3278,7 +3344,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
/* Force mcast msgs to loopback (eg. several QEMUs in same host */
val = 1;
- ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
+ ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
(const char *)&val, sizeof(val));
if (ret < 0) {
perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
@@ -3288,12 +3354,12 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
socket_set_nonblock(fd);
return fd;
fail:
- if (fd >= 0)
- closesocket(fd);
+ if (fd >= 0)
+ socket_close(fd);
return -1;
}
-static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
+static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
int is_connected)
{
struct sockaddr_in saddr;
@@ -3302,7 +3368,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
NetSocketState *s;
/* fd passed: multicast: "learn" dgram_dst address from bound address and save it
- * Because this may be "shared" socket from a "master" process, datagrams would be recv()
+ * Because this may be "shared" socket from a "master" process, datagrams would be recv()
* by ONLY ONE process: we must "clone" this dgram socket --jjo
*/
@@ -3324,7 +3390,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
/* clone newfd to fd, close newfd */
dup2(newfd, fd);
close(newfd);
-
+
} else {
fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
fd, strerror(errno));
@@ -3344,7 +3410,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
if (is_connected) s->dgram_dst=saddr;
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "socket: fd=%d (%s mcast=%s:%d)",
+ "socket: fd=%d (%s mcast=%s:%d)",
fd, is_connected? "cloned" : "",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
return s;
@@ -3356,7 +3422,7 @@ static void net_socket_connect(void *opaque)
qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
}
-static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,
+static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,
int is_connected)
{
NetSocketState *s;
@@ -3364,7 +3430,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,
if (!s)
return NULL;
s->fd = fd;
- s->vc = qemu_new_vlan_client(vlan,
+ s->vc = qemu_new_vlan_client(vlan,
net_socket_receive, NULL, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"socket: fd=%d", fd);
@@ -3376,12 +3442,12 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,
return s;
}
-static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
+static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
int is_connected)
{
int so_type=-1, optlen=sizeof(so_type);
- if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, &optlen)< 0) {
+ if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, (unsigned*)&optlen)< 0) {
fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd);
return NULL;
}
@@ -3400,7 +3466,7 @@ static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
static void net_socket_accept(void *opaque)
{
- NetSocketListenState *s = opaque;
+ NetSocketListenState *s = opaque;
NetSocketState *s1;
struct sockaddr_in saddr;
socklen_t len;
@@ -3415,12 +3481,12 @@ static void net_socket_accept(void *opaque)
break;
}
}
- s1 = net_socket_fd_init(s->vlan, fd, 1);
+ s1 = net_socket_fd_init(s->vlan, fd, 1);
if (!s1) {
- closesocket(fd);
+ socket_close(fd);
} else {
snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
- "socket: connection from %s:%d",
+ "socket: connection from %s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
}
}
@@ -3428,12 +3494,12 @@ static void net_socket_accept(void *opaque)
static int net_socket_listen_init(VLANState *vlan, const char *host_str)
{
NetSocketListenState *s;
- int fd, val, ret;
+ int fd, ret;
struct sockaddr_in saddr;
if (parse_host_port(&saddr, host_str) < 0)
return -1;
-
+
s = qemu_mallocz(sizeof(NetSocketListenState));
if (!s)
return -1;
@@ -3445,10 +3511,8 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str)
}
socket_set_nonblock(fd);
- /* allow fast reuse */
- val = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
-
+ socket_set_xreuseaddr(fd);
+
ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0) {
perror("bind");
@@ -3485,13 +3549,13 @@ static int net_socket_connect_init(VLANState *vlan, const char *host_str)
for(;;) {
ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0) {
- err = socket_error();
+ err = socket_errno;
if (err == EINTR || err == EWOULDBLOCK) {
} else if (err == EINPROGRESS) {
break;
} else {
perror("connect");
- closesocket(fd);
+ socket_close(fd);
return -1;
}
} else {
@@ -3503,7 +3567,7 @@ static int net_socket_connect_init(VLANState *vlan, const char *host_str)
if (!s)
return -1;
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "socket: connect to %s:%d",
+ "socket: connect to %s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
return 0;
}
@@ -3527,9 +3591,9 @@ static int net_socket_mcast_init(VLANState *vlan, const char *host_str)
return -1;
s->dgram_dst = saddr;
-
+
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "socket: mcast=%s:%d",
+ "socket: mcast=%s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
return 0;
@@ -3636,7 +3700,12 @@ int net_client_init(const char *str)
if (!strcmp(device, "none")) {
/* does nothing. It is needed to signal that no network cards
are wanted */
+#if 1 /* ANDROID */
+ fprintf(stderr, "sorry, you need to enable the network to use the Android emulator\n");
+ return -1;
+#else
ret = 0;
+#endif
} else
#ifdef CONFIG_SLIRP
if (!strcmp(device, "user")) {
@@ -3699,7 +3768,7 @@ int net_client_init(const char *str)
if (ret < 0) {
fprintf(stderr, "Could not initialize device '%s'\n", device);
}
-
+
return ret;
}
@@ -3714,7 +3783,7 @@ void do_info_network(void)
term_printf(" %s\n", vc->info_str);
}
}
-
+
/***********************************************************/
/* USB devices */
@@ -3781,7 +3850,6 @@ static int usb_device_del(const char *devname)
{
USBPort *port;
USBPort **lastp;
- USBDevice *dev;
int bus_num, addr;
const char *p;
@@ -3789,7 +3857,7 @@ static int usb_device_del(const char *devname)
return -1;
p = strchr(devname, '.');
- if (!p)
+ if (!p)
return -1;
bus_num = strtoul(devname, NULL, 0);
addr = strtoul(p + 1, NULL, 0);
@@ -3806,10 +3874,8 @@ static int usb_device_del(const char *devname)
if (!port)
return -1;
- dev = port->dev;
*lastp = port->next;
usb_attach(port, NULL);
- dev->handle_destroy(dev);
port->next = free_usb_ports;
free_usb_ports = port;
return 0;
@@ -3819,7 +3885,7 @@ void do_usb_add(const char *devname)
{
int ret;
ret = usb_device_add(devname);
- if (ret < 0)
+ if (ret < 0)
term_printf("Could not add USB device '%s'\n", devname);
}
@@ -3827,7 +3893,7 @@ void do_usb_del(const char *devname)
{
int ret;
ret = usb_device_del(devname);
- if (ret < 0)
+ if (ret < 0)
term_printf("Could not remove USB device '%s'\n", devname);
}
@@ -3847,20 +3913,20 @@ void usb_info(void)
if (!dev)
continue;
switch(dev->speed) {
- case USB_SPEED_LOW:
- speed_str = "1.5";
+ case USB_SPEED_LOW:
+ speed_str = "1.5";
break;
- case USB_SPEED_FULL:
- speed_str = "12";
+ case USB_SPEED_FULL:
+ speed_str = "12";
break;
- case USB_SPEED_HIGH:
- speed_str = "480";
+ case USB_SPEED_HIGH:
+ speed_str = "480";
break;
default:
- speed_str = "?";
+ speed_str = "?";
break;
}
- term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n",
+ term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n",
0, dev->addr, speed_str, dev->devname);
}
}
@@ -3872,7 +3938,7 @@ static char *pid_filename;
/* Remove PID file. Called on normal exit */
-static void remove_pidfile(void)
+static void remove_pidfile(void)
{
unlink (pid_filename);
}
@@ -3899,7 +3965,7 @@ static void create_pidfile(const char *filename)
atexit(remove_pidfile);
}
} else {
- fprintf(stderr, "%s already exists. Remove it and try again.\n",
+ fprintf(stderr, "%s already exists. Remove it and try again.\n",
filename);
exit(1);
}
@@ -3912,7 +3978,7 @@ static void dumb_update(DisplayState *ds, int x, int y, int w, int h)
{
}
-static void dumb_resize(DisplayState *ds, int w, int h)
+static void dumb_resize(DisplayState *ds, int w, int h, int rotation)
{
}
@@ -3942,19 +4008,25 @@ typedef struct IOHandlerRecord {
IOHandler *fd_read;
IOHandler *fd_write;
void *opaque;
+ unsigned state;
/* temporary data */
struct pollfd *ufd;
struct IOHandlerRecord *next;
} IOHandlerRecord;
+typedef enum {
+ IOH_STATE_PENDING = (1 << 0),
+ IOH_STATE_CLOSED = (1 << 1)
+} IOHandlerState;
+
static IOHandlerRecord *first_io_handler;
/* XXX: fd_read_poll should be suppressed, but an API change is
necessary in the character devices to suppress fd_can_read(). */
-int qemu_set_fd_handler2(int fd,
- IOCanRWHandler *fd_read_poll,
- IOHandler *fd_read,
- IOHandler *fd_write,
+int qemu_set_fd_handler2(int fd,
+ IOCanRWHandler *fd_read_poll,
+ IOHandler *fd_read,
+ IOHandler *fd_write,
void *opaque)
{
IOHandlerRecord **pioh, *ioh;
@@ -3967,7 +4039,15 @@ int qemu_set_fd_handler2(int fd,
break;
if (ioh->fd == fd) {
*pioh = ioh->next;
- qemu_free(ioh);
+
+ if (ioh->state == IOH_STATE_PENDING) {
+ /* do not delete this ioh immediately if we're currently
+ * processing it.
+ */
+ ioh->state = IOH_STATE_CLOSED;
+ } else {
+ qemu_free(ioh);
+ }
break;
}
pioh = &ioh->next;
@@ -3992,9 +4072,9 @@ int qemu_set_fd_handler2(int fd,
return 0;
}
-int qemu_set_fd_handler(int fd,
- IOHandler *fd_read,
- IOHandler *fd_write,
+int qemu_set_fd_handler(int fd,
+ IOHandler *fd_read,
+ IOHandler *fd_write,
void *opaque)
{
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
@@ -4004,9 +4084,9 @@ int qemu_set_fd_handler(int fd,
/* Polling handling */
typedef struct PollingEntry {
- PollingFunc *func;
- void *opaque;
- struct PollingEntry *next;
+ PollingFunc* func;
+ void* opaque;
+ struct PollingEntry* next;
} PollingEntry;
static PollingEntry *first_polling_entry;
@@ -4048,7 +4128,7 @@ typedef struct WaitObjects {
} WaitObjects;
static WaitObjects wait_objects = {0};
-
+
int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
{
WaitObjects *w = &wait_objects;
@@ -4075,7 +4155,7 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
w->events[i] = w->events[i + 1];
w->func[i] = w->func[i + 1];
w->opaque[i] = w->opaque[i + 1];
- }
+ }
}
if (found)
w->num--;
@@ -4168,6 +4248,103 @@ int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)
return ftell(f);
}
+void qemu_put_struct(QEMUFile* f, const QField* fields, const void* s)
+{
+ const QField* qf = fields;
+
+ for (;;) {
+ uint8_t* p = (uint8_t*)s + qf->offset;
+
+ switch (qf->type) {
+ case Q_FIELD_END:
+ break;
+ case Q_FIELD_BYTE:
+ qemu_put_byte(f, p[0]);
+ break;
+ case Q_FIELD_INT16:
+ qemu_put_be16(f, ((uint16_t*)p)[0]);
+ break;
+ case Q_FIELD_INT32:
+ qemu_put_be32(f, ((uint32_t*)p)[0]);
+ break;
+ case Q_FIELD_INT64:
+ qemu_put_be64(f, ((uint64_t*)p)[0]);
+ break;
+ case Q_FIELD_BUFFER:
+ if (fields[1].type != Q_FIELD_BUFFER_SIZE ||
+ fields[2].type != Q_FIELD_BUFFER_SIZE)
+ {
+ fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument. aborting\n",
+ __FUNCTION__ );
+ exit(1);
+ }
+ else
+ {
+ uint32_t size = ((uint32_t)fields[1].offset << 16) | (uint32_t)fields[2].offset;
+
+ qemu_put_buffer(f, p, size);
+ qf += 2;
+ }
+ break;
+ default:
+ fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
+ exit(1);
+ }
+ qf++;
+ }
+}
+
+int qemu_get_struct(QEMUFile* f, const QField* fields, void* s)
+{
+ const QField* qf = fields;
+
+ for (;;) {
+ uint8_t* p = (uint8_t*)s + qf->offset;
+
+ switch (qf->type) {
+ case Q_FIELD_END:
+ break;
+ case Q_FIELD_BYTE:
+ p[0] = qemu_get_byte(f);
+ break;
+ case Q_FIELD_INT16:
+ ((uint16_t*)p)[0] = qemu_get_be16(f);
+ break;
+ case Q_FIELD_INT32:
+ ((uint32_t*)p)[0] = qemu_get_be32(f);
+ break;
+ case Q_FIELD_INT64:
+ ((uint64_t*)p)[0] = qemu_get_be64(f);
+ break;
+ case Q_FIELD_BUFFER:
+ if (fields[1].type != Q_FIELD_BUFFER_SIZE ||
+ fields[2].type != Q_FIELD_BUFFER_SIZE)
+ {
+ fprintf(stderr, "%s: invalid QFIELD_BUFFER item passed as argument.\n",
+ __FUNCTION__ );
+ return -1;
+ }
+ else
+ {
+ uint32_t size = ((uint32_t)fields[1].offset << 16) | (uint32_t)fields[2].offset;
+ int ret = qemu_get_buffer(f, p, size);
+
+ if (ret != size) {
+ fprintf(stderr, "%s: not enough bytes to load structure\n", __FUNCTION__);
+ return -1;
+ }
+ qf += 2;
+ }
+ break;
+ default:
+ fprintf(stderr, "%s: invalid fields list passed as argument. aborting\n", __FUNCTION__);
+ exit(1);
+ }
+ qf++;
+ }
+ return 0;
+}
+
typedef struct SaveStateEntry {
char idstr[256];
int instance_id;
@@ -4180,8 +4357,8 @@ typedef struct SaveStateEntry {
static SaveStateEntry *first_se;
-int register_savevm(const char *idstr,
- int instance_id,
+int register_savevm(const char *idstr,
+ int instance_id,
int version_id,
SaveStateHandler *save_state,
LoadStateHandler *load_state,
@@ -4233,7 +4410,7 @@ int qemu_savevm(const char *filename)
/* ID string */
len = strlen(se->idstr);
qemu_put_byte(f, len);
- qemu_put_buffer(f, se->idstr, len);
+ qemu_put_buffer(f, (uint8_t*)se->idstr, len);
qemu_put_be32(f, se->instance_id);
qemu_put_be32(f, se->version_id);
@@ -4241,7 +4418,7 @@ int qemu_savevm(const char *filename)
/* record size: filled later */
len_pos = ftell(f);
qemu_put_be32(f, 0);
-
+
se->save_state(f, se->opaque);
/* fill record size */
@@ -4265,7 +4442,7 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id)
SaveStateEntry *se;
for(se = first_se; se != NULL; se = se->next) {
- if (!strcmp(se->idstr, idstr) &&
+ if (!strcmp(se->idstr, idstr) &&
instance_id == se->instance_id)
return se;
}
@@ -4280,7 +4457,7 @@ int qemu_loadvm(const char *filename)
int saved_vm_running;
unsigned int v;
char idstr[256];
-
+
saved_vm_running = vm_running;
vm_stop(0);
@@ -4304,24 +4481,24 @@ int qemu_loadvm(const char *filename)
len = qemu_get_byte(f);
if (feof(f))
break;
- qemu_get_buffer(f, idstr, len);
+ qemu_get_buffer(f, (uint8_t*)idstr, len);
idstr[len] = '\0';
instance_id = qemu_get_be32(f);
version_id = qemu_get_be32(f);
record_len = qemu_get_be32(f);
#if 0
- printf("idstr=%s instance=0x%x version=%d len=%d\n",
+ printf("idstr=%s instance=0x%x version=%d len=%d\n",
idstr, instance_id, version_id, record_len);
#endif
cur_pos = ftell(f);
se = find_se(idstr, instance_id);
if (!se) {
- fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
+ fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
instance_id, idstr);
} else {
ret = se->load_state(f, se->opaque, version_id);
if (ret < 0) {
- fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
+ fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
instance_id, idstr);
}
}
@@ -4363,14 +4540,14 @@ void cpu_save(QEMUFile *f, void *opaque)
uint16_t fptag, fpus, fpuc, fpregs_format;
uint32_t hflags;
int i;
-
+
for(i = 0; i < CPU_NB_REGS; i++)
qemu_put_betls(f, &env->regs[i]);
qemu_put_betls(f, &env->eip);
qemu_put_betls(f, &env->eflags);
hflags = env->hflags; /* XXX: suppress most of the redundant hflags */
qemu_put_be32s(f, &hflags);
-
+
/* FPU */
fpuc = env->fpuc;
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
@@ -4378,7 +4555,7 @@ void cpu_save(QEMUFile *f, void *opaque)
for(i = 0; i < 8; i++) {
fptag |= ((!env->fptags[i]) << i);
}
-
+
qemu_put_be16s(f, &fpuc);
qemu_put_be16s(f, &fpus);
qemu_put_be16s(f, &fptag);
@@ -4389,7 +4566,7 @@ void cpu_save(QEMUFile *f, void *opaque)
fpregs_format = 1;
#endif
qemu_put_be16s(f, &fpregs_format);
-
+
for(i = 0; i < 8; i++) {
#ifdef USE_X86LDOUBLE
{
@@ -4416,16 +4593,16 @@ void cpu_save(QEMUFile *f, void *opaque)
cpu_put_seg(f, &env->tr);
cpu_put_seg(f, &env->gdt);
cpu_put_seg(f, &env->idt);
-
+
qemu_put_be32s(f, &env->sysenter_cs);
qemu_put_be32s(f, &env->sysenter_esp);
qemu_put_be32s(f, &env->sysenter_eip);
-
+
qemu_put_betls(f, &env->cr[0]);
qemu_put_betls(f, &env->cr[2]);
qemu_put_betls(f, &env->cr[3]);
qemu_put_betls(f, &env->cr[4]);
-
+
for(i = 0; i < 8; i++)
qemu_put_betls(f, &env->dr[i]);
@@ -4492,7 +4669,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_be16s(f, &fpus);
qemu_get_be16s(f, &fptag);
qemu_get_be16s(f, &fpregs_format);
-
+
/* NOTE: we cannot always restore the FPU state if the image come
from a host with a different 'USE_X86LDOUBLE' define. We guess
if we are in an MMX state to restore correctly in that case. */
@@ -4500,7 +4677,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
for(i = 0; i < 8; i++) {
uint64_t mant;
uint16_t exp;
-
+
switch(fpregs_format) {
case 0:
mant = qemu_get_be64(f);
@@ -4531,7 +4708,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
}
#else
env->fpregs[i].mmx.MMX_Q(0) = mant;
-#endif
+#endif
break;
default:
return -EINVAL;
@@ -4546,23 +4723,23 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
for(i = 0; i < 8; i++) {
env->fptags[i] = (fptag >> i) & 1;
}
-
+
for(i = 0; i < 6; i++)
cpu_get_seg(f, &env->segs[i]);
cpu_get_seg(f, &env->ldt);
cpu_get_seg(f, &env->tr);
cpu_get_seg(f, &env->gdt);
cpu_get_seg(f, &env->idt);
-
+
qemu_get_be32s(f, &env->sysenter_cs);
qemu_get_be32s(f, &env->sysenter_esp);
qemu_get_be32s(f, &env->sysenter_eip);
-
+
qemu_get_betls(f, &env->cr[0]);
qemu_get_betls(f, &env->cr[2]);
qemu_get_betls(f, &env->cr[3]);
qemu_get_betls(f, &env->cr[4]);
-
+
for(i = 0; i < 8; i++)
qemu_get_betls(f, &env->dr[i]);
@@ -4692,10 +4869,111 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
/* ??? Need to implement these. */
void cpu_save(QEMUFile *f, void *opaque)
{
+ int i;
+ CPUARMState *env = (CPUARMState *)opaque;
+
+ for (i = 0; i < 16; i++) {
+ qemu_put_be32(f, env->regs[i]);
+ }
+ qemu_put_be32(f, cpsr_read(env));
+ qemu_put_be32(f, env->spsr);
+ for (i = 0; i < 6; i++) {
+ qemu_put_be32(f, env->banked_spsr[i]);
+ qemu_put_be32(f, env->banked_r13[i]);
+ qemu_put_be32(f, env->banked_r14[i]);
+ }
+ for (i = 0; i < 5; i++) {
+ qemu_put_be32(f, env->usr_regs[i]);
+ qemu_put_be32(f, env->fiq_regs[i]);
+ }
+
+ qemu_put_be32(f, env->cp15.c0_cpuid);
+ qemu_put_be32(f, env->cp15.c1_sys);
+ qemu_put_be32(f, env->cp15.c1_coproc);
+ qemu_put_be32(f, env->cp15.c2);
+ qemu_put_be32(f, env->cp15.c3);
+ qemu_put_be32(f, env->cp15.c5_insn);
+ qemu_put_be32(f, env->cp15.c5_data);
+ qemu_put_be32(f, env->cp15.c6_insn);
+ qemu_put_be32(f, env->cp15.c6_data);
+ qemu_put_be32(f, env->cp15.c9_insn);
+ qemu_put_be32(f, env->cp15.c9_data);
+ qemu_put_be32(f, env->cp15.c13_fcse);
+ qemu_put_be32(f, env->cp15.c13_context);
+
+ qemu_put_be32(f, env->features);
+
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
+ for (i = 0; i < 16; i++) {
+ CPU_DoubleU u;
+ u.d = env->vfp.regs[i];
+ qemu_put_be32(f, u.l.upper);
+ qemu_put_be32(f, u.l.lower);
+ }
+ for (i = 0; i < 16; i++) {
+ qemu_put_be32(f, env->vfp.xregs[i]);
+ }
+
+ /* TODO: Should use proper FPSCR access functions. */
+ qemu_put_be32(f, env->vfp.vec_len);
+ qemu_put_be32(f, env->vfp.vec_stride);
+ }
}
int cpu_load(QEMUFile *f, void *opaque, int version_id)
{
+ CPUARMState *env = (CPUARMState *)opaque;
+ int i;
+
+ if (version_id != ARM_CPU_SAVE_VERSION)
+ return -EINVAL;
+
+ for (i = 0; i < 16; i++) {
+ env->regs[i] = qemu_get_be32(f);
+ }
+ cpsr_write(env, qemu_get_be32(f), 0xffffffff);
+ env->spsr = qemu_get_be32(f);
+ for (i = 0; i < 6; i++) {
+ env->banked_spsr[i] = qemu_get_be32(f);
+ env->banked_r13[i] = qemu_get_be32(f);
+ env->banked_r14[i] = qemu_get_be32(f);
+ }
+ for (i = 0; i < 5; i++) {
+ env->usr_regs[i] = qemu_get_be32(f);
+ env->fiq_regs[i] = qemu_get_be32(f);
+ }
+ env->cp15.c0_cpuid = qemu_get_be32(f);
+ env->cp15.c1_sys = qemu_get_be32(f);
+ env->cp15.c1_coproc = qemu_get_be32(f);
+ env->cp15.c2 = qemu_get_be32(f);
+ env->cp15.c3 = qemu_get_be32(f);
+ env->cp15.c5_insn = qemu_get_be32(f);
+ env->cp15.c5_data = qemu_get_be32(f);
+ env->cp15.c6_insn = qemu_get_be32(f);
+ env->cp15.c6_data = qemu_get_be32(f);
+ env->cp15.c9_insn = qemu_get_be32(f);
+ env->cp15.c9_data = qemu_get_be32(f);
+ env->cp15.c13_fcse = qemu_get_be32(f);
+ env->cp15.c13_context = qemu_get_be32(f);
+
+ env->features = qemu_get_be32(f);
+
+ if (arm_feature(env, ARM_FEATURE_VFP)) {
+ for (i = 0; i < 16; i++) {
+ CPU_DoubleU u;
+ u.l.upper = qemu_get_be32(f);
+ u.l.lower = qemu_get_be32(f);
+ env->vfp.regs[i] = u.d;
+ }
+ for (i = 0; i < 16; i++) {
+ env->vfp.xregs[i] = qemu_get_be32(f);
+ }
+
+ /* TODO: Should use proper FPSCR access functions. */
+ env->vfp.vec_len = qemu_get_be32(f);
+ env->vfp.vec_stride = qemu_get_be32(f);
+ }
+
return 0;
}
@@ -4722,7 +5000,7 @@ static void ram_put_page(QEMUFile *f, const uint8_t *buf, int len)
qemu_put_byte(f, v);
return;
normal_save:
- qemu_put_byte(f, 0);
+ qemu_put_byte(f, 0);
qemu_put_buffer(f, buf, len);
}
@@ -4870,7 +5148,7 @@ void vm_start(void)
}
}
-void vm_stop(int reason)
+void vm_stop(int reason)
{
if (vm_running) {
cpu_disable_ticks();
@@ -4928,9 +5206,24 @@ void qemu_system_reset_request(void)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
+#ifdef HAS_AUDIO
+extern void AUD_cleanup();
+#endif
+
void qemu_system_shutdown_request(void)
{
+ int i;
shutdown_requested = 1;
+
+ for (i = 0; i < MAX_DISKS; i++) {
+ if (bs_table[i])
+ bdrv_close(bs_table[i]);
+ }
+
+#ifdef HAS_AUDIO
+ // this is necessary to avoid a deadlock in SDL when quitting
+ AUD_cleanup();
+#endif
if (cpu_single_env)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
@@ -4942,6 +5235,46 @@ void qemu_system_powerdown_request(void)
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
}
+#define MAIN_LOOP_STATS 0
+
+#if MAIN_LOOP_STATS
+typedef struct {
+ int counter;
+ int64_t reset_time; // time when counter is reset
+ int64_t spent_time_total; // total time spent since last counter reset
+ int64_t spent_time_min; // minimum time spent in call
+ int64_t spent_time_max; // maximum time spent in call
+ int64_t wait_time_total; // total time spent waiting for select()
+} MainLoopStats;
+
+static __inline__ int64_t
+mainloopstats_now( void )
+{
+ return qemu_get_clock( vm_clock );
+}
+
+static __inline__ double
+mainloopstats_to_ms( int64_t duration )
+{
+ return duration / 1000000.;
+}
+
+static void
+mainloopstats_reset( MainLoopStats* s )
+{
+ int64_t now = qemu_get_clock( vm_clock );
+
+ s->counter = 0;
+ s->reset_time = now;
+ s->spent_time_total = 0;
+ s->wait_time_total = 0;
+ s->spent_time_min = INT_MAX;
+ s->spent_time_max = 0;
+}
+
+static MainLoopStats main_loop_stats;
+#endif /* MAIN_LOOP_STATS */
+
void main_loop_wait(int timeout)
{
IOHandlerRecord *ioh, *ioh_next;
@@ -4950,6 +5283,16 @@ void main_loop_wait(int timeout)
struct timeval tv;
PollingEntry *pe;
+#if MAIN_LOOP_STATS
+ int64 time_before = mainloopstats_now();
+ int64 time_after_select;
+#endif
+
+#if 0
+ /* disable timeout when we're in polling mode */
+ if (qemu_milli_needed > 0)
+ timeout = 0;
+#endif
/* XXX: need to suppress polling by better using win32 events */
ret = 0;
@@ -4957,14 +5300,27 @@ void main_loop_wait(int timeout)
ret |= pe->func(pe->opaque);
}
#ifdef _WIN32
- if (ret == 0 && timeout > 0) {
+ if (ret == 0) {
int err;
WaitObjects *w = &wait_objects;
-
+
ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout);
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 */
+ int i;
+ for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+
+ /* Check if event is signaled */
+ int 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();
@@ -4992,7 +5348,7 @@ void main_loop_wait(int timeout)
nfds = ioh->fd;
}
}
-
+
tv.tv_sec = 0;
#ifdef _WIN32
tv.tv_usec = 0;
@@ -5005,18 +5361,39 @@ void main_loop_wait(int timeout)
}
#endif
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+#if MAIN_LOOP_STATS
+ time_after_select = mainloopstats_now();
+#endif
if (ret > 0) {
- /* XXX: better handling of removal */
for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
ioh_next = ioh->next;
+
+ ioh->state = IOH_STATE_PENDING;
+
if (FD_ISSET(ioh->fd, &rfds)) {
ioh->fd_read(ioh->opaque);
+ if (ioh->state == IOH_STATE_CLOSED) {
+ qemu_free(ioh);
+ continue;
+ }
}
if (FD_ISSET(ioh->fd, &wfds)) {
ioh->fd_write(ioh->opaque);
+ if (ioh->state == IOH_STATE_CLOSED) {
+ qemu_free(ioh);
+ continue;
+ }
}
+
+ ioh->state = 0;
}
}
+
+#if 0
+ if (qemu_milli_needed && qemu_milli_check())
+ _check_timers();
+#endif
+
#if defined(CONFIG_SLIRP)
if (slirp_inited) {
if (ret < 0) {
@@ -5030,20 +5407,50 @@ void main_loop_wait(int timeout)
#ifdef _WIN32
tap_win32_poll();
#endif
+ charpipe_poll();
if (vm_running) {
- qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
- qemu_get_clock(vm_clock));
+ qemu_run_virtual_timers();
/* run dma transfers, if any */
DMA_run();
}
-
- /* real time timers */
- qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
- qemu_get_clock(rt_clock));
-}
-static CPUState *cur_cpu;
+ qemu_run_realtime_timers();
+ qemu_rearm_alarm_timer();
+
+#if MAIN_LOOP_STATS
+ {
+ MainLoopStats* s = &main_loop_stats;
+ int64_t time_after = mainloopstats_now();
+ int64_t time_diff = time_after - time_before;
+
+ s->spent_time_total += time_diff;
+ if (time_diff < s->spent_time_min)
+ s->spent_time_min = time_diff;
+ if (time_diff > s->spent_time_max)
+ s->spent_time_max = time_diff;
+
+ time_diff = time_after_select - time_before;
+ s->wait_time_total += time_diff;
+
+ if (++s->counter == 1000) {
+ double period = time_after - s->reset_time;
+ double average_spent = s->spent_time_total * 1. / s->counter;
+ double average_wait = s->wait_time_total * 1. / s->counter;
+
+ printf( "main loop stats: iterations: %8ld, period: %10.2f ms, avg wait time: %10.2f ms (%.3f %%), avg exec time %10.2f ms (%.3f %%)\n",
+ s->counter,
+ mainloopstats_to_ms(period),
+ mainloopstats_to_ms(average_wait),
+ s->wait_time_total * 100. / period,
+ mainloopstats_to_ms(average_spent),
+ s->spent_time_total * 100. / period );
+
+ mainloopstats_reset( s );
+ }
+ }
+#endif /* MAIN_LOOP_STATS */
+}
int main_loop(void)
{
@@ -5070,6 +5477,11 @@ int main_loop(void)
#ifdef CONFIG_PROFILER
qemu_time += profile_getclock() - ti;
#endif
+ if (event_pending) {
+ ret = EXCP_INTERRUPT;
+ event_pending = 0;
+ break;
+ }
if (ret != EXCP_HALTED)
break;
/* all CPUs are halted ? */
@@ -5080,6 +5492,15 @@ int main_loop(void)
}
cur_cpu = env;
+#ifdef CONFIG_TRACE
+ if (tbflush_requested) {
+ tbflush_requested = 0;
+ tb_flush(env);
+ ret = EXCP_INTERRUPT;
+ } else if (exit_requested)
+ goto ExitRequested;
+#endif
+
if (shutdown_requested) {
ret = EXCP_INTERRUPT;
break;
@@ -5091,18 +5512,21 @@ int main_loop(void)
}
if (powerdown_requested) {
powerdown_requested = 0;
- qemu_system_powerdown();
+ qemu_system_powerdown();
ret = EXCP_INTERRUPT;
}
if (ret == EXCP_DEBUG) {
vm_stop(EXCP_DEBUG);
}
/* if hlt instruction, we wait until the next IRQ */
- /* XXX: use timeout computed from timers */
- if (ret == EXCP_HLT)
- timeout = 10;
- else
+ if (ret == EXCP_HLT) {
+ timeout = 10 /* _get_timers_timeout() */;
+ //write(2,"%",1);
+ }
+ else {
timeout = 0;
+ //write(2,"&",1);
+ }
} else {
timeout = 10;
}
@@ -5116,6 +5540,15 @@ int main_loop(void)
}
cpu_disable_ticks();
return ret;
+
+#ifdef CONFIG_TRACE
+ExitRequested:
+# ifdef HAS_AUDIO
+ AUD_cleanup();
+# endif
+ exit(1);
+ return 0;
+#endif
}
void help(void)
@@ -5186,6 +5619,7 @@ void help(void)
"\n"
#ifdef CONFIG_SLIRP
"-tftp prefix allow tftp access to files starting with prefix [-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
@@ -5224,6 +5658,19 @@ void help(void)
#endif
"-loadvm file start right away with a saved state (loadvm in monitor)\n"
"-vnc display start a VNC server on display\n"
+#ifdef CONFIG_TRACE
+ "-trace file create an execution trace in 'file' (implies -tracing on)\n"
+ "-tracing off start with tracing off\n"
+ "-trace_miss include tracing of cache miss addresses\n"
+ "-trace_addr include tracing of all load/store addresses\n"
+ "-dcache_load_miss cycles\n"
+ " set the dcache load miss penalty to 'cycles'\n"
+ "-dcache_store_miss cycles\n"
+ " set the dcache store miss penalty to 'cycles'\n"
+#endif
+#ifdef CONFIG_NAND
+ "-nand name[,readonly][,size=size][,pagesize=size][,extrasize=size][,erasepages=pages][,initfile=file][,file=file]"
+#endif
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
@@ -5269,6 +5716,7 @@ enum {
QEMU_OPTION_net,
QEMU_OPTION_tftp,
+ QEMU_OPTION_bootp,
QEMU_OPTION_smb,
QEMU_OPTION_redir,
@@ -5285,9 +5733,7 @@ enum {
QEMU_OPTION_no_code_copy,
QEMU_OPTION_k,
QEMU_OPTION_localtime,
- QEMU_OPTION_cirrusvga,
QEMU_OPTION_g,
- QEMU_OPTION_std_vga,
QEMU_OPTION_monitor,
QEMU_OPTION_serial,
QEMU_OPTION_parallel,
@@ -5302,6 +5748,20 @@ enum {
QEMU_OPTION_smp,
QEMU_OPTION_vnc,
QEMU_OPTION_no_acpi,
+ QEMU_OPTION_noaudio,
+ QEMU_OPTION_mic,
+#ifdef CONFIG_TRACE
+ QEMU_OPTION_trace_file,
+ QEMU_OPTION_tracing,
+ QEMU_OPTION_trace_miss,
+ QEMU_OPTION_trace_addr,
+ QEMU_OPTION_dcache_load_miss,
+ QEMU_OPTION_dcache_store_miss,
+#endif
+#ifdef CONFIG_NAND
+ QEMU_OPTION_nand,
+#endif
+ QEMU_OPTION_clock,
};
typedef struct QEMUOption {
@@ -5337,6 +5797,7 @@ const QEMUOption qemu_options[] = {
{ "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
@@ -5359,13 +5820,12 @@ const QEMUOption qemu_options[] = {
{ "kernel-kqemu", 0, QEMU_OPTION_kernel_kqemu },
#endif
#if defined(TARGET_PPC) || defined(TARGET_SPARC)
- { "g", 1, QEMU_OPTION_g },
+ { "g", HAS_ARG, QEMU_OPTION_g },
#endif
{ "localtime", 0, QEMU_OPTION_localtime },
- { "std-vga", 0, QEMU_OPTION_std_vga },
- { "monitor", 1, QEMU_OPTION_monitor },
- { "serial", 1, QEMU_OPTION_serial },
- { "parallel", 1, QEMU_OPTION_parallel },
+ { "monitor", HAS_ARG, QEMU_OPTION_monitor },
+ { "serial", HAS_ARG, QEMU_OPTION_serial },
+ { "parallel", HAS_ARG, QEMU_OPTION_parallel },
{ "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
{ "full-screen", 0, QEMU_OPTION_full_screen },
{ "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
@@ -5373,11 +5833,26 @@ const QEMUOption qemu_options[] = {
{ "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice },
{ "smp", HAS_ARG, QEMU_OPTION_smp },
{ "vnc", HAS_ARG, QEMU_OPTION_vnc },
-
+
/* temporary options */
{ "usb", 0, QEMU_OPTION_usb },
- { "cirrusvga", 0, QEMU_OPTION_cirrusvga },
{ "no-acpi", 0, QEMU_OPTION_no_acpi },
+
+ /* android stuff */
+ { "noaudio", 0, QEMU_OPTION_noaudio },
+ { "mic", HAS_ARG, QEMU_OPTION_mic },
+#ifdef CONFIG_TRACE
+ { "trace", HAS_ARG, QEMU_OPTION_trace_file },
+ { "tracing", HAS_ARG, QEMU_OPTION_tracing },
+ { "trace_miss", 0, QEMU_OPTION_trace_miss },
+ { "trace_addr", 0, QEMU_OPTION_trace_addr },
+ { "dcache_load_miss", HAS_ARG, QEMU_OPTION_dcache_load_miss },
+ { "dcache_store_miss", HAS_ARG, QEMU_OPTION_dcache_store_miss },
+#endif
+#ifdef CONFIG_NAND
+ { "nand", HAS_ARG, QEMU_OPTION_nand },
+#endif
+ { "clock", HAS_ARG, QEMU_OPTION_clock },
{ NULL },
};
@@ -5417,7 +5892,7 @@ static void read_passwords(void)
if (bs && bdrv_is_encrypted(bs)) {
term_printf("%s is encrypted.\n", bdrv_get_device_name(bs));
for(j = 0; j < 3; j++) {
- monitor_readline("Password: ",
+ monitor_readline("Password: ",
1, password, sizeof(password));
if (bdrv_set_key(bs, password) == 0)
break;
@@ -5446,10 +5921,13 @@ void register_machines(void)
qemu_register_machine(&sun4m_machine);
#endif
#elif defined(TARGET_ARM)
+ qemu_register_machine(&android_arm_machine);
+#if 0
qemu_register_machine(&integratorcp926_machine);
qemu_register_machine(&integratorcp1026_machine);
qemu_register_machine(&versatilepb_machine);
qemu_register_machine(&versatileab_machine);
+#endif
#elif defined(TARGET_SH4)
qemu_register_machine(&shix_machine);
#else
@@ -5459,6 +5937,7 @@ void register_machines(void)
#ifdef HAS_AUDIO
struct soundhw soundhw[] = {
+#if 0 /* ANDROID */
#ifdef TARGET_I386
{
"pcspk",
@@ -5507,7 +5986,7 @@ struct soundhw soundhw[] = {
0,
{ .init_pci = es1370_init }
},
-
+#endif /* ANDROID */
{ NULL, NULL, 0, 0, { NULL } }
};
@@ -5573,6 +6052,7 @@ static void select_soundhw (const char *optarg)
#ifdef _WIN32
static BOOL WINAPI qemu_ctrl_handler(DWORD type)
{
+ //qemu_del_wait_object(host_alarm,NULL,NULL);
exit(STATUS_CONTROL_C_EXIT);
return TRUE;
}
@@ -5670,19 +6150,21 @@ int main(int argc, char **argv)
for(i = 1; i < MAX_SERIAL_PORTS; i++)
serial_devices[i][0] = '\0';
serial_device_index = 0;
-
+
pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc");
for(i = 1; i < MAX_PARALLEL_PORTS; i++)
parallel_devices[i][0] = '\0';
parallel_device_index = 0;
-
+
usb_devices_index = 0;
-
+
nb_net_clients = 0;
nb_nics = 0;
/* default mac address of the first network interface */
-
+
+ android_audio_enabled = 1;
+
optind = 1;
for(;;) {
if (optind >= argc)
@@ -5697,7 +6179,7 @@ int main(int argc, char **argv)
popt = qemu_options;
for(;;) {
if (!popt->name) {
- fprintf(stderr, "%s: invalid option -- '%s'\n",
+ fprintf(stderr, "%s: invalid option -- '%s'\n",
argv[0], r);
exit(1);
}
@@ -5724,7 +6206,7 @@ int main(int argc, char **argv)
printf("Supported machines are:\n");
for(m = first_machine; m != NULL; m = m->next) {
printf("%-10s %s%s\n",
- m->name, m->desc,
+ m->name, m->desc,
m == first_machine ? " (default)" : "");
}
exit(1);
@@ -5802,7 +6284,7 @@ int main(int argc, char **argv)
break;
case QEMU_OPTION_boot:
boot_device = optarg[0];
- if (boot_device != 'a' &&
+ if (boot_device != 'a' &&
#ifdef TARGET_SPARC
// Network boot
boot_device != 'n' &&
@@ -5840,13 +6322,18 @@ int main(int argc, char **argv)
case QEMU_OPTION_tftp:
tftp_prefix = optarg;
break;
-#ifndef _WIN32
+ case QEMU_OPTION_bootp:
+ bootp_filename = optarg;
+ break;
+#if 0 /* ANDROID disabled */
case QEMU_OPTION_smb:
net_slirp_smb(optarg);
break;
#endif
case QEMU_OPTION_redir:
- net_slirp_redir(optarg);
+ if ( net_slirp_redir(optarg) < 0 ) {
+ fprintf(stderr, "qemu: could not set up redirection '%s'\n", optarg);
+ }
break;
#endif
#ifdef HAS_AUDIO
@@ -5859,12 +6346,15 @@ int main(int argc, char **argv)
break;
#endif
case QEMU_OPTION_h:
+ fprintf(stderr, "qemu: -h option used\n");
help();
break;
case QEMU_OPTION_m:
ram_size = atoi(optarg) * 1024 * 1024;
- if (ram_size <= 0)
+ if (ram_size <= 0) {
+ fprintf(stderr, "qemu: invalid RAM size '%s'\n", optarg);
help();
+ }
if (ram_size > PHYS_RAM_MAX_SIZE) {
fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n",
PHYS_RAM_MAX_SIZE / (1024 * 1024));
@@ -5875,7 +6365,7 @@ int main(int argc, char **argv)
{
int mask;
CPULogItem *item;
-
+
mask = cpu_str_to_log_mask(optarg);
if (!mask) {
printf("Log items (comma separated):\n");
@@ -5899,20 +6389,19 @@ int main(int argc, char **argv)
bios_dir = optarg;
break;
case QEMU_OPTION_S:
+#if 1 /* ANDROID */
+ fprintf(stderr, "Sorry, stopped launch is not supported in the Android emulator\n" );
+ exit(1);
+#else
start_emulation = 0;
break;
+#endif
case QEMU_OPTION_k:
keyboard_layout = optarg;
break;
case QEMU_OPTION_localtime:
rtc_utc = 0;
break;
- case QEMU_OPTION_cirrusvga:
- cirrus_vga_enabled = 1;
- break;
- case QEMU_OPTION_std_vga:
- cirrus_vga_enabled = 0;
- break;
case QEMU_OPTION_g:
{
const char *p;
@@ -5933,7 +6422,7 @@ int main(int argc, char **argv)
if (*p == 'x') {
p++;
depth = strtol(p, (char **)&p, 10);
- if (depth != 8 && depth != 15 && depth != 16 &&
+ if (depth != 8 && depth != 15 && depth != 16 &&
depth != 24 && depth != 32)
goto graphic_error;
} else if (*p == '\0') {
@@ -5941,7 +6430,7 @@ int main(int argc, char **argv)
} else {
goto graphic_error;
}
-
+
graphic_width = w;
graphic_height = h;
graphic_depth = depth;
@@ -5955,7 +6444,7 @@ int main(int argc, char **argv)
fprintf(stderr, "qemu: too many serial ports\n");
exit(1);
}
- pstrcpy(serial_devices[serial_device_index],
+ pstrcpy(serial_devices[serial_device_index],
sizeof(serial_devices[0]), optarg);
serial_device_index++;
break;
@@ -5964,7 +6453,7 @@ int main(int argc, char **argv)
fprintf(stderr, "qemu: too many parallel ports\n");
exit(1);
}
- pstrcpy(parallel_devices[parallel_device_index],
+ pstrcpy(parallel_devices[parallel_device_index],
sizeof(parallel_devices[0]), optarg);
parallel_device_index++;
break;
@@ -6021,6 +6510,49 @@ int main(int argc, char **argv)
case QEMU_OPTION_no_acpi:
acpi_enabled = 0;
break;
+ case QEMU_OPTION_clock:
+ qemu_configure_alarms(optarg);
+ break;
+ case QEMU_OPTION_noaudio:
+ android_audio_enabled = 0;
+ break;
+ case QEMU_OPTION_mic:
+ audio_input_source = (char*)optarg;
+ break;
+#ifdef CONFIG_TRACE
+ case QEMU_OPTION_trace_file:
+ trace_filename = optarg;
+ tracing = 1;
+ break;
+ case QEMU_OPTION_trace_miss:
+ trace_cache_miss = 1;
+ break;
+ case QEMU_OPTION_trace_addr:
+ trace_all_addr = 1;
+ break;
+ case QEMU_OPTION_tracing:
+ if (strcmp(optarg, "off") == 0)
+ tracing = 0;
+ else if (strcmp(optarg, "on") == 0 && trace_filename)
+ tracing = 1;
+ else {
+ fprintf(stderr, "Unexpected option to -tracing ('%s')\n",
+ optarg);
+ exit(1);
+ }
+ break;
+ case QEMU_OPTION_dcache_load_miss:
+ dcache_load_miss_penalty = atoi(optarg);
+ break;
+ case QEMU_OPTION_dcache_store_miss:
+ dcache_store_miss_penalty = atoi(optarg);
+ break;
+#endif
+#ifdef CONFIG_NAND
+ case QEMU_OPTION_nand:
+ nand_add_dev(optarg);
+ break;
+#endif
}
}
}
@@ -6030,13 +6562,14 @@ int main(int argc, char **argv)
kqemu_allowed = 0;
#endif
linux_boot = (kernel_filename != NULL);
-
- if (!linux_boot &&
- hd_filename[0] == '\0' &&
+
+ if (!linux_boot &&
+ hd_filename[0] == '\0' &&
(cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') &&
- fd_filename[0] == '\0')
+ fd_filename[0] == '\0') {
+ fprintf(stderr, "qemu: no kernel and no disk image specified\n");
help();
-
+ }
/* boot to cd by default if no hard disk */
if (hd_filename[0] == '\0' && boot_device == 'c') {
if (fd_filename[0] != '\0')
@@ -6046,13 +6579,26 @@ int main(int argc, char **argv)
}
setvbuf(stdout, NULL, _IOLBF, 0);
-
+
init_timers();
- init_timer_alarm();
+ qemu_init_alarm_timer( cpu_signal_alarm );
-#ifdef _WIN32
- socket_init();
+#ifndef _WIN32
+ /* setup sigint handler */
+ {
+ struct sigaction user_act;
+
+ sigfillset(&user_act.sa_mask);
+ user_act.sa_flags = 0;
+#if defined (TARGET_I386) && defined(USE_CODE_COPY)
+ user_act.sa_flags |= SA_ONSTACK;
#endif
+ user_act.sa_handler = sigint_handler;
+ sigaction(SIGINT, &user_act, NULL);
+ }
+#endif
+
+ socket_init();
/* init network clients */
if (nb_net_clients == 0) {
@@ -6158,7 +6704,7 @@ int main(int argc, char **argv)
if (serial_devices[i][0] != '\0') {
serial_hds[i] = qemu_chr_open(serial_devices[i]);
if (!serial_hds[i]) {
- fprintf(stderr, "qemu: could not open serial device '%s'\n",
+ fprintf(stderr, "qemu: could not open serial device '%s'\n",
serial_devices[i]);
exit(1);
}
@@ -6171,7 +6717,7 @@ int main(int argc, char **argv)
if (parallel_devices[i][0] != '\0') {
parallel_hds[i] = qemu_chr_open(parallel_devices[i]);
if (!parallel_hds[i]) {
- fprintf(stderr, "qemu: could not open parallel device '%s'\n",
+ fprintf(stderr, "qemu: could not open parallel device '%s'\n",
parallel_devices[i]);
exit(1);
}
@@ -6180,6 +6726,19 @@ int main(int argc, char **argv)
}
}
+#ifdef CONFIG_TRACE
+ if (trace_filename) {
+ trace_init(trace_filename);
+ qemu_trace_enable();
+ qemu_trace_enable_gencode();
+ qemu_trace_enable_dyngen();
+ dcache_init(dcache_size, dcache_ways, dcache_line_size,
+ dcache_replace_policy, dcache_load_miss_penalty,
+ dcache_store_miss_penalty);
+ fprintf(stderr, "-- When done tracing, exit the emulator. --\n");
+ }
+#endif
+
machine->init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline, initrd_filename);
@@ -6200,17 +6759,21 @@ int main(int argc, char **argv)
#ifdef CONFIG_GDBSTUB
if (use_gdbstub) {
if (gdbserver_start(gdbstub_port) < 0) {
- fprintf(stderr, "Could not open gdbserver socket on port %d\n",
+ fprintf(stderr, "Could not open gdbserver socket on port %d\n",
gdbstub_port);
exit(1);
} else {
printf("Waiting gdb connection on port %d\n", gdbstub_port);
}
- } else
+ } else
#endif
if (loadvm)
qemu_loadvm(loadvm);
+ /* call android-specific setup function */
+ android_emulation_setup();
+ qemu_start_alarm_timer();
+
{
/* XXX: simplify init */
read_passwords();
@@ -6218,7 +6781,10 @@ int main(int argc, char **argv)
vm_start();
}
}
+
main_loop();
- quit_timers();
+ qemu_stop_alarm_timer();
+
+ android_emulation_teardown();
return 0;
}
diff --git a/vl.h b/vl.h
index d97f485..ff954e2 100644
--- a/vl.h
+++ b/vl.h
@@ -1,8 +1,8 @@
/*
* QEMU System Emulator header
- *
+ *
* 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
@@ -38,6 +38,9 @@
#include <fcntl.h>
#include <sys/stat.h>
+#include "qemu_file.h"
+#include "qemu_timers.h"
+
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
@@ -142,7 +145,6 @@ void main_loop_wait(int timeout);
extern int ram_size;
extern int bios_size;
extern int rtc_utc;
-extern int cirrus_vga_enabled;
extern int graphic_width;
extern int graphic_height;
extern int graphic_depth;
@@ -168,14 +170,20 @@ extern int smp_cpus;
#define MOUSE_EVENT_MBUTTON 0x04
typedef void QEMUPutKBDEvent(void *opaque, int keycode);
+typedef void QEMUPutKBDEventN(void *opaque, int* keycodes, int count);
typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state);
+typedef void QEMUPutGenericEvent(void* opaque, int type, int code, int value);
void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque);
+void qemu_add_kbd_event_n_handler(QEMUPutKBDEventN *func, void *opaque);
void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute);
+void qemu_add_generic_event_handler(QEMUPutGenericEvent *func, void* opaque);
void kbd_put_keycode(int keycode);
+void kbd_put_keycodes(int* keycodes, int count);
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state);
int kbd_mouse_is_absolute(void);
+void kbd_generic_event(int type, int code, int value);
/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
constants) */
@@ -208,13 +216,13 @@ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
typedef int IOCanRWHandler(void *opaque);
typedef void IOHandler(void *opaque);
-int qemu_set_fd_handler2(int fd,
- IOCanRWHandler *fd_read_poll,
- IOHandler *fd_read,
- IOHandler *fd_write,
+int qemu_set_fd_handler2(int fd,
+ IOCanRWHandler *fd_read_poll,
+ IOHandler *fd_read,
+ IOHandler *fd_write,
void *opaque);
int qemu_set_fd_handler(int fd,
- IOHandler *fd_read,
+ IOHandler *fd_read,
IOHandler *fd_write,
void *opaque);
@@ -261,8 +269,8 @@ 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,
+ void (*chr_add_read_handler)(struct CharDriverState *s,
+ IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read, void *opaque);
int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
IOEventHandler *chr_event;
@@ -274,12 +282,14 @@ typedef struct CharDriverState {
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,
+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);
int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
+CharDriverState *qemu_chr_open(const char *filename);
+
/* consoles */
typedef struct DisplayState DisplayState;
@@ -289,10 +299,11 @@ typedef void (*vga_hw_update_ptr)(void *);
typedef void (*vga_hw_invalidate_ptr)(void *);
typedef void (*vga_hw_screen_dump_ptr)(void *, const char *);
-TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
- vga_hw_invalidate_ptr invalidate,
+TextConsole *graphic_console_init(DisplayState* ds,
+ vga_hw_update_ptr update,
+ vga_hw_invalidate_ptr invalidate,
vga_hw_screen_dump_ptr screen_dump,
- void *opaque);
+ void* opaque);
void vga_hw_update(void);
void vga_hw_invalidate(void);
void vga_hw_screen_dump(const char *filename);
@@ -326,6 +337,18 @@ struct VLANClientState {
struct VLANClientState *next;
struct VLANState *vlan;
char info_str[256];
+
+ /* statistics */
+ unsigned long tx_packets;
+ unsigned long rx_packets;
+ unsigned long tx_bytes;
+ unsigned long rx_bytes;
+ clock_t clock_start;
+ clock_t clock_last;
+ double tx_max_packet_rate;
+ double rx_max_packet_rate;
+ double tx_max_byte_rate;
+ double rx_max_byte_rate;
};
typedef struct VLANState {
@@ -349,6 +372,8 @@ void do_info_network(void);
int tap_win32_init(VLANState *vlan, const char *ifname);
void tap_win32_poll(void);
+void charpipe_win32_poll(void);
+
/* NIC info */
#define MAX_NICS 8
@@ -362,115 +387,15 @@ typedef struct NICInfo {
extern int nb_nics;
extern NICInfo nd_table[MAX_NICS];
-/* timers */
-
-typedef struct QEMUClock QEMUClock;
-typedef struct QEMUTimer QEMUTimer;
-typedef void QEMUTimerCB(void *opaque);
-
-/* The real time clock should be used only for stuff which does not
- change the virtual machine state, as it is run even if the virtual
- machine is stopped. The real time clock has a frequency of 1000
- Hz. */
-extern QEMUClock *rt_clock;
-
-/* The virtual clock is only run during the emulation. It is stopped
- when the virtual machine is stopped. Virtual timers use a high
- precision clock, usually cpu cycles (use ticks_per_sec). */
-extern QEMUClock *vm_clock;
-
-int64_t qemu_get_clock(QEMUClock *clock);
-
-QEMUTimer *qemu_new_timer(QEMUClock *clock, QEMUTimerCB *cb, void *opaque);
-void qemu_free_timer(QEMUTimer *ts);
-void qemu_del_timer(QEMUTimer *ts);
-void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time);
-int qemu_timer_pending(QEMUTimer *ts);
-
-extern int64_t ticks_per_sec;
-extern int pit_min_timer_count;
-
-int64_t cpu_get_ticks(void);
-void cpu_enable_ticks(void);
-void cpu_disable_ticks(void);
-
/* VM Load/Save */
-typedef FILE QEMUFile;
-
-void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size);
-void qemu_put_byte(QEMUFile *f, int v);
-void qemu_put_be16(QEMUFile *f, unsigned int v);
-void qemu_put_be32(QEMUFile *f, unsigned int v);
-void qemu_put_be64(QEMUFile *f, uint64_t v);
-int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size);
-int qemu_get_byte(QEMUFile *f);
-unsigned int qemu_get_be16(QEMUFile *f);
-unsigned int qemu_get_be32(QEMUFile *f);
-uint64_t qemu_get_be64(QEMUFile *f);
-
-static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv)
-{
- qemu_put_be64(f, *pv);
-}
-
-static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv)
-{
- qemu_put_be32(f, *pv);
-}
-
-static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv)
-{
- qemu_put_be16(f, *pv);
-}
-
-static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv)
-{
- qemu_put_byte(f, *pv);
-}
-
-static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv)
-{
- *pv = qemu_get_be64(f);
-}
-
-static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv)
-{
- *pv = qemu_get_be32(f);
-}
-
-static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv)
-{
- *pv = qemu_get_be16(f);
-}
-
-static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv)
-{
- *pv = qemu_get_byte(f);
-}
-
-#if TARGET_LONG_BITS == 64
-#define qemu_put_betl qemu_put_be64
-#define qemu_get_betl qemu_get_be64
-#define qemu_put_betls qemu_put_be64s
-#define qemu_get_betls qemu_get_be64s
-#else
-#define qemu_put_betl qemu_put_be32
-#define qemu_get_betl qemu_get_be32
-#define qemu_put_betls qemu_put_be32s
-#define qemu_get_betls qemu_get_be32s
-#endif
-
-int64_t qemu_ftell(QEMUFile *f);
-int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence);
-
typedef void SaveStateHandler(QEMUFile *f, void *opaque);
typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id);
int qemu_loadvm(const char *filename);
int qemu_savevm(const char *filename);
-int register_savevm(const char *idstr,
- int instance_id,
+int register_savevm(const char *idstr,
+ int instance_id,
int version_id,
SaveStateHandler *save_state,
LoadStateHandler *load_state,
@@ -497,7 +422,7 @@ extern BlockDriver bdrv_vvfat;
void bdrv_init(void);
BlockDriver *bdrv_find_format(const char *format_name);
-int bdrv_create(BlockDriver *drv,
+int bdrv_create(BlockDriver *drv,
const char *filename, int64_t size_in_sectors,
const char *backing_file, int flags);
BlockDriverState *bdrv_new(const char *device_name);
@@ -506,9 +431,9 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot);
int bdrv_open2(BlockDriverState *bs, const char *filename, int snapshot,
BlockDriver *drv);
void bdrv_close(BlockDriverState *bs);
-int bdrv_read(BlockDriverState *bs, int64_t sector_num,
+int bdrv_read(BlockDriverState *bs, int64_t sector_num,
uint8_t *buf, int nb_sectors);
-int bdrv_write(BlockDriverState *bs, int64_t sector_num,
+int bdrv_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors);
void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
int bdrv_commit(BlockDriverState *bs);
@@ -523,11 +448,11 @@ void bdrv_flush(BlockDriverState *bs);
#define BIOS_ATA_TRANSLATION_NONE 1
#define BIOS_ATA_TRANSLATION_LBA 2
-void bdrv_set_geometry_hint(BlockDriverState *bs,
+void bdrv_set_geometry_hint(BlockDriverState *bs,
int cyls, int heads, int secs);
void bdrv_set_type_hint(BlockDriverState *bs, int type);
void bdrv_set_translation_hint(BlockDriverState *bs, int translation);
-void bdrv_get_geometry_hint(BlockDriverState *bs,
+void bdrv_get_geometry_hint(BlockDriverState *bs,
int *pcyls, int *pheads, int *psecs);
int bdrv_get_type_hint(BlockDriverState *bs);
int bdrv_get_translation_hint(BlockDriverState *bs);
@@ -536,7 +461,7 @@ int bdrv_is_read_only(BlockDriverState *bs);
int bdrv_is_inserted(BlockDriverState *bs);
int bdrv_is_locked(BlockDriverState *bs);
void bdrv_set_locked(BlockDriverState *bs, int locked);
-void bdrv_set_change_cb(BlockDriverState *bs,
+void bdrv_set_change_cb(BlockDriverState *bs,
void (*change_cb)(void *opaque), void *opaque);
void bdrv_get_format(BlockDriverState *bs, char *buf, int buf_size);
void bdrv_info(void);
@@ -544,7 +469,7 @@ BlockDriverState *bdrv_find(const char *name);
void bdrv_iterate(void (*it)(void *opaque, const char *name), void *opaque);
int bdrv_is_encrypted(BlockDriverState *bs);
int bdrv_set_key(BlockDriverState *bs, const char *key);
-void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
+void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
void *opaque);
const char *bdrv_get_device_name(BlockDriverState *bs);
@@ -554,7 +479,7 @@ int qcow_compress_cluster(BlockDriverState *bs, int64_t sector_num,
#ifndef QEMU_TOOL
-typedef void QEMUMachineInitFunc(int ram_size, int vga_ram_size,
+typedef void QEMUMachineInitFunc(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,
@@ -579,9 +504,9 @@ extern target_phys_addr_t isa_mem_base;
typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data);
typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
-int register_ioport_read(int start, int length, int size,
+int register_ioport_read(int start, int length, int size,
IOPortReadFunc *func, void *opaque);
-int register_ioport_write(int start, int length, int size,
+int register_ioport_write(int start, int length, int size,
IOPortWriteFunc *func, void *opaque);
void isa_unassign_ioport(int start, int length);
@@ -592,11 +517,11 @@ extern target_phys_addr_t pci_mem_base;
typedef struct PCIBus PCIBus;
typedef struct PCIDevice PCIDevice;
-typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
+typedef void PCIConfigWriteFunc(PCIDevice *pci_dev,
uint32_t address, uint32_t data, int len);
-typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev,
+typedef uint32_t PCIConfigReadFunc(PCIDevice *pci_dev,
uint32_t address, int len);
-typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
+typedef void PCIMapIORegionFunc(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type);
#define PCI_ADDRESS_SPACE_MEM 0x00
@@ -635,7 +560,7 @@ struct PCIDevice {
int devfn;
char name[64];
PCIIORegion io_regions[PCI_NUM_REGIONS];
-
+
/* do not access the following fields */
PCIConfigReadFunc *config_read;
PCIConfigWriteFunc *config_write;
@@ -645,18 +570,18 @@ struct PCIDevice {
PCIDevice *pci_register_device(PCIBus *bus, const char *name,
int instance_size, int devfn,
- PCIConfigReadFunc *config_read,
+ PCIConfigReadFunc *config_read,
PCIConfigWriteFunc *config_write);
-void pci_register_io_region(PCIDevice *pci_dev, int region_num,
- uint32_t size, int type,
+void pci_register_io_region(PCIDevice *pci_dev, int region_num,
+ 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 pci_default_read_config(PCIDevice *d,
uint32_t address, int len);
-void pci_default_write_config(PCIDevice *d,
+void pci_default_write_config(PCIDevice *d,
uint32_t address, uint32_t val, int len);
void generic_pci_save(QEMUFile* f, void *opaque);
int generic_pci_load(QEMUFile* f, void *opaque, int version_id);
@@ -724,16 +649,17 @@ extern struct soundhw soundhw[];
#define VGA_RAM_SIZE (8192 * 1024)
struct DisplayState {
- uint8_t *data;
- int linesize;
- int depth;
- int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */
- int width;
- int height;
- void *opaque;
+ uint8_t* data;
+ int linesize;
+ int depth;
+ int bgr; /* BGR color order instead of RGB. Only valid for depth == 32 */
+ int width;
+ int height;
+ void* opaque;
+ int rotation; /* 0, 1, 2 or 3 */
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_resize)(struct DisplayState *s, int w, int h, int rotation);
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);
};
@@ -743,20 +669,17 @@ static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
s->dpy_update(s, x, y, w, h);
}
-static inline void dpy_resize(DisplayState *s, int w, int h)
+static inline void dpy_resize(DisplayState *s, int w, int h, int rot)
{
- s->dpy_resize(s, w, h);
+ s->dpy_resize(s, w, h, rot);
}
-int vga_initialize(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
+int vga_initialize(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);
-/* cirrus_vga.c */
-void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size);
-void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
- unsigned long vga_ram_offset, int vga_ram_size);
+/* irq.h */
+typedef struct IRQState *qemu_irq;
/* sdl.c */
void sdl_display_init(DisplayState *ds, int full_screen);
@@ -815,7 +738,7 @@ extern BlockDriverState *fd_table[MAX_FD];
typedef struct fdctrl_t fdctrl_t;
-fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
+fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
uint32_t io_base,
BlockDriverState **fds);
int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num);
@@ -979,29 +902,6 @@ void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdadd
/* sun4u.c */
extern QEMUMachine sun4u_machine;
-/* NVRAM helpers */
-#include "hw/m48t59.h"
-
-void NVRAM_set_byte (m48t59_t *nvram, uint32_t addr, uint8_t value);
-uint8_t NVRAM_get_byte (m48t59_t *nvram, uint32_t addr);
-void NVRAM_set_word (m48t59_t *nvram, uint32_t addr, uint16_t value);
-uint16_t NVRAM_get_word (m48t59_t *nvram, uint32_t addr);
-void NVRAM_set_lword (m48t59_t *nvram, uint32_t addr, uint32_t value);
-uint32_t NVRAM_get_lword (m48t59_t *nvram, uint32_t addr);
-void NVRAM_set_string (m48t59_t *nvram, uint32_t addr,
- const unsigned char *str, uint32_t max);
-int NVRAM_get_string (m48t59_t *nvram, uint8_t *dst, uint16_t addr, int max);
-void NVRAM_set_crc (m48t59_t *nvram, uint32_t addr,
- uint32_t start, uint32_t count);
-int PPC_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
- const unsigned char *arch,
- uint32_t RAM_size, int boot_device,
- uint32_t kernel_image, uint32_t kernel_size,
- const char *cmdline,
- uint32_t initrd_image, uint32_t initrd_size,
- uint32_t NVRAM_image,
- int width, int height, int depth);
-
/* adb.c */
#define MAX_ADB_DEVICES 16
@@ -1034,9 +934,9 @@ int adb_request(ADBBusState *s, uint8_t *buf_out,
const uint8_t *buf, int len);
int adb_poll(ADBBusState *s, uint8_t *buf_out);
-ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
- ADBDeviceRequest *devreq,
- ADBDeviceReset *devreset,
+ADBDevice *adb_register_device(ADBBusState *s, int devaddr,
+ ADBDeviceRequest *devreq,
+ ADBDeviceReset *devreset,
void *opaque);
void adb_kbd_init(ADBBusState *bus);
void adb_mouse_init(ADBBusState *bus);
@@ -1072,48 +972,22 @@ int32_t scsi_send_command(SCSIDevice *s, uint32_t tag, uint8_t *buf, int lun);
int scsi_read_data(SCSIDevice *s, uint8_t *data, uint32_t len);
int scsi_write_data(SCSIDevice *s, uint8_t *data, uint32_t len);
-/* lsi53c895a.c */
-void lsi_scsi_attach(void *opaque, BlockDriverState *bd, int id);
-void *lsi_scsi_init(PCIBus *bus, int devfn);
-
-/* integratorcp.c */
-extern QEMUMachine integratorcp926_machine;
-extern QEMUMachine integratorcp1026_machine;
-
/* versatilepb.c */
extern QEMUMachine versatilepb_machine;
extern QEMUMachine versatileab_machine;
-/* ps2.c */
-void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg);
-void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg);
-void ps2_write_mouse(void *, int val);
-void ps2_write_keyboard(void *, int val);
-uint32_t ps2_read_data(void *);
-void ps2_queue(void *, int b);
-void ps2_keyboard_set_translation(void *opaque, int mode);
-
-/* smc91c111.c */
-void smc91c111_init(NICInfo *, uint32_t, void *, int);
-
-/* pl110.c */
-void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, int);
+/* android_arm */
+extern QEMUMachine android_arm_machine;
+extern int android_audio_enabled;
+extern char* audio_input_source;
-/* pl011.c */
-void pl011_init(uint32_t base, void *pic, int irq, CharDriverState *chr);
-/* pl050.c */
-void pl050_init(uint32_t base, void *pic, int irq, int is_mouse);
-
-/* pl080.c */
-void *pl080_init(uint32_t base, void *pic, int irq);
-
-/* pl190.c */
-void *pl190_init(uint32_t base, void *parent, int irq, int fiq);
+/* smc91c111.c */
+void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
/* 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_boot.c */
@@ -1121,35 +995,13 @@ void arm_load_kernel(int ram_size, const char *kernel_filename,
const char *kernel_cmdline, const char *initrd_filename,
int board_id);
-/* sh7750.c */
-struct SH7750State;
-
-struct SH7750State *sh7750_init(CPUState * cpu);
-
-typedef struct {
- /* The callback will be triggered if any of the designated lines change */
- uint16_t portamask_trigger;
- uint16_t portbmask_trigger;
- /* Return 0 if no action was taken */
- int (*port_change_cb) (uint16_t porta, uint16_t portb,
- uint16_t * periph_pdtra,
- uint16_t * periph_portdira,
- uint16_t * periph_pdtrb,
- uint16_t * periph_portdirb);
-} sh7750_io_device;
-
-int sh7750_register_io_device(struct SH7750State *s,
- sh7750_io_device * device);
-/* tc58128.c */
-int tc58128_init(struct SH7750State *s, char *zone1, char *zone2);
-
/* NOR flash devices */
typedef struct pflash_t pflash_t;
pflash_t *pflash_register (target_ulong base, ram_addr_t off,
BlockDriverState *bs,
target_ulong sector_len, int nb_blocs, int width,
- uint16_t id0, uint16_t id1,
+ uint16_t id0, uint16_t id1,
uint16_t id2, uint16_t id3);
#endif /* defined(QEMU_TOOL) */
diff --git a/vnc.c b/vnc.c
index 1bea966..b4485b4 100644
--- a/vnc.c
+++ b/vnc.c
@@ -24,7 +24,7 @@
*/
#include "vl.h"
-#include "qemu_socket.h"
+#include "sockets.h"
#define VNC_REFRESH_INTERVAL (1000 / 30)
@@ -163,7 +163,7 @@ static void vnc_framebuffer_update(VncState *vs, int x, int y, int w, int h,
vnc_write_s32(vs, encoding);
}
-static void vnc_dpy_resize(DisplayState *ds, int w, int h)
+static void vnc_dpy_resize(DisplayState *ds, int w, int h, int rotation)
{
VncState *vs = ds->opaque;
@@ -522,7 +522,7 @@ static int vnc_client_io_error(VncState *vs, int ret, int last_errno)
return 0;
qemu_set_fd_handler2(vs->csock, NULL, NULL, NULL, NULL);
- closesocket(vs->csock);
+ socket_close(vs->csock);
vs->csock = -1;
buffer_reset(&vs->input);
buffer_reset(&vs->output);
@@ -543,7 +543,7 @@ static void vnc_client_write(void *opaque)
VncState *vs = opaque;
ret = send(vs->csock, vs->output.buffer, vs->output.offset, 0);
- ret = vnc_client_io_error(vs, ret, socket_error());
+ ret = vnc_client_io_error(vs, ret, socket_errno);
if (!ret)
return;
@@ -569,7 +569,7 @@ static void vnc_client_read(void *opaque)
buffer_reserve(&vs->input, 4096);
ret = recv(vs->csock, buffer_end(&vs->input), 4096, 0);
- ret = vnc_client_io_error(vs, ret, socket_error());
+ ret = vnc_client_io_error(vs, ret, socket_errno);
if (!ret)
return;
@@ -840,7 +840,7 @@ static void set_pixel_format(VncState *vs,
vs->send_hextile_tile = send_hextile_tile_generic;
}
- vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height);
+ vnc_dpy_resize(vs->ds, vs->ds->width, vs->ds->height, 0);
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
memset(vs->old_data, 42, vs->ds->linesize * vs->ds->height);
@@ -1019,7 +1019,7 @@ static void vnc_listen_read(void *opaque)
void vnc_display_init(DisplayState *ds, int display)
{
struct sockaddr_in addr;
- int reuse_addr, ret;
+ int ret;
VncState *vs;
vs = qemu_mallocz(sizeof(VncState));
@@ -1051,9 +1051,7 @@ void vnc_display_init(DisplayState *ds, int display)
addr.sin_port = htons(5900 + display);
memset(&addr.sin_addr, 0, sizeof(addr.sin_addr));
- reuse_addr = 1;
- ret = setsockopt(vs->lsock, SOL_SOCKET, SO_REUSEADDR,
- (const char *)&reuse_addr, sizeof(reuse_addr));
+ ret = socket_set_xreuseaddr(vs->lsock);
if (ret == -1) {
fprintf(stderr, "setsockopt() failed\n");
exit(1);
@@ -1081,5 +1079,5 @@ void vnc_display_init(DisplayState *ds, int display)
memset(vs->dirty_row, 0xFF, sizeof(vs->dirty_row));
- vnc_dpy_resize(vs->ds, 640, 400);
+ vnc_dpy_resize(vs->ds, 640, 400, 0);
}